Upload 2.0.2 master 2.0.2
authorAlberto Mardegan <mardy@users.sourceforge.net>
Wed, 6 Jul 2011 16:18:49 +0000 (19:18 +0300)
committerAlberto Mardegan <mardy@users.sourceforge.net>
Wed, 6 Jul 2011 16:18:49 +0000 (19:18 +0300)
521 files changed:
CHANGELOG.txt [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
CREDITS.txt [new file with mode: 0644]
Doxyfile [new file with mode: 0644]
INSTALL.txt [new file with mode: 0644]
LICENSE.txt [new file with mode: 0644]
TODO.txt [new file with mode: 0644]
archivers/dir.c [new file with mode: 0644]
archivers/grp.c [new file with mode: 0644]
archivers/hog.c [new file with mode: 0644]
archivers/lzma.c [new file with mode: 0644]
archivers/mvl.c [new file with mode: 0644]
archivers/qpak.c [new file with mode: 0644]
archivers/wad.c [new file with mode: 0644]
archivers/zip.c [new file with mode: 0644]
extras/PhysFS.NET/AssemblyInfo.cs [new file with mode: 0755]
extras/PhysFS.NET/PhysFS.NET.csproj [new file with mode: 0755]
extras/PhysFS.NET/PhysFS.NET.sln [new file with mode: 0755]
extras/PhysFS.NET/PhysFS.cs [new file with mode: 0755]
extras/PhysFS.NET/PhysFSFileStream.cs [new file with mode: 0755]
extras/PhysFS.NET/PhysFS_DLL.cs [new file with mode: 0755]
extras/PhysFS.NET/README.txt [new file with mode: 0755]
extras/PhysFS.NET/TestApp/App.ico [new file with mode: 0755]
extras/PhysFS.NET/TestApp/AssemblyInfo.cs [new file with mode: 0755]
extras/PhysFS.NET/TestApp/TestApp.csproj [new file with mode: 0755]
extras/PhysFS.NET/TestApp/TestApp.sln [new file with mode: 0755]
extras/PhysFS.NET/TestApp/TestAppForm.cs [new file with mode: 0755]
extras/PhysFS.NET/TestApp/TestAppForm.resx [new file with mode: 0755]
extras/abs-file.h [new file with mode: 0644]
extras/casefolding.txt [new file with mode: 0644]
extras/globbing.c [new file with mode: 0644]
extras/globbing.h [new file with mode: 0644]
extras/ignorecase.c [new file with mode: 0644]
extras/ignorecase.h [new file with mode: 0644]
extras/makecasefoldhashtable.pl [new file with mode: 0755]
extras/physfs_rb/installer.rb [new file with mode: 0644]
extras/physfs_rb/physfs/extconf.rb [new file with mode: 0644]
extras/physfs_rb/physfs/install.rb [new file with mode: 0644]
extras/physfs_rb/physfs/make_install_test.sh [new file with mode: 0755]
extras/physfs_rb/physfs/physfs.rb [new file with mode: 0644]
extras/physfs_rb/physfs/physfsrwops.c [new file with mode: 0644]
extras/physfs_rb/physfs/physfsrwops.h [new file with mode: 0644]
extras/physfs_rb/physfs/rb_physfs.c [new file with mode: 0644]
extras/physfs_rb/physfs/rb_physfs.h [new file with mode: 0644]
extras/physfs_rb/physfs/rb_physfs_file.c [new file with mode: 0644]
extras/physfs_rb/physfs/rb_physfs_file.h [new file with mode: 0644]
extras/physfs_rb/physfs/rb_sdl_rwops.c [new file with mode: 0644]
extras/physfs_rb/physfs/rb_sdl_rwops.h [new file with mode: 0644]
extras/physfs_rb/physfs/test/test_physfs.rb [new file with mode: 0644]
extras/physfshttpd.c [new file with mode: 0644]
extras/physfsrwops.c [new file with mode: 0644]
extras/physfsrwops.h [new file with mode: 0644]
extras/physfsunpack.c [new file with mode: 0644]
extras/selfextract.c [new file with mode: 0644]
lzma/7zC.txt [new file with mode: 0644]
lzma/7zFormat.txt [new file with mode: 0644]
lzma/C/7zCrc.c [new file with mode: 0644]
lzma/C/7zCrc.h [new file with mode: 0644]
lzma/C/7zCrcT8.c [new file with mode: 0644]
lzma/C/Alloc.c [new file with mode: 0644]
lzma/C/Alloc.h [new file with mode: 0644]
lzma/C/Archive/7z/7zAlloc.c [new file with mode: 0644]
lzma/C/Archive/7z/7zAlloc.h [new file with mode: 0644]
lzma/C/Archive/7z/7zBuffer.c [new file with mode: 0644]
lzma/C/Archive/7z/7zBuffer.h [new file with mode: 0644]
lzma/C/Archive/7z/7zDecode.c [new file with mode: 0644]
lzma/C/Archive/7z/7zDecode.h [new file with mode: 0644]
lzma/C/Archive/7z/7zExtract.c [new file with mode: 0644]
lzma/C/Archive/7z/7zExtract.h [new file with mode: 0644]
lzma/C/Archive/7z/7zHeader.c [new file with mode: 0644]
lzma/C/Archive/7z/7zHeader.h [new file with mode: 0644]
lzma/C/Archive/7z/7zIn.c [new file with mode: 0644]
lzma/C/Archive/7z/7zIn.h [new file with mode: 0644]
lzma/C/Archive/7z/7zItem.c [new file with mode: 0644]
lzma/C/Archive/7z/7zItem.h [new file with mode: 0644]
lzma/C/Archive/7z/7zMain.c [new file with mode: 0644]
lzma/C/Archive/7z/7zMethodID.c [new file with mode: 0644]
lzma/C/Archive/7z/7zMethodID.h [new file with mode: 0644]
lzma/C/Archive/7z/7z_C.dsp [new file with mode: 0644]
lzma/C/Archive/7z/7z_C.dsw [new file with mode: 0644]
lzma/C/Archive/7z/makefile [new file with mode: 0644]
lzma/C/Archive/7z/makefile.gcc [new file with mode: 0644]
lzma/C/Compress/Branch/BranchARM.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchARM.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchARMThumb.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchARMThumb.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchIA64.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchIA64.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchPPC.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchPPC.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchSPARC.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchSPARC.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchTypes.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchX86.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchX86.h [new file with mode: 0644]
lzma/C/Compress/Branch/BranchX86_2.c [new file with mode: 0644]
lzma/C/Compress/Branch/BranchX86_2.h [new file with mode: 0644]
lzma/C/Compress/Huffman/HuffmanEncode.c [new file with mode: 0644]
lzma/C/Compress/Huffman/HuffmanEncode.h [new file with mode: 0644]
lzma/C/Compress/Lz/LzHash.h [new file with mode: 0644]
lzma/C/Compress/Lz/MatchFinder.c [new file with mode: 0644]
lzma/C/Compress/Lz/MatchFinder.h [new file with mode: 0644]
lzma/C/Compress/Lz/MatchFinderMt.c [new file with mode: 0644]
lzma/C/Compress/Lz/MatchFinderMt.h [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaDecode.c [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaDecode.h [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaDecodeSize.c [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaStateDecode.c [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaStateDecode.h [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaStateTest.c [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaTest.c [new file with mode: 0644]
lzma/C/Compress/Lzma/LzmaTypes.h [new file with mode: 0644]
lzma/C/CpuArch.h [new file with mode: 0644]
lzma/C/IStream.h [new file with mode: 0644]
lzma/C/Sort.c [new file with mode: 0644]
lzma/C/Sort.h [new file with mode: 0644]
lzma/C/Threads.c [new file with mode: 0644]
lzma/C/Threads.h [new file with mode: 0644]
lzma/C/Types.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7z.ico [new file with mode: 0755]
lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zCompressionMode.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zDecode.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zDecode.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zEncode.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zEncode.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zExtract.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zFolderInStream.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zHandler.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zHandler.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zHeader.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zHeader.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zIn.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zIn.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zItem.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zOut.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zOut.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zProperties.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zProperties.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zRegister.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zSpecStream.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zUpdate.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/7zUpdate.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/7z/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Archive.def [new file with mode: 0644]
lzma/CPP/7zip/Archive/Archive2.def [new file with mode: 0644]
lzma/CPP/7zip/Archive/ArchiveExports.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/CoderMixer2.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/CoderMixer2MT.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/CoderMixer2MT.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/CrossThreadProgress.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/CrossThreadProgress.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/DummyOutStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/DummyOutStream.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/HandlerOut.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/HandlerOut.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/InStreamWithCRC.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/InStreamWithCRC.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/ItemNameUtils.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/ItemNameUtils.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/MultiStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/MultiStream.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/ParseProperties.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/Common/ParseProperties.h [new file with mode: 0644]
lzma/CPP/7zip/Archive/DllExports2.cpp [new file with mode: 0644]
lzma/CPP/7zip/Archive/IArchive.h [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Alone7z/Alone.dsp [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Alone7z/Alone.dsw [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Alone7z/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Alone7z/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Alone7z/makefile [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Alone7z/resource.rc [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zExtractR/makefile [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zExtractR/resource.rc [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zR/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zR/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zR/makefile [new file with mode: 0644]
lzma/CPP/7zip/Bundles/Format7zR/resource.rc [new file with mode: 0644]
lzma/CPP/7zip/Common/CreateCoder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/CreateCoder.h [new file with mode: 0644]
lzma/CPP/7zip/Common/FilePathAutoRename.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/FilePathAutoRename.h [new file with mode: 0644]
lzma/CPP/7zip/Common/FileStreams.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/FileStreams.h [new file with mode: 0644]
lzma/CPP/7zip/Common/FilterCoder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/FilterCoder.h [new file with mode: 0644]
lzma/CPP/7zip/Common/InBuffer.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/InBuffer.h [new file with mode: 0644]
lzma/CPP/7zip/Common/InOutTempBuffer.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/InOutTempBuffer.h [new file with mode: 0644]
lzma/CPP/7zip/Common/LimitedStreams.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/LimitedStreams.h [new file with mode: 0644]
lzma/CPP/7zip/Common/LockedStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/LockedStream.h [new file with mode: 0644]
lzma/CPP/7zip/Common/MethodId.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/MethodId.h [new file with mode: 0644]
lzma/CPP/7zip/Common/MethodProps.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/MethodProps.h [new file with mode: 0644]
lzma/CPP/7zip/Common/OffsetStream.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/OffsetStream.h [new file with mode: 0644]
lzma/CPP/7zip/Common/OutBuffer.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/OutBuffer.h [new file with mode: 0644]
lzma/CPP/7zip/Common/ProgressUtils.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/ProgressUtils.h [new file with mode: 0644]
lzma/CPP/7zip/Common/RegisterArc.h [new file with mode: 0644]
lzma/CPP/7zip/Common/RegisterCodec.h [new file with mode: 0644]
lzma/CPP/7zip/Common/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Common/StreamBinder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/StreamBinder.h [new file with mode: 0644]
lzma/CPP/7zip/Common/StreamObjects.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/StreamObjects.h [new file with mode: 0644]
lzma/CPP/7zip/Common/StreamUtils.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/StreamUtils.h [new file with mode: 0644]
lzma/CPP/7zip/Common/VirtThread.cpp [new file with mode: 0644]
lzma/CPP/7zip/Common/VirtThread.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/ARM.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/ARM.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/ARMThumb.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/ARMThumb.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/BCJ2Register.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/BCJRegister.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/BranchCoder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/BranchCoder.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/BranchRegister.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/IA64.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/IA64.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/PPC.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/PPC.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/SPARC.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/SPARC.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/x86.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/x86.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/x86_2.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Branch/x86_2.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/ByteSwap/ByteSwap.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/ByteSwap/ByteSwap.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/ByteSwap/ByteSwapRegister.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/ByteSwap/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/ByteSwap/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/CodecExports.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Copy/CopyCoder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Copy/CopyCoder.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/Copy/CopyRegister.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Copy/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/Copy/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZ/LZOutWindow.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZ/LZOutWindow.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZ/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/LZMA.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/LZMADecoder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/LZMADecoder.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/LZMARegister.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/AloneLZMA.dsp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/AloneLZMA.dsw [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRam.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRam.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRamDecode.c [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRamDecode.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/makefile [new file with mode: 0644]
lzma/CPP/7zip/Compress/LZMA_Alone/makefile.gcc [new file with mode: 0644]
lzma/CPP/7zip/Compress/RangeCoder/RangeCoder.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBit.cpp [new file with mode: 0644]
lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBit.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBitTree.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/RangeCoder/RangeCoderOpt.h [new file with mode: 0644]
lzma/CPP/7zip/Compress/RangeCoder/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/ICoder.h [new file with mode: 0644]
lzma/CPP/7zip/IDecl.h [new file with mode: 0644]
lzma/CPP/7zip/IPassword.h [new file with mode: 0644]
lzma/CPP/7zip/IProgress.h [new file with mode: 0644]
lzma/CPP/7zip/IStream.h [new file with mode: 0644]
lzma/CPP/7zip/MyVersion.h [new file with mode: 0644]
lzma/CPP/7zip/MyVersionInfo.rc [new file with mode: 0644]
lzma/CPP/7zip/PropID.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Client7z/Client7z.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Client7z/Client7z.dsp [new file with mode: 0644]
lzma/CPP/7zip/UI/Client7z/Client7z.dsw [new file with mode: 0644]
lzma/CPP/7zip/UI/Client7z/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Client7z/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Client7z/makefile [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveCommandLine.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveName.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveName.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/DefaultName.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/DefaultName.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/DirItem.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/EnumDirItems.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/EnumDirItems.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ExitCode.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/Extract.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/Extract.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ExtractMode.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ExtractingFilePath.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/IFileExtractCallback.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/LoadCodecs.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/LoadCodecs.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/OpenArchive.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/OpenArchive.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/PropIDUtils.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/PropIDUtils.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/Property.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/SetProperties.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/SetProperties.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/SortUtils.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/SortUtils.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/TempFiles.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/TempFiles.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/Update.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/Update.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdateAction.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdateAction.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdateCallback.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdateCallback.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdatePair.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdatePair.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdateProduce.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/UpdateProduce.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/WorkDir.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/WorkDir.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Common/ZipRegistry.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/ConsoleClose.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/ConsoleClose.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/List.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/List.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/Main.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/MainAr.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/OpenCallbackConsole.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/OpenCallbackConsole.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/PercentPrinter.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/PercentPrinter.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/StdAfx.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/StdAfx.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/UserInputUtils.cpp [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/UserInputUtils.h [new file with mode: 0644]
lzma/CPP/7zip/UI/Console/afxres.h [new file with mode: 0644]
lzma/CPP/Build.mak [new file with mode: 0644]
lzma/CPP/Common/AutoPtr.h [new file with mode: 0644]
lzma/CPP/Common/Buffer.h [new file with mode: 0644]
lzma/CPP/Common/CRC.cpp [new file with mode: 0644]
lzma/CPP/Common/C_FileIO.cpp [new file with mode: 0644]
lzma/CPP/Common/C_FileIO.h [new file with mode: 0644]
lzma/CPP/Common/ComTry.h [new file with mode: 0644]
lzma/CPP/Common/CommandLineParser.cpp [new file with mode: 0644]
lzma/CPP/Common/CommandLineParser.h [new file with mode: 0644]
lzma/CPP/Common/Defs.h [new file with mode: 0644]
lzma/CPP/Common/DynamicBuffer.h [new file with mode: 0644]
lzma/CPP/Common/IntToString.cpp [new file with mode: 0644]
lzma/CPP/Common/IntToString.h [new file with mode: 0644]
lzma/CPP/Common/ListFileUtils.cpp [new file with mode: 0644]
lzma/CPP/Common/ListFileUtils.h [new file with mode: 0644]
lzma/CPP/Common/MyCom.h [new file with mode: 0644]
lzma/CPP/Common/MyException.h [new file with mode: 0644]
lzma/CPP/Common/MyGuidDef.h [new file with mode: 0644]
lzma/CPP/Common/MyInitGuid.h [new file with mode: 0644]
lzma/CPP/Common/MyString.cpp [new file with mode: 0644]
lzma/CPP/Common/MyString.h [new file with mode: 0644]
lzma/CPP/Common/MyUnknown.h [new file with mode: 0644]
lzma/CPP/Common/MyVector.cpp [new file with mode: 0644]
lzma/CPP/Common/MyVector.h [new file with mode: 0644]
lzma/CPP/Common/MyWindows.h [new file with mode: 0644]
lzma/CPP/Common/NewHandler.cpp [new file with mode: 0644]
lzma/CPP/Common/NewHandler.h [new file with mode: 0644]
lzma/CPP/Common/StdAfx.h [new file with mode: 0644]
lzma/CPP/Common/StdInStream.cpp [new file with mode: 0644]
lzma/CPP/Common/StdInStream.h [new file with mode: 0644]
lzma/CPP/Common/StdOutStream.cpp [new file with mode: 0644]
lzma/CPP/Common/StdOutStream.h [new file with mode: 0644]
lzma/CPP/Common/StringConvert.cpp [new file with mode: 0644]
lzma/CPP/Common/StringConvert.h [new file with mode: 0644]
lzma/CPP/Common/StringToInt.cpp [new file with mode: 0644]
lzma/CPP/Common/StringToInt.h [new file with mode: 0644]
lzma/CPP/Common/Types.h [new file with mode: 0644]
lzma/CPP/Common/UTFConvert.cpp [new file with mode: 0644]
lzma/CPP/Common/UTFConvert.h [new file with mode: 0644]
lzma/CPP/Common/Wildcard.cpp [new file with mode: 0644]
lzma/CPP/Common/Wildcard.h [new file with mode: 0644]
lzma/CPP/Windows/DLL.cpp [new file with mode: 0644]
lzma/CPP/Windows/DLL.h [new file with mode: 0644]
lzma/CPP/Windows/Defs.h [new file with mode: 0644]
lzma/CPP/Windows/Error.cpp [new file with mode: 0644]
lzma/CPP/Windows/Error.h [new file with mode: 0644]
lzma/CPP/Windows/FileDir.cpp [new file with mode: 0644]
lzma/CPP/Windows/FileDir.h [new file with mode: 0644]
lzma/CPP/Windows/FileFind.cpp [new file with mode: 0644]
lzma/CPP/Windows/FileFind.h [new file with mode: 0644]
lzma/CPP/Windows/FileIO.cpp [new file with mode: 0644]
lzma/CPP/Windows/FileIO.h [new file with mode: 0644]
lzma/CPP/Windows/FileMapping.cpp [new file with mode: 0644]
lzma/CPP/Windows/FileMapping.h [new file with mode: 0644]
lzma/CPP/Windows/FileName.cpp [new file with mode: 0644]
lzma/CPP/Windows/FileName.h [new file with mode: 0644]
lzma/CPP/Windows/Handle.h [new file with mode: 0644]
lzma/CPP/Windows/MemoryLock.cpp [new file with mode: 0644]
lzma/CPP/Windows/MemoryLock.h [new file with mode: 0644]
lzma/CPP/Windows/PropVariant.cpp [new file with mode: 0644]
lzma/CPP/Windows/PropVariant.h [new file with mode: 0644]
lzma/CPP/Windows/PropVariantConversions.cpp [new file with mode: 0644]
lzma/CPP/Windows/PropVariantConversions.h [new file with mode: 0644]
lzma/CPP/Windows/StdAfx.h [new file with mode: 0644]
lzma/CPP/Windows/Synchronization.cpp [new file with mode: 0644]
lzma/CPP/Windows/Synchronization.h [new file with mode: 0644]
lzma/CPP/Windows/System.cpp [new file with mode: 0644]
lzma/CPP/Windows/System.h [new file with mode: 0644]
lzma/CPP/Windows/Thread.h [new file with mode: 0644]
lzma/CPP/Windows/Time.h [new file with mode: 0644]
lzma/CS/7zip/Common/CRC.cs [new file with mode: 0644]
lzma/CS/7zip/Common/CommandLineParser.cs [new file with mode: 0644]
lzma/CS/7zip/Common/InBuffer.cs [new file with mode: 0644]
lzma/CS/7zip/Common/OutBuffer.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZ/IMatchFinder.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZ/LzBinTree.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZ/LzInWindow.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZ/LzOutWindow.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZMA/LzmaBase.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZMA/LzmaDecoder.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LZMA/LzmaEncoder.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/LzmaBench.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/RangeCoder/RangeCoder.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs [new file with mode: 0644]
lzma/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs [new file with mode: 0644]
lzma/CS/7zip/ICoder.cs [new file with mode: 0644]
lzma/Java/SevenZip/CRC.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/LZ/BinTree.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/LZ/InWindow.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/LZ/OutWindow.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/LZMA/Base.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/LZMA/Decoder.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/LZMA/Encoder.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/RangeCoder/Decoder.java [new file with mode: 0644]
lzma/Java/SevenZip/Compression/RangeCoder/Encoder.java [new file with mode: 0644]
lzma/Java/SevenZip/ICodeProgress.java [new file with mode: 0644]
lzma/Java/SevenZip/LzmaAlone.java [new file with mode: 0644]
lzma/Java/SevenZip/LzmaBench.java [new file with mode: 0644]
lzma/LGPL.txt [new file with mode: 0644]
lzma/Methods.txt [new file with mode: 0644]
lzma/history.txt [new file with mode: 0644]
lzma/lzma.exe [new file with mode: 0755]
lzma/lzma.txt [new file with mode: 0644]
makeos2.cmd [new file with mode: 0644]
physfs.c [new file with mode: 0644]
physfs.h [new file with mode: 0644]
physfs_byteorder.c [new file with mode: 0644]
physfs_casefolding.h [new file with mode: 0644]
physfs_internal.h [new file with mode: 0644]
physfs_platforms.h [new file with mode: 0644]
physfs_unicode.c [new file with mode: 0644]
platform/beos.cpp [new file with mode: 0644]
platform/macosx.c [new file with mode: 0644]
platform/os2.c [new file with mode: 0644]
platform/pocketpc.c [new file with mode: 0644]
platform/posix.c [new file with mode: 0644]
platform/unix.c [new file with mode: 0644]
platform/windows.c [new file with mode: 0644]
test/test_physfs.c [new file with mode: 0644]
test/wxtest_physfs.cpp [new file with mode: 0644]
welcome [deleted file]
zlib123/README [new file with mode: 0644]
zlib123/adler32.c [new file with mode: 0644]
zlib123/compress.c [new file with mode: 0644]
zlib123/crc32.c [new file with mode: 0644]
zlib123/crc32.h [new file with mode: 0644]
zlib123/deflate.c [new file with mode: 0644]
zlib123/deflate.h [new file with mode: 0644]
zlib123/gzio.c [new file with mode: 0644]
zlib123/infback.c [new file with mode: 0644]
zlib123/inffast.c [new file with mode: 0644]
zlib123/inffast.h [new file with mode: 0644]
zlib123/inffixed.h [new file with mode: 0644]
zlib123/inflate.c [new file with mode: 0644]
zlib123/inflate.h [new file with mode: 0644]
zlib123/inftrees.c [new file with mode: 0644]
zlib123/inftrees.h [new file with mode: 0644]
zlib123/trees.c [new file with mode: 0644]
zlib123/trees.h [new file with mode: 0644]
zlib123/uncompr.c [new file with mode: 0644]
zlib123/zconf.h [new file with mode: 0644]
zlib123/zlib.h [new file with mode: 0644]
zlib123/zutil.c [new file with mode: 0644]
zlib123/zutil.h [new file with mode: 0644]

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644 (file)
index 0000000..fc18f77
--- /dev/null
@@ -0,0 +1,11 @@
+
+The changelog is no longer maintained by hand. It made sense to have a single
+ timeline when we were using CVS, but modern revision control tools make this
+ redundant, at best.
+
+If you want a list of changes, updated in real time, just point your web
+ browser here:
+
+    http://hg.icculus.org/icculus/physfs/
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e5807ba
--- /dev/null
@@ -0,0 +1,388 @@
+# PhysicsFS; a portable, flexible file i/o abstraction.
+# Copyright (C) 2007  Ryan C. Gordon.
+#
+# Please see the file LICENSE.txt in the source's root directory.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+
+PROJECT(PhysicsFS)
+SET(PHYSFS_VERSION 2.0.2)
+
+# Increment this if/when we break backwards compatibility.
+SET(PHYSFS_SOVERSION 1)
+
+# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
+IF(WIN32 AND NOT WINDOWS)
+    SET(WINDOWS TRUE)
+ENDIF(WIN32 AND NOT WINDOWS)
+
+# Bleh, let's do it for "APPLE" too.
+IF(APPLE AND NOT MACOSX)
+    SET(MACOSX TRUE)
+ENDIF(APPLE AND NOT MACOSX)
+
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckCSourceCompiles)
+
+INCLUDE_DIRECTORIES(.)
+#INCLUDE_DIRECTORIES(platform)
+#INCLUDE_DIRECTORIES(archivers)
+
+IF(MACOSX)
+    # Fallback to older OS X on PowerPC to support wider range of systems...
+    IF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+        ADD_DEFINITIONS(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
+        SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
+    ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+
+    # Need these everywhere...
+    ADD_DEFINITIONS(-fno-common)
+    SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -framework Carbon -framework IOKit")
+ENDIF(MACOSX)
+
+# Add some gcc-specific command lines.
+IF(CMAKE_COMPILER_IS_GNUCC)
+    # Always build with debug symbols...you can strip it later.
+    ADD_DEFINITIONS(-g -pipe -Werror -fsigned-char)
+
+    # Stupid BeOS generates warnings in the system headers.
+    IF(NOT BEOS)
+        ADD_DEFINITIONS(-Wall)
+    ENDIF(NOT BEOS)
+
+    CHECK_C_SOURCE_COMPILES("
+        #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
+        int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
+        #else
+        #error This is not gcc4.
+        #endif
+    " PHYSFS_IS_GCC4)
+
+    IF(PHYSFS_IS_GCC4)
+        # Not supported on several operating systems at this time.
+        IF(NOT OS2 AND NOT SOLARIS AND NOT WINDOWS)
+             ADD_DEFINITIONS(-fvisibility=hidden)
+        ENDIF(NOT OS2 AND NOT SOLARIS AND NOT WINDOWS)
+    ENDIF(PHYSFS_IS_GCC4)
+ENDIF(CMAKE_COMPILER_IS_GNUCC)
+
+IF(MSVC)
+    # VS.NET 8.0 got really really anal about strcpy, etc, which even if we
+    #  cleaned up our code, zlib, etc still use...so disable the warning.
+    ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS=1)
+ENDIF(MSVC)
+
+# Basic chunks of source code ...
+
+SET(ZLIB_SRCS
+    zlib123/adler32.c
+    zlib123/compress.c
+    zlib123/crc32.c
+    zlib123/deflate.c
+    zlib123/gzio.c
+    zlib123/infback.c
+    zlib123/inffast.c
+    zlib123/inflate.c
+    zlib123/inftrees.c
+    zlib123/trees.c
+    zlib123/uncompr.c
+    zlib123/zutil.c
+)
+
+SET(LZMA_SRCS
+    lzma/C/7zCrc.c
+    lzma/C/Archive/7z/7zBuffer.c
+    lzma/C/Archive/7z/7zDecode.c
+    lzma/C/Archive/7z/7zExtract.c
+    lzma/C/Archive/7z/7zHeader.c
+    lzma/C/Archive/7z/7zIn.c
+    lzma/C/Archive/7z/7zItem.c
+    lzma/C/Archive/7z/7zMethodID.c
+    lzma/C/Compress/Branch/BranchX86.c
+    lzma/C/Compress/Branch/BranchX86_2.c
+    lzma/C/Compress/Lzma/LzmaDecode.c
+)
+
+IF(BEOS)
+    # We add this explicitly, since we don't want CMake to think this
+    #  is a C++ project unless we're on BeOS.
+    SET(PHYSFS_BEOS_SRCS platform/beos.cpp)
+    FIND_LIBRARY(BE_LIBRARY be)
+    FIND_LIBRARY(ROOT_LIBRARY root)
+    SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
+ENDIF(BEOS)
+
+# Almost everything is "compiled" here, but things that don't apply to the
+#  build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
+#  another project or bring up a new build system: just compile all the source
+#  code and #define the things you want.
+SET(PHYSFS_SRCS
+    physfs.c
+    physfs_byteorder.c
+    physfs_unicode.c
+    platform/os2.c
+    platform/pocketpc.c
+    platform/posix.c
+    platform/unix.c
+    platform/macosx.c
+    platform/windows.c
+    archivers/dir.c
+    archivers/grp.c
+    archivers/hog.c
+    archivers/lzma.c
+    archivers/mvl.c
+    archivers/qpak.c
+    archivers/wad.c
+    archivers/zip.c
+    ${PHYSFS_BEOS_SRCS}
+)
+
+
+# platform layers ...
+
+IF(UNIX)
+    IF(BEOS)
+        SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+        SET(HAVE_PTHREAD_H TRUE)
+    ELSE(BEOS)
+        # !!! FIXME
+        #  AC_DEFINE([PHYSFS_HAVE_LLSEEK], 1, [define if we have llseek])
+        CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
+        IF(HAVE_UCRED_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_UCRED_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_UCRED_H)
+
+        CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
+        IF(HAVE_MNTENT_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_MNTENT_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_MNTENT_H)
+
+        CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
+        IF(HAVE_PTHREAD_H)
+            SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+        ENDIF(HAVE_PTHREAD_H)
+    ENDIF(BEOS)
+ENDIF(UNIX)
+
+IF(WINDOWS)
+    SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+    SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ENDIF(WINDOWS)
+
+IF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+    ADD_DEFINITIONS(-DPHYSFS_NO_CDROM_SUPPORT=1)
+    MESSAGE(WARNING " ***")
+    MESSAGE(WARNING " *** There is no CD-ROM support in this build!")
+    MESSAGE(WARNING " *** PhysicsFS will just pretend there are no discs.")
+    MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+    MESSAGE(WARNING " ***   but is this what you REALLY wanted?")
+    MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+    MESSAGE(WARNING " ***")
+ENDIF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+
+IF(PHYSFS_HAVE_THREAD_SUPPORT)
+    ADD_DEFINITIONS(-D_REENTRANT -D_THREAD_SAFE)
+ELSE(PHYSFS_HAVE_THREAD_SUPPORT)
+    ADD_DEFINITIONS(-DPHYSFS_NO_THREAD_SUPPORT=1)
+    MESSAGE(WARNING " ***")
+    MESSAGE(WARNING " *** There is no thread support in this build!")
+    MESSAGE(WARNING " *** PhysicsFS will NOT be reentrant!")
+    MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+    MESSAGE(WARNING " ***   but is this what you REALLY wanted?")
+    MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+    MESSAGE(WARNING " ***")
+ENDIF(PHYSFS_HAVE_THREAD_SUPPORT)
+
+CHECK_INCLUDE_FILE(assert.h HAVE_ASSERT_H)
+IF(HAVE_ASSERT_H)
+    ADD_DEFINITIONS(-DHAVE_ASSERT_H=1)
+ENDIF(HAVE_ASSERT_H)
+
+
+
+# Archivers ...
+
+OPTION(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
+IF(PHYSFS_ARCHIVE_ZIP)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ZIP=1)
+    SET(PHYSFS_NEED_ZLIB TRUE)
+ENDIF(PHYSFS_ARCHIVE_ZIP)
+
+OPTION(PHYSFS_ARCHIVE_7Z "Enable 7zip support" TRUE)
+IF(PHYSFS_ARCHIVE_7Z)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_7Z=1)
+    # !!! FIXME: rename to 7z.c?
+    SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${LZMA_SRCS})
+ENDIF(PHYSFS_ARCHIVE_7Z)
+
+OPTION(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
+IF(PHYSFS_ARCHIVE_GRP)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_GRP=1)
+ENDIF(PHYSFS_ARCHIVE_GRP)
+
+OPTION(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
+IF(PHYSFS_ARCHIVE_WAD)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_WAD=1)
+ENDIF(PHYSFS_ARCHIVE_WAD)
+
+OPTION(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
+IF(PHYSFS_ARCHIVE_HOG)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_HOG=1)
+ENDIF(PHYSFS_ARCHIVE_HOG)
+
+OPTION(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
+IF(PHYSFS_ARCHIVE_MVL)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_MVL=1)
+ENDIF(PHYSFS_ARCHIVE_MVL)
+
+OPTION(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
+IF(PHYSFS_ARCHIVE_QPAK)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_QPAK=1)
+ENDIF(PHYSFS_ARCHIVE_QPAK)
+
+
+# See if some archiver required zlib, and see about using system version.
+
+IF(PHYSFS_NEED_ZLIB)
+    FIND_PACKAGE(ZLIB)
+
+    IF(ZLIB_FOUND)
+        OPTION(PHYSFS_INTERNAL_ZLIB "Link own zlib instead of system library" FALSE)
+    ELSE(HAVE_SYSTEM_ZLIB)
+        SET(PHYSFS_INTERNAL_ZLIB TRUE)
+    ENDIF(ZLIB_FOUND)
+
+    IF(PHYSFS_INTERNAL_ZLIB)
+        INCLUDE_DIRECTORIES(zlib123)
+        ADD_DEFINITIONS(-DZ_PREFIX=1)
+        SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${ZLIB_SRCS})
+    ELSE(PHYSFS_INTERNAL_ZLIB)
+        SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${ZLIB_LIBRARY})
+        INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
+    ENDIF(PHYSFS_INTERNAL_ZLIB)
+ENDIF(PHYSFS_NEED_ZLIB)
+
+OPTION(PHYSFS_BUILD_STATIC "Build static library" TRUE)
+IF(PHYSFS_BUILD_STATIC)
+    ADD_LIBRARY(physfs-static STATIC ${PHYSFS_SRCS})
+    SET_TARGET_PROPERTIES(physfs-static PROPERTIES OUTPUT_NAME "physfs")
+    SET(PHYSFS_LIB_TARGET physfs-static)
+    SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs-static")
+ENDIF(PHYSFS_BUILD_STATIC)
+
+OPTION(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
+IF(PHYSFS_BUILD_SHARED)
+    ADD_LIBRARY(physfs SHARED ${PHYSFS_SRCS})
+    SET_TARGET_PROPERTIES(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
+    SET_TARGET_PROPERTIES(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
+    TARGET_LINK_LIBRARIES(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
+    SET(PHYSFS_LIB_TARGET physfs)
+    SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
+ENDIF(PHYSFS_BUILD_SHARED)
+
+IF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+    MESSAGE(FATAL "Both shared and static libraries are disabled!")
+ENDIF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+
+# CMake FAQ says I need this...
+IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+    SET_TARGET_PROPERTIES(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+    SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+
+OPTION(PHYSFS_BUILD_TEST "Build stdio test program." TRUE)
+MARK_AS_ADVANCED(PHYSFS_BUILD_TEST)
+IF(PHYSFS_BUILD_TEST)
+    FIND_PATH(READLINE_H readline/readline.h)
+    FIND_PATH(HISTORY_H readline/history.h)
+    IF(READLINE_H AND HISTORY_H)
+        FIND_LIBRARY(CURSES_LIBRARY NAMES curses ncurses)
+        SET(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
+        FIND_LIBRARY(READLINE_LIBRARY readline)
+        FIND_LIBRARY(HISTORY_LIBRARY history)
+        IF(READLINE_LIBRARY AND HISTORY_LIBRARY)
+            SET(HAVE_SYSTEM_READLINE TRUE)
+            SET(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY})
+            INCLUDE_DIRECTORIES(${READLINE_H} ${HISTORY_H})
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_READLINE=1)
+        ENDIF(READLINE_LIBRARY AND HISTORY_LIBRARY)
+    ENDIF(READLINE_H AND HISTORY_H)
+    ADD_EXECUTABLE(test_physfs test/test_physfs.c)
+    TARGET_LINK_LIBRARIES(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
+    SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
+ENDIF(PHYSFS_BUILD_TEST)
+
+OPTION(PHYSFS_BUILD_WX_TEST "Build wxWidgets test program." 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${LIB_SUFFIX}
+        ARCHIVE DESTINATION lib${LIB_SUFFIX})
+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)
+    SET(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz")
+    ADD_CUSTOM_TARGET(
+        dist
+        hg archive -t tgz "${PHYSFS_TARBALL}"
+        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+        COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
+    )
+ENDIF(UNIX)
+
+MACRO(MESSAGE_BOOL_OPTION _NAME _VALUE)
+    IF(${_VALUE})
+        MESSAGE(STATUS "  ${_NAME}: enabled")
+    ELSE(${_VALUE})
+        MESSAGE(STATUS "  ${_NAME}: disabled")
+    ENDIF(${_VALUE})
+ENDMACRO(MESSAGE_BOOL_OPTION)
+
+MESSAGE(STATUS "PhysicsFS will build with the following options:")
+MESSAGE_BOOL_OPTION("ZIP support" PHYSFS_ARCHIVE_ZIP)
+MESSAGE_BOOL_OPTION("7zip support" PHYSFS_ARCHIVE_7Z)
+MESSAGE_BOOL_OPTION("GRP support" PHYSFS_ARCHIVE_GRP)
+MESSAGE_BOOL_OPTION("WAD support" PHYSFS_ARCHIVE_WAD)
+MESSAGE_BOOL_OPTION("HOG support" PHYSFS_ARCHIVE_HOG)
+MESSAGE_BOOL_OPTION("MVL support" PHYSFS_ARCHIVE_MVL)
+MESSAGE_BOOL_OPTION("QPAK support" PHYSFS_ARCHIVE_QPAK)
+MESSAGE_BOOL_OPTION("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT)
+MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
+MESSAGE_BOOL_OPTION("Build own zlib" PHYSFS_INTERNAL_ZLIB)
+MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
+MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
+MESSAGE_BOOL_OPTION("Build wxWidgets test program" PHYSFS_BUILD_WX_TEST)
+MESSAGE_BOOL_OPTION("Build stdio test program" PHYSFS_BUILD_TEST)
+IF(PHYSFS_BUILD_TEST)
+    MESSAGE_BOOL_OPTION("  Use readline in test program" HAVE_SYSTEM_READLINE)
+ENDIF(PHYSFS_BUILD_TEST)
+
+# end of CMakeLists.txt ...
+
diff --git a/CREDITS.txt b/CREDITS.txt
new file mode 100644 (file)
index 0000000..dab8876
--- /dev/null
@@ -0,0 +1,113 @@
+Maintainer and general codemonkey:
+    Ryan C. Gordon
+
+Tons of win32 help:
+    Adam Gates
+
+More win32 hacking:
+    Gregory S. Read
+
+Fixes for missing current working directories,
+PHYSFS_setSaneConfig() improvements,
+other bugfixes:
+    David Hedbor
+
+Darwin support:
+    Patrick Stein
+
+configure fixes,
+RPM specfile:
+    Edward Rudd
+
+GetLastModTime API,
+other stuff:
+    John R. Hall
+
+Various support, fixes and suggestions:
+    Alexander Pipelka
+
+Russian translation,
+Ruby bindings,
+QPAK archiver:
+    Ed Sinjiashvili
+
+French translation:
+    Stéphane Peter
+
+Debian package support:
+    Colin Bayer
+
+"abs-file.h" in "extras" dir:
+    Adam D. Moss
+
+WinCE port and other Win32 patches:
+    Corona688
+
+German translation:
+    Michael Renner
+
+Apple Project Builder support,
+Mac OS X improvements:
+    Eric Wing
+
+iPhone support:
+    Christian Gmeiner
+
+HOG archiver,
+MVL archiver:
+    Bradley Bell
+
+MIX archiver:
+    Sebastian Steinhauer
+
+Bug fixes:
+    Tolga Dalman
+
+Initial PHYSFS_mount() work:
+    Philip D. Bober
+
+Brazillian Portuguese translation:
+    Danny Angelo Carminati Grein
+
+Spanish translation:
+    Pedro J. Pérez
+
+MacOS Classic fixes,
+MPW support,
+bug fixes:
+    Chris Taylor
+
+Mingw support,
+General bug fixes:
+    Matze Braun
+
+Haiku support:
+    scott mc
+
+Bug fixes:
+    Jörg Walter
+
+Bug fixes:
+    Olivier Boudeville
+
+Bug fixes:
+    Henk Boom
+
+Build system fixes:
+    Marc Kleine-Budde
+
+Windows .rc file,
+7zip/lzma archiver:
+    Dennis Schridde
+
+OS/2 updates:
+    Dave Yeo
+
+Bug fixes:
+    Patrice Mandin
+
+Other stuff:
+    Your name here! Patches go to icculus@icculus.org ...
+
+/* end of CREDITS.txt ... */
+
diff --git a/Doxyfile b/Doxyfile
new file mode 100644 (file)
index 0000000..0b913fc
--- /dev/null
+++ b/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         = 2.0.2
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = physfs.h
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output dir.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = DOXYGEN_SHOULD_IGNORE_THIS=1 \
+                         __EXPORT__=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similiar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644 (file)
index 0000000..acbbcc0
--- /dev/null
@@ -0,0 +1,153 @@
+
+The latest PhysicsFS information and releases can be found at:
+  http://icculus.org/physfs/
+
+Building is (ahem) very easy.
+
+
+ALL PLATFORMS:
+
+Please understand your rights and mine: read the text file LICENSE.txt in the
+ root of the source tree. If you can't abide by it, delete this source tree
+ now. The license is extremely liberal, even to closed-source, commercial
+ applications.
+
+If you've got Doxygen (http://www.doxygen.org/) installed, you can run it
+ without any command line arguments in the root of the source tree to generate
+ the API reference (or build the "docs" target from your build system). This
+ is optional. You can browse the API docs online here:
+
+    http://icculus.org/physfs/docs/
+
+
+
+
+UNIX:
+
+You will need CMake (http://www.cmake.org/) 2.4 or later installed.
+
+Make a directory, wherever you like. This will be your build directory.
+
+Chdir to your build directory. Run "cmake /where/i/unpacked/physfs" to
+ generate Makefiles. You can then run "ccmake ." and customize the build,
+ but the defaults are probably okay. You can have CMake generate KDevelop
+ project files if you prefer these.
+
+Run "make". PhysicsFS will now build.
+
+As root, run "make install".
+ If you get sick of the library, run "xargs rm < install_manifest.txt" as root
+ and it will remove all traces of the library from the system paths.
+
+Once you are satisfied, you can delete the build directory.
+
+Primary Unix development is done with GNU/Linux, but PhysicsFS is known to
+ work out of the box with several flavors of Unix. It it doesn't work, patches
+ to get it running can be sent to icculus@icculus.org.
+
+
+
+BeOS, Zeta, and Haiku:
+
+Use the "Unix" instructions, above. The CMake port to BeOS is fairly new at
+ the time of this writing, but it works. You can get a build of CMake from
+ bebits.com or build it yourself from source from cmake.org.
+
+
+
+Windows:
+
+If building with Cygwin, mingw32, MSYS, or something else that uses the GNU
+ toolchain, follow the Unix instructions, above.
+
+If you want to use Visual Studio, nmake, or the Platform SDK, you will need
+ CMake (http://www.cmake.org/) 2.4 or later installed. Point CMake at the
+ CMakeLists.txt file in the root of the source directory and hit the
+ "Configure" button. After telling it what type of compiler you are targeting
+ (Borland, Visual Studio, etc), CMake will process for while and then give you
+ a list of options you can change (what archivers you want to support, etc).
+ If you aren't sure, the defaults are probably fine. Hit the "Configure"
+ button again, then "OK" once configuration has completed with options that
+ match your liking. Now project files for your favorite programming
+ environment will be generated for you in the directory you specified.
+ Go there and use them to build PhysicsFS.
+
+PhysicsFS will only link directly against system libraries that have existed
+ since Windows 95 and Windows NT 3.51. If there's a newer API we want to use,
+ we try to dynamically load it at runtime and fallback to a reasonable
+ behaviour when we can't find it...this is used for Unicode support and
+ locating user-specific directories, etc.
+
+PhysicsFS 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 more than a decade at this point, none of the hardware
+ they've shipped will boot it for almost as many years, and finding
+ developer tools for it is becoming almost impossible. As the switch to Intel
+ hardware has removed the "Classic" emulation environment, it was time to
+ remove support from PhysicsFS. That being said, the PhysicsFS 1.0 branch can
+ still target back to Mac OS 8.5, so you can use that if you need support for
+ this legacy OS. We still very much support Mac OS X, though: see below.
+
+
+
+MAC OS X:
+
+You will need CMake (http://www.cmake.org/) 2.4 or later installed.
+
+You can either generate a Unix makefile with CMake, or generate an Xcode
+ project, whichever makes you more comfortable.
+
+PowerPC and Intel Macs should both be supported.
+
+If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
+ Mac OS X, I'd like to hear from you; send an email to icculus@icculus.org.
+
+
+
+OS/2:
+
+You need Innotek GCC and libc installed (or kLIBC). I tried this on a stock
+ Warp 4 install, no fixpaks. You need to install link386.exe (Selective
+ Install, "link object modules" option). Once klibc and GCC are installed
+ correctly, unpack the source to PhysicsFS and run the script
+ file "makeos2.cmd". I know this isn't ideal, but I wanted to have this build
+ without users having to hunt down a "make" program.
+
+Someone please port CMake to OS/2. Ideally I'd like to be able to target
+ Innotek GCC and OpenWatcom with CMake.
+
+If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
+ OS/2, I'd like to hear from you; send an email to icculus@icculus.org.
+
+
+
+OTHER PLATFORMS:
+
+Many Unix-like platforms might "just work" with CMake. Some of these platforms
+ are known to have worked at one time, but have not been heavily tested, if
+ tested at all. PhysicsFS is, as far as we know, 64-bit and byteorder clean,
+ and is known to compile on several compilers across many platforms. To
+ implement a new platform or archiver, please read the heavily-commented
+ physfs_internal.h and look in the platform/ and archiver/ directories for
+ examples.
+
+--ryan. (icculus@icculus.org)
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..a59b5de
--- /dev/null
@@ -0,0 +1,44 @@
+
+   Copyright (c) 2001-2011 Ryan C. Gordon and others.
+
+   This software is provided 'as-is', without any express or implied warranty.
+   In no event will the authors be held liable for any damages arising from
+   the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software in a
+   product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+       Ryan C. Gordon <icculus@icculus.org>
+
+
+
+
+Notes, separate from the license. This is not legal advice.
+
+Versions of PhysicsFS prior to 0.1.9 are licensed under the GNU Lesser General
+ Public License, which restricts you significantly more. For your own safety,
+ please make sure you've got 0.1.9 or later if you plan to use physfs in a
+ commercial or closed-source project.
+
+Optional pieces of PhysicsFS may fall under other licenses, please consult
+your lawyer for legal advice, which this is not...
+
+   zlib: if you enable ZIP archive support, PhysicsFS uses zlib. Its license
+         requirements are identical to PhysicsFS.
+         Please see zlib123/README for details.
+
+   lzma: if you enable LZMA (7zip) support, PhysicsFS uses the lzma sdk.
+         It uses the LGPL license, with exceptions for closed-source programs.
+         Please see lzma/lzma.txt for details.
+
diff --git a/TODO.txt b/TODO.txt
new file mode 100644 (file)
index 0000000..9425051
--- /dev/null
+++ b/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/archivers/dir.c b/archivers/dir.c
new file mode 100644 (file)
index 0000000..a580743
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Standard directory I/O support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+static PHYSFS_sint64 DIR_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    PHYSFS_sint64 retval;
+    retval = __PHYSFS_platformRead(opaque, buffer, objSize, objCount);
+    return(retval);
+} /* DIR_read */
+
+
+static PHYSFS_sint64 DIR_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    PHYSFS_sint64 retval;
+    retval = __PHYSFS_platformWrite(opaque, buffer, objSize, objCount);
+    return(retval);
+} /* DIR_write */
+
+
+static int DIR_eof(fvoid *opaque)
+{
+    return(__PHYSFS_platformEOF(opaque));
+} /* DIR_eof */
+
+
+static PHYSFS_sint64 DIR_tell(fvoid *opaque)
+{
+    return(__PHYSFS_platformTell(opaque));
+} /* DIR_tell */
+
+
+static int DIR_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    return(__PHYSFS_platformSeek(opaque, offset));
+} /* DIR_seek */
+
+
+static PHYSFS_sint64 DIR_fileLength(fvoid *opaque)
+{
+    return(__PHYSFS_platformFileLength(opaque));
+} /* DIR_fileLength */
+
+
+static int DIR_fileClose(fvoid *opaque)
+{
+    /*
+     * we manually flush the buffer, since that's the place a close will
+     *  most likely fail, but that will leave the file handle in an undefined
+     *  state if it fails. Flush failures we can recover from.
+     */
+    BAIL_IF_MACRO(!__PHYSFS_platformFlush(opaque), NULL, 0);
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(opaque), NULL, 0);
+    return(1);
+} /* DIR_fileClose */
+
+
+static int DIR_isArchive(const char *filename, int forWriting)
+{
+    /* directories ARE archives in this driver... */
+    return(__PHYSFS_platformIsDirectory(filename));
+} /* DIR_isArchive */
+
+
+static void *DIR_openArchive(const char *name, int forWriting)
+{
+    const char *dirsep = PHYSFS_getDirSeparator();
+    char *retval = NULL;
+    size_t namelen = strlen(name);
+    size_t seplen = strlen(dirsep);
+
+    /* !!! FIXME: when is this not called right before openArchive? */
+    BAIL_IF_MACRO(!DIR_isArchive(name, forWriting),
+                    ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    retval = allocator.Malloc(namelen + seplen + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+        /* make sure there's a dir separator at the end of the string */
+    strcpy(retval, name);
+    if (strcmp((name + namelen) - seplen, dirsep) != 0)
+        strcat(retval, dirsep);
+
+    return(retval);
+} /* DIR_openArchive */
+
+
+static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    char *d = __PHYSFS_platformCvtToDependent((char *)opaque, dname, NULL);
+    if (d != NULL)
+    {
+        __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
+                                        origdir, callbackdata);
+        allocator.Free(d);
+    } /* if */
+} /* DIR_enumerateFiles */
+
+
+static int DIR_exists(dvoid *opaque, const char *name)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    retval = __PHYSFS_platformExists(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_exists */
+
+
+static int DIR_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval = 0;
+
+    BAIL_IF_MACRO(d == NULL, NULL, 0);
+    *fileExists = __PHYSFS_platformExists(d);
+    if (*fileExists)
+        retval = __PHYSFS_platformIsDirectory(d);
+    allocator.Free(d);
+    return(retval);
+} /* DIR_isDirectory */
+
+
+static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval = 0;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    *fileExists = __PHYSFS_platformExists(f);
+    if (*fileExists)
+        retval = __PHYSFS_platformIsSymLink(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_isSymLink */
+
+
+static PHYSFS_sint64 DIR_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    PHYSFS_sint64 retval = -1;
+
+    BAIL_IF_MACRO(d == NULL, NULL, 0);
+    *fileExists = __PHYSFS_platformExists(d);
+    if (*fileExists)
+        retval = __PHYSFS_platformGetLastModTime(d);
+    allocator.Free(d);
+    return(retval);
+} /* DIR_getLastModTime */
+
+
+static fvoid *doOpen(dvoid *opaque, const char *name,
+                     void *(*openFunc)(const char *filename),
+                     int *fileExists)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    void *rc = NULL;
+
+    BAIL_IF_MACRO(f == NULL, NULL, NULL);
+
+    if (fileExists != NULL)
+    {
+        *fileExists = __PHYSFS_platformExists(f);
+        if (!(*fileExists))
+        {
+            allocator.Free(f);
+            return(NULL);
+        } /* if */
+    } /* if */
+
+    rc = openFunc(f);
+    allocator.Free(f);
+
+    return((fvoid *) rc);
+} /* doOpen */
+
+
+static fvoid *DIR_openRead(dvoid *opaque, const char *fnm, int *exist)
+{
+    return(doOpen(opaque, fnm, __PHYSFS_platformOpenRead, exist));
+} /* DIR_openRead */
+
+
+static fvoid *DIR_openWrite(dvoid *opaque, const char *filename)
+{
+    return(doOpen(opaque, filename, __PHYSFS_platformOpenWrite, NULL));
+} /* DIR_openWrite */
+
+
+static fvoid *DIR_openAppend(dvoid *opaque, const char *filename)
+{
+    return(doOpen(opaque, filename, __PHYSFS_platformOpenAppend, NULL));
+} /* DIR_openAppend */
+
+
+static int DIR_remove(dvoid *opaque, const char *name)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    retval = __PHYSFS_platformDelete(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_remove */
+
+
+static int DIR_mkdir(dvoid *opaque, const char *name)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    retval = __PHYSFS_platformMkDir(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_mkdir */
+
+
+static void DIR_dirClose(dvoid *opaque)
+{
+    allocator.Free(opaque);
+} /* DIR_dirClose */
+
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_DIR =
+{
+    "",
+    DIR_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <icculus@icculus.org>",
+    "http://icculus.org/physfs/",
+};
+
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
+{
+    &__PHYSFS_ArchiveInfo_DIR,
+    DIR_isArchive,          /* isArchive() method      */
+    DIR_openArchive,        /* openArchive() method    */
+    DIR_enumerateFiles,     /* enumerateFiles() method */
+    DIR_exists,             /* exists() method         */
+    DIR_isDirectory,        /* isDirectory() method    */
+    DIR_isSymLink,          /* isSymLink() method      */
+    DIR_getLastModTime,     /* getLastModTime() method */
+    DIR_openRead,           /* openRead() method       */
+    DIR_openWrite,          /* openWrite() method      */
+    DIR_openAppend,         /* openAppend() method     */
+    DIR_remove,             /* remove() method         */
+    DIR_mkdir,              /* mkdir() method          */
+    DIR_dirClose,           /* dirClose() method       */
+    DIR_read,               /* read() method           */
+    DIR_write,              /* write() method          */
+    DIR_eof,                /* eof() method            */
+    DIR_tell,               /* tell() method           */
+    DIR_seek,               /* seek() method           */
+    DIR_fileLength,         /* fileLength() method     */
+    DIR_fileClose           /* fileClose() method      */
+};
+
+/* end of dir.c ... */
+
diff --git a/archivers/grp.c b/archivers/grp.c
new file mode 100644 (file)
index 0000000..8c63f1e
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * GRP support routines for PhysicsFS.
+ *
+ * This driver handles BUILD engine archives ("groupfiles"). This format
+ *  (but not this driver) was put together by Ken Silverman.
+ *
+ * The format is simple enough. In Ken's words:
+ *
+ *    What's the .GRP file format?
+ *
+ *     The ".grp" file format is just a collection of a lot of files stored
+ *     into 1 big one. I tried to make the format as simple as possible: The
+ *     first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
+ *     the number of files that were compacted into the group file. Then for
+ *     each file, there is a 16 byte structure, where the first 12 bytes are
+ *     the filename, and the last 4 bytes are the file's size. The rest of
+ *     the group file is just the raw data packed one after the other in the
+ *     same order as the list of files.
+ *
+ * (That info is from http://www.advsys.net/ken/build.htm ...)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#if (defined PHYSFS_SUPPORTS_GRP)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    char name[13];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} GRPentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    GRPentry *entries;
+} GRPinfo;
+
+typedef struct
+{
+    void *handle;
+    GRPentry *entry;
+    PHYSFS_uint32 curPos;
+} GRPfileinfo;
+
+
+static void GRP_dirClose(dvoid *opaque)
+{
+    GRPinfo *info = ((GRPinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* GRP_dirClose */
+
+
+static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    GRPentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* GRP_read */
+
+
+static PHYSFS_sint64 GRP_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* GRP_write */
+
+
+static int GRP_eof(fvoid *opaque)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    GRPentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* GRP_eof */
+
+
+static PHYSFS_sint64 GRP_tell(fvoid *opaque)
+{
+    return(((GRPfileinfo *) opaque)->curPos);
+} /* GRP_tell */
+
+
+static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    GRPentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* GRP_seek */
+
+
+static PHYSFS_sint64 GRP_fileLength(fvoid *opaque)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* GRP_fileLength */
+
+
+static int GRP_fileClose(fvoid *opaque)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* GRP_fileClose */
+
+
+static int grp_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint8 buf[12];
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, buf, 12, 1) != 1)
+        goto openGrp_failed;
+
+    if (memcmp(buf, "KenSilverman", 12) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openGrp_failed;
+    } /* if */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openGrp_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    return(1);
+
+openGrp_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* grp_open */
+
+
+static int GRP_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = grp_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* GRP_isArchive */
+
+
+static int grp_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const GRPentry *a = (const GRPentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* grp_entry_cmp */
+
+
+static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        GRPentry tmp;
+        GRPentry *first = &(((GRPentry *) _a)[one]);
+        GRPentry *second = &(((GRPentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (GRPentry));
+        memcpy(first, second, sizeof (GRPentry));
+        memcpy(second, &tmp, sizeof (GRPentry));
+    } /* if */
+} /* grp_entry_swap */
+
+
+static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    PHYSFS_uint32 location = 16;  /* sizeof sig. */
+    GRPentry *entry;
+    char *ptr;
+
+    BAIL_IF_MACRO(!grp_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    location += (16 * fileCount);
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->name, 12, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->name[12] = '\0';  /* name isn't null-terminated in file. */
+        if ((ptr = strchr(entry->name, ' ')) != NULL)
+            *ptr = '\0';  /* trim extra spaces. */
+
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = location;
+        location += entry->size;
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  grp_entry_cmp, grp_entry_swap);
+    return(1);
+} /* grp_load_entries */
+
+
+static void *GRP_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    GRPinfo *info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    memset(info, '\0', sizeof (GRPinfo));
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
+
+    if (!grp_load_entries(name, forWriting, info))
+        goto GRP_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+
+    return(info);
+
+GRP_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* GRP_openArchive */
+
+
+static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    /* no directories in GRP files. */
+    if (*dname == '\0')
+    {
+        GRPinfo *info = (GRPinfo *) opaque;
+        GRPentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
+
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, origdir, entry->name);
+    } /* if */
+} /* GRP_enumerateFiles */
+
+
+static GRPentry *grp_find_entry(GRPinfo *info, const char *name)
+{
+    char *ptr = strchr(name, '.');
+    GRPentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    /*
+     * Rule out filenames to avoid unneeded processing...no dirs,
+     *   big filenames, or extensions > 3 chars.
+     */
+    BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = strcmp(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* grp_find_entry */
+
+
+static int GRP_exists(dvoid *opaque, const char *name)
+{
+    return(grp_find_entry((GRPinfo *) opaque, name) != NULL);
+} /* GRP_exists */
+
+
+static int GRP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = GRP_exists(opaque, name);
+    return(0);  /* never directories in a groupfile. */
+} /* GRP_isDirectory */
+
+
+static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = GRP_exists(opaque, name);
+    return(0);  /* never symlinks in a groupfile. */
+} /* GRP_isSymLink */
+
+
+static PHYSFS_sint64 GRP_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    GRPinfo *info = (GRPinfo *) opaque;
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (grp_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of GRP itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* GRP_getLastModTime */
+
+
+static fvoid *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    GRPinfo *info = (GRPinfo *) opaque;
+    GRPfileinfo *finfo;
+    GRPentry *entry;
+
+    entry = grp_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* GRP_openRead */
+
+
+static fvoid *GRP_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* GRP_openWrite */
+
+
+static fvoid *GRP_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* GRP_openAppend */
+
+
+static int GRP_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* GRP_remove */
+
+
+static int GRP_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* GRP_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
+{
+    "GRP",
+    GRP_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <icculus@icculus.org>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
+{
+    &__PHYSFS_ArchiveInfo_GRP,
+    GRP_isArchive,          /* isArchive() method      */
+    GRP_openArchive,        /* openArchive() method    */
+    GRP_enumerateFiles,     /* enumerateFiles() method */
+    GRP_exists,             /* exists() method         */
+    GRP_isDirectory,        /* isDirectory() method    */
+    GRP_isSymLink,          /* isSymLink() method      */
+    GRP_getLastModTime,     /* getLastModTime() method */
+    GRP_openRead,           /* openRead() method       */
+    GRP_openWrite,          /* openWrite() method      */
+    GRP_openAppend,         /* openAppend() method     */
+    GRP_remove,             /* remove() method         */
+    GRP_mkdir,              /* mkdir() method          */
+    GRP_dirClose,           /* dirClose() method       */
+    GRP_read,               /* read() method           */
+    GRP_write,              /* write() method          */
+    GRP_eof,                /* eof() method            */
+    GRP_tell,               /* tell() method           */
+    GRP_seek,               /* seek() method           */
+    GRP_fileLength,         /* fileLength() method     */
+    GRP_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_GRP */
+
+/* end of grp.c ... */
+
diff --git a/archivers/hog.c b/archivers/hog.c
new file mode 100644 (file)
index 0000000..43620f6
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * HOG support routines for PhysicsFS.
+ *
+ * This driver handles Descent I/II HOG archives.
+ *
+ * The format is very simple:
+ *
+ *   The file always starts with the 3-byte signature "DHF" (Descent
+ *   HOG file). After that the files of a HOG are just attached after
+ *   another, divided by a 17 bytes header, which specifies the name
+ *   and length (in bytes) of the forthcoming file! So you just read
+ *   the header with its information of how big the following file is,
+ *   and then skip exact that number of bytes to get to the next file
+ *   in that HOG.
+ *
+ *    char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
+ *
+ *    struct {
+ *     char file_name[13]; // Filename, padded to 13 bytes with 0s
+ *     int file_size; // filesize in bytes
+ *     char data[file_size]; // The file data
+ *    } FILE_STRUCT; // Repeated until the end of the file.
+ *
+ * (That info is from http://www.descent2.com/ddn/specs/hog/)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Bradley Bell.
+ *  Based on grp.c by Ryan C. Gordon.
+ */
+
+#if (defined PHYSFS_SUPPORTS_HOG)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/*
+ * One HOGentry is kept for each file in an open HOG archive.
+ */
+typedef struct
+{
+    char name[13];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} HOGentry;
+
+/*
+ * One HOGinfo is kept for each open HOG archive.
+ */
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    HOGentry *entries;
+} HOGinfo;
+
+/*
+ * One HOGfileinfo is kept for each open file in a HOG archive.
+ */
+typedef struct
+{
+    void *handle;
+    HOGentry *entry;
+    PHYSFS_uint32 curPos;
+} HOGfileinfo;
+
+
+static void HOG_dirClose(dvoid *opaque)
+{
+    HOGinfo *info = ((HOGinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* HOG_dirClose */
+
+
+static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    HOGentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* HOG_read */
+
+
+static PHYSFS_sint64 HOG_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* HOG_write */
+
+
+static int HOG_eof(fvoid *opaque)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    HOGentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* HOG_eof */
+
+
+static PHYSFS_sint64 HOG_tell(fvoid *opaque)
+{
+    return(((HOGfileinfo *) opaque)->curPos);
+} /* HOG_tell */
+
+
+static int HOG_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    HOGentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* HOG_seek */
+
+
+static PHYSFS_sint64 HOG_fileLength(fvoid *opaque)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* HOG_fileLength */
+
+
+static int HOG_fileClose(fvoid *opaque)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* HOG_fileClose */
+
+
+static int hog_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint8 buf[13];
+    PHYSFS_uint32 size;
+    PHYSFS_sint64 pos;
+
+    *count = 0;
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+
+    if (__PHYSFS_platformRead(*fh, buf, 3, 1) != 1)
+        goto openHog_failed;
+
+    if (memcmp(buf, "DHF", 3) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openHog_failed;
+    } /* if */
+
+    while (1)
+    {
+        if (__PHYSFS_platformRead(*fh, buf, 13, 1) != 1)
+            break; /* eof here is ok */
+
+        if (__PHYSFS_platformRead(*fh, &size, 4, 1) != 1)
+            goto openHog_failed;
+
+        size = PHYSFS_swapULE32(size);
+
+        (*count)++;
+
+        /* Skip over entry... */
+        pos = __PHYSFS_platformTell(*fh);
+        if (pos == -1)
+            goto openHog_failed;
+        if (!__PHYSFS_platformSeek(*fh, pos + size))
+            goto openHog_failed;
+    } /* while */
+
+    /* Rewind to start of entries... */
+    if (!__PHYSFS_platformSeek(*fh, 3))
+        goto openHog_failed;
+
+    return(1);
+
+openHog_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* hog_open */
+
+
+static int HOG_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = hog_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* HOG_isArchive */
+
+
+static int hog_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const HOGentry *a = (const HOGentry *) _a;
+        return(__PHYSFS_stricmpASCII(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* hog_entry_cmp */
+
+
+static void hog_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        HOGentry tmp;
+        HOGentry *first = &(((HOGentry *) _a)[one]);
+        HOGentry *second = &(((HOGentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (HOGentry));
+        memcpy(first, second, sizeof (HOGentry));
+        memcpy(second, &tmp, sizeof (HOGentry));
+    } /* if */
+} /* hog_entry_swap */
+
+
+static int hog_load_entries(const char *name, int forWriting, HOGinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    HOGentry *entry;
+
+    BAIL_IF_MACRO(!hog_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (HOGentry *) allocator.Malloc(sizeof(HOGentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = (unsigned int) __PHYSFS_platformTell(fh);
+        if (entry->startPos == -1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        }
+
+        /* Skip over entry */
+        if (!__PHYSFS_platformSeek(fh, entry->startPos + entry->size))
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        }
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  hog_entry_cmp, hog_entry_swap);
+    return(1);
+} /* hog_load_entries */
+
+
+static void *HOG_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    HOGinfo *info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
+    memset(info, '\0', sizeof (HOGinfo));
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
+
+    if (!hog_load_entries(name, forWriting, info))
+        goto HOG_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+
+    return(info);
+
+HOG_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* HOG_openArchive */
+
+
+static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    /* no directories in HOG files. */
+    if (*dname == '\0')
+    {
+        HOGinfo *info = (HOGinfo *) opaque;
+        HOGentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
+
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, origdir, entry->name);
+    } /* if */
+} /* HOG_enumerateFiles */
+
+
+static HOGentry *hog_find_entry(HOGinfo *info, const char *name)
+{
+    char *ptr = strchr(name, '.');
+    HOGentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    /*
+     * Rule out filenames to avoid unneeded processing...no dirs,
+     *   big filenames, or extensions > 3 chars.
+     */
+    BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = __PHYSFS_stricmpASCII(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* hog_find_entry */
+
+
+static int HOG_exists(dvoid *opaque, const char *name)
+{
+    return(hog_find_entry(((HOGinfo *) opaque), name) != NULL);
+} /* HOG_exists */
+
+
+static int HOG_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = HOG_exists(opaque, name);
+    return(0);  /* never directories in a groupfile. */
+} /* HOG_isDirectory */
+
+
+static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = HOG_exists(opaque, name);
+    return(0);  /* never symlinks in a groupfile. */
+} /* HOG_isSymLink */
+
+
+static PHYSFS_sint64 HOG_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    HOGinfo *info = ((HOGinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (hog_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of HOG itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* HOG_getLastModTime */
+
+
+static fvoid *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    HOGinfo *info = ((HOGinfo *) opaque);
+    HOGfileinfo *finfo;
+    HOGentry *entry;
+
+    entry = hog_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* HOG_openRead */
+
+
+static fvoid *HOG_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* HOG_openWrite */
+
+
+static fvoid *HOG_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* HOG_openAppend */
+
+
+static int HOG_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* HOG_remove */
+
+
+static int HOG_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* HOG_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_HOG =
+{
+    "HOG",
+    HOG_ARCHIVE_DESCRIPTION,
+    "Bradley Bell <btb@icculus.org>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
+{
+    &__PHYSFS_ArchiveInfo_HOG,
+    HOG_isArchive,          /* isArchive() method      */
+    HOG_openArchive,        /* openArchive() method    */
+    HOG_enumerateFiles,     /* enumerateFiles() method */
+    HOG_exists,             /* exists() method         */
+    HOG_isDirectory,        /* isDirectory() method    */
+    HOG_isSymLink,          /* isSymLink() method      */
+    HOG_getLastModTime,     /* getLastModTime() method */
+    HOG_openRead,           /* openRead() method       */
+    HOG_openWrite,          /* openWrite() method      */
+    HOG_openAppend,         /* openAppend() method     */
+    HOG_remove,             /* remove() method         */
+    HOG_mkdir,              /* mkdir() method          */
+    HOG_dirClose,           /* dirClose() method       */
+    HOG_read,               /* read() method           */
+    HOG_write,              /* write() method          */
+    HOG_eof,                /* eof() method            */
+    HOG_tell,               /* tell() method           */
+    HOG_seek,               /* seek() method           */
+    HOG_fileLength,         /* fileLength() method     */
+    HOG_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_HOG */
+
+/* end of hog.c ... */
+
diff --git a/archivers/lzma.c b/archivers/lzma.c
new file mode 100644 (file)
index 0000000..dfdefc1
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ * LZMA support routines for PhysicsFS.
+ *
+ * Please see the file lzma.txt in the lzma/ directory.
+ *
+ *  This file was written by Dennis Schridde, with some peeking at "7zMain.c"
+ *   by Igor Pavlov.
+ */
+
+#if (defined PHYSFS_SUPPORTS_7Z)
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#include "lzma/C/7zCrc.h"
+#include "lzma/C/Archive/7z/7zIn.h"
+#include "lzma/C/Archive/7z/7zExtract.h"
+
+
+/* 7z internal from 7zIn.c */
+extern int TestSignatureCandidate(Byte *testBytes);
+
+
+#ifdef _LZMA_IN_CB
+# define BUFFER_SIZE (1 << 12)
+#endif /* _LZMA_IN_CB */
+
+
+/*
+ * Carries filestream metadata through 7z
+ */
+typedef struct _FileInputStream
+{
+    ISzAlloc allocImp; /* Allocation implementation, used by 7z */
+    ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
+    ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
+    void *file; /* Filehandle, used by read implementation */
+#ifdef _LZMA_IN_CB
+    Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
+#endif /* _LZMA_IN_CB */
+} FileInputStream;
+
+/*
+ * In the 7z format archives are splited into blocks, those are called folders
+ * Set by LZMA_read()
+*/
+typedef struct _LZMAfolder
+{
+    PHYSFS_uint32 index; /* Index of folder in archive */
+    PHYSFS_uint32 references; /* Number of files using this block */
+    PHYSFS_uint8 *cache; /* Cached folder */
+    size_t size; /* Size of folder */
+} LZMAfolder;
+
+/*
+ * Set by LZMA_openArchive(), except folder which gets it's values
+ *  in LZMA_read()
+ */
+typedef struct _LZMAarchive
+{
+    struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */
+    LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */
+    CArchiveDatabaseEx db; /* For 7z: Database */
+    FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */
+} LZMAarchive;
+
+/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
+typedef struct _LZMAfile
+{
+    PHYSFS_uint32 index; /* Index of file in archive */
+    LZMAarchive *archive; /* Link to corresponding archive */
+    LZMAfolder *folder; /* Link to corresponding folder */
+    CFileItem *item; /* For 7z: File info, eg. name, size */
+    size_t offset; /* Offset in folder */
+    size_t position; /* Current "virtual" position in file */
+} LZMAfile;
+
+
+/* Memory management implementations to be passed to 7z */
+
+static void *SzAllocPhysicsFS(size_t size)
+{
+    return ((size == 0) ? NULL : allocator.Malloc(size));
+} /* SzAllocPhysicsFS */
+
+
+static void SzFreePhysicsFS(void *address)
+{
+    if (address != NULL)
+        allocator.Free(address);
+} /* SzFreePhysicsFS */
+
+
+/* Filesystem implementations to be passed to 7z */
+
+#ifdef _LZMA_IN_CB
+
+/*
+ * Read implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
+                        size_t *processedSize)
+{
+    FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */
+    PHYSFS_sint64 processedSizeLoc = 0;
+
+    if (maxReqSize > BUFFER_SIZE)
+        maxReqSize = BUFFER_SIZE;
+    processedSizeLoc = __PHYSFS_platformRead(s->file, s->buffer, 1, maxReqSize);
+    *buffer = s->buffer;
+    if (processedSize != NULL)
+        *processedSize = (size_t) processedSizeLoc;
+
+    return SZ_OK;
+} /* SzFileReadImp */
+
+#else
+
+/*
+ * Read implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
+                        size_t *processedSize)
+{
+    FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
+    size_t processedSizeLoc = __PHYSFS_platformRead(s->file, buffer, 1, size);
+    if (processedSize != 0)
+        *processedSize = processedSizeLoc;
+    return SZ_OK;
+} /* SzFileReadImp */
+
+#endif
+
+/*
+ * Seek implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+    FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
+    if (__PHYSFS_platformSeek(s->file, (PHYSFS_uint64) pos))
+        return SZ_OK;
+    return SZE_FAIL;
+} /* SzFileSeekImp */
+
+
+/*
+ * Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp
+ */
+static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft)
+{
+    /* MS counts in nanoseconds ... */
+    const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000);
+    /* MS likes to count seconds since 01.01.1601 ... */
+    const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600);
+
+    PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32);
+    return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF;
+} /* lzma_filetime_to_unix_timestamp */
+
+
+/*
+ * Compare a file with a given name, C89 stdlib variant
+ * Used for sorting
+ */
+static int lzma_file_cmp_stdlib(const void *key, const void *object)
+{
+    const char *name = (const char *) key;
+    LZMAfile *file = (LZMAfile *) object;
+    return(strcmp(name, file->item->Name));
+} /* lzma_file_cmp_posix */
+
+
+/*
+ * Compare two files with each other based on the name
+ * Used for sorting
+ */
+static int lzma_file_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    LZMAfile *files = (LZMAfile *) _a;
+    return(strcmp(files[one].item->Name, files[two].item->Name));
+} /* lzma_file_cmp */
+
+
+/*
+ * Swap two entries in the file array
+ */
+static void lzma_file_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    LZMAfile tmp;
+    LZMAfile *first = &(((LZMAfile *) _a)[one]);
+    LZMAfile *second = &(((LZMAfile *) _a)[two]);
+    memcpy(&tmp, first, sizeof (LZMAfile));
+    memcpy(first, second, sizeof (LZMAfile));
+    memcpy(second, &tmp, sizeof (LZMAfile));
+} /* lzma_file_swap */
+
+
+/*
+ * Find entry 'name' in 'archive'
+ */
+static LZMAfile * lzma_find_file(LZMAarchive *archive, const char *name)
+{
+    LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */
+
+    BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, NULL);
+
+    return(file);
+} /* lzma_find_file */
+
+
+/*
+ * Load metadata for the file at given index
+ */
+static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex)
+{
+    LZMAfile *file = &archive->files[fileIndex];
+    PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
+
+    file->index = fileIndex; /* Store index into 7z array, since we sort our own. */
+    file->archive = archive;
+    file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */
+    file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */
+    file->position = 0;
+    file->offset = 0; /* Offset will be set by LZMA_read() */
+
+    return(1);
+} /* lzma_load_file */
+
+
+/*
+ * Load metadata for all files
+ */
+static int lzma_files_init(LZMAarchive *archive)
+{
+    PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+
+    for (fileIndex = 0; fileIndex < numFiles; fileIndex++ )
+    {
+        if (!lzma_file_init(archive, fileIndex))
+        {
+            return(0); /* FALSE on failure */
+        }
+    } /* for */
+
+   __PHYSFS_sort(archive->files, numFiles, lzma_file_cmp, lzma_file_swap);
+
+    return(1);
+} /* lzma_load_files */
+
+
+/*
+ * Initialise specified archive
+ */
+static void lzma_archive_init(LZMAarchive *archive)
+{
+    memset(archive, 0, sizeof(*archive));
+
+    /* Prepare callbacks for 7z */
+    archive->stream.inStream.Read = SzFileReadImp;
+    archive->stream.inStream.Seek = SzFileSeekImp;
+
+    archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
+    archive->stream.allocImp.Free = SzFreePhysicsFS;
+
+    archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
+    archive->stream.allocTempImp.Free = SzFreePhysicsFS;
+}
+
+
+/*
+ * Deinitialise archive
+ */
+static void lzma_archive_exit(LZMAarchive *archive)
+{
+    /* Free arrays */
+    allocator.Free(archive->folders);
+    allocator.Free(archive->files);
+    allocator.Free(archive);
+}
+
+/*
+ * Wrap all 7z calls in this, so the physfs error state is set appropriately.
+ */
+static int lzma_err(SZ_RESULT rc)
+{
+    switch (rc)
+    {
+        case SZ_OK: /* Same as LZMA_RESULT_OK */
+            break;
+        case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
+            __PHYSFS_setError(ERR_DATA_ERROR);
+            break;
+        case SZE_OUTOFMEMORY:
+            __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+            break;
+        case SZE_CRC_ERROR:
+            __PHYSFS_setError(ERR_CORRUPTED);
+            break;
+        case SZE_NOTIMPL:
+            __PHYSFS_setError(ERR_NOT_IMPLEMENTED);
+            break;
+        case SZE_FAIL:
+            __PHYSFS_setError(ERR_UNKNOWN_ERROR);  /* !!! FIXME: right? */
+            break;
+        case SZE_ARCHIVE_ERROR:
+            __PHYSFS_setError(ERR_CORRUPTED);  /* !!! FIXME: right? */
+            break;
+        default:
+            __PHYSFS_setError(ERR_UNKNOWN_ERROR);
+    } /* switch */
+
+    return(rc);
+} /* lzma_err */
+
+
+static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+
+    size_t wantedSize = objSize*objCount;
+    size_t remainingSize = file->item->Size - file->position;
+    size_t fileSize = 0;
+
+    BAIL_IF_MACRO(wantedSize == 0, NULL, 0); /* quick rejection. */
+    BAIL_IF_MACRO(remainingSize == 0, ERR_PAST_EOF, 0);
+
+    if (remainingSize < wantedSize)
+    {
+        wantedSize = remainingSize - (remainingSize % objSize);
+        objCount = (PHYSFS_uint32) (remainingSize / objSize);
+        BAIL_IF_MACRO(objCount == 0, ERR_PAST_EOF, 0); /* quick rejection. */
+        __PHYSFS_setError(ERR_PAST_EOF); /* this is always true here. */
+    } /* if */
+
+    /* Only decompress the folder if it is not allready cached */
+    if (file->folder->cache == NULL)
+    {
+        int rc = lzma_err(SzExtract(
+            &file->archive->stream.inStream, /* compressed data */
+            &file->archive->db, /* 7z's database, containing everything */
+            file->index, /* Index into database arrays */
+            /* Index of cached folder, will be changed by SzExtract */
+            &file->folder->index,
+            /* Cache for decompressed folder, allocated/freed by SzExtract */
+            &file->folder->cache,
+            /* Size of cache, will be changed by SzExtract */
+            &file->folder->size,
+            /* Offset of this file inside the cache, set by SzExtract */
+            &file->offset,
+            &fileSize, /* Size of this file */
+            &file->archive->stream.allocImp,
+            &file->archive->stream.allocTempImp));
+
+        if (rc != SZ_OK)
+            return -1;
+    } /* if */
+
+    /* Copy wanted bytes over from cache to outBuffer */
+    memcpy(outBuffer,
+            (file->folder->cache +
+                    file->offset + file->position),
+            wantedSize);
+    file->position += wantedSize; /* Increase virtual position */
+
+    return objCount;
+} /* LZMA_read */
+
+
+static PHYSFS_sint64 LZMA_write(fvoid *opaque, const void *buf,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* LZMA_write */
+
+
+static int LZMA_eof(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+    return (file->position >= file->item->Size);
+} /* LZMA_eof */
+
+
+static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+    return (file->position);
+} /* LZMA_tell */
+
+
+static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+
+    BAIL_IF_MACRO(offset < 0, ERR_SEEK_OUT_OF_RANGE, 0);
+    BAIL_IF_MACRO(offset > file->item->Size, ERR_PAST_EOF, 0);
+
+    file->position = offset; /* We only use a virtual position... */
+
+    return 1;
+} /* LZMA_seek */
+
+
+static PHYSFS_sint64 LZMA_fileLength(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+    return (file->item->Size);
+} /* LZMA_fileLength */
+
+
+static int LZMA_fileClose(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+
+    BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, 0);
+
+       /* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
+    if (file->folder->references > 0)
+        file->folder->references--;
+    if (file->folder->references == 0)
+    {
+        /* Free the cache which might have been allocated by LZMA_read() */
+        allocator.Free(file->folder->cache);
+        file->folder->cache = NULL;
+    }
+
+    return(1);
+} /* LZMA_fileClose */
+
+
+static int LZMA_isArchive(const char *filename, int forWriting)
+{
+    PHYSFS_uint8 sig[k7zSignatureSize];
+    void *in;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    in = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(in == NULL, NULL, 0);
+
+    /* Read signature bytes */
+    if (__PHYSFS_platformRead(in, sig, k7zSignatureSize, 1) != 1)
+    {
+        __PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
+        BAIL_MACRO(NULL, 0);
+    }
+
+    __PHYSFS_platformClose(in);
+
+    /* Test whether sig is the 7z signature */
+    return(TestSignatureCandidate(sig));
+} /* LZMA_isArchive */
+
+
+static void *LZMA_openArchive(const char *name, int forWriting)
+{
+    size_t len = 0;
+    LZMAarchive *archive = NULL;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
+    BAIL_IF_MACRO(!LZMA_isArchive(name,forWriting), ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
+    BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    lzma_archive_init(archive);
+
+    if ( (archive->stream.file = __PHYSFS_platformOpenRead(name)) == NULL )
+    {
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        return(NULL); /* Error is set by platformOpenRead! */
+    }
+
+    CrcGenerateTable();
+    SzArDbExInit(&archive->db);
+    if (lzma_err(SzArchiveOpen(&archive->stream.inStream,
+                               &archive->db,
+                               &archive->stream.allocImp,
+                               &archive->stream.allocTempImp)) != SZ_OK)
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        return NULL; /* Error is set by lzma_err! */
+    } /* if */
+
+    len = archive->db.Database.NumFiles * sizeof (LZMAfile);
+    archive->files = (LZMAfile *) allocator.Malloc(len);
+    if (archive->files == NULL)
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    }
+
+    /*
+     * Init with 0 so we know when a folder is already cached
+     * Values will be set by LZMA_openRead()
+     */
+    memset(archive->files, 0, len);
+
+    len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
+    archive->folders = (LZMAfolder *) allocator.Malloc(len);
+    if (archive->folders == NULL)
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    }
+
+    /*
+     * Init with 0 so we know when a folder is already cached
+     * Values will be set by LZMA_read()
+     */
+    memset(archive->folders, 0, len);
+
+    if(!lzma_files_init(archive))
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(ERR_UNKNOWN_ERROR, NULL);
+    }
+
+    return(archive);
+} /* LZMA_openArchive */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, size_t flen)
+{
+    char *newstr = __PHYSFS_smallAlloc(flen + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, flen);
+    newstr[flen] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void LZMA_enumerateFiles(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                                const char *origdir, void *callbackdata)
+{
+    size_t dlen = strlen(dname),
+           dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = NULL,
+            *lastFile = &archive->files[archive->db.Database.NumFiles];
+        if (dlen)
+        {
+            file = lzma_find_file(archive, dname);
+            if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
+                file += 1;
+        }
+        else
+        {
+            file = archive->files;
+        }
+
+    BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, );
+
+    while (file < lastFile)
+    {
+        const char * fname = file->item->Name;
+        const char * dirNameEnd = fname + dlen_inc;
+
+        if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */
+            break;
+
+        if (strchr(dirNameEnd, '/')) /* Skip subdirs */
+        {
+            file++;
+            continue;
+        }
+
+        /* Do the actual callback... */
+        doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd));
+
+        file++;
+    }
+} /* LZMA_enumerateFiles */
+
+
+static int LZMA_exists(dvoid *opaque, const char *name)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    return(lzma_find_file(archive, name) != NULL);
+} /* LZMA_exists */
+
+
+static PHYSFS_sint64 LZMA_getLastModTime(dvoid *opaque,
+                                         const char *name,
+                                         int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+
+    *fileExists = (file != NULL);
+
+    BAIL_IF_MACRO(file == NULL, NULL, -1);
+       BAIL_IF_MACRO(!file->item->IsLastWriteTimeDefined, NULL, -1); /* write-time may not be defined for every file */
+
+    return(lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime));
+} /* LZMA_getLastModTime */
+
+
+static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+
+    *fileExists = (file != NULL);
+
+    return(file == NULL ? 0 : file->item->IsDirectory);
+} /* LZMA_isDirectory */
+
+
+static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* LZMA_isSymLink */
+
+
+static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+
+    *fileExists = (file != NULL);
+    BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, NULL);
+
+    file->position = 0;
+    file->folder->references++; /* Increase refcount for automatic cleanup... */
+
+    return(file);
+} /* LZMA_openRead */
+
+
+static fvoid *LZMA_openWrite(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* LZMA_openWrite */
+
+
+static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* LZMA_openAppend */
+
+
+static void LZMA_dirClose(dvoid *opaque)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+
+    for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
+    {
+        LZMA_fileClose(&archive->files[fileIndex]);
+    } /* for */
+
+    SzArDbExFree(&archive->db, SzFreePhysicsFS);
+    __PHYSFS_platformClose(archive->stream.file);
+    lzma_archive_exit(archive);
+} /* LZMA_dirClose */
+
+
+static int LZMA_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* LZMA_remove */
+
+
+static int LZMA_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* LZMA_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
+{
+    "7Z",
+    LZMA_ARCHIVE_DESCRIPTION,
+    "Dennis Schridde <devurandom@gmx.net>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
+{
+    &__PHYSFS_ArchiveInfo_LZMA,
+    LZMA_isArchive,          /* isArchive() method      */
+    LZMA_openArchive,        /* openArchive() method    */
+    LZMA_enumerateFiles,     /* enumerateFiles() method */
+    LZMA_exists,             /* exists() method         */
+    LZMA_isDirectory,        /* isDirectory() method    */
+    LZMA_isSymLink,          /* isSymLink() method      */
+    LZMA_getLastModTime,     /* getLastModTime() method */
+    LZMA_openRead,           /* openRead() method       */
+    LZMA_openWrite,          /* openWrite() method      */
+    LZMA_openAppend,         /* openAppend() method     */
+    LZMA_remove,             /* remove() method         */
+    LZMA_mkdir,              /* mkdir() method          */
+    LZMA_dirClose,           /* dirClose() method       */
+    LZMA_read,               /* read() method           */
+    LZMA_write,              /* write() method          */
+    LZMA_eof,                /* eof() method            */
+    LZMA_tell,               /* tell() method           */
+    LZMA_seek,               /* seek() method           */
+    LZMA_fileLength,         /* fileLength() method     */
+    LZMA_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_7Z */
+
+/* end of lzma.c ... */
+
diff --git a/archivers/mvl.c b/archivers/mvl.c
new file mode 100644 (file)
index 0000000..8fbda23
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * MVL support routines for PhysicsFS.
+ *
+ * This driver handles Descent II Movielib archives.
+ *
+ * The file format of MVL is quite easy...
+ *
+ *   //MVL File format - Written by Heiko Herrmann
+ *   char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
+ *
+ *   int num_files; // the number of files in this MVL
+ *
+ *   struct {
+ *    char file_name[13]; // Filename, padded to 13 bytes with 0s
+ *    int file_size; // filesize in bytes
+ *   }DIR_STRUCT[num_files];
+ *
+ *   struct {
+ *    char data[file_size]; // The file data
+ *   }FILE_STRUCT[num_files];
+ *
+ * (That info is from http://www.descent2.com/ddn/specs/mvl/)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Bradley Bell.
+ *  Based on grp.c by Ryan C. Gordon.
+ */
+
+#if (defined PHYSFS_SUPPORTS_MVL)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    char name[13];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} MVLentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    MVLentry *entries;
+} MVLinfo;
+
+typedef struct
+{
+    void *handle;
+    MVLentry *entry;
+    PHYSFS_uint32 curPos;
+} MVLfileinfo;
+
+
+static void MVL_dirClose(dvoid *opaque)
+{
+    MVLinfo *info = ((MVLinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* MVL_dirClose */
+
+
+static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    MVLentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* MVL_read */
+
+
+static PHYSFS_sint64 MVL_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* MVL_write */
+
+
+static int MVL_eof(fvoid *opaque)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    MVLentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* MVL_eof */
+
+
+static PHYSFS_sint64 MVL_tell(fvoid *opaque)
+{
+    return(((MVLfileinfo *) opaque)->curPos);
+} /* MVL_tell */
+
+
+static int MVL_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    MVLentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* MVL_seek */
+
+
+static PHYSFS_sint64 MVL_fileLength(fvoid *opaque)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* MVL_fileLength */
+
+
+static int MVL_fileClose(fvoid *opaque)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* MVL_fileClose */
+
+
+static int mvl_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint8 buf[4];
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, buf, 4, 1) != 1)
+        goto openMvl_failed;
+
+    if (memcmp(buf, "DMVL", 4) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openMvl_failed;
+    } /* if */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openMvl_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    return(1);
+
+openMvl_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* mvl_open */
+
+
+static int MVL_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = mvl_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* MVL_isArchive */
+
+
+static int mvl_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const MVLentry *a = (const MVLentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* mvl_entry_cmp */
+
+
+static void mvl_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        MVLentry tmp;
+        MVLentry *first = &(((MVLentry *) _a)[one]);
+        MVLentry *second = &(((MVLentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (MVLentry));
+        memcpy(first, second, sizeof (MVLentry));
+        memcpy(second, &tmp, sizeof (MVLentry));
+    } /* if */
+} /* mvl_entry_swap */
+
+
+static int mvl_load_entries(const char *name, int forWriting, MVLinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    PHYSFS_uint32 location = 8;  /* sizeof sig. */
+    MVLentry *entry;
+
+    BAIL_IF_MACRO(!mvl_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    location += (17 * fileCount);
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = location;
+        location += entry->size;
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  mvl_entry_cmp, mvl_entry_swap);
+    return(1);
+} /* mvl_load_entries */
+
+
+static void *MVL_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    MVLinfo *info = (MVLinfo *) allocator.Malloc(sizeof (MVLinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (MVLinfo));
+
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, MVL_openArchive_failed);
+    if (!mvl_load_entries(name, forWriting, info))
+        goto MVL_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+    return(info);
+
+MVL_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* MVL_openArchive */
+
+
+static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    /* no directories in MVL files. */
+    if (*dname == '\0')
+    {
+        MVLinfo *info = ((MVLinfo *) opaque);
+        MVLentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
+
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, origdir, entry->name);
+    } /* if */
+} /* MVL_enumerateFiles */
+
+
+static MVLentry *mvl_find_entry(MVLinfo *info, const char *name)
+{
+    char *ptr = strchr(name, '.');
+    MVLentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    /*
+     * Rule out filenames to avoid unneeded processing...no dirs,
+     *   big filenames, or extensions > 3 chars.
+     */
+    BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = __PHYSFS_stricmpASCII(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* mvl_find_entry */
+
+
+static int MVL_exists(dvoid *opaque, const char *name)
+{
+    return(mvl_find_entry(((MVLinfo *) opaque), name) != NULL);
+} /* MVL_exists */
+
+
+static int MVL_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = MVL_exists(opaque, name);
+    return(0);  /* never directories in a groupfile. */
+} /* MVL_isDirectory */
+
+
+static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = MVL_exists(opaque, name);
+    return(0);  /* never symlinks in a groupfile. */
+} /* MVL_isSymLink */
+
+
+static PHYSFS_sint64 MVL_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    MVLinfo *info = ((MVLinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (mvl_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of MVL itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* MVL_getLastModTime */
+
+
+static fvoid *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    MVLinfo *info = ((MVLinfo *) opaque);
+    MVLfileinfo *finfo;
+    MVLentry *entry;
+
+    entry = mvl_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* MVL_openRead */
+
+
+static fvoid *MVL_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* MVL_openWrite */
+
+
+static fvoid *MVL_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* MVL_openAppend */
+
+
+static int MVL_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* MVL_remove */
+
+
+static int MVL_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* MVL_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_MVL =
+{
+    "MVL",
+    MVL_ARCHIVE_DESCRIPTION,
+    "Bradley Bell <btb@icculus.org>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
+{
+    &__PHYSFS_ArchiveInfo_MVL,
+    MVL_isArchive,          /* isArchive() method      */
+    MVL_openArchive,        /* openArchive() method    */
+    MVL_enumerateFiles,     /* enumerateFiles() method */
+    MVL_exists,             /* exists() method         */
+    MVL_isDirectory,        /* isDirectory() method    */
+    MVL_isSymLink,          /* isSymLink() method      */
+    MVL_getLastModTime,     /* getLastModTime() method */
+    MVL_openRead,           /* openRead() method       */
+    MVL_openWrite,          /* openWrite() method      */
+    MVL_openAppend,         /* openAppend() method     */
+    MVL_remove,             /* remove() method         */
+    MVL_mkdir,              /* mkdir() method          */
+    MVL_dirClose,           /* dirClose() method       */
+    MVL_read,               /* read() method           */
+    MVL_write,              /* write() method          */
+    MVL_eof,                /* eof() method            */
+    MVL_tell,               /* tell() method           */
+    MVL_seek,               /* seek() method           */
+    MVL_fileLength,         /* fileLength() method     */
+    MVL_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_MVL */
+
+/* end of mvl.c ... */
+
diff --git a/archivers/qpak.c b/archivers/qpak.c
new file mode 100644 (file)
index 0000000..1aa7a32
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+ * QPAK support routines for PhysicsFS.
+ *
+ *  This archiver handles the archive format utilized by Quake 1 and 2.
+ *  Quake3-based games use the PkZip/Info-Zip format (which our zip.c
+ *  archiver handles).
+ *
+ *  ========================================================================
+ *
+ *  This format info (in more detail) comes from:
+ *     http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
+ *
+ *  Quake PAK Format
+ *
+ *  Header
+ *   (4 bytes)  signature = 'PACK'
+ *   (4 bytes)  directory offset
+ *   (4 bytes)  directory length
+ *
+ *  Directory
+ *   (56 bytes) file name
+ *   (4 bytes)  file position
+ *   (4 bytes)  file length
+ *
+ *  ========================================================================
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#if (defined PHYSFS_SUPPORTS_QPAK)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if 1  /* Make this case insensitive? */
+#define QPAK_strcmp(x, y) __PHYSFS_stricmpASCII(x, y)
+#define QPAK_strncmp(x, y, z) __PHYSFS_strnicmpASCII(x, y, z)
+#else
+#define QPAK_strcmp(x, y) strcmp(x, y)
+#define QPAK_strncmp(x, y, z) strncmp(x, y, z)
+#endif
+
+
+typedef struct
+{
+    char name[56];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} QPAKentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    QPAKentry *entries;
+} QPAKinfo;
+
+typedef struct
+{
+    void *handle;
+    QPAKentry *entry;
+    PHYSFS_uint32 curPos;
+} QPAKfileinfo;
+
+/* Magic numbers... */
+#define QPAK_SIG 0x4b434150   /* "PACK" in ASCII. */
+
+
+static void QPAK_dirClose(dvoid *opaque)
+{
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* QPAK_dirClose */
+
+
+static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    QPAKentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* QPAK_read */
+
+
+static PHYSFS_sint64 QPAK_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* QPAK_write */
+
+
+static int QPAK_eof(fvoid *opaque)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    QPAKentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* QPAK_eof */
+
+
+static PHYSFS_sint64 QPAK_tell(fvoid *opaque)
+{
+    return(((QPAKfileinfo *) opaque)->curPos);
+} /* QPAK_tell */
+
+
+static int QPAK_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    QPAKentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* QPAK_seek */
+
+
+static PHYSFS_sint64 QPAK_fileLength(fvoid *opaque)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* QPAK_fileLength */
+
+
+static int QPAK_fileClose(fvoid *opaque)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* QPAK_fileClose */
+
+
+static int qpak_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint32 buf;
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, &buf, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openQpak_failed;
+
+    buf = PHYSFS_swapULE32(buf);
+    GOTO_IF_MACRO(buf != QPAK_SIG, ERR_UNSUPPORTED_ARCHIVE, openQpak_failed);
+
+    if (__PHYSFS_platformRead(*fh, &buf, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openQpak_failed;
+
+    buf = PHYSFS_swapULE32(buf);  /* directory table offset. */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openQpak_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    /* corrupted archive? */
+    GOTO_IF_MACRO((*count % 64) != 0, ERR_CORRUPTED, openQpak_failed);
+
+    if (!__PHYSFS_platformSeek(*fh, buf))
+        goto openQpak_failed;
+
+    *count /= 64;
+    return(1);
+
+openQpak_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* qpak_open */
+
+
+static int QPAK_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = qpak_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* QPAK_isArchive */
+
+
+static int qpak_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const QPAKentry *a = (const QPAKentry *) _a;
+        return(QPAK_strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* qpak_entry_cmp */
+
+
+static void qpak_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        QPAKentry tmp;
+        QPAKentry *first = &(((QPAKentry *) _a)[one]);
+        QPAKentry *second = &(((QPAKentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (QPAKentry));
+        memcpy(first, second, sizeof (QPAKentry));
+        memcpy(second, &tmp, sizeof (QPAKentry));
+    } /* if */
+} /* qpak_entry_swap */
+
+
+static int qpak_load_entries(const char *name, int forWriting, QPAKinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    QPAKentry *entry;
+
+    BAIL_IF_MACRO(!qpak_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (QPAKentry*) allocator.Malloc(sizeof(QPAKentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        PHYSFS_uint32 loc;
+
+        if (__PHYSFS_platformRead(fh,&entry->name,sizeof(entry->name),1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh,&loc,sizeof(loc),1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh,&entry->size,sizeof(entry->size),1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = PHYSFS_swapULE32(loc);
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  qpak_entry_cmp, qpak_entry_swap);
+    return(1);
+} /* qpak_load_entries */
+
+
+static void *QPAK_openArchive(const char *name, int forWriting)
+{
+    QPAKinfo *info = (QPAKinfo *) allocator.Malloc(sizeof (QPAKinfo));
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (QPAKinfo));
+
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    if (info->filename == NULL)
+    {
+        __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+        goto QPAK_openArchive_failed;
+    } /* if */
+
+    if (!qpak_load_entries(name, forWriting, info))
+        goto QPAK_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+    return(info);
+
+QPAK_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* QPAK_openArchive */
+
+
+static PHYSFS_sint32 qpak_find_start_of_dir(QPAKinfo *info, const char *path,
+                                            int stop_on_first_find)
+{
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    PHYSFS_uint32 dlen = strlen(path);
+    PHYSFS_sint32 retval = -1;
+    const char *name;
+    int rc;
+
+    if (*path == '\0')  /* root dir? */
+        return(0);
+
+    if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        name = info->entries[middle].name;
+        rc = QPAK_strncmp(path, name, dlen);
+        if (rc == 0)
+        {
+            char ch = name[dlen];
+            if (ch < '/') /* make sure this isn't just a substr match. */
+                rc = -1;
+            else if (ch > '/')
+                rc = 1;
+            else 
+            {
+                if (stop_on_first_find) /* Just checking dir's existance? */
+                    return(middle);
+
+                if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+                    return(middle + 1);
+
+                /* there might be more entries earlier in the list. */
+                retval = middle;
+                hi = middle - 1;
+            } /* else */
+        } /* if */
+
+        if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    return(retval);
+} /* qpak_find_start_of_dir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void QPAK_enumerateFiles(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                                const char *origdir, void *callbackdata)
+{
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    PHYSFS_sint32 dlen, dlen_inc, max, i;
+
+    i = qpak_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
+
+    dlen = strlen(dname);
+    if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
+    max = (PHYSFS_sint32) info->entryCount;
+    while (i < max)
+    {
+        char *add;
+        char *ptr;
+        PHYSFS_sint32 ln;
+        char *e = info->entries[i].name;
+        if ((dlen) && ((QPAK_strncmp(e, dname, dlen)) || (e[dlen] != '/')))
+            break;  /* past end of this dir; we're done. */
+
+        add = e + dlen_inc;
+        ptr = strchr(add, '/');
+        ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+        doEnumCallback(cb, callbackdata, origdir, add, ln);
+        ln += dlen_inc;  /* point past entry to children... */
+
+        /* increment counter and skip children of subdirs... */
+        while ((++i < max) && (ptr != NULL))
+        {
+            char *e_new = info->entries[i].name;
+            if ((QPAK_strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+                break;
+        } /* while */
+    } /* while */
+} /* QPAK_enumerateFiles */
+
+
+/*
+ * This will find the QPAKentry associated with a path in platform-independent
+ *  notation. Directories don't have QPAKentries associated with them, but 
+ *  (*isDir) will be set to non-zero if a dir was hit.
+ */
+static QPAKentry *qpak_find_entry(QPAKinfo *info, const char *path, int *isDir)
+{
+    QPAKentry *a = info->entries;
+    PHYSFS_sint32 pathlen = strlen(path);
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    const char *thispath = NULL;
+    int rc;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        thispath = a[middle].name;
+        rc = QPAK_strncmp(path, thispath, pathlen);
+
+        if (rc > 0)
+            lo = middle + 1;
+
+        else if (rc < 0)
+            hi = middle - 1;
+
+        else /* substring match...might be dir or entry or nothing. */
+        {
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return(NULL);
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return(&a[middle]);
+            /* adjust search params, try again. */
+            else if (thispath[pathlen] > '/')
+                hi = middle - 1;
+            else
+                lo = middle + 1;
+        } /* if */
+    } /* while */
+
+    if (isDir != NULL)
+        *isDir = 0;
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* qpak_find_entry */
+
+
+static int QPAK_exists(dvoid *opaque, const char *name)
+{
+    int isDir;    
+    QPAKinfo *info = (QPAKinfo *) opaque;
+    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
+    return((entry != NULL) || (isDir));
+} /* QPAK_exists */
+
+
+static int QPAK_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    QPAKinfo *info = (QPAKinfo *) opaque;
+    int isDir;
+    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (isDir)
+        return(1); /* definitely a dir. */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, 0);
+} /* QPAK_isDirectory */
+
+
+static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = QPAK_exists(opaque, name);
+    return(0);  /* never symlinks in a quake pak. */
+} /* QPAK_isSymLink */
+
+
+static PHYSFS_sint64 QPAK_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    int isDir;
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (*fileExists)  /* use time of QPAK itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* QPAK_getLastModTime */
+
+
+static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    QPAKfileinfo *finfo;
+    QPAKentry *entry;
+    int isDir;
+
+    entry = qpak_find_entry(info, fnm, &isDir);
+    *fileExists = ((entry != NULL) || (isDir));
+    BAIL_IF_MACRO(isDir, ERR_NOT_A_FILE, NULL);
+    BAIL_IF_MACRO(entry == NULL, ERR_NO_SUCH_FILE, NULL);
+
+    finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* QPAK_openRead */
+
+
+static fvoid *QPAK_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* QPAK_openWrite */
+
+
+static fvoid *QPAK_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* QPAK_openAppend */
+
+
+static int QPAK_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* QPAK_remove */
+
+
+static int QPAK_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* QPAK_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_QPAK =
+{
+    "PAK",
+    QPAK_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <icculus@icculus.org>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
+{
+    &__PHYSFS_ArchiveInfo_QPAK,
+    QPAK_isArchive,          /* isArchive() method      */
+    QPAK_openArchive,        /* openArchive() method    */
+    QPAK_enumerateFiles,     /* enumerateFiles() method */
+    QPAK_exists,             /* exists() method         */
+    QPAK_isDirectory,        /* isDirectory() method    */
+    QPAK_isSymLink,          /* isSymLink() method      */
+    QPAK_getLastModTime,     /* getLastModTime() method */
+    QPAK_openRead,           /* openRead() method       */
+    QPAK_openWrite,          /* openWrite() method      */
+    QPAK_openAppend,         /* openAppend() method     */
+    QPAK_remove,             /* remove() method         */
+    QPAK_mkdir,              /* mkdir() method          */
+    QPAK_dirClose,           /* dirClose() method       */
+    QPAK_read,               /* read() method           */
+    QPAK_write,              /* write() method          */
+    QPAK_eof,                /* eof() method            */
+    QPAK_tell,               /* tell() method           */
+    QPAK_seek,               /* seek() method           */
+    QPAK_fileLength,         /* fileLength() method     */
+    QPAK_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_QPAK */
+
+/* end of qpak.c ... */
+
diff --git a/archivers/wad.c b/archivers/wad.c
new file mode 100644 (file)
index 0000000..cb2626c
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * WAD support routines for PhysicsFS.
+ *
+ * This driver handles DOOM engine archives ("wads"). 
+ * This format (but not this driver) was designed by id Software for use
+ *  with the DOOM engine.
+ * The specs of the format are from the unofficial doom specs v1.666
+ * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
+ * The format of the archive: (from the specs)
+ *
+ *  A WAD file has three parts:
+ *  (1) a twelve-byte header
+ *  (2) one or more "lumps"
+ *  (3) a directory or "info table" that contains the names, offsets, and
+ *      sizes of all the lumps in the WAD
+ *
+ *  The header consists of three four-byte parts:
+ *    (a) an ASCII string which must be either "IWAD" or "PWAD"
+ *    (b) a 4-byte (long) integer which is the number of lumps in the wad
+ *    (c) a long integer which is the file offset to the start of
+ *    the directory
+ *
+ *  The directory has one 16-byte entry for every lump. Each entry consists
+ *  of three parts:
+ *
+ *    (a) a long integer, the file offset to the start of the lump
+ *    (b) a long integer, the size of the lump in bytes
+ *    (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
+ *        For example, the "DEMO1" entry in hexadecimal would be
+ *        (44 45 4D 4F 31 00 00 00)
+ * 
+ * Note that there is no way to tell if an opened WAD archive is a
+ *  IWAD or PWAD with this archiver.
+ * I couldn't think of a way to provide that information, without being too
+ *  hacky.
+ * I don't think it's really that important though.
+ *
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Travis Wells, based on the GRP archiver by
+ *  Ryan C. Gordon.
+ */
+
+#if (defined PHYSFS_SUPPORTS_WAD)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    char name[18];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} WADentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    PHYSFS_uint32 entryOffset;
+    WADentry *entries;
+} WADinfo;
+
+typedef struct
+{
+    void *handle;
+    WADentry *entry;
+    PHYSFS_uint32 curPos;
+} WADfileinfo;
+
+
+static void WAD_dirClose(dvoid *opaque)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* WAD_dirClose */
+
+
+static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    WADentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* WAD_read */
+
+
+static PHYSFS_sint64 WAD_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* WAD_write */
+
+
+static int WAD_eof(fvoid *opaque)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    WADentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* WAD_eof */
+
+
+static PHYSFS_sint64 WAD_tell(fvoid *opaque)
+{
+    return(((WADfileinfo *) opaque)->curPos);
+} /* WAD_tell */
+
+
+static int WAD_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    WADentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* WAD_seek */
+
+
+static PHYSFS_sint64 WAD_fileLength(fvoid *opaque)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* WAD_fileLength */
+
+
+static int WAD_fileClose(fvoid *opaque)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* WAD_fileClose */
+
+
+static int wad_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count,PHYSFS_uint32 *offset)
+{
+    PHYSFS_uint8 buf[4];
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, buf, 4, 1) != 1)
+        goto openWad_failed;
+
+    if (memcmp(buf, "IWAD", 4) != 0 && memcmp(buf, "PWAD", 4) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openWad_failed;
+    } /* if */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openWad_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    if (__PHYSFS_platformRead(*fh, offset, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openWad_failed;
+
+    *offset = PHYSFS_swapULE32(*offset);
+
+    return(1);
+
+openWad_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* wad_open */
+
+
+static int WAD_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount,offset;
+    int retval = wad_open(filename, forWriting, &fh, &fileCount,&offset);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* WAD_isArchive */
+
+
+static int wad_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const WADentry *a = (const WADentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* wad_entry_cmp */
+
+
+static void wad_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        WADentry tmp;
+        WADentry *first = &(((WADentry *) _a)[one]);
+        WADentry *second = &(((WADentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (WADentry));
+        memcpy(first, second, sizeof (WADentry));
+        memcpy(second, &tmp, sizeof (WADentry));
+    } /* if */
+} /* wad_entry_swap */
+
+
+static int wad_load_entries(const char *name, int forWriting, WADinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    PHYSFS_uint32 directoryOffset;
+    WADentry *entry;
+    char lastDirectory[9];
+
+    lastDirectory[8] = 0; /* Make sure lastDirectory stays null-terminated. */
+
+    BAIL_IF_MACRO(!wad_open(name, forWriting, &fh, &fileCount,&directoryOffset), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (WADentry *) allocator.Malloc(sizeof(WADentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    __PHYSFS_platformSeek(fh,directoryOffset);
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->startPos, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+        
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh, &entry->name, 8, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->name[8] = '\0'; /* name might not be null-terminated in file. */
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = PHYSFS_swapULE32(entry->startPos);
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  wad_entry_cmp, wad_entry_swap);
+    return(1);
+} /* wad_load_entries */
+
+
+static void *WAD_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    WADinfo *info = (WADinfo *) allocator.Malloc(sizeof (WADinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (WADinfo));
+
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, WAD_openArchive_failed);
+
+    if (!wad_load_entries(name, forWriting, info))
+        goto WAD_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+    return(info);
+
+WAD_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* WAD_openArchive */
+
+
+static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    WADentry *entry = info->entries;
+    PHYSFS_uint32 max = info->entryCount;
+    PHYSFS_uint32 i;
+    const char *name;
+    char *sep;
+
+    if (*dname == '\0')  /* root directory enumeration? */
+    {
+        for (i = 0; i < max; i++, entry++)
+        {
+            name = entry->name;
+            if (strchr(name, '/') == NULL)
+                cb(callbackdata, origdir, name);
+        } /* for */
+    } /* if */
+    else
+    {
+        for (i = 0; i < max; i++, entry++)
+        {
+            name = entry->name;
+            sep = strchr(name, '/');
+            if (sep != NULL)
+            {
+                if (strncmp(dname, name, (sep - name)) == 0)
+                    cb(callbackdata, origdir, sep + 1);
+            } /* if */
+        } /* for */
+    } /* else */
+} /* WAD_enumerateFiles */
+
+
+static WADentry *wad_find_entry(WADinfo *info, const char *name)
+{
+    WADentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = strcmp(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* wad_find_entry */
+
+
+static int WAD_exists(dvoid *opaque, const char *name)
+{
+    return(wad_find_entry(((WADinfo *) opaque), name) != NULL);
+} /* WAD_exists */
+
+
+static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    WADentry *entry = wad_find_entry(((WADinfo *) opaque), name);
+    if (entry != NULL)
+    {
+        char *n;
+
+        *fileExists = 1;
+
+        /* Can't be a directory if it's a subdirectory. */
+        if (strchr(entry->name, '/') != NULL)
+            return(0);
+
+        /* Check if it matches "MAP??" or "E?M?" ... */
+        n = entry->name;
+        if ((n[0] == 'E' && n[2] == 'M') ||
+            (n[0] == 'M' && n[1] == 'A' && n[2] == 'P' && n[6] == 0))
+        {
+            return(1);
+        } /* if */
+        return(0);
+    } /* if */
+    else
+    {
+        *fileExists = 0;
+        return(0);
+    } /* else */
+} /* WAD_isDirectory */
+
+
+static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = WAD_exists(opaque, name);
+    return(0);  /* never symlinks in a wad. */
+} /* WAD_isSymLink */
+
+
+static PHYSFS_sint64 WAD_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (wad_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of WAD itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* WAD_getLastModTime */
+
+
+static fvoid *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    WADfileinfo *finfo;
+    WADentry *entry;
+
+    entry = wad_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (WADfileinfo *) allocator.Malloc(sizeof (WADfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* WAD_openRead */
+
+
+static fvoid *WAD_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* WAD_openWrite */
+
+
+static fvoid *WAD_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* WAD_openAppend */
+
+
+static int WAD_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* WAD_remove */
+
+
+static int WAD_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* WAD_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_WAD =
+{
+    "WAD",
+    WAD_ARCHIVE_DESCRIPTION,
+    "Travis Wells <traviswells@mchsi.com>",
+    "http://www.3dmm2.com/doom/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
+{
+    &__PHYSFS_ArchiveInfo_WAD,
+    WAD_isArchive,          /* isArchive() method      */
+    WAD_openArchive,        /* openArchive() method    */
+    WAD_enumerateFiles,     /* enumerateFiles() method */
+    WAD_exists,             /* exists() method         */
+    WAD_isDirectory,        /* isDirectory() method    */
+    WAD_isSymLink,          /* isSymLink() method      */
+    WAD_getLastModTime,     /* getLastModTime() method */
+    WAD_openRead,           /* openRead() method       */
+    WAD_openWrite,          /* openWrite() method      */
+    WAD_openAppend,         /* openAppend() method     */
+    WAD_remove,             /* remove() method         */
+    WAD_mkdir,              /* mkdir() method          */
+    WAD_dirClose,           /* dirClose() method       */
+    WAD_read,               /* read() method           */
+    WAD_write,              /* write() method          */
+    WAD_eof,                /* eof() method            */
+    WAD_tell,               /* tell() method           */
+    WAD_seek,               /* seek() method           */
+    WAD_fileLength,         /* fileLength() method     */
+    WAD_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_WAD */
+
+/* end of wad.c ... */
+
diff --git a/archivers/zip.c b/archivers/zip.c
new file mode 100644 (file)
index 0000000..b546df2
--- /dev/null
@@ -0,0 +1,1454 @@
+/*
+ * ZIP support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon, with some peeking at "unzip.c"
+ *   by Gilles Vollant.
+ */
+
+#if (defined PHYSFS_SUPPORTS_ZIP)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#include <errno.h>
+#include <time.h>
+#endif
+#include "physfs.h"
+#include "zlib.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/*
+ * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
+ *  and is freed when you close the file; compressed data is read into
+ *  this buffer, and then is decompressed into the buffer passed to
+ *  PHYSFS_read().
+ *
+ * Uncompressed entries in a zipfile do not allocate this buffer; they just
+ *  read data directly into the buffer passed to PHYSFS_read().
+ *
+ * Depending on your speed and memory requirements, you should tweak this
+ *  value.
+ */
+#define ZIP_READBUFSIZE   (16 * 1024)
+
+
+/*
+ * Entries are "unresolved" until they are first opened. At that time,
+ *  local file headers parsed/validated, data offsets will be updated to look
+ *  at the actual file data instead of the header, and symlinks will be
+ *  followed and optimized. This means that we don't seek and read around the
+ *  archive until forced to do so, and after the first time, we had to do
+ *  less reading and parsing, which is very CD-ROM friendly.
+ */
+typedef enum
+{
+    ZIP_UNRESOLVED_FILE,
+    ZIP_UNRESOLVED_SYMLINK,
+    ZIP_RESOLVING,
+    ZIP_RESOLVED,
+    ZIP_BROKEN_FILE,
+    ZIP_BROKEN_SYMLINK
+} ZipResolveType;
+
+
+/*
+ * One ZIPentry is kept for each file in an open ZIP archive.
+ */
+typedef struct _ZIPentry
+{
+    char *name;                         /* Name of file in archive        */
+    struct _ZIPentry *symlink;          /* NULL or file we symlink to     */
+    ZipResolveType resolved;            /* Have we resolved file/symlink? */
+    PHYSFS_uint32 offset;               /* offset of data in archive      */
+    PHYSFS_uint16 version;              /* version made by                */
+    PHYSFS_uint16 version_needed;       /* version needed to extract      */
+    PHYSFS_uint16 compression_method;   /* compression method             */
+    PHYSFS_uint32 crc;                  /* crc-32                         */
+    PHYSFS_uint32 compressed_size;      /* compressed size                */
+    PHYSFS_uint32 uncompressed_size;    /* uncompressed size              */
+    PHYSFS_sint64 last_mod_time;        /* last file mod time             */
+} ZIPentry;
+
+/*
+ * One ZIPinfo is kept for each open ZIP archive.
+ */
+typedef struct
+{
+    char *archiveName;        /* path to ZIP in platform-dependent notation. */
+    PHYSFS_uint16 entryCount; /* Number of files in ZIP.                     */
+    ZIPentry *entries;        /* info on all files in ZIP.                   */
+} ZIPinfo;
+
+/*
+ * One ZIPfileinfo is kept for each open file in a ZIP archive.
+ */
+typedef struct
+{
+    ZIPentry *entry;                      /* Info on file.              */
+    void *handle;                         /* physical file handle.      */
+    PHYSFS_uint32 compressed_position;    /* offset in compressed data. */
+    PHYSFS_uint32 uncompressed_position;  /* tell() position.           */
+    PHYSFS_uint8 *buffer;                 /* decompression buffer.      */
+    z_stream stream;                      /* zlib stream state.         */
+} ZIPfileinfo;
+
+
+/* Magic numbers... */
+#define ZIP_LOCAL_FILE_SIG          0x04034b50
+#define ZIP_CENTRAL_DIR_SIG         0x02014b50
+#define ZIP_END_OF_CENTRAL_DIR_SIG  0x06054b50
+
+/* compression methods... */
+#define COMPMETH_NONE 0
+/* ...and others... */
+
+
+#define UNIX_FILETYPE_MASK    0170000
+#define UNIX_FILETYPE_SYMLINK 0120000
+
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
+{
+    return(((PHYSFS_Allocator *) opaque)->Malloc(items * size));
+} /* zlibPhysfsAlloc */
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static void zlibPhysfsFree(voidpf opaque, voidpf address)
+{
+    ((PHYSFS_Allocator *) opaque)->Free(address);
+} /* zlibPhysfsFree */
+
+
+/*
+ * Construct a new z_stream to a sane state.
+ */
+static void initializeZStream(z_stream *pstr)
+{
+    memset(pstr, '\0', sizeof (z_stream));
+    pstr->zalloc = zlibPhysfsAlloc;
+    pstr->zfree = zlibPhysfsFree;
+    pstr->opaque = &allocator;
+} /* initializeZStream */
+
+
+static const char *zlib_error_string(int rc)
+{
+    switch (rc)
+    {
+        case Z_OK: return(NULL);  /* not an error. */
+        case Z_STREAM_END: return(NULL); /* not an error. */
+#ifndef _WIN32_WCE
+        case Z_ERRNO: return(strerror(errno));
+#endif
+        case Z_NEED_DICT: return(ERR_NEED_DICT);
+        case Z_DATA_ERROR: return(ERR_DATA_ERROR);
+        case Z_MEM_ERROR: return(ERR_MEMORY_ERROR);
+        case Z_BUF_ERROR: return(ERR_BUFFER_ERROR);
+        case Z_VERSION_ERROR: return(ERR_VERSION_ERROR);
+        default: return(ERR_UNKNOWN_ERROR);
+    } /* switch */
+
+    return(NULL);
+} /* zlib_error_string */
+
+
+/*
+ * Wrap all zlib calls in this, so the physfs error state is set appropriately.
+ */
+static int zlib_err(int rc)
+{
+    const char *str = zlib_error_string(rc);
+    if (str != NULL)
+        __PHYSFS_setError(str);
+    return(rc);
+} /* zlib_err */
+
+
+/*
+ * Read an unsigned 32-bit int and swap to native byte order.
+ */
+static int readui32(void *in, PHYSFS_uint32 *val)
+{
+    PHYSFS_uint32 v;
+    BAIL_IF_MACRO(__PHYSFS_platformRead(in, &v, sizeof (v), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE32(v);
+    return(1);
+} /* readui32 */
+
+
+/*
+ * Read an unsigned 16-bit int and swap to native byte order.
+ */
+static int readui16(void *in, PHYSFS_uint16 *val)
+{
+    PHYSFS_uint16 v;
+    BAIL_IF_MACRO(__PHYSFS_platformRead(in, &v, sizeof (v), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE16(v);
+    return(1);
+} /* readui16 */
+
+
+static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    ZIPentry *entry = finfo->entry;
+    PHYSFS_sint64 retval = 0;
+    PHYSFS_sint64 maxread = ((PHYSFS_sint64) objSize) * objCount;
+    PHYSFS_sint64 avail = entry->uncompressed_size -
+                          finfo->uncompressed_position;
+
+    BAIL_IF_MACRO(maxread == 0, NULL, 0);    /* quick rejection. */
+
+    if (avail < maxread)
+    {
+        maxread = avail - (avail % objSize);
+        objCount = (PHYSFS_uint32) (maxread / objSize);
+        BAIL_IF_MACRO(objCount == 0, ERR_PAST_EOF, 0);  /* quick rejection. */
+        __PHYSFS_setError(ERR_PAST_EOF);   /* this is always true here. */
+    } /* if */
+
+    if (entry->compression_method == COMPMETH_NONE)
+    {
+        retval = __PHYSFS_platformRead(finfo->handle, buf, objSize, objCount);
+    } /* if */
+
+    else
+    {
+        finfo->stream.next_out = buf;
+        finfo->stream.avail_out = objSize * objCount;
+
+        while (retval < maxread)
+        {
+            PHYSFS_uint32 before = finfo->stream.total_out;
+            int rc;
+
+            if (finfo->stream.avail_in == 0)
+            {
+                PHYSFS_sint64 br;
+
+                br = entry->compressed_size - finfo->compressed_position;
+                if (br > 0)
+                {
+                    if (br > ZIP_READBUFSIZE)
+                        br = ZIP_READBUFSIZE;
+
+                    br = __PHYSFS_platformRead(finfo->handle,
+                                               finfo->buffer,
+                                               1, (PHYSFS_uint32) br);
+                    if (br <= 0)
+                        break;
+
+                    finfo->compressed_position += (PHYSFS_uint32) br;
+                    finfo->stream.next_in = finfo->buffer;
+                    finfo->stream.avail_in = (PHYSFS_uint32) br;
+                } /* if */
+            } /* if */
+
+            rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
+            retval += (finfo->stream.total_out - before);
+
+            if (rc != Z_OK)
+                break;
+        } /* while */
+
+        retval /= objSize;
+    } /* else */
+
+    if (retval > 0)
+        finfo->uncompressed_position += (PHYSFS_uint32) (retval * objSize);
+
+    return(retval);
+} /* ZIP_read */
+
+
+static PHYSFS_sint64 ZIP_write(fvoid *opaque, const void *buf,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* ZIP_write */
+
+
+static int ZIP_eof(fvoid *opaque)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    return(finfo->uncompressed_position >= finfo->entry->uncompressed_size);
+} /* ZIP_eof */
+
+
+static PHYSFS_sint64 ZIP_tell(fvoid *opaque)
+{
+    return(((ZIPfileinfo *) opaque)->uncompressed_position);
+} /* ZIP_tell */
+
+
+static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    ZIPentry *entry = finfo->entry;
+    void *in = finfo->handle;
+
+    BAIL_IF_MACRO(offset > entry->uncompressed_size, ERR_PAST_EOF, 0);
+
+    if (entry->compression_method == COMPMETH_NONE)
+    {
+        PHYSFS_sint64 newpos = offset + entry->offset;
+        BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, newpos), NULL, 0);
+        finfo->uncompressed_position = (PHYSFS_uint32) offset;
+    } /* if */
+
+    else
+    {
+        /*
+         * If seeking backwards, we need to redecode the file
+         *  from the start and throw away the compressed bits until we hit
+         *  the offset we need. If seeking forward, we still need to
+         *  decode, but we don't rewind first.
+         */
+        if (offset < finfo->uncompressed_position)
+        {
+            /* we do a copy so state is sane if inflateInit2() fails. */
+            z_stream str;
+            initializeZStream(&str);
+            if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
+                return(0);
+
+            if (!__PHYSFS_platformSeek(in, entry->offset))
+                return(0);
+
+            inflateEnd(&finfo->stream);
+            memcpy(&finfo->stream, &str, sizeof (z_stream));
+            finfo->uncompressed_position = finfo->compressed_position = 0;
+        } /* if */
+
+        while (finfo->uncompressed_position != offset)
+        {
+            PHYSFS_uint8 buf[512];
+            PHYSFS_uint32 maxread;
+
+            maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
+            if (maxread > sizeof (buf))
+                maxread = sizeof (buf);
+
+            if (ZIP_read(finfo, buf, maxread, 1) != 1)
+                return(0);
+        } /* while */
+    } /* else */
+
+    return(1);
+} /* ZIP_seek */
+
+
+static PHYSFS_sint64 ZIP_fileLength(fvoid *opaque)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    return(finfo->entry->uncompressed_size);
+} /* ZIP_fileLength */
+
+
+static int ZIP_fileClose(fvoid *opaque)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+        inflateEnd(&finfo->stream);
+
+    if (finfo->buffer != NULL)
+        allocator.Free(finfo->buffer);
+
+    allocator.Free(finfo);
+    return(1);
+} /* ZIP_fileClose */
+
+
+static PHYSFS_sint64 zip_find_end_of_central_dir(void *in, PHYSFS_sint64 *len)
+{
+    PHYSFS_uint8 buf[256];
+    PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
+    PHYSFS_sint32 i = 0;
+    PHYSFS_sint64 filelen;
+    PHYSFS_sint64 filepos;
+    PHYSFS_sint32 maxread;
+    PHYSFS_sint32 totalread = 0;
+    int found = 0;
+
+    filelen = __PHYSFS_platformFileLength(in);
+    BAIL_IF_MACRO(filelen == -1, NULL, 0);  /* !!! FIXME: unlocalized string */
+    BAIL_IF_MACRO(filelen > 0xFFFFFFFF, "ZIP bigger than 2 gigs?!", 0);
+
+    /*
+     * Jump to the end of the file and start reading backwards.
+     *  The last thing in the file is the zipfile comment, which is variable
+     *  length, and the field that specifies its size is before it in the
+     *  file (argh!)...this means that we need to scan backwards until we
+     *  hit the end-of-central-dir signature. We can then sanity check that
+     *  the comment was as big as it should be to make sure we're in the
+     *  right place. The comment length field is 16 bits, so we can stop
+     *  searching for that signature after a little more than 64k at most,
+     *  and call it a corrupted zipfile.
+     */
+
+    if (sizeof (buf) < filelen)
+    {
+        filepos = filelen - sizeof (buf);
+        maxread = sizeof (buf);
+    } /* if */
+    else
+    {
+        filepos = 0;
+        maxread = (PHYSFS_uint32) filelen;
+    } /* else */
+
+    while ((totalread < filelen) && (totalread < 65557))
+    {
+        BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, filepos), NULL, -1);
+
+        /* make sure we catch a signature between buffers. */
+        if (totalread != 0)
+        {
+            if (__PHYSFS_platformRead(in, buf, maxread - 4, 1) != 1)
+                return(-1);
+            memcpy(&buf[maxread - 4], &extra, sizeof (extra));
+            totalread += maxread - 4;
+        } /* if */
+        else
+        {
+            if (__PHYSFS_platformRead(in, buf, maxread, 1) != 1)
+                return(-1);
+            totalread += maxread;
+        } /* else */
+
+        memcpy(&extra, buf, sizeof (extra));
+
+        for (i = maxread - 4; i > 0; i--)
+        {
+            if ((buf[i + 0] == 0x50) &&
+                (buf[i + 1] == 0x4B) &&
+                (buf[i + 2] == 0x05) &&
+                (buf[i + 3] == 0x06) )
+            {
+                found = 1;  /* that's the signature! */
+                break;  
+            } /* if */
+        } /* for */
+
+        if (found)
+            break;
+
+        filepos -= (maxread - 4);
+        if (filepos < 0)
+            filepos = 0;
+    } /* while */
+
+    BAIL_IF_MACRO(!found, ERR_NOT_AN_ARCHIVE, -1);
+
+    if (len != NULL)
+        *len = filelen;
+
+    return(filepos + i);
+} /* zip_find_end_of_central_dir */
+
+
+static int ZIP_isArchive(const char *filename, int forWriting)
+{
+    PHYSFS_uint32 sig;
+    int retval = 0;
+    void *in;
+
+    in = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(in == NULL, NULL, 0);
+
+    /*
+     * The first thing in a zip file might be the signature of the
+     *  first local file record, so it makes for a quick determination.
+     */
+    if (readui32(in, &sig))
+    {
+        retval = (sig == ZIP_LOCAL_FILE_SIG);
+        if (!retval)
+        {
+            /*
+             * No sig...might be a ZIP with data at the start
+             *  (a self-extracting executable, etc), so we'll have to do
+             *  it the hard way...
+             */
+            retval = (zip_find_end_of_central_dir(in, NULL) != -1);
+        } /* if */
+    } /* if */
+
+    __PHYSFS_platformClose(in);
+    return(retval);
+} /* ZIP_isArchive */
+
+
+static void zip_free_entries(ZIPentry *entries, PHYSFS_uint32 max)
+{
+    PHYSFS_uint32 i;
+    for (i = 0; i < max; i++)
+    {
+        ZIPentry *entry = &entries[i];
+        if (entry->name != NULL)
+            allocator.Free(entry->name);
+    } /* for */
+
+    allocator.Free(entries);
+} /* zip_free_entries */
+
+
+/*
+ * This will find the ZIPentry associated with a path in platform-independent
+ *  notation. Directories don't have ZIPentries associated with them, but 
+ *  (*isDir) will be set to non-zero if a dir was hit.
+ */
+static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path, int *isDir)
+{
+    ZIPentry *a = info->entries;
+    PHYSFS_sint32 pathlen = strlen(path);
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    const char *thispath = NULL;
+    int rc;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        thispath = a[middle].name;
+        rc = strncmp(path, thispath, pathlen);
+
+        if (rc > 0)
+            lo = middle + 1;
+
+        else if (rc < 0)
+            hi = middle - 1;
+
+        else /* substring match...might be dir or entry or nothing. */
+        {
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return(NULL);
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return(&a[middle]);
+            /* adjust search params, try again. */
+            else if (thispath[pathlen] > '/')
+                hi = middle - 1;
+            else
+                lo = middle + 1;
+        } /* if */
+    } /* while */
+
+    if (isDir != NULL)
+        *isDir = 0;
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* 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(const ZIPentry *entry)
+{
+    return((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
+           (entry->resolved == ZIP_BROKEN_SYMLINK) ||
+           (entry->symlink));
+} /* zip_entry_is_symlink */
+
+
+static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
+{
+    PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
+
+    return (
+              (zip_version_does_symlinks(entry->version)) &&
+              (entry->uncompressed_size > 0) &&
+              ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK)
+           );
+} /* zip_has_symlink_attr */
+
+
+static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
+{
+#ifdef _WIN32_WCE
+    /* We have no struct tm and no mktime right now.
+       FIXME: This should probably be fixed at some point.
+    */
+    return -1;
+#else
+    PHYSFS_uint32 dosdate;
+    struct tm unixtime;
+    memset(&unixtime, '\0', sizeof (unixtime));
+
+    dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
+    dostime &= 0xFFFF;
+
+    /* dissect date */
+    unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
+    unixtime.tm_mon  = ((dosdate >> 5) & 0x0F) - 1;
+    unixtime.tm_mday = ((dosdate     ) & 0x1F);
+
+    /* dissect time */
+    unixtime.tm_hour = ((dostime >> 11) & 0x1F);
+    unixtime.tm_min  = ((dostime >>  5) & 0x3F);
+    unixtime.tm_sec  = ((dostime <<  1) & 0x3E);
+
+    /* let mktime calculate daylight savings time. */
+    unixtime.tm_isdst = -1;
+
+    return((PHYSFS_sint64) mktime(&unixtime));
+#endif
+} /* zip_dos_time_to_physfs_time */
+
+
+static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
+{
+    PHYSFS_uint16 fnamelen, extralen, commentlen;
+    PHYSFS_uint32 external_attr;
+    PHYSFS_uint16 ui16;
+    PHYSFS_uint32 ui32;
+    PHYSFS_sint64 si64;
+
+    /* sanity check with central directory signature... */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, ERR_CORRUPTED, 0);
+
+    /* Get the pertinent parts of the record... */
+    BAIL_IF_MACRO(!readui16(in, &entry->version), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &entry->version_needed), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* general bits */
+    BAIL_IF_MACRO(!readui16(in, &entry->compression_method), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
+    BAIL_IF_MACRO(!readui32(in, &entry->crc), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &entry->compressed_size), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &entry->uncompressed_size), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &commentlen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* disk number start */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* internal file attribs */
+    BAIL_IF_MACRO(!readui32(in, &external_attr), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &entry->offset), NULL, 0);
+    entry->offset += ofs_fixup;
+
+    entry->symlink = NULL;  /* will be resolved later, if necessary. */
+    entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
+                            ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
+
+    entry->name = (char *) allocator.Malloc(fnamelen + 1);
+    BAIL_IF_MACRO(entry->name == NULL, ERR_OUT_OF_MEMORY, 0);
+    if (__PHYSFS_platformRead(in, entry->name, fnamelen, 1) != 1)
+        goto zip_load_entry_puked;
+
+    entry->name[fnamelen] = '\0';  /* null-terminate the filename. */
+    zip_convert_dos_path(entry, entry->name);
+
+    si64 = __PHYSFS_platformTell(in);
+    if (si64 == -1)
+        goto zip_load_entry_puked;
+
+        /* seek to the start of the next entry in the central directory... */
+    if (!__PHYSFS_platformSeek(in, si64 + extralen + commentlen))
+        goto zip_load_entry_puked;
+
+    return(1);  /* success. */
+
+zip_load_entry_puked:
+    allocator.Free(entry->name);
+    return(0);  /* failure. */
+} /* zip_load_entry */
+
+
+static int zip_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const ZIPentry *a = (const ZIPentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* zip_entry_cmp */
+
+
+static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        ZIPentry tmp;
+        ZIPentry *first = &(((ZIPentry *) _a)[one]);
+        ZIPentry *second = &(((ZIPentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (ZIPentry));
+        memcpy(first, second, sizeof (ZIPentry));
+        memcpy(second, &tmp, sizeof (ZIPentry));
+    } /* if */
+} /* zip_entry_swap */
+
+
+static int zip_load_entries(void *in, ZIPinfo *info,
+                            PHYSFS_uint32 data_ofs, PHYSFS_uint32 central_ofs)
+{
+    PHYSFS_uint32 max = info->entryCount;
+    PHYSFS_uint32 i;
+
+    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, central_ofs), NULL, 0);
+
+    info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
+    BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    for (i = 0; i < max; i++)
+    {
+        if (!zip_load_entry(in, &info->entries[i], data_ofs))
+        {
+            zip_free_entries(info->entries, i);
+            return(0);
+        } /* if */
+    } /* for */
+
+    __PHYSFS_sort(info->entries, max, zip_entry_cmp, zip_entry_swap);
+    return(1);
+} /* zip_load_entries */
+
+
+static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
+                                        PHYSFS_uint32 *data_start,
+                                        PHYSFS_uint32 *central_dir_ofs)
+{
+    PHYSFS_uint32 ui32;
+    PHYSFS_uint16 ui16;
+    PHYSFS_sint64 len;
+    PHYSFS_sint64 pos;
+
+    /* find the end-of-central-dir record, and seek to it. */
+    pos = zip_find_end_of_central_dir(in, &len);
+    BAIL_IF_MACRO(pos == -1, NULL, 0);
+    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, pos), NULL, 0);
+
+    /* check signature again, just in case. */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, ERR_NOT_AN_ARCHIVE, 0);
+
+    /* number of this disk */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+    BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /* number of the disk with the start of the central directory */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+    BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /* total number of entries in the central dir on this disk */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+
+    /* total number of entries in the central dir */
+    BAIL_IF_MACRO(!readui16(in, &info->entryCount), NULL, 0);
+    BAIL_IF_MACRO(ui16 != info->entryCount, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /* size of the central directory */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+
+    /* offset of central directory */
+    BAIL_IF_MACRO(!readui32(in, central_dir_ofs), NULL, 0);
+    BAIL_IF_MACRO(pos < *central_dir_ofs + ui32, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /*
+     * For self-extracting archives, etc, there's crapola in the file
+     *  before the zipfile records; we calculate how much data there is
+     *  prepended by determining how far the central directory offset is
+     *  from where it is supposed to be (start of end-of-central-dir minus
+     *  sizeof central dir)...the difference in bytes is how much arbitrary
+     *  data is at the start of the physical file.
+     */
+    *data_start = (PHYSFS_uint32) (pos - (*central_dir_ofs + ui32));
+
+    /* Now that we know the difference, fix up the central dir offset... */
+    *central_dir_ofs += *data_start;
+
+    /* zipfile comment length */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+
+    /*
+     * Make sure that the comment length matches to the end of file...
+     *  If it doesn't, we're either in the wrong part of the file, or the
+     *  file is corrupted, but we give up either way.
+     */
+    BAIL_IF_MACRO((pos + 22 + ui16) != len, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    return(1);  /* made it. */
+} /* zip_parse_end_of_central_dir */
+
+
+static ZIPinfo *zip_create_zipinfo(const char *name)
+{
+    char *ptr;
+    ZIPinfo *info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
+    memset(info, '\0', sizeof (ZIPinfo));
+
+    ptr = (char *) allocator.Malloc(strlen(name) + 1);
+    if (ptr == NULL)
+    {
+        allocator.Free(info);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    info->archiveName = ptr;
+    strcpy(info->archiveName, name);
+    return(info);
+} /* zip_create_zipinfo */
+
+
+static void *ZIP_openArchive(const char *name, int forWriting)
+{
+    void *in = NULL;
+    ZIPinfo *info = NULL;
+    PHYSFS_uint32 data_start;
+    PHYSFS_uint32 cent_dir_ofs;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
+
+    if ((in = __PHYSFS_platformOpenRead(name)) == NULL)
+        goto zip_openarchive_failed;
+    
+    if ((info = zip_create_zipinfo(name)) == NULL)
+        goto zip_openarchive_failed;
+
+    if (!zip_parse_end_of_central_dir(in, info, &data_start, &cent_dir_ofs))
+        goto zip_openarchive_failed;
+
+    if (!zip_load_entries(in, info, data_start, cent_dir_ofs))
+        goto zip_openarchive_failed;
+
+    __PHYSFS_platformClose(in);
+    return(info);
+
+zip_openarchive_failed:
+    if (info != NULL)
+    {
+        if (info->archiveName != NULL)
+            allocator.Free(info->archiveName);
+        allocator.Free(info);
+    } /* if */
+
+    if (in != NULL)
+        __PHYSFS_platformClose(in);
+
+    return(NULL);
+} /* ZIP_openArchive */
+
+
+static PHYSFS_sint32 zip_find_start_of_dir(ZIPinfo *info, const char *path,
+                                            int stop_on_first_find)
+{
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    PHYSFS_uint32 dlen = strlen(path);
+    PHYSFS_sint32 retval = -1;
+    const char *name;
+    int rc;
+
+    if (*path == '\0')  /* root dir? */
+        return(0);
+
+    if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        name = info->entries[middle].name;
+        rc = strncmp(path, name, dlen);
+        if (rc == 0)
+        {
+            char ch = name[dlen];
+            if ('/' < ch) /* make sure this isn't just a substr match. */
+                rc = -1;
+            else if ('/' > ch)
+                rc = 1;
+            else 
+            {
+                if (stop_on_first_find) /* Just checking dir's existance? */
+                    return(middle);
+
+                if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+                    return(middle + 1);
+
+                /* there might be more entries earlier in the list. */
+                retval = middle;
+                hi = middle - 1;
+            } /* else */
+        } /* if */
+
+        if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    return(retval);
+} /* zip_find_start_of_dir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void ZIP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    ZIPinfo *info = ((ZIPinfo *) opaque);
+    PHYSFS_sint32 dlen, dlen_inc, max, i;
+
+    i = zip_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
+
+    dlen = strlen(dname);
+    if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
+    max = (PHYSFS_sint32) info->entryCount;
+    while (i < max)
+    {
+        char *e = info->entries[i].name;
+        if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
+            break;  /* past end of this dir; we're done. */
+
+        if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
+            i++;
+        else
+        {
+            char *add = e + dlen_inc;
+            char *ptr = strchr(add, '/');
+            PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+            doEnumCallback(cb, callbackdata, origdir, add, ln);
+            ln += dlen_inc;  /* point past entry to children... */
+
+            /* increment counter and skip children of subdirs... */
+            while ((++i < max) && (ptr != NULL))
+            {
+                char *e_new = info->entries[i].name;
+                if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+                    break;
+            } /* while */
+        } /* else */
+    } /* while */
+} /* ZIP_enumerateFiles */
+
+
+static int ZIP_exists(dvoid *opaque, const char *name)
+{
+    int isDir;    
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, name, &isDir);
+    return((entry != NULL) || (isDir));
+} /* ZIP_exists */
+
+
+static PHYSFS_sint64 ZIP_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    int isDir;
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (isDir)
+        return(1);  /* Best I can do for a dir... */
+
+    BAIL_IF_MACRO(entry == NULL, NULL, -1);
+    return(entry->last_mod_time);
+} /* ZIP_getLastModTime */
+
+
+static int ZIP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    int isDir;
+    ZIPentry *entry = zip_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (isDir)
+        return(1); /* definitely a dir. */
+
+    /* Follow symlinks. This means we might need to resolve entries. */
+    BAIL_IF_MACRO(entry == NULL, ERR_NO_SUCH_FILE, 0);
+
+    if (entry->resolved == ZIP_UNRESOLVED_SYMLINK) /* gotta resolve it. */
+    {
+        int rc;
+        void *in = __PHYSFS_platformOpenRead(info->archiveName);
+        BAIL_IF_MACRO(in == NULL, NULL, 0);
+        rc = zip_resolve(in, info, entry);
+        __PHYSFS_platformClose(in);
+        if (!rc)
+            return(0);
+    } /* if */
+
+    BAIL_IF_MACRO(entry->resolved == ZIP_BROKEN_SYMLINK, NULL, 0);
+    BAIL_IF_MACRO(entry->symlink == NULL, ERR_NOT_A_DIR, 0);
+
+    return(zip_find_start_of_dir(info, entry->symlink->name, 1) >= 0);
+} /* ZIP_isDirectory */
+
+
+static int ZIP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    int isDir;
+    const ZIPentry *entry = zip_find_entry((ZIPinfo *) opaque, name, &isDir);
+    *fileExists = ((isDir) || (entry != NULL));
+    BAIL_IF_MACRO(entry == NULL, NULL, 0);
+    return(zip_entry_is_symlink(entry));
+} /* ZIP_isSymLink */
+
+
+static void *zip_get_file_handle(const char *fn, ZIPinfo *inf, ZIPentry *entry)
+{
+    int success;
+    void *retval = __PHYSFS_platformOpenRead(fn);
+    BAIL_IF_MACRO(retval == NULL, NULL, NULL);
+
+    success = zip_resolve(retval, inf, entry);
+    if (success)
+    {
+        PHYSFS_sint64 offset;
+        offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
+        success = __PHYSFS_platformSeek(retval, offset);
+    } /* if */
+
+    if (!success)
+    {
+        __PHYSFS_platformClose(retval);
+        retval = NULL;
+    } /* if */
+
+    return(retval);
+} /* zip_get_file_handle */
+
+
+static fvoid *ZIP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, fnm, NULL);
+    ZIPfileinfo *finfo = NULL;
+    void *in;
+
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    in = zip_get_file_handle(info->archiveName, info, entry);
+    BAIL_IF_MACRO(in == NULL, NULL, NULL);
+
+    finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
+    if (finfo == NULL)
+    {
+        __PHYSFS_platformClose(in);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    memset(finfo, '\0', sizeof (ZIPfileinfo));
+    finfo->handle = in;
+    finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
+    initializeZStream(&finfo->stream);
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+    {
+        if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
+        {
+            ZIP_fileClose(finfo);
+            return(NULL);
+        } /* if */
+
+        finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
+        if (finfo->buffer == NULL)
+        {
+            ZIP_fileClose(finfo);
+            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+    } /* if */
+
+    return(finfo);
+} /* ZIP_openRead */
+
+
+static fvoid *ZIP_openWrite(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* ZIP_openWrite */
+
+
+static fvoid *ZIP_openAppend(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* ZIP_openAppend */
+
+
+static void ZIP_dirClose(dvoid *opaque)
+{
+    ZIPinfo *zi = (ZIPinfo *) (opaque);
+    zip_free_entries(zi->entries, zi->entryCount);
+    allocator.Free(zi->archiveName);
+    allocator.Free(zi);
+} /* ZIP_dirClose */
+
+
+static int ZIP_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* ZIP_remove */
+
+
+static int ZIP_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* ZIP_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP =
+{
+    "ZIP",
+    ZIP_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <icculus@icculus.org>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
+{
+    &__PHYSFS_ArchiveInfo_ZIP,
+    ZIP_isArchive,          /* isArchive() method      */
+    ZIP_openArchive,        /* openArchive() method    */
+    ZIP_enumerateFiles,     /* enumerateFiles() method */
+    ZIP_exists,             /* exists() method         */
+    ZIP_isDirectory,        /* isDirectory() method    */
+    ZIP_isSymLink,          /* isSymLink() method      */
+    ZIP_getLastModTime,     /* getLastModTime() method */
+    ZIP_openRead,           /* openRead() method       */
+    ZIP_openWrite,          /* openWrite() method      */
+    ZIP_openAppend,         /* openAppend() method     */
+    ZIP_remove,             /* remove() method         */
+    ZIP_mkdir,              /* mkdir() method          */
+    ZIP_dirClose,           /* dirClose() method       */
+    ZIP_read,               /* read() method           */
+    ZIP_write,              /* write() method          */
+    ZIP_eof,                /* eof() method            */
+    ZIP_tell,               /* tell() method           */
+    ZIP_seek,               /* seek() method           */
+    ZIP_fileLength,         /* fileLength() method     */
+    ZIP_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_ZIP */
+
+/* end of zip.c ... */
+
diff --git a/extras/PhysFS.NET/AssemblyInfo.cs b/extras/PhysFS.NET/AssemblyInfo.cs
new file mode 100755 (executable)
index 0000000..67157c6
--- /dev/null
@@ -0,0 +1,58 @@
+using System.Reflection;\r
+using System.Runtime.CompilerServices;\r
+\r
+//\r
+// General Information about an assembly is controlled through the following \r
+// set of attributes. Change these attribute values to modify the information\r
+// associated with an assembly.\r
+//\r
+[assembly: AssemblyTitle("PhysFS.NET")]\r
+[assembly: AssemblyDescription("PhysFS Bindings for .NET")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("")]\r
+[assembly: AssemblyProduct("PhysFS.NET")]\r
+[assembly: AssemblyCopyright("(c)2003 Gregory S. Read")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]                \r
+\r
+//\r
+// Version information for an assembly consists of the following four values:\r
+//\r
+//      Major Version\r
+//      Minor Version \r
+//      Build Number\r
+//      Revision\r
+//\r
+// You can specify all the values or you can default the Revision and Build Numbers \r
+// by using the '*' as shown below:\r
+\r
+[assembly: AssemblyVersion("1.0.*")]\r
+\r
+//\r
+// In order to sign your assembly you must specify a key to use. Refer to the \r
+// Microsoft .NET Framework documentation for more information on assembly signing.\r
+//\r
+// Use the attributes below to control which key is used for signing. \r
+//\r
+// Notes: \r
+//   (*) If no key is specified, the assembly is not signed.\r
+//   (*) KeyName refers to a key that has been installed in the Crypto Service\r
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains\r
+//       a key.\r
+//   (*) If the KeyFile and the KeyName values are both specified, the \r
+//       following processing occurs:\r
+//       (1) If the KeyName can be found in the CSP, that key is used.\r
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key \r
+//           in the KeyFile is installed into the CSP and used.\r
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.\r
+//       When specifying the KeyFile, the location of the KeyFile should be\r
+//       relative to the project output directory which is\r
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is\r
+//       located in the project directory, you would specify the AssemblyKeyFile \r
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]\r
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework\r
+//       documentation for more information on this.\r
+//\r
+[assembly: AssemblyDelaySign(false)]\r
+[assembly: AssemblyKeyFile("")]\r
+[assembly: AssemblyKeyName("")]\r
diff --git a/extras/PhysFS.NET/PhysFS.NET.csproj b/extras/PhysFS.NET/PhysFS.NET.csproj
new file mode 100755 (executable)
index 0000000..3b827b8
--- /dev/null
@@ -0,0 +1,113 @@
+<VisualStudioProject>\r
+    <CSHARP\r
+        ProjectType = "Local"\r
+        ProductVersion = "7.0.9466"\r
+        SchemaVersion = "1.0"\r
+        ProjectGuid = "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"\r
+    >\r
+        <Build>\r
+            <Settings\r
+                ApplicationIcon = ""\r
+                AssemblyKeyContainerName = ""\r
+                AssemblyName = "PhysFS.NET"\r
+                AssemblyOriginatorKeyFile = ""\r
+                DefaultClientScript = "JScript"\r
+                DefaultHTMLPageLayout = "Grid"\r
+                DefaultTargetSchema = "IE50"\r
+                DelaySign = "false"\r
+                OutputType = "Library"\r
+                RootNamespace = "PhysFS.NET"\r
+                StartupObject = ""\r
+            >\r
+                <Config\r
+                    Name = "Debug"\r
+                    AllowUnsafeBlocks = "true"\r
+                    BaseAddress = "285212672"\r
+                    CheckForOverflowUnderflow = "false"\r
+                    ConfigurationOverrideFile = ""\r
+                    DefineConstants = "DEBUG;TRACE"\r
+                    DocumentationFile = ""\r
+                    DebugSymbols = "true"\r
+                    FileAlignment = "4096"\r
+                    IncrementalBuild = "true"\r
+                    Optimize = "false"\r
+                    OutputPath = "bin\Debug\"\r
+                    RegisterForComInterop = "false"\r
+                    RemoveIntegerChecks = "false"\r
+                    TreatWarningsAsErrors = "false"\r
+                    WarningLevel = "4"\r
+                />\r
+                <Config\r
+                    Name = "Release"\r
+                    AllowUnsafeBlocks = "true"\r
+                    BaseAddress = "285212672"\r
+                    CheckForOverflowUnderflow = "false"\r
+                    ConfigurationOverrideFile = ""\r
+                    DefineConstants = "TRACE"\r
+                    DocumentationFile = ""\r
+                    DebugSymbols = "false"\r
+                    FileAlignment = "4096"\r
+                    IncrementalBuild = "false"\r
+                    Optimize = "true"\r
+                    OutputPath = "bin\Release\"\r
+                    RegisterForComInterop = "false"\r
+                    RemoveIntegerChecks = "false"\r
+                    TreatWarningsAsErrors = "false"\r
+                    WarningLevel = "4"\r
+                />\r
+            </Settings>\r
+            <References>\r
+                <Reference\r
+                    Name = "System"\r
+                    AssemblyName = "System"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.Data"\r
+                    AssemblyName = "System.Data"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.XML"\r
+                    AssemblyName = "System.Xml"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.Drawing"\r
+                    AssemblyName = "System.Drawing"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.Windows.Forms"\r
+                    AssemblyName = "System.Windows.Forms"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"\r
+                />\r
+            </References>\r
+        </Build>\r
+        <Files>\r
+            <Include>\r
+                <File\r
+                    RelPath = "AssemblyInfo.cs"\r
+                    SubType = "Code"\r
+                    BuildAction = "Compile"\r
+                />\r
+                <File\r
+                    RelPath = "PhysFS.cs"\r
+                    SubType = "Code"\r
+                    BuildAction = "Compile"\r
+                />\r
+                <File\r
+                    RelPath = "PhysFS_DLL.cs"\r
+                    SubType = "Code"\r
+                    BuildAction = "Compile"\r
+                />\r
+                <File\r
+                    RelPath = "PhysFSFileStream.cs"\r
+                    SubType = "Code"\r
+                    BuildAction = "Compile"\r
+                />\r
+            </Include>\r
+        </Files>\r
+    </CSHARP>\r
+</VisualStudioProject>\r
+\r
diff --git a/extras/PhysFS.NET/PhysFS.NET.sln b/extras/PhysFS.NET/PhysFS.NET.sln
new file mode 100755 (executable)
index 0000000..341aa47
--- /dev/null
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 7.00\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysFS.NET", "PhysFS.NET.csproj", "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfiguration) = preSolution\r
+               ConfigName.0 = Debug\r
+               ConfigName.1 = Release\r
+       EndGlobalSection\r
+       GlobalSection(ProjectDependencies) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfiguration) = postSolution\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.ActiveCfg = Debug|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.Build.0 = Debug|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.ActiveCfg = Release|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.Build.0 = Release|.NET\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityAddIns) = postSolution\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/extras/PhysFS.NET/PhysFS.cs b/extras/PhysFS.NET/PhysFS.cs
new file mode 100755 (executable)
index 0000000..30b7dac
--- /dev/null
@@ -0,0 +1,189 @@
+/* PhysFS.cs - (c)2003 Gregory S. Read\r
+ * Provides access to PhysFS API calls not specific to file handle access.\r
+ */\r
+using System;\r
+\r
+namespace PhysFS_NET\r
+{\r
+   public class PhysFS\r
+   {\r
+      /* Initialize\r
+       * Inits the PhysFS API.  This normally does not need to be called unless\r
+       * the API has been manually deinitialized since the PhysFS_DLL class\r
+       * initializes just before the first call is made into the DLL.\r
+       * Parameters\r
+       *    none\r
+       * Returns\r
+       *    none\r
+       * Exceptions\r
+       *    PhysFSException - An error occured in the PhysFS API\r
+       */\r
+      public static void Initialize()\r
+      {\r
+         // Initialize the physfs library, raise an exception if error\r
+         if(PhysFS_DLL.PHYSFS_init("") == 0)\r
+            throw new PhysFSException();\r
+      }\r
+\r
+      /* Deinitialize\r
+       * Deinits the PhysFS API.  It is recommended that this method be called\r
+       * by the application before exiting in order to gracefully deallocate\r
+       * resources and close all filehandles, etc.\r
+       * Parameters\r
+       *    none\r
+       * Returns\r
+       *    none\r
+       * Exceptions\r
+       *    PhysFSException - An error occured in the PhysFS API\r
+       */\r
+      public static void Deinitialize()\r
+      {\r
+         // Deinit, raise an exception if an error occured\r
+         if(PhysFS_DLL.PHYSFS_deinit() == 0)\r
+            throw new PhysFSException();\r
+      }\r
+\r
+      /* BaseDir\r
+       * Gets the base directory configured for PhysFS.  See the PhysFS API\r
+       * documentation for more information.\r
+       * Parameters\r
+       *    none\r
+       * Returns\r
+       *    A string value representing the Base Directory\r
+       * Exceptions\r
+       *    none\r
+       */\r
+      public static string BaseDir\r
+      {\r
+         get\r
+         {\r
+            // Return the current base directory\r
+            return PhysFS_DLL.PHYSFS_getBaseDir();\r
+         }\r
+      }\r
+\r
+      /* WriteDir\r
+       * Gets or sets the write directory configured for PhysFS.  See the PhysFS API\r
+       * documentation for more information.\r
+       * Parameters\r
+       *    set - Path to set the WriteDir property to\r
+       * Returns\r
+       *    A string value representing the Write Directory\r
+       * Exceptions\r
+       *    PhysFSException - An error occured in the PhysFS API when\r
+       *       settings the write directory.\r
+       */\r
+      public static string WriteDir\r
+      {\r
+         get\r
+         {\r
+            // Return the current write directory\r
+            return PhysFS_DLL.PHYSFS_getWriteDir();\r
+         }\r
+         set\r
+         {\r
+            // Set the write directory and raise an exception if an error occured\r
+            if(PhysFS_DLL.PHYSFS_setWriteDir(value) == 0)\r
+               throw new PhysFSException();\r
+         }\r
+      }\r
+\r
+      /* UserDir\r
+       * Gets or sets the write directory configured for PhysFS.  See the PhysFS API\r
+       * documentation for more information.\r
+       * Parameters\r
+       *    set - Path to set the WriteDir property to\r
+       * Returns\r
+       *    A string value representing the Write Directory\r
+       * Exceptions\r
+       *    PhysFSException - An error occured in the PhysFS API when\r
+       *       settings the write directory.\r
+       */\r
+      public static string UserDir\r
+      {\r
+         get\r
+         {\r
+            // Return the current user directory\r
+            return PhysFS_DLL.PHYSFS_getUserDir();\r
+         }\r
+      }\r
+      public static void AddToSearchPath(string NewDir, bool Append)\r
+      {\r
+         if(PhysFS_DLL.PHYSFS_addToSearchPath(NewDir, Append?1:0) == 0)\r
+            throw new PhysFSException();\r
+      }\r
+      public static void RemoveFromSearchPath(string OldDir)\r
+      {\r
+         if(PhysFS_DLL.PHYSFS_removeFromSearchPath(OldDir) == 0)\r
+            throw new PhysFSException();\r
+      }\r
+      public unsafe static string[] GetSearchPath()\r
+      {\r
+         byte** p;                             // Searchpath list from PhysFS dll\r
+         string[] pathlist;    // List converted to an array\r
+\r
+         // Get the CDROM drive listing\r
+         p = PhysFS_DLL.PHYSFS_getSearchPath();\r
+         // Convert the C-style array to a .NET style array\r
+         pathlist = PhysFS_DLL.BytePPToArray(p);\r
+         // Free the original list since we're done with it\r
+         PhysFS_DLL.PHYSFS_freeList(p);\r
+\r
+         return pathlist;\r
+      }\r
+      public unsafe static string[] GetCDROMDrives()\r
+      {\r
+         byte** p;                             // CDROM list from PhysFS dll\r
+         string[] cdromlist;   // List converted to an array\r
+\r
+         // Get the CDROM drive listing\r
+         p = PhysFS_DLL.PHYSFS_getCdRomDirs();\r
+         // Convert the C-style array to a .NET style array\r
+         cdromlist = PhysFS_DLL.BytePPToArray(p);\r
+         // Free the original list since we're done with it\r
+         PhysFS_DLL.PHYSFS_freeList(p);\r
+\r
+         return cdromlist;\r
+      }\r
+      public static void MkDir(string Dirname)\r
+      {\r
+         if(PhysFS_DLL.PHYSFS_mkdir(Dirname) == 0)\r
+            throw new PhysFSException();\r
+      }\r
+      public static void Delete(string Filename)\r
+      {\r
+         if(PhysFS_DLL.PHYSFS_delete(Filename) == 0)\r
+            throw new PhysFSException();\r
+      }\r
+      public static string GetRealDir(string Filename)\r
+      {\r
+         string RetValue;\r
+\r
+         RetValue = PhysFS_DLL.PHYSFS_getRealDir(Filename);\r
+         if(RetValue == null)\r
+            throw new PhysFSException("File not found in search path.");\r
+\r
+         // Return the real file path of the specified filename\r
+         return RetValue;\r
+      }\r
+      public unsafe static string[] EnumerateFiles(string Dirname)\r
+      {\r
+         byte** p;                             // File list from PhysFS dll\r
+         string[] filelist;    // List converted to an array\r
+\r
+         // Get the CDROM drive listing\r
+         p = PhysFS_DLL.PHYSFS_enumerateFiles(Dirname);\r
+         // Convert the C-style array to a .NET style array\r
+         filelist = PhysFS_DLL.BytePPToArray(p);\r
+         // Free the original list since we're done with it\r
+         PhysFS_DLL.PHYSFS_freeList(p);\r
+\r
+         return filelist;\r
+      }\r
+      public static bool IsDirectory(string Filename)\r
+      {\r
+         // Return true if non-zero, otherwise return false\r
+         return (PhysFS_DLL.PHYSFS_isDirectory(Filename) == 0)?false:true;\r
+      }\r
+   }\r
+}\r
diff --git a/extras/PhysFS.NET/PhysFSFileStream.cs b/extras/PhysFS.NET/PhysFSFileStream.cs
new file mode 100755 (executable)
index 0000000..c0f6b05
--- /dev/null
@@ -0,0 +1,194 @@
+/* PhysFSFileStream.cs - (c)2003 Gregory S. Read */\r
+using System;\r
+using System.Collections;\r
+using System.IO;\r
+\r
+namespace PhysFS_NET\r
+{\r
+   public enum PhysFSFileMode {Read, Write, Append};\r
+\r
+   // Our exception class we'll use for throwing all PhysFS API related exception\r
+   public class PhysFSException : IOException\r
+   {\r
+      public PhysFSException(string Message) : base(Message) {}\r
+      public PhysFSException() : base(PhysFS_DLL.PHYSFS_getLastError()) {}\r
+   }\r
+\r
+   public unsafe class PhysFSFileStream : Stream\r
+   {\r
+      // ***Public properties***\r
+      public override bool CanRead\r
+      {\r
+         get\r
+         {\r
+            // Reading is supported\r
+            return true;\r
+         }\r
+      }\r
+      \r
+      public override bool CanSeek\r
+      {\r
+         get\r
+         {\r
+            // Seek is supported\r
+            return true;\r
+         }\r
+      }\r
+\r
+      public override bool CanWrite\r
+      {\r
+         get\r
+         {\r
+            // Writing is supported\r
+            return true;\r
+         }\r
+      }\r
+\r
+      public override long Length\r
+      {\r
+         get\r
+         {\r
+            long TempLength;\r
+            TempLength = PhysFS_DLL.PHYSFS_fileLength(pHandle);\r
+\r
+            // If call returned an error, throw an exception\r
+            if(TempLength == -1)\r
+               throw new PhysFSException();\r
+\r
+            return TempLength;\r
+         }\r
+      }\r
+\r
+      public override long Position\r
+      {\r
+         get\r
+         {\r
+            long TempPosition;\r
+            TempPosition = PhysFS_DLL.PHYSFS_tell(pHandle);\r
+\r
+            // If call returned an error, throw an exception\r
+            if(TempPosition == -1)\r
+               throw new PhysFSException();\r
+\r
+            return TempPosition;\r
+         }\r
+         set\r
+         {\r
+            // Seek from beginning of file using the position value\r
+            Seek(value, SeekOrigin.Begin);\r
+         }\r
+      }\r
+      \r
+      // ***Public methods***\r
+      public PhysFSFileStream(string FileName, PhysFSFileMode FileMode, ulong BufferSize)\r
+      {\r
+         // Open the specified file with the appropriate file access\r
+         switch(FileMode)\r
+         {\r
+            case PhysFSFileMode.Read:\r
+               pHandle = PhysFS_DLL.PHYSFS_openRead(FileName);\r
+               break;\r
+            case PhysFSFileMode.Write:\r
+               pHandle = PhysFS_DLL.PHYSFS_openWrite(FileName);\r
+               break;\r
+            case PhysFSFileMode.Append:\r
+               pHandle = PhysFS_DLL.PHYSFS_openAppend(FileName);\r
+               break;\r
+            default:\r
+               throw new PhysFSException("Invalid FileMode specified");\r
+         }\r
+\r
+         // If handle is null, an error occured, so raise an exception\r
+         //!!! Does object get created if exception is thrown?\r
+         if(pHandle == null)\r
+            throw new PhysFSException();\r
+\r
+         // Set buffer size, raise an exception if an error occured\r
+         if(PhysFS_DLL.PHYSFS_setBuffer(pHandle, BufferSize) == 0)\r
+            throw new PhysFSException();\r
+      }\r
+\r
+      // This constructor sets the buffer size to 0 if not specified\r
+      public PhysFSFileStream(string FileName, PhysFSFileMode FileMode) : this(FileName, FileMode, 0) {}\r
+               \r
+      ~PhysFSFileStream()\r
+      {\r
+         // Don't close the handle if they've specifically closed it already\r
+         if(!Closed)\r
+            Close();\r
+      }\r
+\r
+      public override void Flush()\r
+      {\r
+         if(PhysFS_DLL.PHYSFS_flush(pHandle) == 0)\r
+            throw new PhysFSException();\r
+      }\r
+\r
+      public override int Read(byte[] buffer, int offset, int count)\r
+      {\r
+         long RetValue;\r
+   \r
+         fixed(byte *pbytes = &buffer[offset])\r
+         {\r
+            // Read into our allocated pointer\r
+            RetValue = PhysFS_DLL.PHYSFS_read(pHandle, pbytes, sizeof(byte), (uint)count);\r
+         }\r
+\r
+         if(RetValue == -1)\r
+            throw new PhysFSException();\r
+\r
+         // Return number of bytes read\r
+         // Note: This cast should be safe since we are only reading 'count' items, which\r
+         // is of type 'int'.\r
+         return (int)RetValue;\r
+      }\r
+\r
+      public override void Write(byte[] buffer, int offset, int count)\r
+      {\r
+         long RetValue;\r
+\r
+         fixed(byte* pbytes = &buffer[offset])\r
+         {\r
+            // Write buffer\r
+            RetValue = PhysFS_DLL.PHYSFS_write(pHandle, pbytes, sizeof(byte), (uint)count);\r
+         }\r
+\r
+         if(RetValue == -1)\r
+            throw new PhysFSException();\r
+      }\r
+\r
+      public override long Seek(long offset, SeekOrigin origin)\r
+      {\r
+         // Only seeking from beginning is supported by PhysFS API\r
+         if(origin != SeekOrigin.Begin)\r
+            throw new PhysFSException("Only seek origin of \"Begin\" is supported");\r
+         \r
+         // Seek to specified offset, raise an exception if error occured\r
+         if(PhysFS_DLL.PHYSFS_seek(pHandle, (ulong)offset) == 0)\r
+            throw new PhysFSException();\r
+\r
+         // Since we always seek from beginning, the offset is always\r
+         //  the absolute position.\r
+         return offset;\r
+      }\r
+\r
+      public override void SetLength(long value)\r
+      {\r
+         throw new NotSupportedException("SetLength method not supported in PhysFSFileStream objects.");\r
+      }\r
+\r
+      public override void Close()\r
+      {\r
+         // Close the handle\r
+         if(PhysFS_DLL.PHYSFS_close(pHandle) == 0)\r
+            throw new PhysFSException();\r
+\r
+         // File has been closed.  Rock.\r
+         Closed = true;\r
+      }\r
+\r
+      // ***Private variables***\r
+      private void *pHandle;\r
+      private bool Closed = false;\r
+   }\r
+}
\ No newline at end of file
diff --git a/extras/PhysFS.NET/PhysFS_DLL.cs b/extras/PhysFS.NET/PhysFS_DLL.cs
new file mode 100755 (executable)
index 0000000..bc9300c
--- /dev/null
@@ -0,0 +1,113 @@
+/* PhysFS_DLL - (c)2003 Gregory S. Read\r
+ * Internal class that provides direct access to the PhysFS DLL.  It is\r
+ * not accessible outside of the PhysFS.NET assembly.\r
+ */\r
+using System.Collections;\r
+using System.Runtime.InteropServices;\r
+\r
+namespace PhysFS_NET\r
+{\r
+   internal class PhysFS_DLL\r
+   {\r
+      /* Static constructor\r
+       * Initializes the PhysFS API before any method is called in this class.  This\r
+       * relieves the user from having to explicitly initialize the API.\r
+       * Parameters\r
+       *    none\r
+       * Returns\r
+       *    none\r
+       * Exceptions\r
+       *    PhysFSException - An error occured in the PhysFS API\r
+       */\r
+      static PhysFS_DLL()\r
+      {\r
+         if(PHYSFS_init("") == 0)\r
+            throw new PhysFSException();\r
+      }\r
+\r
+      /* BytePPToArray\r
+       * Converts a C-style string array into a .NET managed string array\r
+       * Parameters\r
+       *    C-style string array pointer returned from PhysFS\r
+       * Returns\r
+       *    .NET managed string array\r
+       * Exceptions\r
+       *    none\r
+       */\r
+      public unsafe static string[] BytePPToArray(byte **bytearray)\r
+      {\r
+         byte** ptr;\r
+         byte* c;\r
+         string tempstr;\r
+         ArrayList MyArrayList = new ArrayList();\r
+         string[] RetArray;\r
+\r
+         for(ptr = bytearray; *ptr != null; ptr++)
+         {
+            tempstr = "";
+            for(c = *ptr; *c != 0; c++)
+            {
+               tempstr += (char)*c;\r
+            }\r
+\r
+            // Add string to our list\r
+            MyArrayList.Add(tempstr);\r
+         }\r
+\r
+         // Return a normal array of the list\r
+         RetArray = new string[MyArrayList.Count];\r
+         MyArrayList.CopyTo(RetArray, 0);\r
+         return RetArray;\r
+      }\r
+\r
+      // Name of DLL to import\r
+      private const string PHYSFS_DLLNAME = "physfs.dll";\r
+\r
+      // DLL import declarations\r
+      [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_init(string argv0);\r
+      [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_deinit();\r
+      [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();\r
+      [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);\r
+      [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);
+   }\r
+}\r
diff --git a/extras/PhysFS.NET/README.txt b/extras/PhysFS.NET/README.txt
new file mode 100755 (executable)
index 0000000..62ecf63
--- /dev/null
@@ -0,0 +1,10 @@
+PhysFS.NET is a library that encapsulates the PhysFS API into a .NET assembly.\r
+\r
+There are two class objects that are exposed in the assembly:\r
+   PhysFS.cs\r
+      This class exposes any non-filehandle specific functionality contained in\r
+      the PhysFS library.\r
+   PhysFSFileStream.cs\r
+      A System.IO.Stream derived class which provides file access via the\r
+      PhysFS API.  Usage of this object is identical to a standard stream\r
+      object.    
\ No newline at end of file
diff --git a/extras/PhysFS.NET/TestApp/App.ico b/extras/PhysFS.NET/TestApp/App.ico
new file mode 100755 (executable)
index 0000000..3a5525f
Binary files /dev/null and b/extras/PhysFS.NET/TestApp/App.ico differ
diff --git a/extras/PhysFS.NET/TestApp/AssemblyInfo.cs b/extras/PhysFS.NET/TestApp/AssemblyInfo.cs
new file mode 100755 (executable)
index 0000000..177a4f0
--- /dev/null
@@ -0,0 +1,58 @@
+using System.Reflection;\r
+using System.Runtime.CompilerServices;\r
+\r
+//\r
+// General Information about an assembly is controlled through the following \r
+// set of attributes. Change these attribute values to modify the information\r
+// associated with an assembly.\r
+//\r
+[assembly: AssemblyTitle("")]\r
+[assembly: AssemblyDescription("")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("")]\r
+[assembly: AssemblyProduct("")]\r
+[assembly: AssemblyCopyright("")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]                \r
+\r
+//\r
+// Version information for an assembly consists of the following four values:\r
+//\r
+//      Major Version\r
+//      Minor Version \r
+//      Build Number\r
+//      Revision\r
+//\r
+// You can specify all the values or you can default the Revision and Build Numbers \r
+// by using the '*' as shown below:\r
+\r
+[assembly: AssemblyVersion("1.0.*")]\r
+\r
+//\r
+// In order to sign your assembly you must specify a key to use. Refer to the \r
+// Microsoft .NET Framework documentation for more information on assembly signing.\r
+//\r
+// Use the attributes below to control which key is used for signing. \r
+//\r
+// Notes: \r
+//   (*) If no key is specified, the assembly is not signed.\r
+//   (*) KeyName refers to a key that has been installed in the Crypto Service\r
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains\r
+//       a key.\r
+//   (*) If the KeyFile and the KeyName values are both specified, the \r
+//       following processing occurs:\r
+//       (1) If the KeyName can be found in the CSP, that key is used.\r
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key \r
+//           in the KeyFile is installed into the CSP and used.\r
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.\r
+//       When specifying the KeyFile, the location of the KeyFile should be\r
+//       relative to the project output directory which is\r
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is\r
+//       located in the project directory, you would specify the AssemblyKeyFile \r
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]\r
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework\r
+//       documentation for more information on this.\r
+//\r
+[assembly: AssemblyDelaySign(false)]\r
+[assembly: AssemblyKeyFile("")]\r
+[assembly: AssemblyKeyName("")]\r
diff --git a/extras/PhysFS.NET/TestApp/TestApp.csproj b/extras/PhysFS.NET/TestApp/TestApp.csproj
new file mode 100755 (executable)
index 0000000..e576a21
--- /dev/null
@@ -0,0 +1,116 @@
+<VisualStudioProject>\r
+    <CSHARP\r
+        ProjectType = "Local"\r
+        ProductVersion = "7.0.9466"\r
+        SchemaVersion = "1.0"\r
+        ProjectGuid = "{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}"\r
+    >\r
+        <Build>\r
+            <Settings\r
+                ApplicationIcon = "App.ico"\r
+                AssemblyKeyContainerName = ""\r
+                AssemblyName = "TestApp"\r
+                AssemblyOriginatorKeyFile = ""\r
+                DefaultClientScript = "JScript"\r
+                DefaultHTMLPageLayout = "Grid"\r
+                DefaultTargetSchema = "IE50"\r
+                DelaySign = "false"\r
+                OutputType = "WinExe"\r
+                RootNamespace = "TestApp"\r
+                StartupObject = ""\r
+            >\r
+                <Config\r
+                    Name = "Debug"\r
+                    AllowUnsafeBlocks = "false"\r
+                    BaseAddress = "285212672"\r
+                    CheckForOverflowUnderflow = "false"\r
+                    ConfigurationOverrideFile = ""\r
+                    DefineConstants = "DEBUG;TRACE"\r
+                    DocumentationFile = ""\r
+                    DebugSymbols = "true"\r
+                    FileAlignment = "4096"\r
+                    IncrementalBuild = "true"\r
+                    Optimize = "false"\r
+                    OutputPath = "bin\Debug\"\r
+                    RegisterForComInterop = "false"\r
+                    RemoveIntegerChecks = "false"\r
+                    TreatWarningsAsErrors = "false"\r
+                    WarningLevel = "4"\r
+                />\r
+                <Config\r
+                    Name = "Release"\r
+                    AllowUnsafeBlocks = "false"\r
+                    BaseAddress = "285212672"\r
+                    CheckForOverflowUnderflow = "false"\r
+                    ConfigurationOverrideFile = ""\r
+                    DefineConstants = "TRACE"\r
+                    DocumentationFile = ""\r
+                    DebugSymbols = "false"\r
+                    FileAlignment = "4096"\r
+                    IncrementalBuild = "false"\r
+                    Optimize = "true"\r
+                    OutputPath = "bin\Release\"\r
+                    RegisterForComInterop = "false"\r
+                    RemoveIntegerChecks = "false"\r
+                    TreatWarningsAsErrors = "false"\r
+                    WarningLevel = "4"\r
+                />\r
+            </Settings>\r
+            <References>\r
+                <Reference\r
+                    Name = "System"\r
+                    AssemblyName = "System"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.Data"\r
+                    AssemblyName = "System.Data"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.Drawing"\r
+                    AssemblyName = "System.Drawing"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.Windows.Forms"\r
+                    AssemblyName = "System.Windows.Forms"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"\r
+                />\r
+                <Reference\r
+                    Name = "System.XML"\r
+                    AssemblyName = "System.Xml"\r
+                    HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"\r
+                />\r
+                <Reference\r
+                    Name = "PhysFS.NET"\r
+                    Project = "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"\r
+                    Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"\r
+                />\r
+            </References>\r
+        </Build>\r
+        <Files>\r
+            <Include>\r
+                <File\r
+                    RelPath = "App.ico"\r
+                    BuildAction = "Content"\r
+                />\r
+                <File\r
+                    RelPath = "AssemblyInfo.cs"\r
+                    BuildAction = "Compile"\r
+                />\r
+                <File\r
+                    RelPath = "TestAppForm.cs"\r
+                    SubType = "Form"\r
+                    BuildAction = "Compile"\r
+                />\r
+                <File\r
+                    RelPath = "TestAppForm.resx"\r
+                    DependentUpon = "TestAppForm.cs"\r
+                    BuildAction = "EmbeddedResource"\r
+                />\r
+            </Include>\r
+        </Files>\r
+    </CSHARP>\r
+</VisualStudioProject>\r
+\r
diff --git a/extras/PhysFS.NET/TestApp/TestApp.sln b/extras/PhysFS.NET/TestApp/TestApp.sln
new file mode 100755 (executable)
index 0000000..d339089
--- /dev/null
@@ -0,0 +1,27 @@
+Microsoft Visual Studio Solution File, Format Version 7.00\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp.csproj", "{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}"\r
+EndProject\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysFS.NET", "..\PhysFS.NET.csproj", "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfiguration) = preSolution\r
+               ConfigName.0 = Debug\r
+               ConfigName.1 = Release\r
+       EndGlobalSection\r
+       GlobalSection(ProjectDependencies) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfiguration) = postSolution\r
+               {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Debug.ActiveCfg = Debug|.NET\r
+               {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Debug.Build.0 = Debug|.NET\r
+               {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Release.ActiveCfg = Release|.NET\r
+               {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Release.Build.0 = Release|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.ActiveCfg = Debug|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.Build.0 = Debug|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.ActiveCfg = Release|.NET\r
+               {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.Build.0 = Release|.NET\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityAddIns) = postSolution\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/extras/PhysFS.NET/TestApp/TestAppForm.cs b/extras/PhysFS.NET/TestApp/TestAppForm.cs
new file mode 100755 (executable)
index 0000000..b897ae6
--- /dev/null
@@ -0,0 +1,274 @@
+using System;\r
+using System.Drawing;\r
+using System.Collections;\r
+using System.ComponentModel;\r
+using System.Windows.Forms;\r
+using System.Data;\r
+using System.IO;\r
+using PhysFS_NET;\r
+\r
+namespace TestApp\r
+{\r
+       /// <summary>\r
+       /// Summary description for Form1.\r
+       /// </summary>\r
+       public class TestAppForm : System.Windows.Forms.Form\r
+       {\r
+      private System.Windows.Forms.Label label2;\r
+      private System.Windows.Forms.Button RefreshCDsButton;\r
+      private System.Windows.Forms.ListBox CDDrivesList;\r
+      private System.Windows.Forms.ListBox SearchPathList;\r
+      private System.Windows.Forms.Label label1;\r
+      private System.Windows.Forms.TextBox EnumFilesPath;\r
+      private System.Windows.Forms.ListBox EnumList;\r
+      private System.Windows.Forms.Label label3;\r
+      private System.Windows.Forms.TextBox NewSearchPathText;\r
+      private System.Windows.Forms.Button AddSearchPathButton;\r
+      private System.Windows.Forms.Button RemovePathButton;\r
+      private System.Windows.Forms.Button RefreshEnumList;\r
+      private System.Windows.Forms.Button RefreshSearchPathButton;\r
+               /// <summary>\r
+               /// Required designer variable.\r
+               /// </summary>\r
+               private System.ComponentModel.Container components = null;\r
+\r
+               public TestAppForm()\r
+               {\r
+                       //\r
+                       // Required for Windows Form Designer support\r
+                       //\r
+                       InitializeComponent();\r
+\r
+                       //\r
+                       // TODO: Add any constructor code after InitializeComponent call\r
+                       //\r
+               }\r
+\r
+               /// <summary>\r
+               /// Clean up any resources being used.\r
+               /// </summary>\r
+               protected override void Dispose( bool disposing )\r
+               {\r
+                       if( disposing )\r
+                       {\r
+                               if (components != null) \r
+                               {\r
+                                       components.Dispose();\r
+                               }\r
+                       }\r
+                       base.Dispose( disposing );\r
+               }\r
+\r
+               #region Windows Form Designer generated code\r
+               /// <summary>\r
+               /// Required method for Designer support - do not modify\r
+               /// the contents of this method with the code editor.\r
+               /// </summary>\r
+               private void InitializeComponent()\r
+               {\r
+         this.label2 = new System.Windows.Forms.Label();\r
+         this.RefreshCDsButton = new System.Windows.Forms.Button();\r
+         this.CDDrivesList = new System.Windows.Forms.ListBox();\r
+         this.SearchPathList = new System.Windows.Forms.ListBox();\r
+         this.label1 = new System.Windows.Forms.Label();\r
+         this.EnumFilesPath = new System.Windows.Forms.TextBox();\r
+         this.EnumList = new System.Windows.Forms.ListBox();\r
+         this.label3 = new System.Windows.Forms.Label();\r
+         this.RefreshEnumList = new System.Windows.Forms.Button();\r
+         this.NewSearchPathText = new System.Windows.Forms.TextBox();\r
+         this.AddSearchPathButton = new System.Windows.Forms.Button();\r
+         this.RemovePathButton = new System.Windows.Forms.Button();\r
+         this.RefreshSearchPathButton = new System.Windows.Forms.Button();\r
+         this.SuspendLayout();\r
+         // \r
+         // label2\r
+         // \r
+         this.label2.Location = new System.Drawing.Point(8, 8);\r
+         this.label2.Name = "label2";\r
+         this.label2.Size = new System.Drawing.Size(136, 16);\r
+         this.label2.TabIndex = 2;\r
+         this.label2.Text = "Available CD-ROM Drives";\r
+         // \r
+         // RefreshCDsButton\r
+         // \r
+         this.RefreshCDsButton.Location = new System.Drawing.Point(8, 152);\r
+         this.RefreshCDsButton.Name = "RefreshCDsButton";\r
+         this.RefreshCDsButton.Size = new System.Drawing.Size(72, 24);\r
+         this.RefreshCDsButton.TabIndex = 4;\r
+         this.RefreshCDsButton.Text = "Refresh";\r
+         this.RefreshCDsButton.Click += new System.EventHandler(this.RefreshCDsButton_Click);\r
+         // \r
+         // CDDrivesList\r
+         // \r
+         this.CDDrivesList.Location = new System.Drawing.Point(8, 24);\r
+         this.CDDrivesList.Name = "CDDrivesList";\r
+         this.CDDrivesList.Size = new System.Drawing.Size(136, 121);\r
+         this.CDDrivesList.TabIndex = 7;\r
+         // \r
+         // SearchPathList\r
+         // \r
+         this.SearchPathList.Location = new System.Drawing.Point(152, 24);\r
+         this.SearchPathList.Name = "SearchPathList";\r
+         this.SearchPathList.Size = new System.Drawing.Size(248, 95);\r
+         this.SearchPathList.TabIndex = 8;\r
+         // \r
+         // label1\r
+         // \r
+         this.label1.Location = new System.Drawing.Point(152, 8);\r
+         this.label1.Name = "label1";\r
+         this.label1.Size = new System.Drawing.Size(136, 16);\r
+         this.label1.TabIndex = 10;\r
+         this.label1.Text = "Search Path";\r
+         // \r
+         // EnumFilesPath\r
+         // \r
+         this.EnumFilesPath.Location = new System.Drawing.Point(408, 128);\r
+         this.EnumFilesPath.Name = "EnumFilesPath";\r
+         this.EnumFilesPath.Size = new System.Drawing.Size(208, 20);\r
+         this.EnumFilesPath.TabIndex = 11;\r
+         this.EnumFilesPath.Text = "";\r
+         // \r
+         // EnumList\r
+         // \r
+         this.EnumList.Location = new System.Drawing.Point(408, 24);\r
+         this.EnumList.Name = "EnumList";\r
+         this.EnumList.Size = new System.Drawing.Size(208, 95);\r
+         this.EnumList.TabIndex = 12;\r
+         // \r
+         // label3\r
+         // \r
+         this.label3.Location = new System.Drawing.Point(408, 8);\r
+         this.label3.Name = "label3";\r
+         this.label3.Size = new System.Drawing.Size(136, 16);\r
+         this.label3.TabIndex = 13;\r
+         this.label3.Text = "Enumerate Files";\r
+         // \r
+         // RefreshEnumList\r
+         // \r
+         this.RefreshEnumList.Location = new System.Drawing.Point(544, 152);\r
+         this.RefreshEnumList.Name = "RefreshEnumList";\r
+         this.RefreshEnumList.Size = new System.Drawing.Size(72, 24);\r
+         this.RefreshEnumList.TabIndex = 14;\r
+         this.RefreshEnumList.Text = "Refresh";\r
+         this.RefreshEnumList.Click += new System.EventHandler(this.RefreshEnumList_Click);\r
+         // \r
+         // NewSearchPathText\r
+         // \r
+         this.NewSearchPathText.Location = new System.Drawing.Point(152, 128);\r
+         this.NewSearchPathText.Name = "NewSearchPathText";\r
+         this.NewSearchPathText.Size = new System.Drawing.Size(248, 20);\r
+         this.NewSearchPathText.TabIndex = 15;\r
+         this.NewSearchPathText.Text = "";\r
+         // \r
+         // AddSearchPathButton\r
+         // \r
+         this.AddSearchPathButton.Location = new System.Drawing.Point(152, 152);\r
+         this.AddSearchPathButton.Name = "AddSearchPathButton";\r
+         this.AddSearchPathButton.Size = new System.Drawing.Size(72, 24);\r
+         this.AddSearchPathButton.TabIndex = 9;\r
+         this.AddSearchPathButton.Text = "Add Path";\r
+         this.AddSearchPathButton.Click += new System.EventHandler(this.AddSearchPathButton_Click);\r
+         // \r
+         // RemovePathButton\r
+         // \r
+         this.RemovePathButton.Location = new System.Drawing.Point(232, 152);\r
+         this.RemovePathButton.Name = "RemovePathButton";\r
+         this.RemovePathButton.Size = new System.Drawing.Size(88, 24);\r
+         this.RemovePathButton.TabIndex = 16;\r
+         this.RemovePathButton.Text = "Remove Path";\r
+         this.RemovePathButton.Click += new System.EventHandler(this.RemovePathButton_Click);\r
+         // \r
+         // RefreshSearchPathButton\r
+         // \r
+         this.RefreshSearchPathButton.Location = new System.Drawing.Point(328, 152);\r
+         this.RefreshSearchPathButton.Name = "RefreshSearchPathButton";\r
+         this.RefreshSearchPathButton.Size = new System.Drawing.Size(72, 24);\r
+         this.RefreshSearchPathButton.TabIndex = 17;\r
+         this.RefreshSearchPathButton.Text = "Refresh";\r
+         this.RefreshSearchPathButton.Click += new System.EventHandler(this.RefreshSearchPathButton_Click);\r
+         // \r
+         // TestAppForm\r
+         // \r
+         this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);\r
+         this.ClientSize = new System.Drawing.Size(624, 309);\r
+         this.Controls.AddRange(new System.Windows.Forms.Control[] {\r
+                                                                      this.RefreshSearchPathButton,\r
+                                                                      this.RemovePathButton,\r
+                                                                      this.NewSearchPathText,\r
+                                                                      this.RefreshEnumList,\r
+                                                                      this.label3,\r
+                                                                      this.EnumList,\r
+                                                                      this.EnumFilesPath,\r
+                                                                      this.label1,\r
+                                                                      this.SearchPathList,\r
+                                                                      this.CDDrivesList,\r
+                                                                      this.RefreshCDsButton,\r
+                                                                      this.label2,\r
+                                                                      this.AddSearchPathButton});\r
+         this.Name = "TestAppForm";\r
+         this.Text = "PhysFS Test Application";\r
+         this.Load += new System.EventHandler(this.TestAppForm_Load);\r
+         this.ResumeLayout(false);\r
+\r
+      }\r
+               #endregion\r
+\r
+               /// <summary>\r
+               /// The main entry point for the application.\r
+               /// </summary>\r
+               [STAThread]\r
+               static void Main() \r
+               {\r
+         Application.Run(new TestAppForm());\r
+               }\r
+\r
+      private void TestAppForm_Load(object sender, System.EventArgs e)\r
+      {\r
+      \r
+      }\r
+\r
+      private void RefreshCDsButton_Click(object sender, System.EventArgs e)\r
+      {\r
+         // Clear ths listbox if it contains any items\r
+         CDDrivesList.Items.Clear();\r
+         // Add the items to the list\r
+         CDDrivesList.Items.AddRange(PhysFS.GetCDROMDrives());\r
+      }\r
+\r
+      private void RefreshSearchPathButton_Click(object sender, System.EventArgs e)\r
+      {\r
+         // Clear ths listbox if it contains any items\r
+         SearchPathList.Items.Clear();\r
+         // Add the items to the list\r
+         SearchPathList.Items.AddRange(PhysFS.GetSearchPath());\r
+      }\r
+\r
+      private void AddSearchPathButton_Click(object sender, System.EventArgs e)\r
+      {\r
+         // Add search path\r
+         PhysFS.AddToSearchPath(NewSearchPathText.Text, false);\r
+         // Clear ths listbox if it contains any items\r
+         SearchPathList.Items.Clear();\r
+         // Add the items to the list\r
+         SearchPathList.Items.AddRange(PhysFS.GetSearchPath());\r
+      }\r
+\r
+      private void RemovePathButton_Click(object sender, System.EventArgs e)\r
+      {\r
+         if(SearchPathList.SelectedItem != null)\r
+         {\r
+            PhysFS.RemoveFromSearchPath(SearchPathList.SelectedItem.ToString());\r
+            // Clear ths listbox if it contains any items\r
+            SearchPathList.Items.Clear();\r
+            // Add the items to the list\r
+            SearchPathList.Items.AddRange(PhysFS.GetSearchPath());\r
+         }\r
+      }\r
+\r
+      private void RefreshEnumList_Click(object sender, System.EventArgs e)\r
+      {\r
+         EnumList.Items.Clear();\r
+         EnumList.Items.AddRange(PhysFS.EnumerateFiles(EnumFilesPath.Text));\r
+      }\r
+       }\r
+}\r
diff --git a/extras/PhysFS.NET/TestApp/TestAppForm.resx b/extras/PhysFS.NET/TestApp/TestAppForm.resx
new file mode 100755 (executable)
index 0000000..26e9d79
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<root>\r
+  <!-- \r
+            Microsoft ResX Schema \r
+        \r
+            Version 1.3\r
+                \r
+            The primary goals of this format is to allow a simple XML format \r
+            that is mostly human readable. The generation and parsing of the \r
+            various data types are done through the TypeConverter classes \r
+            associated with the data types.\r
+        \r
+            Example:\r
+        \r
+                ... ado.net/XML headers & schema ...\r
+                <resheader name="resmimetype">text/microsoft-resx</resheader>\r
+                <resheader name="version">1.3</resheader>\r
+                <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r
+                <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r
+                <data name="Name1">this is my long string</data>\r
+                <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>\r
+                <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">\r
+                    [base64 mime encoded serialized .NET Framework object]\r
+                </data>\r
+                <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">\r
+                    [base64 mime encoded string representing a byte array form of the .NET Framework object]\r
+                </data>\r
+        \r
+            There are any number of "resheader" rows that contain simple \r
+            name/value pairs.\r
+            \r
+            Each data row contains a name, and value. The row also contains a \r
+            type or mimetype. Type corresponds to a .NET class that support \r
+            text/value conversion through the TypeConverter architecture. \r
+            Classes that don't support this are serialized and stored with the \r
+            mimetype set.\r
+                     \r
+            The mimetype is used for serialized objects, and tells the \r
+            ResXResourceReader how to depersist the object. This is currently not \r
+            extensible. For a given mimetype the value must be set accordingly:\r
+        \r
+            Note - application/x-microsoft.net.object.binary.base64 is the format \r
+                   that the ResXResourceWriter will generate, however the reader can \r
+                   read any of the formats listed below.\r
+        \r
+            mimetype: application/x-microsoft.net.object.binary.base64\r
+            value   : The object must be serialized with \r
+                    : System.Serialization.Formatters.Binary.BinaryFormatter\r
+                    : and then encoded with base64 encoding.\r
+        \r
+            mimetype: application/x-microsoft.net.object.soap.base64\r
+            value   : The object must be serialized with \r
+                    : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r
+                    : and then encoded with base64 encoding.\r
+            mimetype: application/x-microsoft.net.object.bytearray.base64\r
+            value   : The object must be serialized into a byte array \r
+                    : using a System.ComponentModel.TypeConverter\r
+                    : and then encoded with base64 encoding.\r
+        -->\r
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">\r
+    <xsd:element name="root" msdata:IsDataSet="true">\r
+      <xsd:complexType>\r
+        <xsd:choice maxOccurs="unbounded">\r
+          <xsd:element name="data">\r
+            <xsd:complexType>\r
+              <xsd:sequence>\r
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />\r
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />\r
+              </xsd:sequence>\r
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />\r
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />\r
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />\r
+            </xsd:complexType>\r
+          </xsd:element>\r
+          <xsd:element name="resheader">\r
+            <xsd:complexType>\r
+              <xsd:sequence>\r
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />\r
+              </xsd:sequence>\r
+              <xsd:attribute name="name" type="xsd:string" use="required" />\r
+            </xsd:complexType>\r
+          </xsd:element>\r
+        </xsd:choice>\r
+      </xsd:complexType>\r
+    </xsd:element>\r
+  </xsd:schema>\r
+  <resheader name="resmimetype">\r
+    <value>text/microsoft-resx</value>\r
+  </resheader>\r
+  <resheader name="version">\r
+    <value>1.3</value>\r
+  </resheader>\r
+  <resheader name="reader">\r
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r
+  </resheader>\r
+  <resheader name="writer">\r
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r
+  </resheader>\r
+  <data name="$this.Name">\r
+    <value>TestAppForm</value>\r
+  </data>\r
+</root>
\ No newline at end of file
diff --git a/extras/abs-file.h b/extras/abs-file.h
new file mode 100644 (file)
index 0000000..c7e7b49
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * stdio/physfs abstraction layer 2003-04-02
+ *
+ * Adam D. Moss <adam@gimp.org> <aspirin@icculus.org>
+ *
+ * These wrapper macros and functions are designed to allow a program
+ * to perform file I/O with identical semantics and syntax regardless
+ * of whether PhysicsFS is being used or not.
+ */
+#ifndef _ABS_FILE_H
+#define _ABS_FILE_H
+/*
+PLEASE NOTE: This license applies to abs-file.h ONLY (to make it clear that
+you may embed this wrapper code within commercial software); PhysicsFS itself
+is (at the time of writing) released under a different license with
+additional restrictions.
+
+Copyright (C) 2002-2003 Adam D. Moss (the "Author").  All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is fur-
+nished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the Author of the
+Software shall not be used in advertising or otherwise to promote the sale,
+use or other dealings in this Software without prior written authorization
+from the Author.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * API:
+ *
+ * Macro/function       use like stdio equivalent...
+ * --------------       ----------------------------
+ * MY_FILETYPE          FILE
+ * MY_OPEN_FOR_READ     fopen(..., "rb")
+ * MY_READ              fread(...)
+ * MY_CLOSE             fclose(...)
+ * MY_GETC              fgetc(...)
+ * MY_GETS              fgets(...)
+ * MY_ATEOF             feof(...)
+ * MY_TELL              ftell(...)
+ * MY_SEEK              fseek(..., SEEK_SET)
+ * MY_REWIND            rewind(...)
+ * MY_SETBUFFER         (not a standard for stdio, does nothing there)
+ */
+
+/*
+ * Important DEFINEs:
+ *   It is important to define these consistantly across the various
+ *   compilation modules of your program if you wish to exchange file
+ *   handles between them.
+ *
+ *   USE_PHYSFS: Define USE_PHYSFS if PhysicsFS is being used; note that if
+ *     you do intend to use PhysicsFS then you will still need to initialize
+ *     PhysicsFS yourself and set up its search-paths.
+ *
+ * Optional DEFINEs:
+ *
+ *   PHYSFS_DEFAULT_READ_BUFFER <bytes>: If set then abs-file.h sets the
+ *     PhysicsFS buffer size to this value whenever you open a file.  You
+ *     may over-ride this on a per-filehandle basis by using the
+ *     MY_SETBUFFER() macro (which simply does nothing when not using
+ *     PhysicsFS).  If you have not defined this value explicitly then
+ *     abs-file.h will default to the same default buffer size as used by
+ *     stdio if it can be determined, or 8192 bytes otherwise.
+ */
+#ifndef PHYSFS_DEFAULT_READ_BUFFER
+#ifdef BUFSIZ
+#define PHYSFS_DEFAULT_READ_BUFFER BUFSIZ
+#else
+#define PHYSFS_DEFAULT_READ_BUFFER 8192
+#endif
+#endif
+
+#ifdef USE_PHYSFS
+
+#include <physfs.h>
+#define MY_FILETYPE PHYSFS_File
+#define MY_SETBUFFER(fp,size) PHYSFS_setBuffer(fp,size)
+#define MY_READ(p,s,n,fp) PHYSFS_read(fp,p,s,n)
+#if PHYSFS_DEFAULT_READ_BUFFER
+static MY_FILETYPE* MY_OPEN_FOR_READ(const char *const filename)
+{
+  MY_FILETYPE *const file = PHYSFS_openRead(filename);
+  if (file) {
+    MY_SETBUFFER(file, PHYSFS_DEFAULT_READ_BUFFER);
+  }
+  return file;
+}
+#else
+#define MY_OPEN_FOR_READ(fn) PHYSFS_openRead(fn)
+#endif
+static int MY_GETC(MY_FILETYPE *const fp) {
+  unsigned char c;
+  /*if (PHYSFS_eof(fp)) {
+    return EOF;
+  }
+  MY_READ(&c, 1, 1, fp);*/
+  if (MY_READ(&c, 1, 1, fp) != 1) {
+    return EOF;
+  }
+  return c;
+}
+static char * MY_GETS(char * const str, const int size, 
+                      MY_FILETYPE *const fp) {
+  int i = 0;
+  int c;
+  do {
+    if (i == size-1) {
+      break;
+    }
+    c = MY_GETC(fp);
+    if (c == EOF) {
+      break;
+    }
+    str[i++] = c;
+  } while (c != '\0' && 
+      c != -1 && 
+      c != '\n');
+  str[i] = '\0';
+  if (i == 0) {
+    return NULL;
+  }
+  return str;
+}
+#define MY_CLOSE(fp) PHYSFS_close(fp)
+#define MY_ATEOF(fp) PHYSFS_eof(fp)
+#define MY_TELL(fp) PHYSFS_tell(fp)
+#define MY_SEEK(fp,o) PHYSFS_seek(fp,o)
+#define MY_REWIND(fp) MY_SEEK(fp,0)
+
+#else
+
+#define MY_FILETYPE FILE
+#define MY_READ(p,s,n,fp) fread(p,s,n,fp)
+#define MY_OPEN_FOR_READ(n) fopen(n, "rb")
+#define MY_GETC(fp) fgetc(fp)
+#define MY_GETS(str,size,fp) fgets(str,size,fp)
+#define MY_CLOSE(fp) fclose(fp)
+#define MY_ATEOF(fp) feof(fp)
+#define MY_TELL(fp) ftell(fp)
+#define MY_SEEK(fp,o) fseek(fp,o, SEEK_SET)
+#define MY_REWIND(fp) rewind(fp)
+/*static void MY_SETBUFFER(const MY_FILETYPE *const file, const int num) { }*/
+#define MY_SETBUFFER(fp,size)
+#endif
+
+#endif
diff --git a/extras/casefolding.txt b/extras/casefolding.txt
new file mode 100644 (file)
index 0000000..f25d9bf
--- /dev/null
@@ -0,0 +1,1064 @@
+# CaseFolding-4.1.0.txt
+# Date: 2005-03-26, 00:24:43 GMT [MD]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2005 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+#
+# Case Folding Properties
+#
+# This file is a supplement to the UnicodeData file.
+# It provides a case folding mapping generated from the Unicode Character Database.
+# If all characters are mapped according to the full mapping below, then
+# case differences (according to UnicodeData.txt and SpecialCasing.txt)
+# are eliminated.
+#
+# The data supports both implementations that require simple case foldings
+# (where string lengths don't change), and implementations that allow full case folding
+# (where string lengths may grow). Note that where they can be supported, the
+# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match.
+#
+# All code points not listed in this file map to themselves.
+#
+# NOTE: case folding does not preserve normalization formats!
+#
+# For information on case folding, see
+# UTR #21 Case Mappings, at http://www.unicode.org/unicode/reports/tr21/
+#
+# ================================================================================
+# Format
+# ================================================================================
+# The entries in this file are in the following machine-readable format:
+#
+# <code>; <status>; <mapping>; # <name>
+#
+# The status field is:
+# C: common case folding, common mappings shared by both simple and full mappings.
+# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces.
+# S: simple case folding, mappings to single characters where different from F.
+# T: special case for uppercase I and dotted uppercase I
+#    - For non-Turkic languages, this mapping is normally not used.
+#    - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters.
+#      Note that the Turkic mappings do not maintain canonical equivalence without additional processing.
+#      See the discussions of case mapping in the Unicode Standard for more information.
+#
+# Usage:
+#  A. To do a simple case folding, use the mappings with status C + S.
+#  B. To do a full case folding, use the mappings with status C + F.
+#
+#    The mappings with status T can be used or omitted depending on the desired case-folding
+#    behavior. (The default option is to exclude them.)
+#
+# =================================================================
+
+0041; C; 0061; # LATIN CAPITAL LETTER A
+0042; C; 0062; # LATIN CAPITAL LETTER B
+0043; C; 0063; # LATIN CAPITAL LETTER C
+0044; C; 0064; # LATIN CAPITAL LETTER D
+0045; C; 0065; # LATIN CAPITAL LETTER E
+0046; C; 0066; # LATIN CAPITAL LETTER F
+0047; C; 0067; # LATIN CAPITAL LETTER G
+0048; C; 0068; # LATIN CAPITAL LETTER H
+0049; C; 0069; # LATIN CAPITAL LETTER I
+0049; T; 0131; # LATIN CAPITAL LETTER I
+004A; C; 006A; # LATIN CAPITAL LETTER J
+004B; C; 006B; # LATIN CAPITAL LETTER K
+004C; C; 006C; # LATIN CAPITAL LETTER L
+004D; C; 006D; # LATIN CAPITAL LETTER M
+004E; C; 006E; # LATIN CAPITAL LETTER N
+004F; C; 006F; # LATIN CAPITAL LETTER O
+0050; C; 0070; # LATIN CAPITAL LETTER P
+0051; C; 0071; # LATIN CAPITAL LETTER Q
+0052; C; 0072; # LATIN CAPITAL LETTER R
+0053; C; 0073; # LATIN CAPITAL LETTER S
+0054; C; 0074; # LATIN CAPITAL LETTER T
+0055; C; 0075; # LATIN CAPITAL LETTER U
+0056; C; 0076; # LATIN CAPITAL LETTER V
+0057; C; 0077; # LATIN CAPITAL LETTER W
+0058; C; 0078; # LATIN CAPITAL LETTER X
+0059; C; 0079; # LATIN CAPITAL LETTER Y
+005A; C; 007A; # LATIN CAPITAL LETTER Z
+00B5; C; 03BC; # MICRO SIGN
+00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE
+00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE
+00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE
+00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS
+00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE
+00C6; C; 00E6; # LATIN CAPITAL LETTER AE
+00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA
+00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE
+00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE
+00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS
+00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE
+00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE
+00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS
+00D0; C; 00F0; # LATIN CAPITAL LETTER ETH
+00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE
+00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE
+00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE
+00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE
+00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE
+00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE
+00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE
+00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS
+00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE
+00DE; C; 00FE; # LATIN CAPITAL LETTER THORN
+00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S
+0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON
+0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE
+0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK
+0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE
+0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON
+010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON
+0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE
+0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON
+0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE
+0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK
+011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON
+011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE
+0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA
+0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE
+0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE
+012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON
+012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE
+012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK
+0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132; C; 0133; # LATIN CAPITAL LIGATURE IJ
+0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA
+0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE
+013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA
+013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON
+013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE
+0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE
+0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA
+0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON
+0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014A; C; 014B; # LATIN CAPITAL LETTER ENG
+014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON
+014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE
+0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152; C; 0153; # LATIN CAPITAL LIGATURE OE
+0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE
+0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA
+0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON
+015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE
+015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA
+0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON
+0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA
+0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON
+0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE
+0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE
+016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON
+016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE
+016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE
+0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK
+0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS
+0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE
+017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON
+017F; C; 0073; # LATIN SMALL LETTER LONG S
+0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK
+0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR
+0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX
+0186; C; 0254; # LATIN CAPITAL LETTER OPEN O
+0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK
+0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D
+018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK
+018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR
+018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E
+018F; C; 0259; # LATIN CAPITAL LETTER SCHWA
+0190; C; 025B; # LATIN CAPITAL LETTER OPEN E
+0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK
+0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK
+0194; C; 0263; # LATIN CAPITAL LETTER GAMMA
+0196; C; 0269; # LATIN CAPITAL LETTER IOTA
+0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE
+0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK
+019C; C; 026F; # LATIN CAPITAL LETTER TURNED M
+019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN
+01A2; C; 01A3; # LATIN CAPITAL LETTER OI
+01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK
+01A6; C; 0280; # LATIN LETTER YR
+01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO
+01A9; C; 0283; # LATIN CAPITAL LETTER ESH
+01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK
+01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN
+01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON
+01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK
+01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK
+01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE
+01B7; C; 0292; # LATIN CAPITAL LETTER EZH
+01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED
+01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE
+01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON
+01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+01C7; C; 01C9; # LATIN CAPITAL LETTER LJ
+01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J
+01CA; C; 01CC; # LATIN CAPITAL LETTER NJ
+01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J
+01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON
+01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON
+01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON
+01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON
+01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON
+01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE
+01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON
+01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON
+01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK
+01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON
+01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON
+01F1; C; 01F3; # LATIN CAPITAL LETTER DZ
+01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE
+01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR
+01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN
+01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE
+01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE
+01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C; C; 021D; # LATIN CAPITAL LETTER YOGH
+021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON
+0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222; C; 0223; # LATIN CAPITAL LETTER OU
+0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK
+0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA
+022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON
+023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE
+023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR
+0241; C; 0294; # LATIN CAPITAL LETTER GLOTTAL STOP
+0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI
+0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS
+0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS
+038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS
+038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS
+038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS
+0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA
+0392; C; 03B2; # GREEK CAPITAL LETTER BETA
+0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA
+0394; C; 03B4; # GREEK CAPITAL LETTER DELTA
+0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON
+0396; C; 03B6; # GREEK CAPITAL LETTER ZETA
+0397; C; 03B7; # GREEK CAPITAL LETTER ETA
+0398; C; 03B8; # GREEK CAPITAL LETTER THETA
+0399; C; 03B9; # GREEK CAPITAL LETTER IOTA
+039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA
+039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA
+039C; C; 03BC; # GREEK CAPITAL LETTER MU
+039D; C; 03BD; # GREEK CAPITAL LETTER NU
+039E; C; 03BE; # GREEK CAPITAL LETTER XI
+039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON
+03A0; C; 03C0; # GREEK CAPITAL LETTER PI
+03A1; C; 03C1; # GREEK CAPITAL LETTER RHO
+03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA
+03A4; C; 03C4; # GREEK CAPITAL LETTER TAU
+03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON
+03A6; C; 03C6; # GREEK CAPITAL LETTER PHI
+03A7; C; 03C7; # GREEK CAPITAL LETTER CHI
+03A8; C; 03C8; # GREEK CAPITAL LETTER PSI
+03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA
+03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA
+03D0; C; 03B2; # GREEK BETA SYMBOL
+03D1; C; 03B8; # GREEK THETA SYMBOL
+03D5; C; 03C6; # GREEK PHI SYMBOL
+03D6; C; 03C0; # GREEK PI SYMBOL
+03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA
+03DA; C; 03DB; # GREEK LETTER STIGMA
+03DC; C; 03DD; # GREEK LETTER DIGAMMA
+03DE; C; 03DF; # GREEK LETTER KOPPA
+03E0; C; 03E1; # GREEK LETTER SAMPI
+03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI
+03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI
+03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI
+03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI
+03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA
+03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA
+03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI
+03F0; C; 03BA; # GREEK KAPPA SYMBOL
+03F1; C; 03C1; # GREEK RHO SYMBOL
+03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL
+03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL
+03F7; C; 03F8; # GREEK CAPITAL LETTER SHO
+03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL
+03FA; C; 03FB; # GREEK CAPITAL LETTER SAN
+0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE
+0401; C; 0451; # CYRILLIC CAPITAL LETTER IO
+0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE
+0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE
+0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE
+0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0407; C; 0457; # CYRILLIC CAPITAL LETTER YI
+0408; C; 0458; # CYRILLIC CAPITAL LETTER JE
+0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE
+040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE
+040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE
+040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE
+040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE
+040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U
+040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE
+0410; C; 0430; # CYRILLIC CAPITAL LETTER A
+0411; C; 0431; # CYRILLIC CAPITAL LETTER BE
+0412; C; 0432; # CYRILLIC CAPITAL LETTER VE
+0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE
+0414; C; 0434; # CYRILLIC CAPITAL LETTER DE
+0415; C; 0435; # CYRILLIC CAPITAL LETTER IE
+0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE
+0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE
+0418; C; 0438; # CYRILLIC CAPITAL LETTER I
+0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I
+041A; C; 043A; # CYRILLIC CAPITAL LETTER KA
+041B; C; 043B; # CYRILLIC CAPITAL LETTER EL
+041C; C; 043C; # CYRILLIC CAPITAL LETTER EM
+041D; C; 043D; # CYRILLIC CAPITAL LETTER EN
+041E; C; 043E; # CYRILLIC CAPITAL LETTER O
+041F; C; 043F; # CYRILLIC CAPITAL LETTER PE
+0420; C; 0440; # CYRILLIC CAPITAL LETTER ER
+0421; C; 0441; # CYRILLIC CAPITAL LETTER ES
+0422; C; 0442; # CYRILLIC CAPITAL LETTER TE
+0423; C; 0443; # CYRILLIC CAPITAL LETTER U
+0424; C; 0444; # CYRILLIC CAPITAL LETTER EF
+0425; C; 0445; # CYRILLIC CAPITAL LETTER HA
+0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE
+0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE
+0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA
+0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA
+042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN
+042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU
+042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN
+042D; C; 044D; # CYRILLIC CAPITAL LETTER E
+042E; C; 044E; # CYRILLIC CAPITAL LETTER YU
+042F; C; 044F; # CYRILLIC CAPITAL LETTER YA
+0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA
+0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT
+0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E
+0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS
+0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS
+046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI
+0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI
+0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA
+0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA
+0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478; C; 0479; # CYRILLIC CAPITAL LETTER UK
+047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E; C; 047F; # CYRILLIC CAPITAL LETTER OT
+0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA
+048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK
+0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE
+04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE
+04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA
+04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE
+04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA
+04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O
+04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE
+0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE
+0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE
+0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE
+0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE
+050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE
+050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE
+050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE
+0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB
+0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN
+0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM
+0534; C; 0564; # ARMENIAN CAPITAL LETTER DA
+0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH
+0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA
+0537; C; 0567; # ARMENIAN CAPITAL LETTER EH
+0538; C; 0568; # ARMENIAN CAPITAL LETTER ET
+0539; C; 0569; # ARMENIAN CAPITAL LETTER TO
+053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE
+053B; C; 056B; # ARMENIAN CAPITAL LETTER INI
+053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN
+053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH
+053E; C; 056E; # ARMENIAN CAPITAL LETTER CA
+053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN
+0540; C; 0570; # ARMENIAN CAPITAL LETTER HO
+0541; C; 0571; # ARMENIAN CAPITAL LETTER JA
+0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD
+0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH
+0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN
+0545; C; 0575; # ARMENIAN CAPITAL LETTER YI
+0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW
+0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA
+0548; C; 0578; # ARMENIAN CAPITAL LETTER VO
+0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA
+054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH
+054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH
+054C; C; 057C; # ARMENIAN CAPITAL LETTER RA
+054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH
+054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW
+054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN
+0550; C; 0580; # ARMENIAN CAPITAL LETTER REH
+0551; C; 0581; # ARMENIAN CAPITAL LETTER CO
+0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN
+0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR
+0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH
+0555; C; 0585; # ARMENIAN CAPITAL LETTER OH
+0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH
+0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN
+10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN
+10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN
+10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN
+10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON
+10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN
+10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN
+10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN
+10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN
+10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN
+10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN
+10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS
+10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN
+10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR
+10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON
+10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR
+10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR
+10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE
+10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN
+10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR
+10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN
+10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR
+10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR
+10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN
+10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR
+10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN
+10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN
+10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN
+10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL
+10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL
+10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR
+10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN
+10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN
+10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE
+10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE
+10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE
+10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE
+10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR
+10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE
+1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW
+1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA
+1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON
+1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE
+1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE
+1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE
+1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE
+1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE
+1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE
+1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW
+1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS
+1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE
+1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE
+1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING
+1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE
+1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE
+1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI
+1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA
+1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA
+1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA
+1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA
+1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA
+1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI
+1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI
+1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA
+1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA
+1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA
+1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA
+1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI
+1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA
+1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA
+1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA
+1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA
+1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA
+1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI
+1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI
+1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA
+1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA
+1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA
+1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA
+1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA
+1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI
+1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI
+1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA
+1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA
+1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA
+1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA
+1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI
+1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
+1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
+1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
+1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI
+1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA
+1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA
+1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA
+1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA
+1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA
+1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI
+1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
+1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
+1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
+1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
+1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
+1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
+1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
+1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
+1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI
+1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY
+1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON
+1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA
+1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA
+1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE; C; 03B9; # GREEK PROSGEGRAMMENI
+1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
+1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
+1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI
+1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA
+1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA
+1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA
+1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA
+1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
+1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI
+1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY
+1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON
+1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA
+1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
+1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
+1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI
+1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI
+1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY
+1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON
+1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA
+1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA
+1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
+1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
+1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI
+1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA
+1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA
+1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA
+1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA
+1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2126; C; 03C9; # OHM SIGN
+212A; C; 006B; # KELVIN SIGN
+212B; C; 00E5; # ANGSTROM SIGN
+2160; C; 2170; # ROMAN NUMERAL ONE
+2161; C; 2171; # ROMAN NUMERAL TWO
+2162; C; 2172; # ROMAN NUMERAL THREE
+2163; C; 2173; # ROMAN NUMERAL FOUR
+2164; C; 2174; # ROMAN NUMERAL FIVE
+2165; C; 2175; # ROMAN NUMERAL SIX
+2166; C; 2176; # ROMAN NUMERAL SEVEN
+2167; C; 2177; # ROMAN NUMERAL EIGHT
+2168; C; 2178; # ROMAN NUMERAL NINE
+2169; C; 2179; # ROMAN NUMERAL TEN
+216A; C; 217A; # ROMAN NUMERAL ELEVEN
+216B; C; 217B; # ROMAN NUMERAL TWELVE
+216C; C; 217C; # ROMAN NUMERAL FIFTY
+216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED
+216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED
+216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND
+24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A
+24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B
+24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C
+24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D
+24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E
+24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F
+24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G
+24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H
+24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I
+24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J
+24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K
+24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L
+24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M
+24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N
+24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O
+24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P
+24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q
+24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R
+24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S
+24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T
+24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U
+24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V
+24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W
+24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X
+24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y
+24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z
+2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU
+2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY
+2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE
+2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI
+2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO
+2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU
+2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE
+2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO
+2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA
+2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE
+2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE
+2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I
+2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI
+2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO
+2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE
+2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE
+2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI
+2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU
+2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI
+2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI
+2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO
+2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO
+2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU
+2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU
+2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU
+2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU
+2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE
+2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA
+2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI
+2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI
+2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA
+2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU
+2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI
+2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI
+2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA
+2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU
+2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS
+2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL
+2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO
+2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS
+2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS
+2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS
+2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA
+2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA
+2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC
+2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A
+2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA
+2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA
+2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA
+2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA
+2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE
+2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU
+2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA
+2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE
+2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE
+2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA
+2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA
+2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA
+2C98; C; 2C99; # COPTIC CAPITAL LETTER MI
+2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI
+2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI
+2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O
+2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI
+2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO
+2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA
+2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU
+2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA
+2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI
+2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI
+2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI
+2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU
+2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI
+2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU
+FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF
+FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI
+FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL
+FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI
+FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL
+FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T
+FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST
+FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW
+FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH
+FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI
+FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW
+FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH
+FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A
+FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B
+FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C
+FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D
+FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E
+FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F
+FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G
+FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H
+FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I
+FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J
+FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K
+FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L
+FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M
+FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N
+FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O
+FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P
+FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q
+FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R
+FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S
+FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T
+FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U
+FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V
+FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W
+FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X
+FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y
+FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z
+10400; C; 10428; # DESERET CAPITAL LETTER LONG I
+10401; C; 10429; # DESERET CAPITAL LETTER LONG E
+10402; C; 1042A; # DESERET CAPITAL LETTER LONG A
+10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH
+10404; C; 1042C; # DESERET CAPITAL LETTER LONG O
+10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO
+10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I
+10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E
+10408; C; 10430; # DESERET CAPITAL LETTER SHORT A
+10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH
+1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O
+1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO
+1040C; C; 10434; # DESERET CAPITAL LETTER AY
+1040D; C; 10435; # DESERET CAPITAL LETTER OW
+1040E; C; 10436; # DESERET CAPITAL LETTER WU
+1040F; C; 10437; # DESERET CAPITAL LETTER YEE
+10410; C; 10438; # DESERET CAPITAL LETTER H
+10411; C; 10439; # DESERET CAPITAL LETTER PEE
+10412; C; 1043A; # DESERET CAPITAL LETTER BEE
+10413; C; 1043B; # DESERET CAPITAL LETTER TEE
+10414; C; 1043C; # DESERET CAPITAL LETTER DEE
+10415; C; 1043D; # DESERET CAPITAL LETTER CHEE
+10416; C; 1043E; # DESERET CAPITAL LETTER JEE
+10417; C; 1043F; # DESERET CAPITAL LETTER KAY
+10418; C; 10440; # DESERET CAPITAL LETTER GAY
+10419; C; 10441; # DESERET CAPITAL LETTER EF
+1041A; C; 10442; # DESERET CAPITAL LETTER VEE
+1041B; C; 10443; # DESERET CAPITAL LETTER ETH
+1041C; C; 10444; # DESERET CAPITAL LETTER THEE
+1041D; C; 10445; # DESERET CAPITAL LETTER ES
+1041E; C; 10446; # DESERET CAPITAL LETTER ZEE
+1041F; C; 10447; # DESERET CAPITAL LETTER ESH
+10420; C; 10448; # DESERET CAPITAL LETTER ZHEE
+10421; C; 10449; # DESERET CAPITAL LETTER ER
+10422; C; 1044A; # DESERET CAPITAL LETTER EL
+10423; C; 1044B; # DESERET CAPITAL LETTER EM
+10424; C; 1044C; # DESERET CAPITAL LETTER EN
+10425; C; 1044D; # DESERET CAPITAL LETTER ENG
+10426; C; 1044E; # DESERET CAPITAL LETTER OI
+10427; C; 1044F; # DESERET CAPITAL LETTER EW
diff --git a/extras/globbing.c b/extras/globbing.c
new file mode 100644 (file)
index 0000000..bb83d6a
--- /dev/null
@@ -0,0 +1,159 @@
+/** \file globbing.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "physfs.h"
+#include "globbing.h"
+
+/**
+ * Please see globbing.h for details.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  \author Ryan C. Gordon.
+ */
+
+
+static int matchesPattern(const char *fname, const char *wildcard,
+                          int caseSensitive)
+{
+    char x, y;
+    const char *fnameptr = fname;
+    const char *wildptr = wildcard;
+
+    while ((*wildptr) && (*fnameptr))
+    {
+        y = *wildptr;
+        if (y == '*')
+        {
+            do
+            {
+                wildptr++;  /* skip multiple '*' in a row... */
+            } while (*wildptr == '*');
+
+            y = (caseSensitive) ? *wildptr : (char) tolower(*wildptr);
+
+            while (1)
+            {
+                x = (caseSensitive) ? *fnameptr : (char) tolower(*fnameptr);
+                if ((!x) || (x == y))
+                    break;
+                else
+                    fnameptr++;
+            } /* while */
+        } /* if */
+
+        else if (y == '?')
+        {
+            wildptr++;
+            fnameptr++;
+        } /* else if */
+
+        else
+        {
+            if (caseSensitive)
+                x = *fnameptr;
+            else
+            {
+                x = tolower(*fnameptr);
+                y = tolower(y);
+            } /* if */
+
+            wildptr++;
+            fnameptr++;
+
+            if (x != y)
+                return(0);
+        } /* else */
+    } /* while */
+
+    while (*wildptr == '*')
+        wildptr++;
+
+    return(*fnameptr == *wildptr);
+} /* matchesPattern */
+
+
+char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
+                                        int caseSensitive)
+{
+    char **rc = PHYSFS_enumerateFiles(dir);
+    char **i = rc;
+    char **j;
+
+    while (*i != NULL)
+    {
+        if (matchesPattern(*i, wildcard, caseSensitive))
+            i++;
+        else
+        {
+            /* FIXME: This counts on physfs's allocation method not changing! */
+            free(*i);
+            for (j = i; *j != NULL; j++)
+                j[0] = j[1];
+        } /* else */
+    } /* for */
+
+    return(rc);
+} /* PHYSFSEXT_enumerateFilesWildcard */
+
+
+#ifdef TEST_PHYSFSEXT_ENUMERATEFILESWILDCARD
+int main(int argc, char **argv)
+{
+    int rc;
+    char **flist;
+    char **i;
+
+    if (argc != 3)
+    {
+        printf("USAGE: %s <pattern> <caseSen>\n"
+               "   where <caseSen> is 1 or 0.\n", argv[0]);
+        return(1);
+    } /* if */
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError());
+        return(1);
+    } /* if */
+
+    if (!PHYSFS_addToSearchPath(".", 1))
+    {
+        fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    flist = PHYSFSEXT_enumerateFilesWildcard("/", argv[1], atoi(argv[2]));
+    rc = 0;
+    for (i = flist; *i; i++)
+    {
+        printf("%s\n", *i);
+        rc++;
+    } /* for */
+    printf("\n  total %d files.\n\n", rc);
+
+    PHYSFS_freeList(flist);
+    PHYSFS_deinit();
+
+    return(0);
+} /* main */
+#endif
+
+/* end of globbing.c ... */
+
diff --git a/extras/globbing.h b/extras/globbing.h
new file mode 100644 (file)
index 0000000..3784413
--- /dev/null
@@ -0,0 +1,77 @@
+/** \file globbing.h */
+
+/**
+ * \mainpage PhysicsFS globbing
+ *
+ * This is an extension to PhysicsFS to let you search for files with basic
+ *  wildcard matching, regardless of what sort of filesystem or archive they
+ *  reside in. It does this by enumerating directories as needed and manually
+ *  locating matching entries.
+ *
+ * Usage: Set up PhysicsFS as you normally would, then use
+ *  PHYSFSEXT_enumerateFilesPattern() when enumerating files. This is just
+ *  like PHYSFS_enumerateFiles(), but it returns a subset that matches your
+ *  wildcard pattern. You must call PHYSFS_freeList() on the results, just
+ *  like you would with PHYSFS_enumerateFiles().
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  \author Ryan C. Gordon.
+ */
+
+
+/**
+ * \fn char **PHYSFS_enumerateFilesWildcard(const char *dir, const char *wildcard, int caseSensitive)
+ * \brief Get a file listing of a search path's directory.
+ *
+ * Matching directories are interpolated. That is, if "C:\mydir" is in the
+ *  search path and contains a directory "savegames" that contains "x.sav",
+ *  "y.Sav", and "z.txt", and there is also a "C:\userdir" in the search path
+ *  that has a "savegames" subdirectory with "w.sav", then the following code:
+ *
+ * \code
+ * char **rc = PHYSFS_enumerateFilesWildcard("savegames", "*.sav", 0);
+ * char **i;
+ *
+ * for (i = rc; *i != NULL; i++)
+ *     printf(" * We've got [%s].\n", *i);
+ *
+ * PHYSFS_freeList(rc);
+ * \endcode
+ *
+ *  ...will print:
+ *
+ * \verbatim
+ * We've got [x.sav].
+ * We've got [y.Sav].
+ * We've got [w.sav].\endverbatim
+ *
+ * Feel free to sort the list however you like. We only promise there will
+ *  be no duplicates, but not what order the final list will come back in.
+ *
+ * Wildcard strings can use the '*' and '?' characters, currently.
+ * Matches can be case-insensitive if you pass a zero for argument 3.
+ *
+ * Don't forget to call PHYSFS_freeList() with the return value from this
+ *  function when you are done with it.
+ *
+ *    \param dir directory in platform-independent notation to enumerate.
+ *   \return Null-terminated array of null-terminated strings.
+ */
+__EXPORT__ char **PHYSFSEXT_enumerateFilesWildcard(const char *dir,
+                                                   const char *wildcard,
+                                                   int caseSensitive);
+
+/* end of globbing.h ... */
+
diff --git a/extras/ignorecase.c b/extras/ignorecase.c
new file mode 100644 (file)
index 0000000..16e807d
--- /dev/null
@@ -0,0 +1,219 @@
+/** \file ignorecase.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "physfs.h"
+#include "ignorecase.h"
+
+/**
+ * Please see ignorecase.h for details.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  \author Ryan C. Gordon.
+ */
+
+/* I'm not screwing around with stricmp vs. strcasecmp... */
+/* !!! FIXME: this will NOT work with UTF-8 strings in physfs2.0 */
+static int caseInsensitiveStringCompare(const char *x, const char *y)
+{
+    int ux, uy;
+    do
+    {
+        ux = toupper((int) *x);
+        uy = toupper((int) *y);
+        if (ux != uy)
+            return((ux > uy) ? 1 : -1);
+        x++;
+        y++;
+    } while ((ux) && (uy));
+
+    return(0);
+} /* caseInsensitiveStringCompare */
+
+
+static int locateOneElement(char *buf)
+{
+    char *ptr;
+    char **rc;
+    char **i;
+
+    if (PHYSFS_exists(buf))
+        return(1);  /* quick rejection: exists in current case. */
+
+    ptr = strrchr(buf, '/');  /* find entry at end of path. */
+    if (ptr == NULL)
+    {
+        rc = PHYSFS_enumerateFiles("/");
+        ptr = buf;
+    } /* if */
+    else
+    {
+        *ptr = '\0';
+        rc = PHYSFS_enumerateFiles(buf);
+        *ptr = '/';
+        ptr++;  /* point past dirsep to entry itself. */
+    } /* else */
+
+    for (i = rc; *i != NULL; i++)
+    {
+        if (caseInsensitiveStringCompare(*i, ptr) == 0)
+        {
+            strcpy(ptr, *i); /* found a match. Overwrite with this case. */
+            PHYSFS_freeList(rc);
+            return(1);
+        } /* if */
+    } /* for */
+
+    /* no match at all... */
+    PHYSFS_freeList(rc);
+    return(0);
+} /* locateOneElement */
+
+
+int PHYSFSEXT_locateCorrectCase(char *buf)
+{
+    int rc;
+    char *ptr;
+    char *prevptr;
+
+    while (*buf == '/')  /* skip any '/' at start of string... */
+        buf++;
+
+    ptr = prevptr = buf;
+    if (*ptr == '\0')
+        return(0);  /* Uh...I guess that's success. */
+
+    while (ptr = strchr(ptr + 1, '/'))
+    {
+        *ptr = '\0';  /* block this path section off */
+        rc = locateOneElement(buf);
+        *ptr = '/'; /* restore path separator */
+        if (!rc)
+            return(-2);  /* missing element in path. */
+    } /* while */
+
+    /* check final element... */
+    return(locateOneElement(buf) ? 0 : -1);
+} /* PHYSFSEXT_locateCorrectCase */
+
+
+#ifdef TEST_PHYSFSEXT_LOCATECORRECTCASE
+int main(int argc, char **argv)
+{
+    int rc;
+    char buf[128];
+    PHYSFS_File *f;
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError());
+        return(1);
+    } /* if */
+
+    if (!PHYSFS_addToSearchPath(".", 1))
+    {
+        fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    if (!PHYSFS_setWriteDir("."))
+    {
+        fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    if (!PHYSFS_mkdir("/a/b/c"))
+    {
+        fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    if (!PHYSFS_mkdir("/a/b/C"))
+    {
+        fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    f = PHYSFS_openWrite("/a/b/c/x.txt");
+    PHYSFS_close(f);
+    if (f == NULL)
+    {
+        fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    f = PHYSFS_openWrite("/a/b/C/X.txt");
+    PHYSFS_close(f);
+    if (f == NULL)
+    {
+        fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError());
+        PHYSFS_deinit();
+        return(1);
+    } /* if */
+
+    strcpy(buf, "/a/b/c/x.txt");
+    rc = PHYSFSEXT_locateCorrectCase(buf);
+    if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
+        printf("test 1 failed\n");
+
+    strcpy(buf, "/a/B/c/x.txt");
+    rc = PHYSFSEXT_locateCorrectCase(buf);
+    if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
+        printf("test 2 failed\n");
+
+    strcpy(buf, "/a/b/C/x.txt");
+    rc = PHYSFSEXT_locateCorrectCase(buf);
+    if ((rc != 0) || (strcmp(buf, "/a/b/C/X.txt") != 0))
+        printf("test 3 failed\n");
+
+    strcpy(buf, "/a/b/c/X.txt");
+    rc = PHYSFSEXT_locateCorrectCase(buf);
+    if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
+        printf("test 4 failed\n");
+
+    strcpy(buf, "/a/b/c/z.txt");
+    rc = PHYSFSEXT_locateCorrectCase(buf);
+    if ((rc != -1) || (strcmp(buf, "/a/b/c/z.txt") != 0))
+        printf("test 5 failed\n");
+
+    strcpy(buf, "/A/B/Z/z.txt");
+    rc = PHYSFSEXT_locateCorrectCase(buf);
+    if ((rc != -2) || (strcmp(buf, "/a/b/Z/z.txt") != 0))
+        printf("test 6 failed\n");
+
+    printf("Testing completed.\n");
+    printf("  If no errors were reported, you're good to go.\n");
+
+    PHYSFS_delete("/a/b/c/x.txt");
+    PHYSFS_delete("/a/b/C/X.txt");
+    PHYSFS_delete("/a/b/c");
+    PHYSFS_delete("/a/b/C");
+    PHYSFS_delete("/a/b");
+    PHYSFS_delete("/a");
+    PHYSFS_deinit();
+    return(0);
+} /* main */
+#endif
+
+/* end of ignorecase.c ... */
+
diff --git a/extras/ignorecase.h b/extras/ignorecase.h
new file mode 100644 (file)
index 0000000..1d98355
--- /dev/null
@@ -0,0 +1,75 @@
+/** \file ignorecase.h */
+
+/**
+ * \mainpage PhysicsFS ignorecase
+ *
+ * This is an extension to PhysicsFS to let you handle files in a
+ *  case-insensitive manner, regardless of what sort of filesystem or
+ *  archive they reside in. It does this by enumerating directories as
+ *  needed and manually locating matching entries.
+ *
+ * Please note that this brings with it some caveats:
+ *  - On filesystems that are case-insensitive to start with, such as those
+ *    used on Windows or MacOS, you are adding extra overhead.
+ *  - On filesystems that are case-sensitive, you might select the wrong dir
+ *    or file (which brings security considerations and potential bugs). This
+ *    code favours exact case matches, but you will lose access to otherwise
+ *    duplicate filenames, or you might go down a wrong directory tree, etc.
+ *    In practive, this is rarely a problem, but you need to be aware of it.
+ *  - This doesn't do _anything_ with the write directory; you're on your
+ *    own for opening the right files for writing. You can sort of get around
+ *    this by adding your write directory to the search path, but then the
+ *    interpolated directory tree can screw you up even more.
+ *
+ * This code should be considered an aid for legacy code. New development
+ *  shouldn't do dumbass things that require this aid in the first place.  :)
+ *
+ * Usage: Set up PhysicsFS as you normally would, then use
+ *  PHYSFSEXT_locateCorrectCase() to get a "correct" pathname to pass to
+ *  functions like PHYSFS_openRead(), etc.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  \author Ryan C. Gordon.
+ */
+
+
+/**
+ * \fn int PHYSFSEXT_locateCorrectCase(char *buf)
+ * \brief Find an existing filename with matching case.
+ *
+ * This function will look for a path/filename that matches the passed in
+ *  buffer. Each element of the buffer's path is checked for a
+ *  case-insensitive match. The buffer must specify a null-terminated string
+ *  in platform-independent notation.
+ *
+ * Please note results may be skewed differently depending on whether symlinks
+ *  are enabled or not.
+ *
+ * Each element of the buffer is overwritten with the actual case of an
+ *  existing match. If there is no match, the search aborts and reports an
+ *  error. Exact matches are favored over case-insensitive matches.
+ *
+ * THIS IS RISKY. Please do not use this function for anything but crappy
+ *  legacy code.
+ *
+ *   \param buf Buffer with null-terminated string of path/file to locate.
+ *               This buffer will be modified by this function.
+ *  \return zero if match was found, -1 if the final element (the file itself)
+ *               is missing, -2 if one of the parent directories is missing.
+ */
+int PHYSFSEXT_locateCorrectCase(char *buf);
+
+/* end of ignorecase.h ... */
+
diff --git a/extras/makecasefoldhashtable.pl b/extras/makecasefoldhashtable.pl
new file mode 100755 (executable)
index 0000000..7be2e93
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+
+print <<__EOF__;
+/*
+ * This file is part of PhysicsFS (http://icculus.org/physfs/)
+ *
+ * This data generated by physfs/extras/makecasefoldhashtable.pl ...
+ * Do not manually edit this file!
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ */
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+__EOF__
+
+
+my @foldPairs;
+
+for (my $i = 0; $i < 256; $i++) {
+    $foldPairs[$i] = '';
+}
+
+open(FH,'<','casefolding.txt') or die("failed to open casefolding.txt: $!\n");
+while (<FH>) {
+    chomp;
+    # strip comments from textfile...
+    s/\#.*\Z//;
+
+    # strip whitespace...
+    s/\A\s+//;
+    s/\s+\Z//;
+
+    next if not /\A([a-fA-F0-9]+)\;\s*(.)\;\s*(.+)\;/;
+    my ($code, $status, $mapping) = ($1, $2, $3);
+    my $hexxed = hex($code);
+    my $hashed = (($hexxed ^ ($hexxed >> 8)) & 0xFF);
+    #print("// code '$code'   status '$status'   mapping '$mapping'\n");
+    #print("// hexxed '$hexxed'  hashed '$hashed'\n");
+
+    if (($status eq 'C') or ($status eq 'F')) {
+        my ($map1, $map2, $map3) = ('0000', '0000', '0000');
+        $map1 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
+        $map2 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
+        $map3 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
+        die("mapping space too small for '$code'\n") if ($mapping ne '');
+        $foldPairs[$hashed] .= "    { 0x$code, 0x$map1, 0x$map2, 0x$map3 },\n";
+    }
+}
+close(FH);
+
+for (my $i = 0; $i < 256; $i++) {
+    $foldPairs[$i] =~ s/,\n\Z//;
+    my $str = $foldPairs[$i];
+    next if $str eq '';
+    my $num = '000' . $i;
+    $num =~ s/\A.*?(\d\d\d)\Z/$1/;
+    my $sym = "case_fold_${num}";
+    print("static const CaseFoldMapping ${sym}[] = {\n$str\n};\n\n");
+}
+
+print("\nstatic const CaseFoldHashBucket case_fold_hash[256] = {\n");
+
+for (my $i = 0; $i < 256; $i++) {
+    my $str = $foldPairs[$i];
+    if ($str eq '') {
+        print("    { 0, NULL },\n");
+    } else {
+        my $num = '000' . $i;
+        $num =~ s/\A.*?(\d\d\d)\Z/$1/;
+        my $sym = "case_fold_${num}";
+        print("    { __PHYSFS_ARRAYLEN($sym), $sym },\n");
+    }
+}
+print("};\n\n");
+
+exit 0;
+
+# end of makecashfoldhashtable.pl ...
+
diff --git a/extras/physfs_rb/installer.rb b/extras/physfs_rb/installer.rb
new file mode 100644 (file)
index 0000000..a62bd28
--- /dev/null
@@ -0,0 +1,103 @@
+# $Id: installer.rb,v 1.3 2003/07/21 03:46:50 icculus Exp $
+
+require 'rbconfig'
+require 'find'
+require 'ftools'
+
+include Config
+
+module Slimb
+  class Installer
+    def initialize target_dir = "", &user_skip 
+      @user_skip = user_skip or proc {|f| false}
+      
+      @version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
+      @libdir = File.join(CONFIG["libdir"], "ruby", @version)
+      @sitedir = CONFIG["sitedir"] || File.join(@libdir, "site_ruby")
+      @dest = File.join @sitedir, target_dir
+
+      File::makedirs @dest
+      File::chmod 0755, @dest, true
+    end
+
+    def skip? file
+      @user_skip[file] or
+       file[0] == ?. or file[-1] == ?~ or file[-1] == ?#
+    end
+    
+    def install_dir dir 
+      File::makedirs(File.join(@dest, dir))
+      File::chmod(0755, File.join(@dest, dir), true)
+      Dir.foreach(dir) {|file|
+       next if skip? file
+       
+       if File.ftype(File.join(dir, file)) == "directory"
+         install_dir File.join(dir, file)
+       else
+         install_file File.join(dir, file)
+       end
+      }
+    end
+
+    def install_file file
+      if file =~ /\.so$/
+       install_so file
+      else
+       File::install file, File.join(@dest, file), 0644, true
+      end
+    end
+
+    def install_so file
+      File::install file, File.join(CONFIG["sitearchdir"], file), 0644, true
+    end
+
+    def uninstall_so file
+      file = File.join(CONFIG["sitearchdir"], file)
+      File::safe_unlink file
+    end
+
+    def install something
+      case something
+      when Array
+       something.each {|x|
+         install x if x.is_a? String
+       }
+      when String
+       if File.ftype(something) == "directory"
+         install_dir something
+       else
+         install_file something
+       end
+      end
+    end
+
+    def uninstall what = "*"
+      case what
+      when Array
+       files = what.map {|x| File.join(@dest, x)}
+      when String
+       files = Dir[File.join(@dest, what)]
+      end
+      
+      files.each {|x|
+       # FIXME: recursive uninstall is a must
+       next if FileTest.directory? x
+       File::safe_unlink x
+      }
+    end
+
+    def run files, argv
+      if !argv.grep(/--uninstall/).empty?
+       uninstall files
+      else
+       install files
+      end      
+    end
+  end
+end
+
+# self-installation 
+if $0 == __FILE__
+  $stderr.puts "Installing slimb installer..."
+  Slimb::Installer.new("slimb").install File.basename(__FILE__)
+end
diff --git a/extras/physfs_rb/physfs/extconf.rb b/extras/physfs_rb/physfs/extconf.rb
new file mode 100644 (file)
index 0000000..f344059
--- /dev/null
@@ -0,0 +1,9 @@
+require 'mkmf'
+
+$CFLAGS += `sdl-config --cflags`.chomp
+$LDFLAGS += `sdl-config --libs`.chomp
+
+have_library "physfs", "PHYSFS_init"
+have_library "SDL", "SDL_AllocRW"
+
+create_makefile "physfs_so"
diff --git a/extras/physfs_rb/physfs/install.rb b/extras/physfs_rb/physfs/install.rb
new file mode 100644 (file)
index 0000000..29bd454
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/local/bin/ruby
+
+if __FILE__ == $0
+  require 'slimb/installer'
+  files = ["physfs.rb", "physfs_so.so"]
+  installer = Slimb::Installer.new.run files, ARGV
+end
diff --git a/extras/physfs_rb/physfs/make_install_test.sh b/extras/physfs_rb/physfs/make_install_test.sh
new file mode 100755 (executable)
index 0000000..ac616c8
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+ruby extconf.rb
+make
+cd ..
+ruby installer.rb
+cd physfs
+ruby install.rb
+cd test
+ruby test_physfs.rb
\ No newline at end of file
diff --git a/extras/physfs_rb/physfs/physfs.rb b/extras/physfs_rb/physfs/physfs.rb
new file mode 100644 (file)
index 0000000..88da331
--- /dev/null
@@ -0,0 +1,121 @@
+#
+# PhysicsFS - ruby interface
+#
+# Author: Ed Sinjiashvili (slimb@vlinkmail.com)
+# License: LGPL
+#
+
+require 'physfs_so'
+
+module PhysicsFS
+
+  class Version
+    def initialize major, minor, patch
+      @major = major
+      @minor = minor
+      @patch = patch
+    end
+
+    attr_reader :major, :minor, :patch
+
+    def to_s
+      "#@major.#@minor.#@patch"
+    end
+  end
+
+  class ArchiveInfo
+    def initialize ext, desc, author, url
+      @extension = ext
+      @description = desc
+      @author = author
+      @url = url
+    end
+
+    attr_reader :extension, :description
+    attr_reader :author, :url
+
+    def to_s
+      " * #@extension: #@description\n    Written by #@author.\n    #@url\n"
+    end
+  end
+
+  #
+  # convenience methods
+  #
+  class << self  
+
+    def init argv0 = $0
+      init_internal argv0
+    end
+
+    def append_search_path str
+      add_to_search_path str, 1
+      self
+    end
+
+    def prepend_search_path str
+      add_to_search_path str, 0
+      self
+    end
+
+    alias_method :<<,      :append_search_path
+    alias_method :push,    :append_search_path
+    alias_method :unshift, :prepend_search_path
+
+    def ls path = ""
+      enumerate path
+    end
+  end
+
+  #
+  # File - PhysicsFS abstract file - can be drawn from various sources
+  # 
+  class File
+    def write_str str
+      write str, 1, str.length
+    end
+    
+    def cat
+      prev_pos = tell
+      seek 0
+      r = read length, 1
+      seek prev_pos
+      r
+    end
+    
+    alias_method :size, :length
+  end
+
+  #
+  # RWops - general stdio like operations on file-like creatures
+  #
+  class RWops
+    SEEK_SET = 0
+    SEEK_CUR = 1
+    SEEK_END = 2
+
+    # tell current position of RWopted entity
+    def tell
+      seek 0, SEEK_CUR
+    end
+
+    # length of RWops abstracted entity
+    def length
+      cur = tell
+      r = seek 0, SEEK_END
+      seek cur, SEEK_SET
+      r
+    end
+
+    alias_method :size, :length
+
+    #
+    # create rwops from PhysicsFS file object
+    # 
+    def self.from_physfs file
+      file.to_rwops
+    end
+  end
+end
+
+# physfs.rb ends here #
diff --git a/extras/physfs_rb/physfs/physfsrwops.c b/extras/physfs_rb/physfs/physfsrwops.c
new file mode 100644 (file)
index 0000000..8dd23bf
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser
+ *  General Public License: http://www.gnu.org/licenses/lgpl.txt
+ *
+ * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    int pos = 0;
+
+    if (whence == SEEK_SET)
+    {
+        pos = offset;
+    } /* if */
+
+    else if (whence == SEEK_CUR)
+    {
+        PHYSFS_sint64 current = PHYSFS_tell(handle);
+        if (current == -1)
+        {
+            SDL_SetError("Can't find position in file: %s",
+                          PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) current;
+        if ( ((PHYSFS_sint64) pos) != current )
+        {
+            SDL_SetError("Can't fit current file position in an int!");
+            return(-1);
+        } /* if */
+
+        if (offset == 0)  /* this is a "tell" call. We're done. */
+            return(pos);
+
+        pos += offset;
+    } /* else if */
+
+    else if (whence == SEEK_END)
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+        if (len == -1)
+        {
+            SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) len;
+        if ( ((PHYSFS_sint64) pos) != len )
+        {
+            SDL_SetError("Can't fit end-of-file position in an int!");
+            return(-1);
+        } /* if */
+
+        pos += offset;
+    } /* else if */
+
+    else
+    {
+        SDL_SetError("Invalid 'whence' parameter.");
+        return(-1);
+    } /* else */
+
+    if ( pos < 0 )
+    {
+        SDL_SetError("Attempt to seek past start of file.");
+        return(-1);
+    } /* if */
+    
+    if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
+    {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+        return(-1);
+    } /* if */
+
+    return(pos);
+} /* physfsrwops_seek */
+
+
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum);
+    if (rc != maxnum)
+    {
+        if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+            SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    } /* if */
+
+    return((int) rc);
+} /* physfsrwops_read */
+
+
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num);
+    if (rc != num)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+    return((int) rc);
+} /* physfsrwops_write */
+
+
+static int physfsrwops_close(SDL_RWops *rw)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    if (!PHYSFS_close(handle))
+    {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+        return(-1);
+    } /* if */
+
+    SDL_FreeRW(rw);
+    return(0);
+} /* physfsrwops_close */
+
+
+static SDL_RWops *create_rwops(PHYSFS_File *handle)
+{
+    SDL_RWops *retval = NULL;
+
+    if (handle == NULL)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    else
+    {
+        retval = SDL_AllocRW();
+        if (retval != NULL)
+        {
+            retval->seek  = physfsrwops_seek;
+            retval->read  = physfsrwops_read;
+            retval->write = physfsrwops_write;
+            retval->close = physfsrwops_close;
+            retval->hidden.unknown.data1 = handle;
+        } /* if */
+    } /* else */
+
+    return(retval);
+} /* create_rwops */
+
+
+SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
+{
+    SDL_RWops *retval = NULL;
+    if (handle == NULL)
+        SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
+    else
+        retval = create_rwops(handle);
+
+    return(retval);
+} /* PHYSFSRWOPS_makeRWops */
+
+
+SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
+{
+    return(create_rwops(PHYSFS_openRead(fname)));
+} /* PHYSFSRWOPS_openRead */
+
+
+SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
+{
+    return(create_rwops(PHYSFS_openWrite(fname)));
+} /* PHYSFSRWOPS_openWrite */
+
+
+SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
+{
+    return(create_rwops(PHYSFS_openAppend(fname)));
+} /* PHYSFSRWOPS_openAppend */
+
+
+/* end of physfsrwops.c ... */
+
diff --git a/extras/physfs_rb/physfs/physfsrwops.h b/extras/physfs_rb/physfs/physfsrwops.h
new file mode 100644 (file)
index 0000000..5ff519a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser
+ *  General Public License: http://www.gnu.org/licenses/lgpl.txt
+ *
+ * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
+
+/**
+ * Open a platform-independent filename for writing, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
+
+/**
+ * Open a platform-independent filename for appending, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
+
+/**
+ * Make a SDL_RWops from an existing PhysicsFS file handle. You should
+ *  dispose of any references to the handle after successful creation of
+ *  the RWops. The actual PhysicsFS handle will be destroyed when the
+ *  RWops is closed.
+ *
+ *   @param handle a valid PhysicsFS file handle.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+
diff --git a/extras/physfs_rb/physfs/rb_physfs.c b/extras/physfs_rb/physfs/rb_physfs.c
new file mode 100644 (file)
index 0000000..043d911
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * PhysicsFS - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License:: LGPL
+ */
+
+#include "physfs.h"
+#include "ruby.h"
+
+#include "rb_physfs.h" 
+#include "rb_physfs_file.h"
+
+VALUE modulePhysfs;
+
+/*
+ * PhysicsFS::init str
+ *
+ * initialize PhysicsFS
+ */
+VALUE physfs_init (VALUE self, VALUE str)
+{
+    int result = PHYSFS_init (STR2CSTR(str));
+
+    if (result)
+       return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::deinit
+ */
+VALUE physfs_deinit (VALUE self)
+{
+    if (PHYSFS_deinit ())
+       return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::version
+ * 
+ * return PhysicsFS::Version object
+ */
+VALUE physfs_version (VALUE self)
+{
+    char evalStr[200];
+    PHYSFS_Version ver;
+
+    PHYSFS_getLinkedVersion (&ver);
+
+    sprintf (evalStr, "PhysicsFS::Version.new %d, %d, %d", 
+            ver.major, ver.minor, ver.patch);
+    return rb_eval_string (evalStr);
+}
+
+/*
+ * PhysicsFS::supported_archives
+ *
+ * return Array of PhysicsFS::ArchiveInfo objects
+ */
+VALUE physfs_supported_archives (VALUE self)
+{
+    const PHYSFS_ArchiveInfo **info = PHYSFS_supportedArchiveTypes();
+    VALUE klass = rb_const_get (modulePhysfs, rb_intern ("ArchiveInfo"));
+    VALUE ary = rb_ary_new ();
+    VALUE params[4];
+
+    while ( *info != 0 ) 
+    {
+        params[0] = rb_str_new2 ((*info)->extension);
+        params[1] = rb_str_new2 ((*info)->description);
+        params[2] = rb_str_new2 ((*info)->author);
+        params[3] = rb_str_new2 ((*info)->url);
+
+        rb_ary_push (ary, rb_class_new_instance (4, params, klass));
+        info++;
+    }
+
+    return ary;
+}
+
+/*
+ * PhysicsFS::last_error
+ *
+ * return string representation of last PhysicsFS error
+ */
+VALUE physfs_last_error (VALUE self)
+{
+    const char *last_error = PHYSFS_getLastError ();
+
+    if (last_error == 0)
+       last_error = "";
+
+    return rb_str_new2 (last_error);
+}
+
+/*
+ * PhysicsFS::dir_separator
+ *
+ * return platform directory separator
+ */
+VALUE physfs_dir_separator (VALUE self)
+{
+    return rb_str_new2 (PHYSFS_getDirSeparator ());
+}
+
+/*
+ * PhysicsFS::permit_symlinks boolValue
+ *
+ * turn symlinks support on/off
+ */
+VALUE physfs_permit_symlinks (VALUE self, VALUE allow)
+{
+    int p = 1;
+    
+    if (allow == Qfalse || allow == Qnil)
+        p = 0;
+
+    PHYSFS_permitSymbolicLinks (p);
+    return Qtrue;
+}
+
+/*
+ * PhysicsFS::cdrom_dirs
+ *
+ * return Array of strings containing available CDs 
+ */
+VALUE physfs_cdrom_dirs (VALUE self)
+{
+    char **cds = PHYSFS_getCdRomDirs();
+    char **i;
+    VALUE ary = rb_ary_new ();
+
+    for (i = cds; *i != 0; i++)
+        rb_ary_push (ary, rb_str_new2 (*i));
+
+    PHYSFS_freeList (cds);
+    return ary;
+}
+
+/*
+ * PhysicsFS::base_dir
+ *
+ * return base directory
+ */
+VALUE physfs_base_dir (VALUE self)
+{
+    const char *base_dir = PHYSFS_getBaseDir ();
+    if (base_dir == 0)
+        base_dir = "";
+
+    return rb_str_new2 (base_dir);
+}
+
+/*
+ * PhysicsFS::user_dir
+ *
+ * return user directory
+ */
+VALUE physfs_user_dir (VALUE self)
+{
+    const char *user_dir = PHYSFS_getBaseDir ();
+    if (user_dir == 0)
+        user_dir = "";
+
+    return rb_str_new2 (user_dir);
+}
+   
+/*
+ * PhysicsFS::write_dir 
+ *
+ * return write directory
+ */
+VALUE physfs_write_dir (VALUE self)
+{
+    const char *write_dir = PHYSFS_getWriteDir ();
+    if (write_dir == 0)
+        return Qnil;
+
+    return rb_str_new2 (write_dir);
+}
+
+/*
+ * PhysicsFS::write_dir= str
+ *
+ * set write directory to *str*
+ */
+VALUE physfs_set_write_dir (VALUE self, VALUE str)
+{
+    int result = PHYSFS_setWriteDir (STR2CSTR(str));
+
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::add_to_search_path str, append
+ *
+ * if append > 0 - append str to search path, otherwise prepend it
+ */
+VALUE physfs_add_search_path (VALUE self, VALUE str, VALUE append)
+{
+    int result = PHYSFS_addToSearchPath (STR2CSTR(str), FIX2INT(append));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::remove_from_search_path str
+ *
+ * removes str from search path
+ */
+VALUE physfs_remove_search_path (VALUE self, VALUE str)
+{
+    int result = PHYSFS_removeFromSearchPath (STR2CSTR(str));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::search_path
+ *
+ * return current search_path - as array of strings
+ */
+VALUE physfs_search_path (VALUE self)
+{
+    char **path = PHYSFS_getSearchPath ();
+    char **i;
+    VALUE ary = rb_ary_new ();
+
+    for (i = path ; *i != 0; i++)
+        rb_ary_push (ary, rb_str_new2 (*i));
+
+    PHYSFS_freeList (path);
+    return ary;
+}
+
+// 
+VALUE physfs_setSaneConfig(VALUE self, VALUE org, VALUE app, VALUE ext,
+                           VALUE includeCdroms, VALUE archivesFirst)
+{
+    int res = PHYSFS_setSaneConfig (STR2CSTR(org), STR2CSTR(app), STR2CSTR(ext),
+                                   RTEST(includeCdroms), RTEST(archivesFirst));
+    if (res)
+        return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::mkdir newdir
+ *
+ * create new directory 
+ */ 
+VALUE physfs_mkdir (VALUE self, VALUE newdir)
+{
+    int result = PHYSFS_mkdir (STR2CSTR(newdir));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::delete name
+ *
+ * delete file with name
+ */
+VALUE physfs_delete (VALUE self, VALUE name)
+{
+    int result = PHYSFS_delete (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::real_dir name
+ *
+ * return real directory (in search path) of a name
+ */
+VALUE physfs_real_dir (VALUE self, VALUE name)
+{
+    const char *path = PHYSFS_getRealDir (STR2CSTR(name));
+    if (path == 0)
+        return Qnil;
+
+    return rb_str_new2 (path);
+}
+
+/*
+ * PhysicsFS::enumerate dir
+ *
+ * list a dir from a search path
+ */
+VALUE physfs_enumerate (VALUE self, VALUE dir)
+{
+    char **files = PHYSFS_enumerateFiles (STR2CSTR(dir));
+    char **i;
+    VALUE ary = rb_ary_new ();
+
+    for (i = files; *i != 0; i++)
+        rb_ary_push (ary, rb_str_new2 (*i));
+
+    PHYSFS_freeList (files);
+    return ary;
+}
+
+/*
+ * PhysicsFS::exists? name
+ *
+ * does a file with name exist?
+ */
+VALUE physfs_exists (VALUE self, VALUE name)
+{
+    int result = PHYSFS_exists (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::is_directory? name
+ *
+ * return true if name is directory
+ */
+VALUE physfs_is_directory (VALUE self, VALUE name)
+{
+    int result = PHYSFS_isDirectory (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::is_symlink? name
+ *
+ * return true if name is symlink
+ */
+VALUE physfs_is_symlink (VALUE self, VALUE name)
+{
+    int result = PHYSFS_isSymbolicLink (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::last_mod_time name
+ *
+ * return last modification time of a file
+ */
+VALUE physfs_last_mod_time (VALUE self, VALUE name)
+{
+    int result = PHYSFS_getLastModTime (STR2CSTR(name));
+    
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::open_read name
+ *
+ * return +PhysicsFS::File+ ready for reading
+ */
+VALUE physfs_open_read (VALUE self, VALUE name)
+{
+    PHYSFS_File *file = PHYSFS_openRead (STR2CSTR(name));
+    return physfs_file_new (file);
+}
+
+/*
+ * PhysicsFS::open_write name
+ *
+ * return PhysicsFS::File ready for writing
+ */
+VALUE physfs_open_write (VALUE self, VALUE name)
+{
+    PHYSFS_File *file = PHYSFS_openWrite (STR2CSTR(name));
+    return physfs_file_new (file);
+}
+
+/*
+ * PhysicsFS::open_append name
+ *
+ * return PhysicsFS::File ready for appending
+ */
+VALUE physfs_open_append (VALUE self, VALUE name)
+{
+    PHYSFS_File *file = PHYSFS_openAppend (STR2CSTR(name));
+    return physfs_file_new (file);
+}
+
+void Init_physfs_so (void)
+{
+    modulePhysfs = rb_define_module ("PhysicsFS");
+
+    rb_define_singleton_method (modulePhysfs, "init_internal", physfs_init, 1);
+    rb_define_singleton_method (modulePhysfs, "deinit", physfs_deinit, 0);
+    rb_define_singleton_method (modulePhysfs, "version", physfs_version, 0);
+    rb_define_singleton_method (modulePhysfs, "supported_archives",
+                               physfs_supported_archives, 0);
+    rb_define_singleton_method (modulePhysfs, "last_error", 
+                               physfs_last_error, 0);
+    rb_define_singleton_method (modulePhysfs, "dir_separator",
+                               physfs_dir_separator, 0);
+    rb_define_singleton_method (modulePhysfs, "permit_symlinks",
+                                physfs_permit_symlinks, 1);
+    rb_define_singleton_method (modulePhysfs, "cdrom_dirs", 
+                                physfs_cdrom_dirs, 0);
+    rb_define_singleton_method (modulePhysfs, "base_dir", physfs_base_dir, 0);
+    rb_define_singleton_method (modulePhysfs, "user_dir", physfs_user_dir, 0);
+
+    rb_define_singleton_method (modulePhysfs, "write_dir", physfs_write_dir, 0);
+    rb_define_singleton_method (modulePhysfs, "write_dir=", 
+                                physfs_set_write_dir, 1);
+
+    rb_define_singleton_method (modulePhysfs, "add_to_search_path",
+                                physfs_add_search_path, 2);
+    rb_define_singleton_method (modulePhysfs, "remove_from_search_path",
+                                physfs_remove_search_path, 1);
+    rb_define_singleton_method (modulePhysfs, "search_path",
+                                physfs_search_path, 0);
+
+    rb_define_singleton_method (modulePhysfs, "set_sane_config",
+                                physfs_setSaneConfig, 5);
+
+    rb_define_singleton_method (modulePhysfs, "mkdir", physfs_mkdir, 1);
+    rb_define_singleton_method (modulePhysfs, "delete", physfs_delete, 1);
+    rb_define_singleton_method (modulePhysfs, "real_dir",
+                                physfs_real_dir, 1);
+    rb_define_singleton_method (modulePhysfs, "enumerate", physfs_enumerate, 1);
+    rb_define_singleton_method (modulePhysfs, "exists?", physfs_exists, 1);
+    rb_define_singleton_method (modulePhysfs, "is_directory?", 
+                                physfs_is_directory, 1);
+    rb_define_singleton_method (modulePhysfs, "is_symlink?", 
+                                physfs_is_symlink, 1);
+    rb_define_singleton_method (modulePhysfs, "last_mod_time",
+                                physfs_last_mod_time, 1);
+
+    rb_define_singleton_method (modulePhysfs, "open_read", 
+                                physfs_open_read, 1);
+    rb_define_singleton_method (modulePhysfs, "open_write", 
+                                physfs_open_write, 1);
+    rb_define_singleton_method (modulePhysfs, "open_append", 
+                                physfs_open_append, 1);
+
+    init_physfs_file ();
+    init_sdl_rwops ();
+}
+
+/*
+// Local Variables:
+// mode: C
+// c-indentation-style: "stroustrup"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/extras/physfs_rb/physfs/rb_physfs.h b/extras/physfs_rb/physfs/rb_physfs.h
new file mode 100644 (file)
index 0000000..ca82036
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * PhysicsFS - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License:: LGPL
+ */
+
+#ifndef __RB__PHYSFS__H__
+#define __RB__PHYSFS__H__
+
+extern VALUE modulePhysfs;
+
+#endif
diff --git a/extras/physfs_rb/physfs/rb_physfs_file.c b/extras/physfs_rb/physfs/rb_physfs_file.c
new file mode 100644 (file)
index 0000000..3e50880
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * PhysicsFS File abstraction - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License:: LGPL
+ */
+
+#include "physfs.h"
+#include "ruby.h"
+
+#include "rb_physfs.h"
+#include "rb_physfs_file.h"
+#include "physfsrwops.h"
+
+VALUE classPhysfsFile;
+
+/*
+ * construct new PhysicsFS::File object
+ */
+VALUE physfs_file_new (PHYSFS_File *file)
+{
+    if (file == 0)
+        return Qnil;
+
+    return Data_Wrap_Struct (classPhysfsFile, 0, 0, file);
+}
+
+/*
+ * PhysicsFS::File#close 
+ *
+ * Close the file. It's illegal to use the object after its closure.
+ */
+VALUE physfs_file_close (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+    Data_Get_Struct (self, PHYSFS_File, file);
+
+    if (file == 0)
+       return Qfalse;
+
+    result = PHYSFS_close (file);
+    DATA_PTR(self) = 0;
+
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::File#read obj_size, num_objects
+ *
+ * Read *objCount* objects which are *objSize* each.
+ * return String instance containing raw data or nil if failure.
+ * #length of string will reflect real number of objects read.
+ */
+VALUE physfs_file_read (VALUE self, VALUE objSize, VALUE objCount)
+{
+    int objRead;
+    void *buffer;
+    VALUE result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil; //wasted file - no read possible
+
+    buffer  = malloc (FIX2UINT(objSize) * FIX2UINT(objCount));
+    if (buffer == 0)
+       return Qnil;
+
+    objRead = PHYSFS_read (file, buffer, FIX2UINT(objSize), FIX2UINT(objCount));
+    if (objRead == -1)
+    {
+        free (buffer);
+        return Qnil;
+    }
+
+    result = rb_str_new (buffer, objRead * FIX2UINT(objSize));
+    free (buffer);
+    return result;
+}
+
+/*
+ * PhysicsFS::File#write buffer, obj_size, num_objects
+ *
+ * return nil on failure or number of objects written.
+ */
+VALUE physfs_file_write (VALUE self, VALUE buf, VALUE objSize, VALUE objCount)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil;
+
+    result = PHYSFS_write (file, STR2CSTR(buf), 
+                           FIX2UINT(objSize), FIX2UINT(objCount));
+    if (result == -1)
+        return Qnil;
+
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::File#eof? 
+ */
+VALUE physfs_file_eof (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil;
+
+    result = PHYSFS_eof (file);
+
+    if (result)
+        return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::File#tell
+ *
+ * tells current position in file
+ */
+VALUE physfs_file_tell (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil;
+
+    result = PHYSFS_tell (file);
+
+    if (result == -1)
+        return Qnil;
+
+    return INT2FIX(result);
+}    
+
+/*
+ * PhysicsFS::File#seek pos
+ *
+ * seek to pos in file
+ */
+VALUE physfs_file_seek (VALUE self, VALUE pos)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil;
+
+    result = PHYSFS_seek (file, FIX2LONG(pos));
+
+    if (result)
+        return Qtrue;
+
+    return Qfalse;    
+}
+
+/*
+ * PhysicsFS::File#length 
+ */
+VALUE physfs_file_length (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil;
+
+    result = PHYSFS_fileLength (file);
+
+    if (result == -1)
+        return Qnil;
+
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::File#to_rwops
+ *
+ * File object is converted to RWops object. 
+ * File object becomes unusable after that - every operation
+ * should be done through new-born RWops object. 
+ */
+VALUE physfs_file_to_rwops (VALUE self)
+{
+    PHYSFS_File *file;
+    SDL_RWops   *rwops;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+       return Qnil;
+
+    rwops = PHYSFSRWOPS_makeRWops (file);
+    if (rwops == 0)
+       return Qnil;
+
+    DATA_PTR(self) = 0; // oh, gosh, we've sacrificed ourselves!
+    return sdl_rwops_new (rwops);
+}
+
+void init_physfs_file (void)
+{
+    classPhysfsFile = rb_define_class_under (modulePhysfs, "File", rb_cObject);
+
+    rb_define_method (classPhysfsFile, "close",    physfs_file_close,    0);
+    rb_define_method (classPhysfsFile, "eof?",     physfs_file_eof,      0);
+    rb_define_method (classPhysfsFile, "tell",     physfs_file_tell,     0);
+    rb_define_method (classPhysfsFile, "seek",     physfs_file_seek,     1);
+    rb_define_method (classPhysfsFile, "length",   physfs_file_length,   0);
+    rb_define_method (classPhysfsFile, "read",     physfs_file_read,     2);
+    rb_define_method (classPhysfsFile, "write",    physfs_file_write,    3);
+    rb_define_method (classPhysfsFile, "to_rwops", physfs_file_to_rwops, 0);
+}
diff --git a/extras/physfs_rb/physfs/rb_physfs_file.h b/extras/physfs_rb/physfs/rb_physfs_file.h
new file mode 100644 (file)
index 0000000..5cc1b21
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * PhysicsFS File abstraction - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License:: LGPL
+ */
+
+#ifndef __RB__PHYSFS__FILE__H__
+#define __RB__PHYSFS__FILE__H__
+
+extern VALUE classPhysfsFile;
+
+VALUE physfs_file_new    (PHYSFS_file *file);
+VALUE physfs_file_close  (VALUE self);
+VALUE physfs_file_read   (VALUE self, VALUE objSize, VALUE objCount);
+VALUE physfs_file_write  (VALUE self, VALUE buf, VALUE objSize, VALUE objCount);
+VALUE physfs_file_eof    (VALUE self);
+VALUE physfs_file_tell   (VALUE self);
+VALUE physfs_file_seek   (VALUE self, VALUE pos);
+VALUE physfs_file_length (VALUE self);
+
+void init_physfs_file (void);
+
+#endif
diff --git a/extras/physfs_rb/physfs/rb_sdl_rwops.c b/extras/physfs_rb/physfs/rb_sdl_rwops.c
new file mode 100644 (file)
index 0000000..6574906
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * SDL_RWops - ruby interface
+ *
+ * Author::    Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License::   LGPL
+ */
+
+#include "SDL_rwops.h"
+#include "ruby.h"
+
+#include "rb_physfs.h"
+#include "rb_sdl_rwops.h"
+
+VALUE classRWops;
+
+/*
+ * RWops constructor
+ */
+VALUE sdl_rwops_new (SDL_RWops *ops)
+{
+    VALUE result; 
+
+    if (ops == 0)
+       return Qnil;
+
+    result = Data_Wrap_Struct (classRWops, 0, SDL_FreeRW, ops);
+    return result;
+}
+
+/*
+ * PhysicsFS::RWops::from_file name, mode
+ *
+ * create RWops object from file
+ */
+VALUE sdl_rwops_from_file (VALUE self, VALUE name, VALUE mode)
+{
+    SDL_RWops *ops = SDL_RWFromFile(STR2CSTR(name), STR2CSTR(mode));
+    return sdl_rwops_new (ops);
+}
+
+/*
+ * PhysicsFS::RWops::from_memory string
+ *
+ * create RWops object from memory
+ */
+VALUE sdl_rwops_from_mem (VALUE self, VALUE str)
+{
+    int          len      = RSTRING(str)->len;
+    void *mem     = STR2CSTR(str);
+    SDL_RWops *ops = SDL_RWFromMem(mem, len);
+
+    return sdl_rwops_new (ops);
+}
+
+/*
+ * PhysicsFS::RWops#seek offset, whence
+ *
+ * position RWops object 
+ */
+VALUE sdl_rwops_seek (VALUE self, VALUE offset, VALUE whence)
+{
+    int result;
+    SDL_RWops *ops;
+    
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+       return Qnil;
+
+    result = SDL_RWseek(ops, FIX2INT(offset), FIX2INT(whence));
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::RWops#close
+ *
+ * close RWops. No use of the object is possible after that.
+ */
+VALUE sdl_rwops_close (VALUE self)
+{
+    int result;
+    SDL_RWops *ops;
+    
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+       return Qnil;
+    
+    result = SDL_RWclose (ops);
+    DATA_PTR(self) = 0;
+
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::RWops#read
+ *
+ * read from RWops object objCount objSize'd entities.
+ * return string containing raw data or nil
+ */
+VALUE sdl_rwops_read (VALUE self, VALUE objSize, VALUE objCount)
+{
+    int objRead;
+    void *buffer;
+    VALUE result;
+    SDL_RWops *ops;
+
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+       return Qnil;
+
+    buffer = malloc (FIX2UINT(objSize) * FIX2UINT(objCount));
+    if (buffer == 0)
+       return Qnil;
+
+    objRead = SDL_RWread (ops, buffer, FIX2UINT(objSize), FIX2UINT(objCount));
+    if (objRead == -1)
+    {
+       free (buffer);
+       return Qnil;
+    }
+
+    result = rb_str_new (buffer, objRead * FIX2UINT(objSize));
+    free (buffer);
+    return result;
+}
+
+/*
+ * PhysicsFS::RWops#write buffer, size, n
+ *
+ * write raw string containing n objects size length each.
+ * return number of objects written or nil
+ */
+VALUE sdl_rwops_write (VALUE self, VALUE buffer, VALUE size, VALUE n)
+{
+    int result;
+    SDL_RWops *ops;
+
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+       return Qnil;
+
+    result = SDL_RWwrite (ops, STR2CSTR(buffer), FIX2INT(size), FIX2INT(n));
+       
+    if (result == -1)
+       return Qnil;
+
+    return INT2FIX(result);
+}
+
+void init_sdl_rwops (void)
+{
+    classRWops = rb_define_class_under (modulePhysfs, "RWops", rb_cObject);
+    
+    rb_define_method (classRWops, "seek",  sdl_rwops_seek,  2);
+    rb_define_method (classRWops, "read",  sdl_rwops_read,  2);
+    rb_define_method (classRWops, "write", sdl_rwops_write, 3);
+    rb_define_method (classRWops, "close", sdl_rwops_close, 0);
+    
+    rb_define_singleton_method (classRWops, "from_file", 
+                               sdl_rwops_from_file, 2);
+    rb_define_singleton_method (classRWops, "from_memory", 
+                               sdl_rwops_from_mem, 1);
+}
diff --git a/extras/physfs_rb/physfs/rb_sdl_rwops.h b/extras/physfs_rb/physfs/rb_sdl_rwops.h
new file mode 100644 (file)
index 0000000..05f51bc
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * SDL_RWops - ruby interface
+ *
+ * Author::    Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License::   LGPL
+ */
+
+#ifndef __RB__SDL__RWOPS__H__
+#define __RB__SDL__RWOPS__H__
+
+extern VALUE classRWops;
+
+VALUE sdl_rwops_new (SDL_RWops *ops);
+void init_sdl_rwops (void);
+
+#endif
diff --git a/extras/physfs_rb/physfs/test/test_physfs.rb b/extras/physfs_rb/physfs/test/test_physfs.rb
new file mode 100644 (file)
index 0000000..3f194c1
--- /dev/null
@@ -0,0 +1,358 @@
+#
+# PhysicsFS test program - mimics real physfs_test
+#
+require 'readline'
+require 'physfs'
+
+def die msg
+  puts "#{msg} - reason: #{PhysicsFS.last_error}"
+end
+
+#
+# parse line to command and args
+# 
+def parse line
+  return false if line.nil?
+  
+  if line.strip =~ /^(.*?) (?: (?:\s+(.*)) | $)/x
+    run $1, $2
+  else
+    false
+  end
+end
+
+#
+# parse command args
+# 
+def parse_args args
+  args.strip!
+
+  dquoted  = /^ " (.*?) "/x
+  squoted  = /^ ' (.*?) '/x
+  unquoted = /^([^\s\'\"]+)/
+  
+  regexps = [dquoted, squoted, unquoted]
+  
+  result = []
+  while args != ""
+    regexps.each do |r|
+      if args =~ r
+       result << $1
+       args.sub! r, ""
+       args.sub!(/\s+/, "")
+       break
+      end
+    end
+  end
+  result
+end
+
+def usage cmd, prefix = "usage: "
+  print prefix
+  args = Commands::HELP[cmd]
+  if args
+    print cmd
+    args.scan(/\w+/).each {|x|
+      print " <#{x}>"
+    }
+    puts
+  else
+    puts %|#{cmd} (no arguments)|
+  end
+end
+  
+# commands go below
+module Commands
+  HELP = {
+    "init"           => "argv0",
+    "addarchive"     => "archiveLocation append",
+    "removearchive"  => "archiveLocation",
+    "enumerate"      => "dirToEnumerate",
+    "ls"             => "dirToEnumerate",
+    "setwritedir"    => "newWriteDir",
+    "permitsymlinks" => "1or0",
+    "setsaneconfig"  => "org appName arcExt includeCdRoms archivesFirst",
+    "mkdir"         => "dirToMk",
+    "delete"         => "dirToDelete",
+    "getrealdir"     => "fileToFind",
+    "exists"         => "fileToCheck",
+    "isdir"          => "fileToCheck",
+    "issymlink"      => "fileToCheck",
+    "cat"            => "fileToCat",
+    "filelength"     => "fileToCheck",
+    "append"         => "fileToAppend",
+    "write"          => "fileToCreateOrTrash",
+    "getlastmodtime" => "fileToExamine"
+  }
+
+  def quit_cmd
+    exit
+  end
+
+  alias q_cmd quit_cmd
+
+  def help_cmd
+    commands = ::Commands.instance_methods.grep(/_cmd$/).sort
+    puts "Commands:"
+    commands.each do |c|
+      usage c.sub("_cmd", ""), "  - "
+    end
+
+    true
+  end
+
+  def e val
+    if val
+      puts "Successful."
+    else
+      puts "Failure. reason: #{PhysicsFS.last_error}"
+    end
+    true
+  end
+
+  def init_cmd arg
+    e PhysicsFS.init(arg)
+  end
+
+  def deinit_cmd
+    e PhysicsFS.deinit
+  end
+
+  def addarchive_cmd archive, append
+    e PhysicsFS.add_to_search_path(archive, append)
+  end
+
+  def removearchive_cmd archive
+    e PhysicsFS.remove_from_search_path archive
+  end
+
+  def enumerate_cmd path
+    entries = PhysicsFS.enumerate(path)
+    entries.each {|x|
+      puts x
+    }
+    true
+  end
+
+  alias ls_cmd enumerate_cmd
+
+  def getlasterror_cmd
+    puts "Last error is [#{PhysicsFS.last_error}]"
+    true
+  end
+
+  def getdirsep_cmd
+    puts "Directory separator is [#{PhysicsFS.dir_separator}]"
+    true
+  end
+
+  def getcdromdirs_cmd
+    dirs = PhysicsFS.cdrom_dirs
+    dirs.each {|x|
+      puts x
+    }
+    puts " total [#{dirs.length}] drives."
+    true
+  end
+
+  def getsearchpath_cmd
+    spath = PhysicsFS.search_path
+    spath.each {|x|
+      puts x
+    }
+    puts "total [#{spath.length}] directories."
+    true
+  end
+
+  def getbasedir_cmd
+    dir = PhysicsFS.base_dir
+    puts dir if dir
+    true
+  end
+
+  def getuserdir_cmd
+    puts PhysicsFS.user_dir
+    true
+  end
+
+  def getwritedir_cmd
+    dir = PhysicsFS.write_dir
+    if dir
+      puts "Write directory is [#{dir}]."
+    else
+      puts "No write directory defined."
+    end
+    true
+  end
+
+  def setwritedir_cmd dir
+    e(PhysicsFS.write_dir = dir)
+  end
+
+  def permitsymlinks_cmd val
+    if val.to_i == 1
+      PhysicsFS.permit_symlinks true
+      puts "Symlinks are now permitted"
+    else
+      PhysicsFS.permit_symlinks false
+      puts "Symlinks are now forbidden"
+    end
+    true
+  end
+
+  def setsaneconfig_cmd org, appname, ext, includeCdroms, archivesFirst
+    includeCdroms = includeCdroms.to_i == 1
+    archiveFirst = archivesFirst == 1
+    e PhysicsFS.set_sane_config(org, appname, ext, includeCdroms, archivesFirst)
+  end
+
+  def mkdir_cmd dir
+    e PhysicsFS.mkdir(dir)
+  end
+
+  def delete_cmd dir
+    e PhysicsFS.delete(dir)
+  end
+
+  def getrealdir_cmd file
+    dir = PhysicsFS.real_dir file
+    if dir
+      puts "Found at [#{dir}]"
+    else
+      puts "Not found."
+    end
+    true
+  end
+
+  def exists_cmd file
+    if PhysicsFS.exists? file
+      puts "File exists"
+    else
+      puts "File does not exist"
+    end
+    true
+  end
+
+  def isdir_cmd file
+    if PhysicsFS.is_directory? file
+      puts "File is a directory"
+    else
+      puts "File is NOT a directory"
+    end
+    true
+  end
+
+  def issymlink_cmd file
+    if PhysicsFS.is_symlink? file
+      puts "File is a symlink"
+    else
+      puts "File is NOT a symlink"
+    end
+    true
+  end
+
+  def cat_cmd filename
+    file = PhysicsFS.open_read filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    puts file.cat
+    true
+  end
+
+  def filelength_cmd filename
+    file = PhysicsFS.open_read filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    puts file.length
+    file.close
+    true
+  end
+
+  WRITE_STR = "Rubyfied PhysicsFS works just fine.\n\n"
+  
+  def append_cmd filename
+    file = PhysicsFS.open_append filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    file.write WRITE_STR, 1, WRITE_STR.length
+    file.close
+    true
+  end
+
+  def write_cmd filename
+    file = PhysicsFS.open_write filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    file.write_str WRITE_STR
+    file.close
+    true
+  end
+
+  def getlastmodtime_cmd filename
+    t = PhysicsFS.last_mod_time filename
+    if t == -1
+      puts "failed to determin. reason: #{PhysicsFS.last_error}"
+    else
+      puts "Last modified: #{Time.at(t)}"
+    end
+    true
+  end
+end
+
+include Commands
+
+def run command, args
+  if args
+    args = parse_args args
+  else
+    args = []
+  end
+
+  begin
+    cmd = method "#{command}_cmd"
+    if args.length == cmd.arity
+      return cmd.call *args
+    else
+      usage command
+      true
+    end
+  rescue NameError
+    puts 'Unknown command. Enter "help" for instructions.'
+    true
+  end
+end
+
+if __FILE__ == $0
+  
+  PhysicsFS.init($0) or die "PhysicsFS init failed"
+  
+  puts "PhysicsFS version: #{PhysicsFS.version}"
+  puts
+
+  puts "Supported archives: "
+  puts PhysicsFS.supported_archives
+  puts
+
+  puts 'Enter commands. Enter "help" for instructions.'
+
+  loop {
+    line = Readline::readline "physfs_rb> ", true
+    break unless parse line
+  }
+end
+
+
+
+
diff --git a/extras/physfshttpd.c b/extras/physfshttpd.c
new file mode 100644 (file)
index 0000000..e1dfb1c
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This is a quick and dirty HTTP server that uses PhysicsFS to retrieve
+ *  files. It is not robust at all, probably buggy, and definitely poorly
+ *  designed. It's just meant to show that it can be done.
+ *
+ * Basically, you compile this code, and run it:
+ *   ./physfshttpd archive1.zip archive2.zip /path/to/a/real/dir etc...
+ *
+ * The files are appended in order to the PhysicsFS search path, and when
+ *  a client request comes it, it looks for the file in said search path.
+ *
+ * My goal was to make this work in less than 300 lines of C, so again, it's
+ *  not to be used for any serious purpose. Patches to make this application
+ *  suck less will be readily and gratefully accepted.
+ *
+ * Command line I used to build this on Linux:
+ *  gcc -Wall -Werror -g -o bin/physfshttpd extras/physfshttpd.c -lphysfs
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifndef LACKING_SIGNALS
+#include <signal.h>
+#endif
+
+#ifndef LACKING_PROTOENT
+#include <netdb.h>
+#endif
+
+#include "physfs.h"
+
+
+#define DEFAULT_PORTNUM  6667
+
+typedef struct
+{
+    int sock;
+    struct sockaddr *addr;
+    socklen_t addrlen;
+} http_args;
+
+
+static char *txt404 =
+"HTTP/1.0 404 Not Found\n"
+"Connection: close\n"
+"Content-Type: text/html; charset=utf-8\n"
+"\n"
+"<html><head><title>404 Not Found</title></head>\n"
+"<body>Can't find that.</body></html>\n\n";
+
+
+static void feed_file_http(const char *ipstr, int sock, const char *fname)
+{
+    PHYSFS_File *in = PHYSFS_openRead(fname);
+    char buffer[1024];
+    printf("%s: requested [%s].\n", ipstr, fname);
+    if (in == NULL)
+    {
+        printf("%s: Can't open [%s]: %s.\n",
+               ipstr, fname, PHYSFS_getLastError());
+        write(sock, txt404, strlen(txt404));  /* !!! FIXME: Check retval */
+    } /* if */
+    else
+    {
+        do
+        {
+            PHYSFS_sint64 br = PHYSFS_read(in, buffer, 1, sizeof (buffer));
+            if (br == -1)
+            {
+                printf("%s: Read error: %s.\n", ipstr, PHYSFS_getLastError());
+                break;
+            } /* if */
+
+            write(sock, buffer, (int) br);   /* !!! FIXME: CHECK THIS RETVAL! */
+        } while (!PHYSFS_eof(in));
+
+        PHYSFS_close(in);
+    } /* else */
+} /* feed_file_http */
+
+
+static void *do_http(void *_args)
+{
+    http_args *args = (http_args *) _args;
+    char ipstr[128];
+    char buffer[512];
+    char *ptr;
+    strncpy(ipstr, inet_ntoa(((struct sockaddr_in *) args->addr)->sin_addr),
+            sizeof (ipstr));
+    ipstr[sizeof (ipstr) - 1] = '\0';
+
+    printf("%s: connected.\n", ipstr);
+    read(args->sock, buffer, sizeof (buffer));
+    buffer[sizeof (buffer) - 1] = '\0';
+    ptr = strchr(buffer, '\n');
+    if (!ptr)
+        printf("%s: potentially bogus request.\n", ipstr);
+    else
+    {
+        *ptr = '\0';
+        ptr = strchr(buffer, '\r');
+        if (ptr != NULL)
+            *ptr = '\0';
+
+        if ((toupper(buffer[0]) == 'G') &&
+            (toupper(buffer[1]) == 'E') &&
+            (toupper(buffer[2]) == 'T') &&
+            (toupper(buffer[3]) == ' ') &&
+            (toupper(buffer[4]) == '/'))
+        {
+            ptr = strchr(buffer + 5, ' ');
+            if (ptr != NULL)
+                *ptr = '\0';
+            feed_file_http(ipstr, args->sock, buffer + 4);
+        } /* if */
+    } /* else */
+
+    /* !!! FIXME: Time the transfer. */
+    printf("%s: closing connection.\n", ipstr);
+    close(args->sock);
+    free(args->addr);
+    free(args);
+    return(NULL);
+} /* do_http */
+
+
+static void serve_http_request(int sock, struct sockaddr *addr,
+                               socklen_t addrlen)
+{
+    http_args *args = (http_args *) malloc(sizeof (http_args));
+    if (args == NULL)
+    {
+        printf("out of memory.\n");
+        return;
+    } /* if */
+    args->addr = (struct sockaddr *) malloc(addrlen);
+    if (args->addr == NULL)
+    {
+        free(args);
+        printf("out of memory.\n");
+        return;
+    } /* if */
+
+    args->sock = sock;
+    args->addrlen = addrlen;
+    memcpy(args->addr, addr, addrlen);
+
+    /* !!! FIXME: optionally spin a thread... */
+    do_http((void *) args);
+} /* server_http_request */
+
+
+static int create_listen_socket(short portnum)
+{
+    int retval = -1;
+    int protocol = 0;  /* pray this is right. */
+
+#ifndef LACKING_PROTOENT
+    struct protoent *prot;
+    setprotoent(0);
+    prot = getprotobyname("tcp");
+    if (prot != NULL)
+        protocol = prot->p_proto;
+#endif
+
+    retval = socket(PF_INET, SOCK_STREAM, protocol);
+    if (retval >= 0)
+    {
+        struct sockaddr_in addr;
+        addr.sin_family = AF_INET;
+        addr.sin_port = htons(portnum);
+        addr.sin_addr.s_addr = INADDR_ANY;
+        if ((bind(retval, &addr, (socklen_t) sizeof (addr)) == -1) ||
+            (listen(retval, 5) == -1))
+        {
+            close(retval);
+            retval = -1;
+        } /* if */
+    } /* if */
+
+    return(retval);
+} /* create_listen_socket */
+
+
+static int listensocket = -1;
+
+void at_exit_cleanup(void)
+{
+    /*
+     * !!! FIXME: If thread support, signal threads to terminate and
+     * !!! FIXME:  wait for them to clean up.
+     */
+
+    if (listensocket >= 0)
+        close(listensocket);
+
+    if (!PHYSFS_deinit())
+        printf("PHYSFS_deinit() failed: %s\n", PHYSFS_getLastError());
+} /* at_exit_cleanup */
+
+
+int main(int argc, char **argv)
+{
+    int i;
+    int portnum = DEFAULT_PORTNUM;
+
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+
+#ifndef LACKING_SIGNALS
+    /* I'm not sure if this qualifies as a cheap trick... */
+    signal(SIGTERM, exit);
+    signal(SIGINT, exit);
+    signal(SIGFPE, exit);
+    signal(SIGSEGV, exit);
+    signal(SIGPIPE, exit);
+    signal(SIGILL, exit);
+#endif
+
+    if (argc == 1)
+    {
+        printf("USAGE: %s <archive1> [archive2 [... archiveN]]\n", argv[0]);
+        return(42);
+    } /* if */
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        printf("PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
+        return(42);
+    } /* if */
+
+    /* normally, this is bad practice, but oh well. */
+    atexit(at_exit_cleanup);
+
+    for (i = 1; i < argc; i++)
+    {
+        if (!PHYSFS_addToSearchPath(argv[i], 1))
+            printf(" WARNING: failed to add [%s] to search path.\n", argv[i]);
+    } /* else */
+
+    listensocket = create_listen_socket(portnum);
+    if (listensocket < 0)
+    {
+        printf("listen socket failed to create.\n");
+        return(42);
+    } /* if */
+
+    while (1)  /* infinite loop for now. */
+    {
+        struct sockaddr addr;
+        socklen_t len;
+        int s = accept(listensocket, &addr, &len);
+        if (s < 0)
+        {
+            printf("accept() failed: %s\n", strerror(errno));
+            close(listensocket);
+            return(42);
+        } /* if */
+
+        serve_http_request(s, &addr, len);
+    } /* while */
+
+    return(0);
+} /* main */
+
+/* end of physfshttpd.c ... */
+
diff --git a/extras/physfsrwops.c b/extras/physfsrwops.c
new file mode 100644 (file)
index 0000000..a6c8815
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    int pos = 0;
+
+    if (whence == SEEK_SET)
+    {
+        pos = offset;
+    } /* if */
+
+    else if (whence == SEEK_CUR)
+    {
+        PHYSFS_sint64 current = PHYSFS_tell(handle);
+        if (current == -1)
+        {
+            SDL_SetError("Can't find position in file: %s",
+                          PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) current;
+        if ( ((PHYSFS_sint64) pos) != current )
+        {
+            SDL_SetError("Can't fit current file position in an int!");
+            return(-1);
+        } /* if */
+
+        if (offset == 0)  /* this is a "tell" call. We're done. */
+            return(pos);
+
+        pos += offset;
+    } /* else if */
+
+    else if (whence == SEEK_END)
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+        if (len == -1)
+        {
+            SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) len;
+        if ( ((PHYSFS_sint64) pos) != len )
+        {
+            SDL_SetError("Can't fit end-of-file position in an int!");
+            return(-1);
+        } /* if */
+
+        pos += offset;
+    } /* else if */
+
+    else
+    {
+        SDL_SetError("Invalid 'whence' parameter.");
+        return(-1);
+    } /* else */
+
+    if ( pos < 0 )
+    {
+        SDL_SetError("Attempt to seek past start of file.");
+        return(-1);
+    } /* if */
+    
+    if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
+    {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+        return(-1);
+    } /* if */
+
+    return(pos);
+} /* physfsrwops_seek */
+
+
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum);
+    if (rc != maxnum)
+    {
+        if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+            SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    } /* if */
+
+    return((int) rc);
+} /* physfsrwops_read */
+
+
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num);
+    if (rc != num)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+    return((int) rc);
+} /* physfsrwops_write */
+
+
+static int physfsrwops_close(SDL_RWops *rw)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    if (!PHYSFS_close(handle))
+    {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+        return(-1);
+    } /* if */
+
+    SDL_FreeRW(rw);
+    return(0);
+} /* physfsrwops_close */
+
+
+static SDL_RWops *create_rwops(PHYSFS_File *handle)
+{
+    SDL_RWops *retval = NULL;
+
+    if (handle == NULL)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    else
+    {
+        retval = SDL_AllocRW();
+        if (retval != NULL)
+        {
+            retval->seek  = physfsrwops_seek;
+            retval->read  = physfsrwops_read;
+            retval->write = physfsrwops_write;
+            retval->close = physfsrwops_close;
+            retval->hidden.unknown.data1 = handle;
+        } /* if */
+    } /* else */
+
+    return(retval);
+} /* create_rwops */
+
+
+SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
+{
+    SDL_RWops *retval = NULL;
+    if (handle == NULL)
+        SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
+    else
+        retval = create_rwops(handle);
+
+    return(retval);
+} /* PHYSFSRWOPS_makeRWops */
+
+
+SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
+{
+    return(create_rwops(PHYSFS_openRead(fname)));
+} /* PHYSFSRWOPS_openRead */
+
+
+SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
+{
+    return(create_rwops(PHYSFS_openWrite(fname)));
+} /* PHYSFSRWOPS_openWrite */
+
+
+SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
+{
+    return(create_rwops(PHYSFS_openAppend(fname)));
+} /* PHYSFSRWOPS_openAppend */
+
+
+/* end of physfsrwops.c ... */
+
diff --git a/extras/physfsrwops.h b/extras/physfsrwops.h
new file mode 100644 (file)
index 0000000..406fba6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
+
+/**
+ * Open a platform-independent filename for writing, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
+
+/**
+ * Open a platform-independent filename for appending, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
+
+/**
+ * Make a SDL_RWops from an existing PhysicsFS file handle. You should
+ *  dispose of any references to the handle after successful creation of
+ *  the RWops. The actual PhysicsFS handle will be destroyed when the
+ *  RWops is closed.
+ *
+ *   @param handle a valid PhysicsFS file handle.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+
diff --git a/extras/physfsunpack.c b/extras/physfsunpack.c
new file mode 100644 (file)
index 0000000..1d26502
--- /dev/null
@@ -0,0 +1,181 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "physfs.h"
+
+
+static int failure = 0;
+
+static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
+{
+    const char *str = "unknown modtime";
+    if (modtime != -1)
+    {
+        time_t t = (time_t) modtime;
+        str = ctime(&t);
+    } /* if */
+
+    strncpy(modstr, str, strsize);
+    modstr[strsize-1] = '\0';
+    strsize = strlen(modstr);
+    while ((modstr[strsize-1] == '\n') || (modstr[strsize-1] == '\r'))
+        modstr[--strsize] = '\0';
+} /* modTimeToStr */
+
+
+static void fail(const char *what, const char *why)
+{
+    if (why == NULL)
+        why = PHYSFS_getLastError();
+    fprintf(stderr, "%s failed: %s\n", what, why);
+    failure = 1;
+} /* fail */
+
+
+static void dumpFile(const char *fname)
+{
+    const int origfailure = failure;
+    PHYSFS_File *out = NULL;
+    PHYSFS_File *in = NULL;
+
+    failure = 0;
+
+    if ((in = PHYSFS_openRead(fname)) == NULL)
+        fail("\nPHYSFS_openRead", NULL);
+    else if ((out = PHYSFS_openWrite(fname)) == NULL)
+        fail("\nPHYSFS_openWrite", NULL);
+    else
+    {
+        char modstr[64];
+        PHYSFS_sint64 size = PHYSFS_fileLength(in);
+
+        printf("(");
+        if (size == -1)
+            printf("?");
+        else
+            printf("%lld", (long long) size);
+        printf(" bytes");
+
+        modTimeToStr(PHYSFS_getLastModTime(fname), modstr, sizeof (modstr));
+        printf(", %s)\n", modstr);
+
+        while ( (!failure) && (!PHYSFS_eof(in)) )
+        {
+            static char buf[64 * 1024];
+            PHYSFS_sint64 br = PHYSFS_read(in, buf, 1, sizeof (buf));
+            if (br == -1)
+                fail("PHYSFS_read", NULL);
+            else
+            {
+                PHYSFS_sint64 bw = PHYSFS_write(out, buf, 1, br);
+                if (bw != br)
+                    fail("PHYSFS_write", NULL);
+                else
+                    size -= bw;
+            } /* else */
+        } /* while */
+
+        if ((!failure) && (size != 0))
+            fail("PHYSFS_eof", "BUG! eof != PHYSFS_fileLength bytes!");
+    } /* else */
+
+    if (in != NULL)
+        PHYSFS_close(in);
+
+    if (out != NULL)
+    {
+        if (!PHYSFS_close(out))
+            fail("PHYSFS_close", NULL);
+    } /* if */
+
+    if (failure)
+        PHYSFS_delete(fname);
+    else
+        failure = origfailure;
+} /* dumpFile */
+
+
+static void unpackCallback(void *_depth, const char *origdir, const char *str)
+{
+    int depth = *((int *) _depth);
+    const int len = strlen(origdir) + strlen(str) + 2;
+    char *fname = (char *) malloc(len);
+    if (fname == NULL)
+        fail("malloc", "Out of memory!");
+    else
+    {
+        if (strcmp(origdir, "/") == 0)
+            origdir = "";
+
+        snprintf(fname, len, "%s/%s", origdir, str);
+
+        printf("%s ", fname);
+        if (PHYSFS_isDirectory(fname))
+        {
+            depth++;
+            printf("(directory)\n");
+            if (!PHYSFS_mkdir(fname))
+                fail("PHYSFS_mkdir", NULL);
+            else
+                PHYSFS_enumerateFilesCallback(fname, unpackCallback, &depth);
+        } /* if */
+
+        else if (PHYSFS_isSymbolicLink(fname))
+        {
+            printf("(symlink)\n");
+            /* !!! FIXME: ?  if (!symlink(fname, */
+        } /* else if */
+
+        else  /* ...file. */
+        {
+            dumpFile(fname);
+        } /* else */
+
+        free(fname);
+    } /* else */
+} /* unpackCallback */
+
+
+int main(int argc, char **argv)
+{
+    int zero = 0;
+
+    if (argc != 3)
+    {
+        fprintf(stderr, "USAGE: %s <archive> <unpackDirectory>\n", argv[0]);
+        return 1;
+    } /* if */
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
+        return 2;
+    } /* if */
+
+    if (!PHYSFS_setWriteDir(argv[2]))
+    {
+        fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n",
+                argv[2], PHYSFS_getLastError());
+        return 3;
+    } /* if */
+
+    if (!PHYSFS_mount(argv[1], NULL, 1))
+    {
+        fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n",
+                argv[1], PHYSFS_getLastError());
+        return 4;
+    } /* if */
+
+    PHYSFS_permitSymbolicLinks(1);
+    PHYSFS_enumerateFilesCallback("/", unpackCallback, &zero);
+    PHYSFS_deinit();
+    if (failure)
+        return 5;
+
+    return 0;
+} /* main */
+
+/* end of physfsunpack.c ... */
+
diff --git a/extras/selfextract.c b/extras/selfextract.c
new file mode 100644 (file)
index 0000000..3568d01
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This code shows how to read a zipfile included in an app's binary.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+/*
+ * Compile this program and then attach a .zip file to the end of the
+ *  compiled binary.
+ *
+ * On Linux, something like this will build the final binary:
+ *   gcc -o selfextract.tmp selfextract.c -lphysfs && \
+ *   cat selfextract.tmp myzipfile.zip >> selfextract && \
+ *   chmod a+x selfextract && \
+ *   rm -f selfextract.tmp
+ *
+ * This may not work on all platforms, and it probably only works with
+ *  .zip files, since they are designed to be appended to another file.
+ */
+
+#include <stdio.h>
+#include "physfs.h"
+
+int main(int argc, char **argv)
+{
+    int rc = 0;
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        printf("PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
+        return(42);
+    } /* if */
+
+    rc = PHYSFS_addToSearchPath(argv[0], 0);
+    if (!rc)
+    {
+        printf("Couldn't find self-extract data: %s\n", PHYSFS_getLastError());
+        printf("This might mean you didn't append a zipfile to the binary.\n");
+        return(42);
+    } /* if */
+
+    char **files = PHYSFS_enumerateFiles("/");
+    char **i;
+    for (i = files; *i != NULL; i++)
+    {
+        const char *dirorfile = PHYSFS_isDirectory(*i) ? "Directory" : "File";
+        printf(" * %s '%s' is in root of attached data.\n", dirorfile, *i);
+    } /* for */
+    PHYSFS_freeList(files);
+
+    return(0);
+} /* main */
+
diff --git a/lzma/7zC.txt b/lzma/7zC.txt
new file mode 100644 (file)
index 0000000..8412954
--- /dev/null
@@ -0,0 +1,237 @@
+7z ANSI-C Decoder 4.48
+----------------------
+
+7z ANSI-C Decoder 4.48 Copyright (C) 1999-2006 Igor Pavlov
+
+7z ANSI-C provides 7z/LZMA decoding.
+7z ANSI-C version is simplified version ported from C++ code.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high 
+compression ratio and very fast decompression.
+
+
+LICENSE
+-------
+
+Read lzma.txt for information about license.
+
+
+Files
+---------------------
+
+7zAlloc.*    - Allocate and Free
+7zBuffer.*   - Buffer structure
+7zCrc.*      - CRC32 code
+7zDecode.*   - Low level memory->memory decoding
+7zExtract.*  - High level stream->memory decoding
+7zHeader.*   - .7z format constants
+7zIn.*       - .7z archive opening
+7zItem.*     - .7z structures
+7zMain.c     - Test application
+7zMethodID.* - MethodID structure
+7zTypes.h    - Base types and constants
+
+
+How To Use
+----------
+
+You must download 7-Zip program from www.7-zip.org.
+
+You can create .7z archive with 7z.exe or 7za.exe:
+
+  7za.exe a archive.7z *.htm -r -mx -m0fb=255
+
+If you have big number of files in archive, and you need fast extracting, 
+you can use partly-solid archives:
+  
+  7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
+
+In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only 
+512KB for extracting one file from such archive.
+
+
+Limitations of current version of 7z ANSI-C Decoder
+---------------------------------------------------
+
+ - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
+ - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
+ - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
+These limitations will be fixed in future versions.
+
+
+Using 7z ANSI-C Decoder Test application:
+-----------------------------------------
+
+Usage: 7zDec <command> <archive_name>
+
+<Command>:
+  e: Extract files from archive
+  l: List contents of archive
+  t: Test integrity of archive
+
+Example: 
+
+  7zDec l archive.7z
+
+lists contents of archive.7z
+
+  7zDec e archive.7z
+
+extracts files from archive.7z to current folder.
+
+
+How to use .7z Decoder
+----------------------
+
+.7z Decoder can be compiled in one of two modes:
+
+1) Default mode. In that mode 7z Decoder will read full compressed 
+   block to RAM before decompressing.
+  
+2) Mode with defined _LZMA_IN_CB. In that mode 7z Decoder can read
+   compressed block by parts. And you can specify desired buffer size. 
+   So memory requirements can be reduced. But decompressing speed will 
+   be 5-10% lower and code size is slightly larger.
+
+   
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+7z Decoder uses two memory pools:
+1) Temporary pool
+2) Main pool
+Such scheme can allow you to avoid fragmentation of allocated blocks.
+
+Steps for using 7z decoder
+--------------------------
+
+Use code at 7zMain.c as example.
+
+1) Declare variables:
+  inStream                     /* implements ISzInStream interface */
+  CArchiveDatabaseEx db;       /* 7z archive database structure */
+  ISzAlloc allocImp;           /* memory functions for main pool */
+  ISzAlloc allocTempImp;       /* memory functions for temporary pool */
+
+2) call InitCrcTable(); function to initialize CRC structures.
+
+3) call SzArDbExInit(&db); function to initialize db structures.
+
+4) call SzArchiveOpen(inStream, &db, &allocMain, &allocTemp) to open archive
+
+This function opens archive "inStream" and reads headers to "db".
+All items in "db" will be allocated with "allocMain" functions.
+SzArchiveOpen function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+  Listing code:
+  ~~~~~~~~~~~~~
+    {
+      UInt32 i;
+      for (i = 0; i < db.Database.NumFiles; i++)
+      {
+        CFileItem *f = db.Database.Files + i;
+        printf("%10d  %s\n", (int)f->Size, f->Name);
+      }
+    }
+
+  Extracting code:
+  ~~~~~~~~~~~~~~~~
+
+  SZ_RESULT SzExtract(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    UInt32 fileIndex,         /* index of file */
+    UInt32 *blockIndex,       /* index of solid block */
+    Byte **outBuffer,         /* pointer to pointer to output buffer (allocated with allocMain) */
+    size_t *outBufferSize,    /* buffer size for output buffer */
+    size_t *offset,           /* offset of stream for required file in *outBuffer */
+    size_t *outSizeProcessed, /* size of file in *outBuffer */
+    ISzAlloc *allocMain,
+    ISzAlloc *allocTemp);
+
+  If you need to decompress more than one file, you can send these values from previous call:
+    blockIndex, 
+    outBuffer, 
+    outBufferSize,
+  You can consider "outBuffer" as cache of solid block. If your archive is solid, 
+  it will increase decompression speed.
+
+  After decompressing you must free "outBuffer":
+  allocImp.Free(outBuffer);
+
+6) call SzArDbExFree(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding 
+------------------------------------
+
+Memory usage for Archive opening:
+  - Temporary pool:
+     - Memory for compressed .7z headers (if _LZMA_IN_CB is not defined)
+     - Memory for uncompressed .7z headers
+     - some other temporary blocks
+  - Main pool:
+     - Memory for database: 
+       Estimated size of one file structures in solid archive:
+         - Size (4 or 8 Bytes)
+         - CRC32 (4 bytes)
+         - LastWriteTime (8 bytes)
+         - Some file information (4 bytes)
+         - File Name (variable length) + pointer + allocation structures
+
+Memory usage for archive Decompressing:
+  - Temporary pool:
+     - Memory for compressed solid block (if _LZMA_IN_CB is not defined)
+     - Memory for LZMA decompressing structures
+  - Main pool:
+     - Memory for decompressed solid block
+     - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these 
+       temprorary buffers can be about 15% of solid block size. 
+  
+
+If _LZMA_IN_CB is defined, 7z Decoder will not allocate memory for 
+compressed blocks. Instead of this, you must allocate buffer with desired 
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+
+EXIT codes
+-----------
+
+7z Decoder functions can return one of the following codes:
+
+#define SZ_OK (0)
+#define SZE_DATA_ERROR (1)
+#define SZE_OUTOFMEMORY (2)
+#define SZE_CRC_ERROR (3)
+
+#define SZE_NOTIMPL (4)
+#define SZE_FAIL (5)
+
+#define SZE_ARCHIVE_ERROR (6)
+
+
+
+LZMA Defines
+------------
+
+_LZMA_IN_CB       - Use special callback mode for input stream to reduce memory requirements
+
+_SZ_FILE_SIZE_32  - define it if you need only support for files smaller than 4 GB
+_SZ_NO_INT_64     - define it if your compiler doesn't support long long int or __int64.
+
+_LZMA_PROB32      - it can increase LZMA decompressing speed on some 32-bit CPUs.
+
+_SZ_ALLOC_DEBUG   - define it if you want to debug alloc/free operations to stderr.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/support.html
diff --git a/lzma/7zFormat.txt b/lzma/7zFormat.txt
new file mode 100644 (file)
index 0000000..e1cf738
--- /dev/null
@@ -0,0 +1,471 @@
+7z Format description (2.30 Beta 25)
+-----------------------------------
+
+This file contains description of 7z archive format. 
+7z archive can contain files compressed with any method.
+See "Methods.txt" for description for defined compressing methods.
+
+
+Format structure Overview
+-------------------------
+
+Some fields can be optional.
+
+Archive structure
+~~~~~~~~~~~~~~~~~  
+SignatureHeader
+[PackedStreams]
+[PackedStreamsForHeaders]
+[
+  Header 
+  or 
+  {
+    Packed Header
+    HeaderInfo
+  }
+]
+
+
+
+Header structure
+~~~~~~~~~~~~~~~~  
+{
+  ArchiveProperties
+  AdditionalStreams
+  {
+    PackInfo
+    {
+      PackPos
+      NumPackStreams
+      Sizes[NumPackStreams]
+      CRCs[NumPackStreams]
+    }
+    CodersInfo
+    {
+      NumFolders
+      Folders[NumFolders]
+      {
+        NumCoders
+        CodersInfo[NumCoders]
+        {
+          ID
+          NumInStreams;
+          NumOutStreams;
+          PropertiesSize
+          Properties[PropertiesSize]
+        }
+        NumBindPairs
+        BindPairsInfo[NumBindPairs]
+        {
+          InIndex;
+          OutIndex;
+        }
+        PackedIndices
+      }
+      UnPackSize[Folders][Folders.NumOutstreams]
+      CRCs[NumFolders]
+    }
+    SubStreamsInfo
+    {
+      NumUnPackStreamsInFolders[NumFolders];
+      UnPackSizes[]
+      CRCs[]
+    }
+  }
+  MainStreamsInfo
+  {
+    (Same as in AdditionalStreams)
+  }
+  FilesInfo
+  {
+    NumFiles
+    Properties[]
+    {
+      ID
+      Size
+      Data
+    }
+  }
+}
+
+HeaderInfo structure
+~~~~~~~~~~~~~~~~~~~~
+{
+  (Same as in AdditionalStreams)
+}
+
+
+
+Notes about Notation and encoding
+---------------------------------
+
+7z uses little endian encoding.
+
+7z archive format has optional headers that are marked as
+[]
+Header
+[]
+
+REAL_UINT64 means real UINT64.
+
+UINT64 means real UINT64 encoded with the following scheme:
+
+  Size of encoding sequence depends from first byte:
+  First_Byte  Extra_Bytes        Value
+  (binary)   
+  0xxxxxxx               : ( xxxxxxx           )
+  10xxxxxx    BYTE y[1]  : (  xxxxxx << (8 * 1)) + y
+  110xxxxx    BYTE y[2]  : (   xxxxx << (8 * 2)) + y
+  ...
+  1111110x    BYTE y[6]  : (       x << (8 * 6)) + y
+  11111110    BYTE y[7]  :                         y
+  11111111    BYTE y[8]  :                         y
+
+
+
+Property IDs
+------------
+
+0x00 = kEnd,
+
+0x01 = kHeader,
+
+0x02 = kArchiveProperties,
+    
+0x03 = kAdditionalStreamsInfo,
+0x04 = kMainStreamsInfo,
+0x05 = kFilesInfo,
+    
+0x06 = kPackInfo,
+0x07 = kUnPackInfo,
+0x08 = kSubStreamsInfo,
+
+0x09 = kSize,
+0x0A = kCRC,
+
+0x0B = kFolder,
+
+0x0C = kCodersUnPackSize,
+0x0D = kNumUnPackStream,
+
+0x0E = kEmptyStream,
+0x0F = kEmptyFile,
+0x10 = kAnti,
+
+0x11 = kName,
+0x12 = kCreationTime,
+0x13 = kLastAccessTime,
+0x14 = kLastWriteTime,
+0x15 = kWinAttributes,
+0x16 = kComment,
+
+0x17 = kEncodedHeader,
+
+
+7z format headers
+-----------------
+
+SignatureHeader
+~~~~~~~~~~~~~~~
+  BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+  ArchiveVersion
+  {
+    BYTE Major;   // now = 0
+    BYTE Minor;   // now = 2
+  };
+
+  UINT32 StartHeaderCRC;
+
+  StartHeader
+  {
+    REAL_UINT64 NextHeaderOffset
+    REAL_UINT64 NextHeaderSize
+    UINT32 NextHeaderCRC
+  }
+
+
+...........................
+
+
+ArchiveProperties
+~~~~~~~~~~~~~~~~~
+BYTE NID::kArchiveProperties (0x02)
+for (;;)
+{
+  BYTE PropertyType;
+  if (aType == 0)
+    break;
+  UINT64 PropertySize;
+  BYTE PropertyData[PropertySize];
+}
+
+
+Digests (NumStreams)
+~~~~~~~~~~~~~~~~~~~~~
+  BYTE AllAreDefined
+  if (AllAreDefined == 0)
+  {
+    for(NumStreams)
+      BIT Defined
+  }
+  UINT32 CRCs[NumDefined]
+
+
+PackInfo
+~~~~~~~~~~~~
+  BYTE NID::kPackInfo  (0x06)
+  UINT64 PackPos
+  UINT64 NumPackStreams
+
+  []
+  BYTE NID::kSize    (0x09)
+  UINT64 PackSizes[NumPackStreams]
+  []
+
+  []
+  BYTE NID::kCRC      (0x0A)
+  PackStreamDigests[NumPackStreams]
+  []
+
+  BYTE NID::kEnd
+
+
+Folder
+~~~~~~
+  UINT64 NumCoders;
+  for (NumCoders)
+  {
+    BYTE 
+    {
+      0:3 DecompressionMethod.IDSize
+      4:
+        0 - IsSimple
+        1 - Is not simple
+      5:
+        0 - No Attributes
+        1 - There Are Attributes
+      7:
+        0 - Last Method in Alternative_Method_List
+        1 - There are more alternative methods
+    } 
+    BYTE DecompressionMethod.ID[DecompressionMethod.IDSize]
+    if (!IsSimple)
+    {
+      UINT64 NumInStreams;
+      UINT64 NumOutStreams;
+    }
+    if (DecompressionMethod[0] != 0)
+    {
+      UINT64 PropertiesSize
+      BYTE Properties[PropertiesSize]
+    }
+  }
+    
+  NumBindPairs = NumOutStreamsTotal - 1;
+
+  for (NumBindPairs)
+  {
+    UINT64 InIndex;
+    UINT64 OutIndex;
+  }
+
+  NumPackedStreams = NumInStreamsTotal - NumBindPairs;
+  if (NumPackedStreams > 1)
+    for(NumPackedStreams)
+    {
+      UINT64 Index;
+    };
+
+
+
+
+Coders Info
+~~~~~~~~~~~
+
+  BYTE NID::kUnPackInfo  (0x07)
+
+
+  BYTE NID::kFolder  (0x0B)
+  UINT64 NumFolders
+  BYTE External
+  switch(External)
+  {
+    case 0:
+      Folders[NumFolders]
+    case 1:
+      UINT64 DataStreamIndex
+  }
+
+
+  BYTE ID::kCodersUnPackSize  (0x0C)
+  for(Folders)
+    for(Folder.NumOutStreams)
+     UINT64 UnPackSize;
+
+
+  []
+  BYTE NID::kCRC   (0x0A)
+  UnPackDigests[NumFolders]
+  []
+
+  
+
+  BYTE NID::kEnd
+
+
+
+SubStreams Info
+~~~~~~~~~~~~~~
+  BYTE NID::kSubStreamsInfo; (0x08)
+
+  []
+  BYTE NID::kNumUnPackStream; (0x0D)
+  UINT64 NumUnPackStreamsInFolders[NumFolders];
+  []
+
+
+  []
+  BYTE NID::kSize  (0x09)
+  UINT64 UnPackSizes[]
+  []
+
+
+  []
+  BYTE NID::kCRC  (0x0A)
+  Digests[Number of streams with unknown CRC]
+  []
+
+  
+  BYTE NID::kEnd
+
+
+Streams Info
+~~~~~~~~~~~~
+
+  []
+  PackInfo
+  []
+
+
+  []
+  CodersInfo
+  []
+
+
+  []
+  SubStreamsInfo
+  []
+
+  BYTE NID::kEnd
+
+
+FilesInfo
+~~~~~~~~~
+  BYTE NID::kFilesInfo;  (0x05)
+  UINT64 NumFiles
+
+  for (;;)
+  {
+    BYTE PropertyType;
+    if (aType == 0)
+      break;
+
+    UINT64 Size;
+
+    switch(PropertyType)
+    {
+      kEmptyStream:   (0x0E)
+        for(NumFiles)
+          BIT IsEmptyStream
+
+      kEmptyFile:     (0x0F)
+        for(EmptyStreams)
+          BIT IsEmptyFile
+
+      kAnti:          (0x10)
+        for(EmptyStreams)
+          BIT IsAntiFile
+      
+      case kCreationTime:   (0x12)
+      case kLastAccessTime: (0x13)
+      case kLastWriteTime:  (0x14)
+        BYTE AllAreDefined
+        if (AllAreDefined == 0)
+        {
+          for(NumFiles)
+            BIT TimeDefined
+        }
+        BYTE External;
+        if(External != 0)
+          UINT64 DataIndex
+        []
+        for(Definded Items)
+          UINT32 Time
+        []
+      
+      kNames:     (0x11)
+        BYTE External;
+        if(External != 0)
+          UINT64 DataIndex
+        []
+        for(Files)
+        {
+          wchar_t Names[NameSize];
+          wchar_t 0;
+        }
+        []
+
+      kAttributes:  (0x15)
+        BYTE AllAreDefined
+        if (AllAreDefined == 0)
+        {
+          for(NumFiles)
+            BIT AttributesAreDefined
+        }
+        BYTE External;
+        if(External != 0)
+          UINT64 DataIndex
+        []
+        for(Definded Attributes)
+          UINT32 Attributes
+        []
+    }
+  }
+
+
+Header
+~~~~~~
+  BYTE NID::kHeader (0x01)
+
+  []
+  ArchiveProperties
+  []
+
+  []
+  BYTE NID::kAdditionalStreamsInfo; (0x03)
+  StreamsInfo
+  []
+
+  []
+  BYTE NID::kMainStreamsInfo;    (0x04)
+  StreamsInfo
+  []
+
+  []
+  FilesInfo
+  []
+
+  BYTE NID::kEnd
+
+
+HeaderInfo
+~~~~~~~~~~
+  []
+  BYTE NID::kEncodedHeader; (0x17)
+  StreamsInfo for Encoded Header
+  []
+
+
+---
+End of document
diff --git a/lzma/C/7zCrc.c b/lzma/C/7zCrc.c
new file mode 100644 (file)
index 0000000..1436b99
--- /dev/null
@@ -0,0 +1,32 @@
+/* 7zCrc.c */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+UInt32 g_CrcTable[256];
+
+void MY_FAST_CALL CrcGenerateTable(void)
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = i;
+    int j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+    g_CrcTable[i] = r;
+  }
+}
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+  const Byte *p = (const Byte *)data;
+  for (; size > 0 ; size--, p++) 
+    v = CRC_UPDATE_BYTE(v, *p);
+  return v;
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+  return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF;
+}
diff --git a/lzma/C/7zCrc.h b/lzma/C/7zCrc.h
new file mode 100644 (file)
index 0000000..6cb1016
--- /dev/null
@@ -0,0 +1,21 @@
+/* 7zCrc.h */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include <stddef.h>
+
+#include "Types.h"
+
+extern UInt32 g_CrcTable[];
+
+void MY_FAST_CALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
+
+#endif
diff --git a/lzma/C/7zCrcT8.c b/lzma/C/7zCrcT8.c
new file mode 100644 (file)
index 0000000..83aa95f
--- /dev/null
@@ -0,0 +1,40 @@
+/* 7zCrcT8.c */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+#define CRC_NUM_TABLES 8
+
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+void MY_FAST_CALL CrcGenerateTable()
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = i;
+    int j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+    g_CrcTable[i] = r;
+  }
+  #if CRC_NUM_TABLES > 1
+  for (; i < 256 * CRC_NUM_TABLES; i++)
+  {
+    UInt32 r = g_CrcTable[i - 256];
+    g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+  }
+  #endif
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+  return CrcUpdateT8(v, data, size, g_CrcTable);
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+  return CrcUpdateT8(CRC_INIT_VAL, data, size, g_CrcTable) ^ 0xFFFFFFFF;
+}
diff --git a/lzma/C/Alloc.c b/lzma/C/Alloc.c
new file mode 100644 (file)
index 0000000..7b5af42
--- /dev/null
@@ -0,0 +1,119 @@
+/* Alloc.c */
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+#endif
+
+void *MyAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount++);
+  #endif
+  return malloc(size);
+}
+
+void MyFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+    fprintf(stderr, "\nFree; count = %10d", --g_allocCount);
+  #endif
+  free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc_Mid %10d bytes;  count = %10d", size, g_allocCountMid++);
+  #endif
+  return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+    fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
+  #endif
+  if (address == 0)
+    return;
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#ifndef MEM_LARGE_PAGES
+#undef _7ZIP_LARGE_PAGES
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+SIZE_T g_LargePageSize = 0;
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
+#endif
+
+void SetLargePageSize()
+{
+  #ifdef _7ZIP_LARGE_PAGES
+  SIZE_T size = 0;
+  GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+        GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+  if (largePageMinimum == 0)
+    return;
+  size = largePageMinimum();
+  if (size == 0 || (size & (size - 1)) != 0)
+    return;
+  g_LargePageSize = size;
+  #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc_Big %10d bytes;  count = %10d", size, g_allocCountBig++);
+  #endif
+  
+  #ifdef _7ZIP_LARGE_PAGES
+  if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
+  {
+    void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), 
+        MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+    if (res != 0)
+      return res;
+  }
+  #endif
+  return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+    fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
+  #endif
+  
+  if (address == 0)
+    return;
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif
diff --git a/lzma/C/Alloc.h b/lzma/C/Alloc.h
new file mode 100644 (file)
index 0000000..d748cb1
--- /dev/null
@@ -0,0 +1,29 @@
+/* Alloc.h */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include <stddef.h>
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+
+#ifdef _WIN32
+
+void SetLargePageSize();
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+#endif
diff --git a/lzma/C/Archive/7z/7zAlloc.c b/lzma/C/Archive/7z/7zAlloc.c
new file mode 100644 (file)
index 0000000..21bb30c
--- /dev/null
@@ -0,0 +1,70 @@
+/* 7zAlloc.c */
+
+#include <stdlib.h>
+#include "7zAlloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+
+#ifdef _SZ_ALLOC_DEBUG
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountTemp = 0;
+#endif
+
+void *SzAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
+  g_allocCount++;
+  #endif
+  return malloc(size);
+}
+
+void SzFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+  {
+    g_allocCount--;
+    fprintf(stderr, "\nFree; count = %10d", g_allocCount);
+  }
+  #endif
+  free(address);
+}
+
+void *SzAllocTemp(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc_temp %10d bytes;  count = %10d", size, g_allocCountTemp);
+  g_allocCountTemp++;
+  #ifdef _WIN32
+  return HeapAlloc(GetProcessHeap(), 0, size);
+  #endif
+  #endif
+  return malloc(size);
+}
+
+void SzFreeTemp(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+  {
+    g_allocCountTemp--;
+    fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
+  }
+  #ifdef _WIN32
+  HeapFree(GetProcessHeap(), 0, address);
+  return;
+  #endif
+  #endif
+  free(address);
+}
diff --git a/lzma/C/Archive/7z/7zAlloc.h b/lzma/C/Archive/7z/7zAlloc.h
new file mode 100644 (file)
index 0000000..4ca4170
--- /dev/null
@@ -0,0 +1,20 @@
+/* 7zAlloc.h */
+
+#ifndef __7Z_ALLOC_H
+#define __7Z_ALLOC_H
+
+#include <stddef.h>
+
+typedef struct _ISzAlloc
+{
+  void *(*Alloc)(size_t size);
+  void (*Free)(void *address); /* address can be 0 */
+} ISzAlloc;
+
+void *SzAlloc(size_t size);
+void SzFree(void *address);
+
+void *SzAllocTemp(size_t size);
+void SzFreeTemp(void *address);
+
+#endif
diff --git a/lzma/C/Archive/7z/7zBuffer.c b/lzma/C/Archive/7z/7zBuffer.c
new file mode 100644 (file)
index 0000000..3c4b71e
--- /dev/null
@@ -0,0 +1,29 @@
+/* 7zBuffer.c */
+
+#include "7zBuffer.h"
+#include "7zAlloc.h"
+
+void SzByteBufferInit(CSzByteBuffer *buffer)
+{
+  buffer->Capacity = 0;
+  buffer->Items = 0;
+}
+
+int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size))
+{
+  buffer->Capacity = newCapacity;
+  if (newCapacity == 0)
+  {
+    buffer->Items = 0;
+    return 1;
+  }
+  buffer->Items = (Byte *)allocFunc(newCapacity);
+  return (buffer->Items != 0);
+}
+
+void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *))
+{
+  freeFunc(buffer->Items);
+  buffer->Items = 0;
+  buffer->Capacity = 0;
+}
diff --git a/lzma/C/Archive/7z/7zBuffer.h b/lzma/C/Archive/7z/7zBuffer.h
new file mode 100644 (file)
index 0000000..05c6d74
--- /dev/null
@@ -0,0 +1,19 @@
+/* 7zBuffer.h */
+
+#ifndef __7Z_BUFFER_H
+#define __7Z_BUFFER_H
+
+#include <stddef.h>
+#include "../../Types.h"
+
+typedef struct _CSzByteBuffer
+{
+  size_t Capacity;
+  Byte *Items;
+}CSzByteBuffer;
+
+void SzByteBufferInit(CSzByteBuffer *buffer);
+int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size));
+void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *));
+
+#endif
diff --git a/lzma/C/Archive/7z/7zDecode.c b/lzma/C/Archive/7z/7zDecode.c
new file mode 100644 (file)
index 0000000..524e547
--- /dev/null
@@ -0,0 +1,345 @@
+/* 7zDecode.c */
+
+#include <memory.h>
+
+/* BEGIN PHYSFS CHANGE */
+#include <string.h>
+/* END PHYSFS CHANGE */
+
+#include "7zDecode.h"
+#ifdef _SZ_ONE_DIRECTORY
+#include "LzmaDecode.h"
+#else
+#include "../../Compress/Lzma/LzmaDecode.h"
+#include "../../Compress/Branch/BranchX86.h"
+#include "../../Compress/Branch/BranchX86_2.h"
+#endif
+
+#define k_Copy 0
+#define k_LZMA 0x30101
+#define k_BCJ 0x03030103
+#define k_BCJ2 0x0303011B
+
+#ifdef _LZMA_IN_CB
+
+typedef struct _CLzmaInCallbackImp
+{
+  ILzmaInCallback InCallback;
+  ISzInStream *InStream;
+  CFileSize Size;
+} CLzmaInCallbackImp;
+
+int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
+{
+  CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
+  size_t processedSize;
+  SZ_RESULT res;
+  size_t curSize = (1 << 20);
+  if (curSize > cb->Size)
+    curSize = (size_t)cb->Size;
+  *size = 0;
+  res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, curSize, &processedSize);
+  *size = (SizeT)processedSize;
+  if (processedSize > curSize)
+    return (int)SZE_FAIL;
+  cb->Size -= processedSize;
+  if (res == SZ_OK)
+    return 0;
+  return (int)res;
+}
+
+#endif
+
+SZ_RESULT SzDecodeLzma(CCoderInfo *coder, CFileSize inSize,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
+{
+  #ifdef _LZMA_IN_CB
+  CLzmaInCallbackImp lzmaCallback;
+  #else
+  SizeT inProcessed;
+  #endif
+  
+  CLzmaDecoderState state;  /* it's about 24-80 bytes structure, if int is 32-bit */
+  int result;
+  SizeT outSizeProcessedLoc;
+  
+  #ifdef _LZMA_IN_CB
+  lzmaCallback.Size = inSize;
+  lzmaCallback.InStream = inStream;
+  lzmaCallback.InCallback.Read = LzmaReadImp;
+  #endif
+  
+  if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items, 
+      (unsigned)coder->Properties.Capacity) != LZMA_RESULT_OK)
+    return SZE_FAIL;
+  
+  state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+  if (state.Probs == 0)
+    return SZE_OUTOFMEMORY;
+  
+  #ifdef _LZMA_OUT_READ
+  if (state.Properties.DictionarySize == 0)
+    state.Dictionary = 0;
+  else
+  {
+    state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize);
+    if (state.Dictionary == 0)
+    {
+      allocMain->Free(state.Probs);
+      return SZE_OUTOFMEMORY;
+    }
+  }
+  LzmaDecoderInit(&state);
+  #endif
+  
+  result = LzmaDecode(&state,
+  #ifdef _LZMA_IN_CB
+    &lzmaCallback.InCallback,
+  #else
+    inBuffer, (SizeT)inSize, &inProcessed,
+  #endif
+    outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
+  allocMain->Free(state.Probs);
+  #ifdef _LZMA_OUT_READ
+  allocMain->Free(state.Dictionary);
+  #endif
+  if (result == LZMA_RESULT_DATA_ERROR)
+    return SZE_DATA_ERROR;
+  if (result != LZMA_RESULT_OK)
+    return SZE_FAIL;
+  return (outSizeProcessedLoc == outSize) ? SZ_OK : SZE_DATA_ERROR;
+}
+
+#ifdef _LZMA_IN_CB
+SZ_RESULT SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer)
+{
+  while (inSize > 0)
+  {
+    void *inBuffer;
+    size_t processedSize, curSize = (1 << 18);
+    if (curSize > inSize)
+      curSize = (size_t)(inSize);
+    RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, curSize, &processedSize));
+    if (processedSize == 0)
+      return SZE_DATA_ERROR;
+    if (processedSize > curSize)
+      return SZE_FAIL;
+    memcpy(outBuffer, inBuffer, processedSize);
+    outBuffer += processedSize;
+    inSize -= processedSize;
+  }
+  return SZ_OK;
+}
+#endif
+
+#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
+#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
+#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
+#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
+
+SZ_RESULT CheckSupportedFolder(const CFolder *f)
+{
+  if (f->NumCoders < 1 || f->NumCoders > 4)
+    return SZE_NOTIMPL;
+  if (IS_UNSUPPORTED_CODER(f->Coders[0]))
+    return SZE_NOTIMPL;
+  if (f->NumCoders == 1)
+  {
+    if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
+      return SZE_NOTIMPL;
+    return SZ_OK;
+  }
+  if (f->NumCoders == 2)
+  {
+    if (IS_NO_BCJ(f->Coders[1]) ||
+        f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
+        f->NumBindPairs != 1 ||
+        f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
+      return SZE_NOTIMPL;
+    return SZ_OK;
+  }
+  if (f->NumCoders == 4)
+  {
+    if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
+        IS_UNSUPPORTED_CODER(f->Coders[2]) ||
+        IS_NO_BCJ2(f->Coders[3]))
+      return SZE_NOTIMPL;
+    if (f->NumPackStreams != 4 || 
+        f->PackStreams[0] != 2 ||
+        f->PackStreams[1] != 6 ||
+        f->PackStreams[2] != 1 ||
+        f->PackStreams[3] != 0 ||
+        f->NumBindPairs != 3 ||
+        f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
+        f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
+        f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
+      return SZE_NOTIMPL;
+    return SZ_OK;
+  }
+  return SZE_NOTIMPL;
+}
+
+CFileSize GetSum(const CFileSize *values, UInt32 index)
+{
+  CFileSize sum = 0;
+  UInt32 i;
+  for (i = 0; i < index; i++)
+    sum += values[i];
+  return sum;
+}
+
+SZ_RESULT SzDecode2(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream, CFileSize startPos,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain,
+    Byte *tempBuf[])
+{
+  UInt32 ci;
+  size_t tempSizes[3] = { 0, 0, 0};
+  size_t tempSize3 = 0;
+  Byte *tempBuf3 = 0;
+
+  RINOK(CheckSupportedFolder(folder));
+
+  for (ci = 0; ci < folder->NumCoders; ci++)
+  {
+    CCoderInfo *coder = &folder->Coders[ci];
+
+    if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
+    {
+      UInt32 si = 0;
+      CFileSize offset;
+      CFileSize inSize;
+      Byte *outBufCur = outBuffer;
+      size_t outSizeCur = outSize;
+      if (folder->NumCoders == 4)
+      {
+        UInt32 indices[] = { 3, 2, 0 };
+        CFileSize unpackSize = folder->UnPackSizes[ci];
+        si = indices[ci];
+        if (ci < 2)
+        {
+          Byte *temp;
+          outSizeCur = (size_t)unpackSize;
+          if (outSizeCur != unpackSize)
+            return SZE_OUTOFMEMORY;
+          temp = (Byte *)allocMain->Alloc(outSizeCur);
+          if (temp == 0 && outSizeCur != 0)
+            return SZE_OUTOFMEMORY;
+          outBufCur = tempBuf[1 - ci] = temp;
+          tempSizes[1 - ci] = outSizeCur;
+        }
+        else if (ci == 2)
+        {
+          if (unpackSize > outSize)
+            return SZE_OUTOFMEMORY;
+          tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
+          tempSize3 = outSizeCur = (size_t)unpackSize;
+        }
+        else
+          return SZE_NOTIMPL;
+      }
+      offset = GetSum(packSizes, si);
+      inSize = packSizes[si];
+      #ifdef _LZMA_IN_CB
+      RINOK(inStream->Seek(inStream, startPos + offset));
+      #endif
+
+      if (coder->MethodID == k_Copy)
+      {
+        if (inSize != outSizeCur)
+          return SZE_DATA_ERROR;
+        
+        #ifdef _LZMA_IN_CB
+        RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
+        #else
+        memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize);
+        #endif
+      }
+      else
+      {
+        SZ_RESULT res = SzDecodeLzma(coder, inSize,
+            #ifdef _LZMA_IN_CB
+            inStream,
+            #else
+            inBuffer + (size_t)offset,
+            #endif
+            outBufCur, outSizeCur, allocMain);
+        RINOK(res)
+      }
+    }
+    else if (coder->MethodID == k_BCJ)
+    {
+      UInt32 state;
+      if (ci != 1)
+        return SZE_NOTIMPL;
+      x86_Convert_Init(state);
+      x86_Convert(outBuffer, outSize, 0, &state, 0);
+    }
+    else if (coder->MethodID == k_BCJ2)
+    {
+      CFileSize offset = GetSum(packSizes, 1);
+      CFileSize s3Size = packSizes[1];
+      SZ_RESULT res;
+      if (ci != 3)
+        return SZE_NOTIMPL;
+
+      #ifdef _LZMA_IN_CB
+      RINOK(inStream->Seek(inStream, startPos + offset));
+      tempSizes[2] = (size_t)s3Size;
+      if (tempSizes[2] != s3Size)
+        return SZE_OUTOFMEMORY;
+      tempBuf[2] = (Byte *)allocMain->Alloc(tempSizes[2]);
+      if (tempBuf[2] == 0 && tempSizes[2] != 0)
+        return SZE_OUTOFMEMORY;
+      res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
+      RINOK(res)
+      #endif
+
+      res = x86_2_Decode(
+          tempBuf3, tempSize3, 
+          tempBuf[0], tempSizes[0], 
+          tempBuf[1], tempSizes[1], 
+          #ifdef _LZMA_IN_CB
+          tempBuf[2], tempSizes[2], 
+          #else
+          inBuffer + (size_t)offset, (size_t)s3Size, 
+          #endif
+          outBuffer, outSize);
+      RINOK(res)
+    }
+    else 
+      return SZE_NOTIMPL;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream, CFileSize startPos,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
+{
+  Byte *tempBuf[3] = { 0, 0, 0};
+  int i;
+  SZ_RESULT res = SzDecode2(packSizes, folder,
+      #ifdef _LZMA_IN_CB
+      inStream, startPos,
+      #else
+      inBuffer,
+      #endif
+      outBuffer, outSize, allocMain, tempBuf);
+  for (i = 0; i < 3; i++)
+    allocMain->Free(tempBuf[i]);
+  return res;
+}
diff --git a/lzma/C/Archive/7z/7zDecode.h b/lzma/C/Archive/7z/7zDecode.h
new file mode 100644 (file)
index 0000000..175896e
--- /dev/null
@@ -0,0 +1,20 @@
+/* 7zDecode.h */
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "7zItem.h"
+#include "7zAlloc.h"
+#ifdef _LZMA_IN_CB
+#include "7zIn.h"
+#endif
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *stream, CFileSize startPos,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
+
+#endif
diff --git a/lzma/C/Archive/7z/7zExtract.c b/lzma/C/Archive/7z/7zExtract.c
new file mode 100644 (file)
index 0000000..1760a3c
--- /dev/null
@@ -0,0 +1,119 @@
+/* 7zExtract.c */
+
+#include "7zExtract.h"
+#include "7zDecode.h"
+#include "../../7zCrc.h"
+
+SZ_RESULT SzExtract(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    UInt32 fileIndex,
+    UInt32 *blockIndex,
+    Byte **outBuffer, 
+    size_t *outBufferSize,
+    size_t *offset, 
+    size_t *outSizeProcessed, 
+    ISzAlloc *allocMain,
+    ISzAlloc *allocTemp)
+{
+  UInt32 folderIndex = db->FileIndexToFolderIndexMap[fileIndex];
+  SZ_RESULT res = SZ_OK;
+  *offset = 0;
+  *outSizeProcessed = 0;
+  if (folderIndex == (UInt32)-1)
+  {
+    allocMain->Free(*outBuffer);
+    *blockIndex = folderIndex;
+    *outBuffer = 0;
+    *outBufferSize = 0;
+    return SZ_OK;
+  }
+
+  if (*outBuffer == 0 || *blockIndex != folderIndex)
+  {
+    CFolder *folder = db->Database.Folders + folderIndex;
+    CFileSize unPackSizeSpec = SzFolderGetUnPackSize(folder);
+    size_t unPackSize = (size_t)unPackSizeSpec;
+    CFileSize startOffset = SzArDbGetFolderStreamPos(db, folderIndex, 0);
+    #ifndef _LZMA_IN_CB
+    Byte *inBuffer = 0;
+    size_t processedSize;
+    CFileSize packSizeSpec;
+    size_t packSize;
+    RINOK(SzArDbGetFolderFullPackSize(db, folderIndex, &packSizeSpec));
+    packSize = (size_t)packSizeSpec;
+    if (packSize != packSizeSpec)
+      return SZE_OUTOFMEMORY;
+    #endif
+    if (unPackSize != unPackSizeSpec)
+      return SZE_OUTOFMEMORY;
+    *blockIndex = folderIndex;
+    allocMain->Free(*outBuffer);
+    *outBuffer = 0;
+    
+    RINOK(inStream->Seek(inStream, startOffset));
+    
+    #ifndef _LZMA_IN_CB
+    if (packSize != 0)
+    {
+      inBuffer = (Byte *)allocTemp->Alloc(packSize);
+      if (inBuffer == 0)
+        return SZE_OUTOFMEMORY;
+    }
+    res = inStream->Read(inStream, inBuffer, packSize, &processedSize);
+    if (res == SZ_OK && processedSize != packSize)
+      res = SZE_FAIL;
+    #endif
+    if (res == SZ_OK)
+    {
+      *outBufferSize = unPackSize;
+      if (unPackSize != 0)
+      {
+        *outBuffer = (Byte *)allocMain->Alloc(unPackSize);
+        if (*outBuffer == 0)
+          res = SZE_OUTOFMEMORY;
+      }
+      if (res == SZ_OK)
+      {
+        res = SzDecode(db->Database.PackSizes + 
+          db->FolderStartPackStreamIndex[folderIndex], folder, 
+          #ifdef _LZMA_IN_CB
+          inStream, startOffset, 
+          #else
+          inBuffer, 
+          #endif
+          *outBuffer, unPackSize, allocTemp);
+        if (res == SZ_OK)
+        {
+          if (folder->UnPackCRCDefined)
+          {
+            if (CrcCalc(*outBuffer, unPackSize) != folder->UnPackCRC)
+              res = SZE_CRC_ERROR;
+          }
+        }
+      }
+    }
+    #ifndef _LZMA_IN_CB
+    allocTemp->Free(inBuffer);
+    #endif
+  }
+  if (res == SZ_OK)
+  {
+    UInt32 i; 
+    CFileItem *fileItem = db->Database.Files + fileIndex;
+    *offset = 0;
+    for(i = db->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
+      *offset += (UInt32)db->Database.Files[i].Size;
+    *outSizeProcessed = (size_t)fileItem->Size;
+    if (*offset + *outSizeProcessed > *outBufferSize)
+      return SZE_FAIL;
+    {
+      if (fileItem->IsFileCRCDefined)
+      {
+        if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC)
+          res = SZE_CRC_ERROR;
+      }
+    }
+  }
+  return res;
+}
diff --git a/lzma/C/Archive/7z/7zExtract.h b/lzma/C/Archive/7z/7zExtract.h
new file mode 100644 (file)
index 0000000..e9a4fb4
--- /dev/null
@@ -0,0 +1,40 @@
+/* 7zExtract.h */
+
+#ifndef __7Z_EXTRACT_H
+#define __7Z_EXTRACT_H
+
+#include "7zIn.h"
+
+/*
+  SzExtract extracts file from archive
+
+  *outBuffer must be 0 before first call for each new archive. 
+
+  Extracting cache:
+    If you need to decompress more than one file, you can send 
+    these values from previous call:
+      *blockIndex, 
+      *outBuffer, 
+      *outBufferSize
+    You can consider "*outBuffer" as cache of solid block. If your archive is solid, 
+    it will increase decompression speed.
+  
+    If you use external function, you can declare these 3 cache variables 
+    (blockIndex, outBuffer, outBufferSize) as static in that external function.
+    
+    Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
+*/
+
+SZ_RESULT SzExtract(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    UInt32 fileIndex,         /* index of file */
+    UInt32 *blockIndex,       /* index of solid block */
+    Byte **outBuffer,         /* pointer to pointer to output buffer (allocated with allocMain) */
+    size_t *outBufferSize,    /* buffer size for output buffer */
+    size_t *offset,           /* offset of stream for required file in *outBuffer */
+    size_t *outSizeProcessed, /* size of file in *outBuffer */
+    ISzAlloc *allocMain,
+    ISzAlloc *allocTemp);
+
+#endif
diff --git a/lzma/C/Archive/7z/7zHeader.c b/lzma/C/Archive/7z/7zHeader.c
new file mode 100644 (file)
index 0000000..3be4bc2
--- /dev/null
@@ -0,0 +1,5 @@
+/*  7zHeader.c */
+
+#include "7zHeader.h"
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
diff --git a/lzma/C/Archive/7z/7zHeader.h b/lzma/C/Archive/7z/7zHeader.h
new file mode 100644 (file)
index 0000000..3e67cf5
--- /dev/null
@@ -0,0 +1,55 @@
+/* 7zHeader.h */
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "../../Types.h"
+
+#define k7zSignatureSize 6
+extern Byte k7zSignature[k7zSignatureSize];
+
+#define k7zMajorVersion 0
+
+#define k7zStartHeaderSize 0x20
+
+enum EIdEnum
+{
+  k7zIdEnd,
+    
+  k7zIdHeader,
+    
+  k7zIdArchiveProperties,
+    
+  k7zIdAdditionalStreamsInfo,
+  k7zIdMainStreamsInfo,
+  k7zIdFilesInfo,
+  
+  k7zIdPackInfo,
+  k7zIdUnPackInfo,
+  k7zIdSubStreamsInfo,
+  
+  k7zIdSize,
+  k7zIdCRC,
+  
+  k7zIdFolder,
+  
+  k7zIdCodersUnPackSize,
+  k7zIdNumUnPackStream,
+  
+  k7zIdEmptyStream,
+  k7zIdEmptyFile,
+  k7zIdAnti,
+  
+  k7zIdName,
+  k7zIdCreationTime,
+  k7zIdLastAccessTime,
+  k7zIdLastWriteTime,
+  k7zIdWinAttributes,
+  k7zIdComment,
+  
+  k7zIdEncodedHeader,
+  
+  k7zIdStartPos
+};
+
+#endif
diff --git a/lzma/C/Archive/7z/7zIn.c b/lzma/C/Archive/7z/7zIn.c
new file mode 100644 (file)
index 0000000..ac25dbc
--- /dev/null
@@ -0,0 +1,1314 @@
+/* 7zIn.c */
+
+#include "7zIn.h"
+#include "7zDecode.h"
+#include "../../7zCrc.h"
+
+#define RINOM(x) { if((x) == 0) return SZE_OUTOFMEMORY; }
+
+void SzArDbExInit(CArchiveDatabaseEx *db)
+{
+  SzArchiveDatabaseInit(&db->Database);
+  db->FolderStartPackStreamIndex = 0;
+  db->PackStreamStartPositions = 0;
+  db->FolderStartFileIndex = 0;
+  db->FileIndexToFolderIndexMap = 0;
+}
+
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *))
+{
+  freeFunc(db->FolderStartPackStreamIndex);
+  freeFunc(db->PackStreamStartPositions);
+  freeFunc(db->FolderStartFileIndex);
+  freeFunc(db->FileIndexToFolderIndexMap);
+  SzArchiveDatabaseFree(&db->Database, freeFunc);
+  SzArDbExInit(db);
+}
+
+/*
+CFileSize GetFolderPackStreamSize(int folderIndex, int streamIndex) const 
+{
+  return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+}
+
+CFileSize GetFilePackSize(int fileIndex) const
+{
+  int folderIndex = FileIndexToFolderIndexMap[fileIndex];
+  if (folderIndex >= 0)
+  {
+    const CFolder &folderInfo = Folders[folderIndex];
+    if (FolderStartFileIndex[folderIndex] == fileIndex)
+    return GetFolderFullPackSize(folderIndex);
+  }
+  return 0;
+}
+*/
+
+#define MY_ALLOC(T, p, size, allocFunc) { if ((size) == 0) p = 0; else \
+  if ((p = (T *)allocFunc((size) * sizeof(T))) == 0) return SZE_OUTOFMEMORY; }
+
+SZ_RESULT SzArDbExFill(CArchiveDatabaseEx *db, void * (*allocFunc)(size_t size))
+{
+  UInt32 startPos = 0;
+  CFileSize startPosSize = 0;
+  UInt32 i;
+  UInt32 folderIndex = 0;
+  UInt32 indexInFolder = 0;
+  MY_ALLOC(UInt32, db->FolderStartPackStreamIndex, db->Database.NumFolders, allocFunc);
+  for(i = 0; i < db->Database.NumFolders; i++)
+  {
+    db->FolderStartPackStreamIndex[i] = startPos;
+    startPos += db->Database.Folders[i].NumPackStreams;
+  }
+
+  MY_ALLOC(CFileSize, db->PackStreamStartPositions, db->Database.NumPackStreams, allocFunc);
+
+  for(i = 0; i < db->Database.NumPackStreams; i++)
+  {
+    db->PackStreamStartPositions[i] = startPosSize;
+    startPosSize += db->Database.PackSizes[i];
+  }
+
+  MY_ALLOC(UInt32, db->FolderStartFileIndex, db->Database.NumFolders, allocFunc);
+  MY_ALLOC(UInt32, db->FileIndexToFolderIndexMap, db->Database.NumFiles, allocFunc);
+
+  for (i = 0; i < db->Database.NumFiles; i++)
+  {
+    CFileItem *file = db->Database.Files + i;
+    int emptyStream = !file->HasStream;
+    if (emptyStream && indexInFolder == 0)
+    {
+      db->FileIndexToFolderIndexMap[i] = (UInt32)-1;
+      continue;
+    }
+    if (indexInFolder == 0)
+    {
+      /*
+      v3.13 incorrectly worked with empty folders
+      v4.07: Loop for skipping empty folders
+      */
+      for (;;)
+      {
+        if (folderIndex >= db->Database.NumFolders)
+          return SZE_ARCHIVE_ERROR;
+        db->FolderStartFileIndex[folderIndex] = i;
+        if (db->Database.Folders[folderIndex].NumUnPackStreams != 0)
+          break;
+        folderIndex++;
+      }
+    }
+    db->FileIndexToFolderIndexMap[i] = folderIndex;
+    if (emptyStream)
+      continue;
+    indexInFolder++;
+    if (indexInFolder >= db->Database.Folders[folderIndex].NumUnPackStreams)
+    {
+      folderIndex++;
+      indexInFolder = 0;
+    }
+  }
+  return SZ_OK;
+}
+
+
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder)
+{
+  return db->ArchiveInfo.DataStartPosition + 
+    db->PackStreamStartPositions[db->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+}
+
+int SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex, CFileSize *resSize)
+{
+  UInt32 packStreamIndex = db->FolderStartPackStreamIndex[folderIndex];
+  CFolder *folder = db->Database.Folders + folderIndex;
+  CFileSize size = 0;
+  UInt32 i;
+  for (i = 0; i < folder->NumPackStreams; i++)
+  {
+    CFileSize t = size + db->Database.PackSizes[packStreamIndex + i];
+    if (t < size)
+      return SZE_FAIL;
+    size = t;
+  }
+  *resSize = size;
+  return SZ_OK;
+}
+
+
+/*
+SZ_RESULT SzReadTime(const CObjectVector<CSzByteBuffer> &dataVector,
+    CObjectVector<CFileItem> &files, UInt64 type)
+{
+  CBoolVector boolVector;
+  RINOK(ReadBoolVector2(files.Size(), boolVector))
+
+  CStreamSwitch streamSwitch;
+  RINOK(streamSwitch.Set(this, &dataVector));
+
+  for(int i = 0; i < files.Size(); i++)
+  {
+    CFileItem &file = files[i];
+    CArchiveFileTime fileTime;
+    bool defined = boolVector[i];
+    if (defined)
+    {
+      UInt32 low, high;
+      RINOK(SzReadUInt32(low));
+      RINOK(SzReadUInt32(high));
+      fileTime.dwLowDateTime = low;
+      fileTime.dwHighDateTime = high;
+    }
+    switch(type)
+    {
+      case k7zIdCreationTime:
+        file.IsCreationTimeDefined = defined;
+        if (defined)
+          file.CreationTime = fileTime;
+        break;
+      case k7zIdLastWriteTime:
+        file.IsLastWriteTimeDefined = defined;
+        if (defined)
+          file.LastWriteTime = fileTime;
+        break;
+      case k7zIdLastAccessTime:
+        file.IsLastAccessTimeDefined = defined;
+        if (defined)
+          file.LastAccessTime = fileTime;
+        break;
+    }
+  }
+  return SZ_OK;
+}
+*/
+
+SZ_RESULT SafeReadDirect(ISzInStream *inStream, Byte *data, size_t size)
+{
+  #ifdef _LZMA_IN_CB
+  while (size > 0)
+  {
+    void *inBufferSpec;
+    size_t processedSize;
+    const Byte *inBuffer;
+    RINOK(inStream->Read(inStream, (void **)&inBufferSpec, size, &processedSize));
+    inBuffer = (const Byte *)inBufferSpec;
+    if (processedSize == 0 || processedSize > size)
+      return SZE_FAIL;
+    size -= processedSize;
+    do
+    {
+      *data++ = *inBuffer++;
+    }
+    while (--processedSize != 0);
+  }
+  #else
+  size_t processedSize;
+  RINOK(inStream->Read(inStream, data, size, &processedSize));
+  if (processedSize != size)
+    return SZE_FAIL;
+  #endif
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectByte(ISzInStream *inStream, Byte *data)
+{
+  return SafeReadDirect(inStream, data, 1);
+}
+
+SZ_RESULT SafeReadDirectUInt32(ISzInStream *inStream, UInt32 *value, UInt32 *crc)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt32)b << (8 * i));
+    *crc = CRC_UPDATE_BYTE(*crc, b);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectUInt64(ISzInStream *inStream, UInt64 *value, UInt32 *crc)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt64)b << (8 * i));
+    *crc = CRC_UPDATE_BYTE(*crc, b);
+  }
+  return SZ_OK;
+}
+
+int TestSignatureCandidate(Byte *testBytes)
+{
+  size_t i;
+  for (i = 0; i < k7zSignatureSize; i++)
+    if (testBytes[i] != k7zSignature[i])
+      return 0;
+  return 1;
+}
+
+typedef struct _CSzState
+{
+  Byte *Data;
+  size_t Size;
+}CSzData;
+
+SZ_RESULT SzReadByte(CSzData *sd, Byte *b)
+{
+  if (sd->Size == 0)
+    return SZE_ARCHIVE_ERROR;
+  sd->Size--;
+  *b = *sd->Data++;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadBytes(CSzData *sd, Byte *data, size_t size)
+{
+  size_t i;
+  for (i = 0; i < size; i++)
+  {
+    RINOK(SzReadByte(sd, data + i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadUInt32(CSzData *sd, UInt32 *value)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SzReadByte(sd, &b));
+    *value |= ((UInt32)(b) << (8 * i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber(CSzData *sd, UInt64 *value)
+{
+  Byte firstByte;
+  Byte mask = 0x80;
+  int i;
+  RINOK(SzReadByte(sd, &firstByte));
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    if ((firstByte & mask) == 0)
+    {
+      UInt64 highPart = firstByte & (mask - 1);
+      *value += (highPart << (8 * i));
+      return SZ_OK;
+    }
+    RINOK(SzReadByte(sd, &b));
+    *value |= ((UInt64)b << (8 * i));
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadSize(CSzData *sd, CFileSize *value)
+{
+  UInt64 value64;
+  RINOK(SzReadNumber(sd, &value64));
+  *value = (CFileSize)value64;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+  UInt64 value64;
+  RINOK(SzReadNumber(sd, &value64));
+  if (value64 >= 0x80000000)
+    return SZE_NOTIMPL;
+  if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
+    return SZE_NOTIMPL;
+  *value = (UInt32)value64;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadID(CSzData *sd, UInt64 *value) 
+{ 
+  return SzReadNumber(sd, value); 
+}
+
+SZ_RESULT SzSkeepDataSize(CSzData *sd, UInt64 size)
+{
+  if (size > sd->Size)
+    return SZE_ARCHIVE_ERROR;
+  sd->Size -= (size_t)size;
+  sd->Data += (size_t)size;
+  return SZ_OK;
+}
+
+SZ_RESULT SzSkeepData(CSzData *sd)
+{
+  UInt64 size;
+  RINOK(SzReadNumber(sd, &size));
+  return SzSkeepDataSize(sd, size);
+}
+
+SZ_RESULT SzReadArchiveProperties(CSzData *sd)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    SzSkeepData(sd);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzWaitAttribute(CSzData *sd, UInt64 attribute)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == attribute)
+      return SZ_OK;
+    if (type == k7zIdEnd)
+      return SZE_ARCHIVE_ERROR;
+    RINOK(SzSkeepData(sd));
+  }
+}
+
+SZ_RESULT SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+  Byte b = 0;
+  Byte mask = 0;
+  size_t i;
+  MY_ALLOC(Byte, *v, numItems, allocFunc);
+  for (i = 0; i < numItems; i++)
+  {
+    if (mask == 0)
+    {
+      RINOK(SzReadByte(sd, &b));
+      mask = 0x80;
+    }
+    (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+  Byte allAreDefined;
+  size_t i;
+  RINOK(SzReadByte(sd, &allAreDefined));
+  if (allAreDefined == 0)
+    return SzReadBoolVector(sd, numItems, v, allocFunc);
+  MY_ALLOC(Byte, *v, numItems, allocFunc);
+  for(i = 0; i < numItems; i++)
+    (*v)[i] = 1;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadHashDigests(
+    CSzData *sd, 
+    size_t numItems,
+    Byte **digestsDefined, 
+    UInt32 **digests, 
+    void * (*allocFunc)(size_t size))
+{
+  size_t i;
+  RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, allocFunc));
+  MY_ALLOC(UInt32, *digests, numItems, allocFunc);
+  for(i = 0; i < numItems; i++)
+    if ((*digestsDefined)[i])
+    {
+      RINOK(SzReadUInt32(sd, (*digests) + i));
+    }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadPackInfo(
+    CSzData *sd, 
+    CFileSize *dataOffset,
+    UInt32 *numPackStreams,
+    CFileSize **packSizes,
+    Byte **packCRCsDefined,
+    UInt32 **packCRCs,
+    void * (*allocFunc)(size_t size))
+{
+  UInt32 i;
+  RINOK(SzReadSize(sd, dataOffset));
+  RINOK(SzReadNumber32(sd, numPackStreams));
+
+  RINOK(SzWaitAttribute(sd, k7zIdSize));
+
+  MY_ALLOC(CFileSize, *packSizes, (size_t)*numPackStreams, allocFunc);
+
+  for(i = 0; i < *numPackStreams; i++)
+  {
+    RINOK(SzReadSize(sd, (*packSizes) + i));
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    if (type == k7zIdCRC)
+    {
+      RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, allocFunc)); 
+      continue;
+    }
+    RINOK(SzSkeepData(sd));
+  }
+  if (*packCRCsDefined == 0)
+  {
+    MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, allocFunc);
+    MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, allocFunc);
+    for(i = 0; i < *numPackStreams; i++)
+    {
+      (*packCRCsDefined)[i] = 0;
+      (*packCRCs)[i] = 0;
+    }
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadSwitch(CSzData *sd)
+{
+  Byte external;
+  RINOK(SzReadByte(sd, &external));
+  return (external == 0) ? SZ_OK: SZE_ARCHIVE_ERROR;
+}
+
+SZ_RESULT SzGetNextFolderItem(CSzData *sd, CFolder *folder, void * (*allocFunc)(size_t size))
+{
+  UInt32 numCoders;
+  UInt32 numBindPairs;
+  UInt32 numPackedStreams;
+  UInt32 i;
+  UInt32 numInStreams = 0;
+  UInt32 numOutStreams = 0;
+  RINOK(SzReadNumber32(sd, &numCoders));
+  folder->NumCoders = numCoders;
+
+  MY_ALLOC(CCoderInfo, folder->Coders, (size_t)numCoders, allocFunc);
+
+  for (i = 0; i < numCoders; i++)
+    SzCoderInfoInit(folder->Coders + i);
+
+  for (i = 0; i < numCoders; i++)
+  {
+    Byte mainByte;
+    CCoderInfo *coder = folder->Coders + i;
+    {
+      unsigned idSize, j;
+      Byte longID[15];
+      RINOK(SzReadByte(sd, &mainByte));
+      idSize = (unsigned)(mainByte & 0xF);
+      RINOK(SzReadBytes(sd, longID, idSize));
+      if (idSize > sizeof(coder->MethodID))
+        return SZE_NOTIMPL;
+      coder->MethodID = 0;
+      for (j = 0; j < idSize; j++)
+        coder->MethodID |= (CMethodID)longID[idSize - 1 - j] << (8 * j);
+
+      if ((mainByte & 0x10) != 0)
+      {
+        RINOK(SzReadNumber32(sd, &coder->NumInStreams));
+        RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
+      }
+      else
+      {
+        coder->NumInStreams = 1;
+        coder->NumOutStreams = 1;
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt64 propertiesSize = 0;
+        RINOK(SzReadNumber(sd, &propertiesSize));
+        if (!SzByteBufferCreate(&coder->Properties, (size_t)propertiesSize, allocFunc))
+          return SZE_OUTOFMEMORY;
+        RINOK(SzReadBytes(sd, coder->Properties.Items, (size_t)propertiesSize));
+      }
+    }
+    while ((mainByte & 0x80) != 0)
+    {
+      RINOK(SzReadByte(sd, &mainByte));
+      RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
+      if ((mainByte & 0x10) != 0)
+      {
+        UInt32 n;
+        RINOK(SzReadNumber32(sd, &n));
+        RINOK(SzReadNumber32(sd, &n));
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt64 propertiesSize = 0;
+        RINOK(SzReadNumber(sd, &propertiesSize));
+        RINOK(SzSkeepDataSize(sd, propertiesSize));
+      }
+    }
+    numInStreams += (UInt32)coder->NumInStreams;
+    numOutStreams += (UInt32)coder->NumOutStreams;
+  }
+
+  numBindPairs = numOutStreams - 1;
+  folder->NumBindPairs = numBindPairs;
+
+
+  MY_ALLOC(CBindPair, folder->BindPairs, (size_t)numBindPairs, allocFunc);
+
+  for (i = 0; i < numBindPairs; i++)
+  {
+    CBindPair *bindPair = folder->BindPairs + i;;
+    RINOK(SzReadNumber32(sd, &bindPair->InIndex));
+    RINOK(SzReadNumber32(sd, &bindPair->OutIndex)); 
+  }
+
+  numPackedStreams = numInStreams - (UInt32)numBindPairs;
+
+  folder->NumPackStreams = numPackedStreams;
+  MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackedStreams, allocFunc);
+
+  if (numPackedStreams == 1)
+  {
+    UInt32 j;
+    UInt32 pi = 0;
+    for (j = 0; j < numInStreams; j++)
+      if (SzFolderFindBindPairForInStream(folder, j) < 0)
+      {
+        folder->PackStreams[pi++] = j;
+        break;
+      }
+  }
+  else
+    for(i = 0; i < numPackedStreams; i++)
+    {
+      RINOK(SzReadNumber32(sd, folder->PackStreams + i));
+    }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadUnPackInfo(
+    CSzData *sd, 
+    UInt32 *numFolders,
+    CFolder **folders,  /* for allocFunc */
+    void * (*allocFunc)(size_t size),
+    ISzAlloc *allocTemp)
+{
+  UInt32 i;
+  RINOK(SzWaitAttribute(sd, k7zIdFolder));
+  RINOK(SzReadNumber32(sd, numFolders));
+  {
+    RINOK(SzReadSwitch(sd));
+
+    MY_ALLOC(CFolder, *folders, (size_t)*numFolders, allocFunc);
+
+    for(i = 0; i < *numFolders; i++)
+      SzFolderInit((*folders) + i);
+
+    for(i = 0; i < *numFolders; i++)
+    {
+      RINOK(SzGetNextFolderItem(sd, (*folders) + i, allocFunc));
+    }
+  }
+
+  RINOK(SzWaitAttribute(sd, k7zIdCodersUnPackSize));
+
+  for(i = 0; i < *numFolders; i++)
+  {
+    UInt32 j;
+    CFolder *folder = (*folders) + i;
+    UInt32 numOutStreams = SzFolderGetNumOutStreams(folder);
+
+    MY_ALLOC(CFileSize, folder->UnPackSizes, (size_t)numOutStreams, allocFunc);
+
+    for(j = 0; j < numOutStreams; j++)
+    {
+      RINOK(SzReadSize(sd, folder->UnPackSizes + j));
+    }
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      return SZ_OK;
+    if (type == k7zIdCRC)
+    {
+      SZ_RESULT res;
+      Byte *crcsDefined = 0;
+      UInt32 *crcs = 0;
+      res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp->Alloc); 
+      if (res == SZ_OK)
+      {
+        for(i = 0; i < *numFolders; i++)
+        {
+          CFolder *folder = (*folders) + i;
+          folder->UnPackCRCDefined = crcsDefined[i];
+          folder->UnPackCRC = crcs[i];
+        }
+      }
+      allocTemp->Free(crcs);
+      allocTemp->Free(crcsDefined);
+      RINOK(res);
+      continue;
+    }
+    RINOK(SzSkeepData(sd));
+  }
+}
+
+SZ_RESULT SzReadSubStreamsInfo(
+    CSzData *sd, 
+    UInt32 numFolders,
+    CFolder *folders,
+    UInt32 *numUnPackStreams,
+    CFileSize **unPackSizes,
+    Byte **digestsDefined,
+    UInt32 **digests,
+    ISzAlloc *allocTemp)
+{
+  UInt64 type = 0;
+  UInt32 i;
+  UInt32 si = 0;
+  UInt32 numDigests = 0;
+
+  for(i = 0; i < numFolders; i++)
+    folders[i].NumUnPackStreams = 1;
+  *numUnPackStreams = numFolders;
+
+  for (;;)
+  {
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdNumUnPackStream)
+    {
+      *numUnPackStreams = 0;
+      for(i = 0; i < numFolders; i++)
+      {
+        UInt32 numStreams;
+        RINOK(SzReadNumber32(sd, &numStreams));
+        folders[i].NumUnPackStreams = numStreams;
+        *numUnPackStreams += numStreams;
+      }
+      continue;
+    }
+    if (type == k7zIdCRC || type == k7zIdSize)
+      break;
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SzSkeepData(sd));
+  }
+
+  if (*numUnPackStreams == 0)
+  {
+    *unPackSizes = 0;
+    *digestsDefined = 0;
+    *digests = 0;
+  }
+  else
+  {
+    *unPackSizes = (CFileSize *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(CFileSize));
+    RINOM(*unPackSizes);
+    *digestsDefined = (Byte *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(Byte));
+    RINOM(*digestsDefined);
+    *digests = (UInt32 *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(UInt32));
+    RINOM(*digests);
+  }
+
+  for(i = 0; i < numFolders; i++)
+  {
+    /*
+    v3.13 incorrectly worked with empty folders
+    v4.07: we check that folder is empty
+    */
+    CFileSize sum = 0;
+    UInt32 j;
+    UInt32 numSubstreams = folders[i].NumUnPackStreams;
+    if (numSubstreams == 0)
+      continue;
+    if (type == k7zIdSize)
+    for (j = 1; j < numSubstreams; j++)
+    {
+      CFileSize size;
+      RINOK(SzReadSize(sd, &size));
+      (*unPackSizes)[si++] = size;
+      sum += size;
+    }
+    (*unPackSizes)[si++] = SzFolderGetUnPackSize(folders + i) - sum;
+  }
+  if (type == k7zIdSize)
+  {
+    RINOK(SzReadID(sd, &type));
+  }
+
+  for(i = 0; i < *numUnPackStreams; i++)
+  {
+    (*digestsDefined)[i] = 0;
+    (*digests)[i] = 0;
+  }
+
+
+  for(i = 0; i < numFolders; i++)
+  {
+    UInt32 numSubstreams = folders[i].NumUnPackStreams;
+    if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
+      numDigests += numSubstreams;
+  }
+
+  si = 0;
+  for (;;)
+  {
+    if (type == k7zIdCRC)
+    {
+      int digestIndex = 0;
+      Byte *digestsDefined2 = 0; 
+      UInt32 *digests2 = 0;
+      SZ_RESULT res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp->Alloc);
+      if (res == SZ_OK)
+      {
+        for (i = 0; i < numFolders; i++)
+        {
+          CFolder *folder = folders + i;
+          UInt32 numSubstreams = folder->NumUnPackStreams;
+          if (numSubstreams == 1 && folder->UnPackCRCDefined)
+          {
+            (*digestsDefined)[si] = 1;
+            (*digests)[si] = folder->UnPackCRC;
+            si++;
+          }
+          else
+          {
+            UInt32 j;
+            for (j = 0; j < numSubstreams; j++, digestIndex++)
+            {
+              (*digestsDefined)[si] = digestsDefined2[digestIndex];
+              (*digests)[si] = digests2[digestIndex];
+              si++;
+            }
+          }
+        }
+      }
+      allocTemp->Free(digestsDefined2);
+      allocTemp->Free(digests2);
+      RINOK(res);
+    }
+    else if (type == k7zIdEnd)
+      return SZ_OK;
+    else
+    {
+      RINOK(SzSkeepData(sd));
+    }
+    RINOK(SzReadID(sd, &type));
+  }
+}
+
+
+SZ_RESULT SzReadStreamsInfo(
+    CSzData *sd, 
+    CFileSize *dataOffset,
+    CArchiveDatabase *db,
+    UInt32 *numUnPackStreams,
+    CFileSize **unPackSizes, /* allocTemp */
+    Byte **digestsDefined,   /* allocTemp */
+    UInt32 **digests,        /* allocTemp */
+    void * (*allocFunc)(size_t size),
+    ISzAlloc *allocTemp)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if ((UInt64)(int)type != type)
+      return SZE_FAIL;
+    switch((int)type)
+    {
+      case k7zIdEnd:
+        return SZ_OK;
+      case k7zIdPackInfo:
+      {
+        RINOK(SzReadPackInfo(sd, dataOffset, &db->NumPackStreams, 
+            &db->PackSizes, &db->PackCRCsDefined, &db->PackCRCs, allocFunc));
+        break;
+      }
+      case k7zIdUnPackInfo:
+      {
+        RINOK(SzReadUnPackInfo(sd, &db->NumFolders, &db->Folders, allocFunc, allocTemp));
+        break;
+      }
+      case k7zIdSubStreamsInfo:
+      {
+        RINOK(SzReadSubStreamsInfo(sd, db->NumFolders, db->Folders, 
+            numUnPackStreams, unPackSizes, digestsDefined, digests, allocTemp));
+        break;
+      }
+      default:
+        return SZE_FAIL;
+    }
+  }
+}
+
+Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+SZ_RESULT SzReadFileNames(CSzData *sd, UInt32 numFiles, CFileItem *files, 
+    void * (*allocFunc)(size_t size))
+{
+  UInt32 i;
+  for(i = 0; i < numFiles; i++)
+  {
+    UInt32 len = 0;
+    UInt32 pos = 0;
+    CFileItem *file = files + i;
+    while(pos + 2 <= sd->Size)
+    {
+      int numAdds;
+      UInt32 value = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+      pos += 2;
+      len++;
+      if (value == 0)
+        break;
+      if (value < 0x80)
+        continue;
+      if (value >= 0xD800 && value < 0xE000)
+      {
+        UInt32 c2;
+        if (value >= 0xDC00)
+          return SZE_ARCHIVE_ERROR;
+        if (pos + 2 > sd->Size)
+          return SZE_ARCHIVE_ERROR;
+        c2 = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+        pos += 2;
+        if (c2 < 0xDC00 || c2 >= 0xE000)
+          return SZE_ARCHIVE_ERROR;
+        value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+      }
+      for (numAdds = 1; numAdds < 5; numAdds++)
+        if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+          break;
+      len += numAdds;
+    }
+
+    MY_ALLOC(char, file->Name, (size_t)len, allocFunc);
+
+    len = 0;
+    while(2 <= sd->Size)
+    {
+      int numAdds;
+      UInt32 value = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+      SzSkeepDataSize(sd, 2);
+      if (value < 0x80)
+      {
+        file->Name[len++] = (char)value;
+        if (value == 0)
+          break;
+        continue;
+      }
+      if (value >= 0xD800 && value < 0xE000)
+      {
+        UInt32 c2 = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+        SzSkeepDataSize(sd, 2);
+        value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+      }
+      for (numAdds = 1; numAdds < 5; numAdds++)
+        if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+          break;
+      file->Name[len++] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+      do
+      {
+        numAdds--;
+        file->Name[len++] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+      }
+      while(numAdds > 0);
+
+      len += numAdds;
+    }
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadHeader2(
+    CSzData *sd, 
+    CArchiveDatabaseEx *db,   /* allocMain */
+    CFileSize **unPackSizes,  /* allocTemp */
+    Byte **digestsDefined,    /* allocTemp */
+    UInt32 **digests,         /* allocTemp */
+    Byte **emptyStreamVector, /* allocTemp */
+    Byte **emptyFileVector,   /* allocTemp */
+    Byte **lwtVector,         /* allocTemp */
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  UInt64 type;
+  UInt32 numUnPackStreams = 0;
+  UInt32 numFiles = 0;
+  CFileItem *files = 0;
+  UInt32 numEmptyStreams = 0;
+  UInt32 i;
+
+  RINOK(SzReadID(sd, &type));
+
+  if (type == k7zIdArchiveProperties)
+  {
+    RINOK(SzReadArchiveProperties(sd));
+    RINOK(SzReadID(sd, &type));
+  }
+  if (type == k7zIdMainStreamsInfo)
+  {
+    RINOK(SzReadStreamsInfo(sd,
+        &db->ArchiveInfo.DataStartPosition,
+        &db->Database, 
+        &numUnPackStreams,
+        unPackSizes,
+        digestsDefined,
+        digests, allocMain->Alloc, allocTemp));
+    db->ArchiveInfo.DataStartPosition += db->ArchiveInfo.StartPositionAfterHeader;
+    RINOK(SzReadID(sd, &type));
+  }
+
+  if (type == k7zIdEnd)
+    return SZ_OK;
+  if (type != k7zIdFilesInfo)
+    return SZE_ARCHIVE_ERROR;
+  
+  RINOK(SzReadNumber32(sd, &numFiles));
+  db->Database.NumFiles = numFiles;
+
+  MY_ALLOC(CFileItem, files, (size_t)numFiles, allocMain->Alloc);
+
+  db->Database.Files = files;
+  for(i = 0; i < numFiles; i++)
+    SzFileInit(files + i);
+
+  for (;;)
+  {
+    UInt64 type;
+    UInt64 size;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SzReadNumber(sd, &size));
+
+    if ((UInt64)(int)type != type)
+    {
+      RINOK(SzSkeepDataSize(sd, size));
+    }
+    else
+    switch((int)type)
+    {
+      case k7zIdName:
+      {
+        RINOK(SzReadSwitch(sd));
+        RINOK(SzReadFileNames(sd, numFiles, files, allocMain->Alloc))
+        break;
+      }
+      case k7zIdEmptyStream:
+      {
+        RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp->Alloc));
+        numEmptyStreams = 0;
+        for (i = 0; i < numFiles; i++)
+          if ((*emptyStreamVector)[i])
+            numEmptyStreams++;
+        break;
+      }
+      case k7zIdEmptyFile:
+      {
+        RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp->Alloc));
+        break;
+      }
+      case k7zIdLastWriteTime:
+      {
+        RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp->Alloc));
+        RINOK(SzReadSwitch(sd));
+        for (i = 0; i < numFiles; i++)
+        {
+          CFileItem *f = &files[i];
+          Byte defined = (*lwtVector)[i];
+          f->IsLastWriteTimeDefined = defined;
+          f->LastWriteTime.Low = f->LastWriteTime.High = 0;
+          if (defined)
+          {
+            RINOK(SzReadUInt32(sd, &f->LastWriteTime.Low));
+            RINOK(SzReadUInt32(sd, &f->LastWriteTime.High));
+          }
+        }
+        break;
+      }
+      default:
+      {
+        RINOK(SzSkeepDataSize(sd, size));
+      }
+    }
+  }
+
+  {
+    UInt32 emptyFileIndex = 0;
+    UInt32 sizeIndex = 0;
+    for(i = 0; i < numFiles; i++)
+    {
+      CFileItem *file = files + i;
+      file->IsAnti = 0;
+      if (*emptyStreamVector == 0)
+        file->HasStream = 1;
+      else
+        file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
+      if(file->HasStream)
+      {
+        file->IsDirectory = 0;
+        file->Size = (*unPackSizes)[sizeIndex];
+        file->FileCRC = (*digests)[sizeIndex];
+        file->IsFileCRCDefined = (Byte)(*digestsDefined)[sizeIndex];
+        sizeIndex++;
+      }
+      else
+      {
+        if (*emptyFileVector == 0)
+          file->IsDirectory = 1;
+        else
+          file->IsDirectory = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
+        emptyFileIndex++;
+        file->Size = 0;
+        file->IsFileCRCDefined = 0;
+      }
+    }
+  }
+  return SzArDbExFill(db, allocMain->Alloc);
+}
+
+SZ_RESULT SzReadHeader(
+    CSzData *sd, 
+    CArchiveDatabaseEx *db, 
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  CFileSize *unPackSizes = 0;
+  Byte *digestsDefined = 0;
+  UInt32 *digests = 0;
+  Byte *emptyStreamVector = 0;
+  Byte *emptyFileVector = 0;
+  Byte *lwtVector = 0;
+  SZ_RESULT res = SzReadHeader2(sd, db, 
+      &unPackSizes, &digestsDefined, &digests,
+      &emptyStreamVector, &emptyFileVector, &lwtVector, 
+      allocMain, allocTemp);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  allocTemp->Free(emptyStreamVector);
+  allocTemp->Free(emptyFileVector);
+  allocTemp->Free(lwtVector);
+  return res;
+} 
+
+SZ_RESULT SzReadAndDecodePackedStreams2(
+    ISzInStream *inStream, 
+    CSzData *sd,
+    CSzByteBuffer *outBuffer,
+    CFileSize baseOffset, 
+    CArchiveDatabase *db,
+    CFileSize **unPackSizes,
+    Byte **digestsDefined,
+    UInt32 **digests,
+    #ifndef _LZMA_IN_CB
+    Byte **inBuffer,
+    #endif
+    ISzAlloc *allocTemp)
+{
+
+  UInt32 numUnPackStreams = 0;
+  CFileSize dataStartPos;
+  CFolder *folder;
+  #ifndef _LZMA_IN_CB
+  CFileSize packSize = 0;
+  UInt32 i = 0;
+  #endif
+  CFileSize unPackSize;
+  SZ_RESULT res;
+
+  RINOK(SzReadStreamsInfo(sd, &dataStartPos, db,
+      &numUnPackStreams,  unPackSizes, digestsDefined, digests, 
+      allocTemp->Alloc, allocTemp));
+  
+  dataStartPos += baseOffset;
+  if (db->NumFolders != 1)
+    return SZE_ARCHIVE_ERROR;
+
+  folder = db->Folders;
+  unPackSize = SzFolderGetUnPackSize(folder);
+  
+  RINOK(inStream->Seek(inStream, dataStartPos));
+
+  #ifndef _LZMA_IN_CB
+  for (i = 0; i < db->NumPackStreams; i++)
+    packSize += db->PackSizes[i];
+
+  MY_ALLOC(Byte, *inBuffer, (size_t)packSize, allocTemp->Alloc);
+
+  RINOK(SafeReadDirect(inStream, *inBuffer, (size_t)packSize));
+  #endif
+
+  if (!SzByteBufferCreate(outBuffer, (size_t)unPackSize, allocTemp->Alloc))
+    return SZE_OUTOFMEMORY;
+  
+  res = SzDecode(db->PackSizes, folder, 
+          #ifdef _LZMA_IN_CB
+          inStream, dataStartPos, 
+          #else
+          *inBuffer, 
+          #endif
+          outBuffer->Items, (size_t)unPackSize, allocTemp);
+  RINOK(res)
+  if (folder->UnPackCRCDefined)
+    if (CrcCalc(outBuffer->Items, (size_t)unPackSize) != folder->UnPackCRC)
+      return SZE_FAIL;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadAndDecodePackedStreams(
+    ISzInStream *inStream, 
+    CSzData *sd,
+    CSzByteBuffer *outBuffer,
+    CFileSize baseOffset, 
+    ISzAlloc *allocTemp)
+{
+  CArchiveDatabase db;
+  CFileSize *unPackSizes = 0;
+  Byte *digestsDefined = 0;
+  UInt32 *digests = 0;
+  #ifndef _LZMA_IN_CB
+  Byte *inBuffer = 0;
+  #endif
+  SZ_RESULT res;
+  SzArchiveDatabaseInit(&db);
+  res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, 
+    &db, &unPackSizes, &digestsDefined, &digests, 
+    #ifndef _LZMA_IN_CB
+    &inBuffer,
+    #endif
+    allocTemp);
+  SzArchiveDatabaseFree(&db, allocTemp->Free);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  #ifndef _LZMA_IN_CB
+  allocTemp->Free(inBuffer);
+  #endif
+  return res;
+}
+
+SZ_RESULT SzArchiveOpen2(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  Byte signature[k7zSignatureSize];
+  Byte version;
+  UInt32 crcFromArchive;
+  UInt64 nextHeaderOffset;
+  UInt64 nextHeaderSize;
+  UInt32 nextHeaderCRC;
+  UInt32 crc = 0;
+  CFileSize pos = 0;
+  CSzByteBuffer buffer;
+  CSzData sd;
+  SZ_RESULT res;
+
+  RINOK(SafeReadDirect(inStream, signature, k7zSignatureSize));
+
+  if (!TestSignatureCandidate(signature))
+    return SZE_ARCHIVE_ERROR;
+
+  /*
+  db.Clear();
+  db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+  */
+  RINOK(SafeReadDirectByte(inStream, &version));
+  if (version != k7zMajorVersion)
+    return SZE_ARCHIVE_ERROR;
+  RINOK(SafeReadDirectByte(inStream, &version));
+
+  RINOK(SafeReadDirectUInt32(inStream, &crcFromArchive, &crc));
+
+  crc = CRC_INIT_VAL;
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderOffset, &crc));
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderSize, &crc));
+  RINOK(SafeReadDirectUInt32(inStream, &nextHeaderCRC, &crc));
+
+  pos = k7zStartHeaderSize;
+  db->ArchiveInfo.StartPositionAfterHeader = pos;
+  
+  if (CRC_GET_DIGEST(crc) != crcFromArchive)
+    return SZE_ARCHIVE_ERROR;
+
+  if (nextHeaderSize == 0)
+    return SZ_OK;
+
+  RINOK(inStream->Seek(inStream, (CFileSize)(pos + nextHeaderOffset)));
+
+  if (!SzByteBufferCreate(&buffer, (size_t)nextHeaderSize, allocTemp->Alloc))
+    return SZE_OUTOFMEMORY;
+
+  res = SafeReadDirect(inStream, buffer.Items, (size_t)nextHeaderSize);
+  if (res == SZ_OK)
+  {
+    res = SZE_ARCHIVE_ERROR;
+    if (CrcCalc(buffer.Items, (UInt32)nextHeaderSize) == nextHeaderCRC)
+    {
+      for (;;)
+      {
+        UInt64 type;
+        sd.Data = buffer.Items;
+        sd.Size = buffer.Capacity;
+        res = SzReadID(&sd, &type);
+        if (res != SZ_OK)
+          break;
+        if (type == k7zIdHeader)
+        {
+          res = SzReadHeader(&sd, db, allocMain, allocTemp);
+          break;
+        }
+        if (type != k7zIdEncodedHeader)
+        {
+          res = SZE_ARCHIVE_ERROR;
+          break;
+        }
+        {
+          CSzByteBuffer outBuffer;
+          res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, 
+              db->ArchiveInfo.StartPositionAfterHeader, 
+              allocTemp);
+          if (res != SZ_OK)
+          {
+            SzByteBufferFree(&outBuffer, allocTemp->Free);
+            break;
+          }
+          SzByteBufferFree(&buffer, allocTemp->Free);
+          buffer.Items = outBuffer.Items;
+          buffer.Capacity = outBuffer.Capacity;
+        }
+      }
+    }
+  }
+  SzByteBufferFree(&buffer, allocTemp->Free);
+  return res;
+}
+
+SZ_RESULT SzArchiveOpen(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  SZ_RESULT res = SzArchiveOpen2(inStream, db, allocMain, allocTemp);
+  if (res != SZ_OK)
+    SzArDbExFree(db, allocMain->Free);
+  return res;
+}
diff --git a/lzma/C/Archive/7z/7zIn.h b/lzma/C/Archive/7z/7zIn.h
new file mode 100644 (file)
index 0000000..0b4ca08
--- /dev/null
@@ -0,0 +1,55 @@
+/* 7zIn.h */
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "7zHeader.h"
+#include "7zItem.h"
+#include "7zAlloc.h"
+typedef struct _CInArchiveInfo
+{
+  CFileSize StartPositionAfterHeader; 
+  CFileSize DataStartPosition;
+}CInArchiveInfo;
+
+typedef struct _CArchiveDatabaseEx
+{
+  CArchiveDatabase Database;
+  CInArchiveInfo ArchiveInfo;
+  UInt32 *FolderStartPackStreamIndex;
+  CFileSize *PackStreamStartPositions;
+  UInt32 *FolderStartFileIndex;
+  UInt32 *FileIndexToFolderIndexMap;
+}CArchiveDatabaseEx;
+
+void SzArDbExInit(CArchiveDatabaseEx *db);
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *));
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex, CFileSize *resSize);
+
+typedef struct _ISzInStream
+{
+  #ifdef _LZMA_IN_CB
+  SZ_RESULT (*Read)(
+      void *object,           /* pointer to ISzInStream itself */
+      void **buffer,          /* out: pointer to buffer with data */
+      size_t maxRequiredSize, /* max required size to read */
+      size_t *processedSize); /* real processed size. 
+                                 processedSize can be less than maxRequiredSize.
+                                 If processedSize == 0, then there are no more 
+                                 bytes in stream. */
+  #else
+  SZ_RESULT (*Read)(void *object, void *buffer, size_t size, size_t *processedSize);
+  #endif
+  SZ_RESULT (*Seek)(void *object, CFileSize pos);
+} ISzInStream;
+
+int SzArchiveOpen(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp);
+#endif
diff --git a/lzma/C/Archive/7z/7zItem.c b/lzma/C/Archive/7z/7zItem.c
new file mode 100644 (file)
index 0000000..a88afe9
--- /dev/null
@@ -0,0 +1,134 @@
+/* 7zItem.c */
+
+#include "7zItem.h"
+#include "7zAlloc.h"
+
+void SzCoderInfoInit(CCoderInfo *coder)
+{
+  SzByteBufferInit(&coder->Properties);
+}
+
+void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p))
+{
+  SzByteBufferFree(&coder->Properties, freeFunc);
+  SzCoderInfoInit(coder);
+}
+
+void SzFolderInit(CFolder *folder)
+{
+  folder->NumCoders = 0;
+  folder->Coders = 0;
+  folder->NumBindPairs = 0;
+  folder->BindPairs = 0;
+  folder->NumPackStreams = 0;
+  folder->PackStreams = 0;
+  folder->UnPackSizes = 0;
+  folder->UnPackCRCDefined = 0;
+  folder->UnPackCRC = 0;
+  folder->NumUnPackStreams = 0;
+}
+
+void SzFolderFree(CFolder *folder, void (*freeFunc)(void *p))
+{
+  UInt32 i;
+  for (i = 0; i < folder->NumCoders; i++)
+    SzCoderInfoFree(&folder->Coders[i], freeFunc);
+  freeFunc(folder->Coders);
+  freeFunc(folder->BindPairs);
+  freeFunc(folder->PackStreams);
+  freeFunc(folder->UnPackSizes);
+  SzFolderInit(folder);
+}
+
+UInt32 SzFolderGetNumOutStreams(CFolder *folder)
+{
+  UInt32 result = 0;
+  UInt32 i;
+  for (i = 0; i < folder->NumCoders; i++)
+    result += folder->Coders[i].NumOutStreams;
+  return result;
+}
+
+int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex)
+{
+  UInt32 i;
+  for(i = 0; i < folder->NumBindPairs; i++)
+    if (folder->BindPairs[i].InIndex == inStreamIndex)
+      return i;
+  return -1;
+}
+
+
+int SzFolderFindBindPairForOutStream(CFolder *folder, UInt32 outStreamIndex)
+{
+  UInt32 i;
+  for(i = 0; i < folder->NumBindPairs; i++)
+    if (folder->BindPairs[i].OutIndex == outStreamIndex)
+      return i;
+  return -1;
+}
+
+CFileSize SzFolderGetUnPackSize(CFolder *folder)
+{ 
+  int i = (int)SzFolderGetNumOutStreams(folder);
+  if (i == 0)
+    return 0;
+  for (i--; i >= 0; i--)
+    if (SzFolderFindBindPairForOutStream(folder, i) < 0)
+      return folder->UnPackSizes[i];
+  /* throw 1; */
+  return 0;
+}
+
+/*
+int FindPackStreamArrayIndex(int inStreamIndex) const
+{
+  for(int i = 0; i < PackStreams.Size(); i++)
+  if (PackStreams[i] == inStreamIndex)
+    return i;
+  return -1;
+}
+*/
+
+void SzFileInit(CFileItem *fileItem)
+{
+  fileItem->IsFileCRCDefined = 0;
+  fileItem->HasStream = 1;
+  fileItem->IsDirectory = 0;
+  fileItem->IsAnti = 0;
+  fileItem->IsLastWriteTimeDefined = 0;
+  fileItem->Name = 0;
+}
+
+void SzFileFree(CFileItem *fileItem, void (*freeFunc)(void *p))
+{
+  freeFunc(fileItem->Name);
+  SzFileInit(fileItem);
+}
+
+void SzArchiveDatabaseInit(CArchiveDatabase *db)
+{
+  db->NumPackStreams = 0;
+  db->PackSizes = 0;
+  db->PackCRCsDefined = 0;
+  db->PackCRCs = 0;
+  db->NumFolders = 0;
+  db->Folders = 0;
+  db->NumFiles = 0;
+  db->Files = 0;
+}
+
+void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *))
+{
+  UInt32 i;
+  for (i = 0; i < db->NumFolders; i++)
+    SzFolderFree(&db->Folders[i], freeFunc);
+  for (i = 0; i < db->NumFiles; i++)
+    SzFileFree(&db->Files[i], freeFunc);
+  freeFunc(db->PackSizes);
+  freeFunc(db->PackCRCsDefined);
+  freeFunc(db->PackCRCs);
+  freeFunc(db->Folders);
+  freeFunc(db->Files);
+  SzArchiveDatabaseInit(db);
+}
diff --git a/lzma/C/Archive/7z/7zItem.h b/lzma/C/Archive/7z/7zItem.h
new file mode 100644 (file)
index 0000000..05567bf
--- /dev/null
@@ -0,0 +1,95 @@
+/* 7zItem.h */
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "7zMethodID.h"
+#include "7zHeader.h"
+#include "7zBuffer.h"
+
+typedef struct _CCoderInfo
+{
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+  CMethodID MethodID;
+  CSzByteBuffer Properties;
+}CCoderInfo;
+
+void SzCoderInfoInit(CCoderInfo *coder);
+void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p));
+
+typedef struct _CBindPair
+{
+  UInt32 InIndex;
+  UInt32 OutIndex;
+}CBindPair;
+
+typedef struct _CFolder
+{
+  UInt32 NumCoders;
+  CCoderInfo *Coders;
+  UInt32 NumBindPairs;
+  CBindPair *BindPairs;
+  UInt32 NumPackStreams; 
+  UInt32 *PackStreams;
+  CFileSize *UnPackSizes;
+  int UnPackCRCDefined;
+  UInt32 UnPackCRC;
+
+  UInt32 NumUnPackStreams;
+}CFolder;
+
+void SzFolderInit(CFolder *folder);
+CFileSize SzFolderGetUnPackSize(CFolder *folder);
+int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex);
+UInt32 SzFolderGetNumOutStreams(CFolder *folder);
+CFileSize SzFolderGetUnPackSize(CFolder *folder);
+
+typedef struct _CArchiveFileTime
+{
+  UInt32 Low;
+  UInt32 High;
+} CArchiveFileTime;
+
+typedef struct _CFileItem
+{
+  CArchiveFileTime LastWriteTime;
+  /*
+  CFileSize StartPos;
+  UInt32 Attributes; 
+  */
+  CFileSize Size;
+  UInt32 FileCRC;
+  char *Name;
+
+  Byte IsFileCRCDefined;
+  Byte HasStream;
+  Byte IsDirectory;
+  Byte IsAnti;
+  Byte IsLastWriteTimeDefined;
+  /*
+  int AreAttributesDefined;
+  int IsLastWriteTimeDefined;
+  int IsStartPosDefined;
+  */
+}CFileItem;
+
+void SzFileInit(CFileItem *fileItem);
+
+typedef struct _CArchiveDatabase
+{
+  UInt32 NumPackStreams;
+  CFileSize *PackSizes;
+  Byte *PackCRCsDefined;
+  UInt32 *PackCRCs;
+  UInt32 NumFolders;
+  CFolder *Folders;
+  UInt32 NumFiles;
+  CFileItem *Files;
+}CArchiveDatabase;
+
+void SzArchiveDatabaseInit(CArchiveDatabase *db);
+void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *));
+
+
+#endif
diff --git a/lzma/C/Archive/7z/7zMain.c b/lzma/C/Archive/7z/7zMain.c
new file mode 100644 (file)
index 0000000..0deef89
--- /dev/null
@@ -0,0 +1,428 @@
+/* 
+7zMain.c
+Test application for 7z Decoder
+LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-06-04)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define USE_WINDOWS_FUNCTIONS
+#endif
+
+#ifdef USE_WINDOWS_FUNCTIONS
+#include <windows.h>
+#endif
+
+#include "7zIn.h"
+#include "7zExtract.h"
+
+#include "../../7zCrc.h"
+
+
+#ifdef USE_WINDOWS_FUNCTIONS
+typedef HANDLE MY_FILE_HANDLE;
+#else
+typedef FILE *MY_FILE_HANDLE;
+#endif
+
+void ConvertNumberToString(CFileSize value, char *s)
+{
+  char temp[32];
+  int pos = 0;
+  do 
+  {
+    temp[pos++] = (char)('0' + (int)(value % 10));
+    value /= 10;
+  }
+  while (value != 0);
+  do
+    *s++ = temp[--pos];
+  while(pos > 0);
+  *s = '\0';
+}
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+void ConvertFileTimeToString(CArchiveFileTime *ft, char *s)
+{
+  unsigned year, mon, day, hour, min, sec;
+  UInt64 v64 = ft->Low | ((UInt64)ft->High << 32);
+  Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  unsigned temp;
+  UInt32 v; 
+  v64 /= 10000000;
+  sec = (unsigned)(v64 % 60);
+  v64 /= 60;
+  min = (unsigned)(v64 % 60);
+  v64 /= 60;
+  hour = (unsigned)(v64 % 24);
+  v64 /= 24;
+
+  v = (UInt32)v64;
+
+  year = (unsigned)(1601 + v / PERIOD_400 * 400);
+  v %= PERIOD_400;
+
+  temp = (unsigned)(v / PERIOD_100);
+  if (temp == 4)
+    temp = 3;
+  year += temp * 100;
+  v -= temp * PERIOD_100;
+
+  temp = v / PERIOD_4;
+  if (temp == 25)
+    temp = 24;
+  year += temp * 4;
+  v -= temp * PERIOD_4;
+
+  temp = v / 365;
+  if (temp == 4)
+    temp = 3;
+  year += temp;
+  v -= temp * 365;
+
+  if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+    ms[1] = 29;
+  for (mon = 1; mon <= 12; mon++)
+  {
+    unsigned s = ms[mon - 1];
+    if (v < s)
+      break;
+    v -= s;
+  }
+  day = (unsigned)v + 1;
+  sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
+}
+
+
+#ifdef USE_WINDOWS_FUNCTIONS
+/*
+   ReadFile and WriteFile functions in Windows have BUG:
+   If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 
+   from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 
+   (Insufficient system resources exist to complete the requested service).
+*/
+#define kChunkSizeMax (1 << 24)
+#endif
+
+size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  #ifdef USE_WINDOWS_FUNCTIONS
+  {
+    size_t processedSize = 0;
+    do
+    {
+      DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
+      DWORD processedLoc = 0;
+      BOOL res = ReadFile(file, data, curSize, &processedLoc, NULL);
+      data = (void *)((unsigned char *)data + processedLoc);
+      size -= processedLoc;
+      processedSize += processedLoc;
+      if (!res || processedLoc == 0)
+        break;
+    }
+    while (size > 0);
+    return processedSize;
+  }
+  #else
+  return fread(data, 1, size, file); 
+  #endif
+}
+
+size_t MyWriteFile(MY_FILE_HANDLE file, void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  #ifdef USE_WINDOWS_FUNCTIONS
+  {
+    size_t processedSize = 0;
+    do
+    {
+      DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
+      DWORD processedLoc = 0;
+      BOOL res = WriteFile(file, data, curSize, &processedLoc, NULL);
+      data = (void *)((unsigned char *)data + processedLoc);
+      size -= processedLoc;
+      processedSize += processedLoc;
+      if (!res)
+        break;
+    }
+    while (size > 0);
+    return processedSize;
+  }
+  #else
+  return fwrite(data, 1, size, file); 
+  #endif
+}
+
+int MyCloseFile(MY_FILE_HANDLE file)
+{ 
+  #ifdef USE_WINDOWS_FUNCTIONS
+  return (CloseHandle(file) != FALSE) ? 0 : 1;
+  #else
+  return fclose(file); 
+  #endif
+}
+
+typedef struct _CFileInStream
+{
+  ISzInStream InStream;
+  MY_FILE_HANDLE File;
+} CFileInStream;
+
+#ifdef _LZMA_IN_CB
+
+#define kBufferSize (1 << 12)
+Byte g_Buffer[kBufferSize];
+
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
+{
+  CFileInStream *s = (CFileInStream *)object;
+  size_t processedSizeLoc;
+  if (maxRequiredSize > kBufferSize)
+    maxRequiredSize = kBufferSize;
+  processedSizeLoc = MyReadFile(s->File, g_Buffer, maxRequiredSize);
+  *buffer = g_Buffer;
+  if (processedSize != 0)
+    *processedSize = processedSizeLoc;
+  return SZ_OK;
+}
+
+#else
+
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
+{
+  CFileInStream *s = (CFileInStream *)object;
+  size_t processedSizeLoc = MyReadFile(s->File, buffer, size);
+  if (processedSize != 0)
+    *processedSize = processedSizeLoc;
+  return SZ_OK;
+}
+
+#endif
+
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+  CFileInStream *s = (CFileInStream *)object;
+
+  #ifdef USE_WINDOWS_FUNCTIONS
+  {
+    LARGE_INTEGER value;
+    value.LowPart = (DWORD)pos;
+    value.HighPart = (LONG)((UInt64)pos >> 32);
+    #ifdef _SZ_FILE_SIZE_32
+    /* VC 6.0 has bug with >> 32 shifts. */
+    value.HighPart = 0;
+    #endif
+    value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart, FILE_BEGIN);
+    if (value.LowPart == 0xFFFFFFFF)
+      if(GetLastError() != NO_ERROR) 
+        return SZE_FAIL;
+    return SZ_OK;
+  }
+  #else
+  int res = fseek(s->File, (long)pos, SEEK_SET);
+  if (res == 0)
+    return SZ_OK;
+  return SZE_FAIL;
+  #endif
+}
+
+void PrintError(char *sz)
+{
+  printf("\nERROR: %s\n", sz);
+}
+
+int main(int numargs, char *args[])
+{
+  CFileInStream archiveStream;
+  CArchiveDatabaseEx db;
+  SZ_RESULT res;
+  ISzAlloc allocImp;
+  ISzAlloc allocTempImp;
+
+  printf("\n7z ANSI-C Decoder 4.48  Copyright (c) 1999-2007 Igor Pavlov  2007-06-21\n");
+  if (numargs == 1)
+  {
+    printf(
+      "\nUsage: 7zDec <command> <archive_name>\n\n"
+      "<Commands>\n"
+      "  e: Extract files from archive\n"
+      "  l: List contents of archive\n"
+      "  t: Test integrity of archive\n");
+    return 0;
+  }
+  if (numargs < 3)
+  {
+    PrintError("incorrect command");
+    return 1;
+  }
+
+  archiveStream.File = 
+  #ifdef USE_WINDOWS_FUNCTIONS
+  CreateFile(args[2], GENERIC_READ, FILE_SHARE_READ, 
+      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (archiveStream.File == INVALID_HANDLE_VALUE)
+  #else
+  archiveStream.File = fopen(args[2], "rb");
+  if (archiveStream.File == 0)
+  #endif
+  {
+    PrintError("can not open input file");
+    return 1;
+  }
+
+  archiveStream.InStream.Read = SzFileReadImp;
+  archiveStream.InStream.Seek = SzFileSeekImp;
+
+  allocImp.Alloc = SzAlloc;
+  allocImp.Free = SzFree;
+
+  allocTempImp.Alloc = SzAllocTemp;
+  allocTempImp.Free = SzFreeTemp;
+
+  CrcGenerateTable();
+
+  SzArDbExInit(&db);
+  res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
+  if (res == SZ_OK)
+  {
+    char *command = args[1];
+    int listCommand = 0;
+    int testCommand = 0;
+    int extractCommand = 0;
+    if (strcmp(command, "l") == 0)
+      listCommand = 1;
+    if (strcmp(command, "t") == 0)
+      testCommand = 1;
+    else if (strcmp(command, "e") == 0)
+      extractCommand = 1;
+
+    if (listCommand)
+    {
+      UInt32 i;
+      for (i = 0; i < db.Database.NumFiles; i++)
+      {
+        CFileItem *f = db.Database.Files + i;
+        char s[32], t[32];
+        ConvertNumberToString(f->Size, s);
+        if (f->IsLastWriteTimeDefined)
+          ConvertFileTimeToString(&f->LastWriteTime, t);
+        else
+          strcpy(t, "                   ");
+
+        printf("%10s %s  %s\n", s, t, f->Name);
+      }
+    }
+    else if (testCommand || extractCommand)
+    {
+      UInt32 i;
+
+      /*
+      if you need cache, use these 3 variables.
+      if you use external function, you can make these variable as static.
+      */
+      UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
+      Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
+      size_t outBufferSize = 0;  /* it can have any value before first call (if outBuffer = 0) */
+
+      printf("\n");
+      for (i = 0; i < db.Database.NumFiles; i++)
+      {
+        size_t offset;
+        size_t outSizeProcessed;
+        CFileItem *f = db.Database.Files + i;
+        if (f->IsDirectory)
+          printf("Directory ");
+        else
+          printf(testCommand ? 
+            "Testing   ":
+            "Extracting");
+        printf(" %s", f->Name);
+        if (f->IsDirectory)
+        {
+          printf("\n");
+          continue;
+        }
+        res = SzExtract(&archiveStream.InStream, &db, i, 
+            &blockIndex, &outBuffer, &outBufferSize, 
+            &offset, &outSizeProcessed, 
+            &allocImp, &allocTempImp);
+        if (res != SZ_OK)
+          break;
+        if (!testCommand)
+        {
+          MY_FILE_HANDLE outputHandle;
+          size_t processedSize;
+          char *fileName = f->Name;
+          size_t nameLen = strlen(f->Name);
+          for (; nameLen > 0; nameLen--)
+            if (f->Name[nameLen - 1] == '/')
+            {
+              fileName = f->Name + nameLen;
+              break;
+            }
+            
+          outputHandle = 
+          #ifdef USE_WINDOWS_FUNCTIONS
+            CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ, 
+                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+          if (outputHandle == INVALID_HANDLE_VALUE)
+          #else
+          fopen(fileName, "wb+");
+          if (outputHandle == 0)
+          #endif
+          {
+            PrintError("can not open output file");
+            res = SZE_FAIL;
+            break;
+          }
+          processedSize = MyWriteFile(outputHandle, outBuffer + offset, outSizeProcessed);
+          if (processedSize != outSizeProcessed)
+          {
+            PrintError("can not write output file");
+            res = SZE_FAIL;
+            break;
+          }
+          if (MyCloseFile(outputHandle))
+          {
+            PrintError("can not close output file");
+            res = SZE_FAIL;
+            break;
+          }
+        }
+        printf("\n");
+      }
+      allocImp.Free(outBuffer);
+    }
+    else
+    {
+      PrintError("incorrect command");
+      res = SZE_FAIL;
+    }
+  }
+  SzArDbExFree(&db, allocImp.Free);
+
+  MyCloseFile(archiveStream.File);
+  if (res == SZ_OK)
+  {
+    printf("\nEverything is Ok\n");
+    return 0;
+  }
+  if (res == (SZ_RESULT)SZE_NOTIMPL)
+    PrintError("decoder doesn't support this archive");
+  else if (res == (SZ_RESULT)SZE_OUTOFMEMORY)
+    PrintError("can not allocate memory");
+  else if (res == (SZ_RESULT)SZE_CRC_ERROR)
+    PrintError("CRC error");
+  else     
+    printf("\nERROR #%d\n", res);
+  return 1;
+}
diff --git a/lzma/C/Archive/7z/7zMethodID.c b/lzma/C/Archive/7z/7zMethodID.c
new file mode 100644 (file)
index 0000000..a7e825d
--- /dev/null
@@ -0,0 +1,10 @@
+/* 7zMethodID.c */
+
+#include "7zMethodID.h"
+
+/*
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2)
+{
+  return (*a1 == *a2) ? 1 : 0;
+}
+*/
diff --git a/lzma/C/Archive/7z/7zMethodID.h b/lzma/C/Archive/7z/7zMethodID.h
new file mode 100644 (file)
index 0000000..57f22a5
--- /dev/null
@@ -0,0 +1,10 @@
+/* 7zMethodID.h */
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Types.h"
+
+typedef UInt64 CMethodID;
+
+#endif
diff --git a/lzma/C/Archive/7z/7z_C.dsp b/lzma/C/Archive/7z/7z_C.dsp
new file mode 100644 (file)
index 0000000..9a040ad
--- /dev/null
@@ -0,0 +1,211 @@
+# Microsoft Developer Studio Project File - Name="7z_C" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=7z_C - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "7z_C.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "7z_C.mak" CFG="7z_C - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "7z_C - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "7z_C - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "7z_C - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zDec.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "7z_C - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zDec.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "7z_C - Win32 Release"
+# Name "7z_C - Win32 Debug"
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma\LzmaDecode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma\LzmaDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma\LzmaTypes.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7zCrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Types.h
+# End Source File
+# End Group
+# Begin Group "Branch"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86_2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86_2.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zAlloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zAlloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zBuffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMethodID.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMethodID.h
+# End Source File
+# End Target
+# End Project
diff --git a/lzma/C/Archive/7z/7z_C.dsw b/lzma/C/Archive/7z/7z_C.dsw
new file mode 100644 (file)
index 0000000..6fd3962
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7z_C"=.\7z_C.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/C/Archive/7z/makefile b/lzma/C/Archive/7z/makefile
new file mode 100644 (file)
index 0000000..6ea3119
--- /dev/null
@@ -0,0 +1,74 @@
+PROG = 7zDec.exe
+
+!IFDEF CPU
+LIBS = $(LIBS) bufferoverflowU.lib 
+CFLAGS = $(CFLAGS) -GS- -Zc:forScope -WX -GS- -Gy -W4 
+!ENDIF
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -D_LZMA_IN_CB
+CFLAGS_O1 = $(CFLAGS) -O1
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98 -OPT:REF
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1   = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2   = $(CPP) $(CFLAGS_O2) $**
+COMPL      = $(CPP) $(CFLAGS_O1) $**
+
+C_OBJS = \
+  $O\7zCrc.obj \
+
+
+7Z_OBJS = \
+  $O\7zAlloc.obj \
+  $O\7zBuffer.obj \
+  $O\7zDecode.obj \
+  $O\7zExtract.obj \
+  $O\7zHeader.obj \
+  $O\7zIn.obj \
+  $O\7zItem.obj \
+  $O\7zMain.obj \
+  $O\7zMethodID.obj \
+
+OBJS = \
+  $(7Z_OBJS) \
+  $O\LzmaDecode.obj \
+  $O\BranchX86.obj \
+  $O\BranchX86_2.obj \
+  $(C_OBJS) \
+
+all: $(PROGPATH) 
+
+clean:
+       -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch 
+
+$O:
+       if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS)
+       link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+
+$(7Z_OBJS): $(*B).c
+       $(COMPL)
+$O\LzmaDecode.obj: ../../Compress/Lzma/$(*B).c
+       $(COMPL_O2)
+
+$O\BranchX86.obj: ../../Compress/Branch/$(*B).c
+       $(COMPL_O2)
+
+$O\BranchX86_2.obj: ../../Compress/Branch/$(*B).c
+       $(COMPL_O2)
+
+$(C_OBJS): ../../$(*B).c
+       $(COMPL_O2)
diff --git a/lzma/C/Archive/7z/makefile.gcc b/lzma/C/Archive/7z/makefile.gcc
new file mode 100644 (file)
index 0000000..664ac25
--- /dev/null
@@ -0,0 +1,55 @@
+PROG = 7zDec
+CXX = g++
+LIB = 
+RM = rm -f
+CFLAGS = -c -O2 -Wall -D_LZMA_IN_CB
+
+OBJS = 7zAlloc.o 7zBuffer.o 7zCrc.o 7zDecode.o 7zExtract.o 7zHeader.o 7zIn.o 7zItem.o 7zMain.o 7zMethodID.o LzmaDecode.o BranchX86.o BranchX86_2.o
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+       $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
+
+7zAlloc.o: 7zAlloc.c
+       $(CXX) $(CFLAGS) 7zAlloc.c
+
+7zBuffer.o: 7zBuffer.c
+       $(CXX) $(CFLAGS) 7zBuffer.c
+
+7zCrc.o: ../../7zCrc.c
+       $(CXX) $(CFLAGS) ../../7zCrc.c
+
+7zDecode.o: 7zDecode.c
+       $(CXX) $(CFLAGS) 7zDecode.c
+
+7zExtract.o: 7zExtract.c
+       $(CXX) $(CFLAGS) 7zExtract.c
+
+7zHeader.o: 7zHeader.c
+       $(CXX) $(CFLAGS) 7zHeader.c
+
+7zIn.o: 7zIn.c
+       $(CXX) $(CFLAGS) 7zIn.c
+
+7zItem.o: 7zItem.c
+       $(CXX) $(CFLAGS) 7zItem.c
+
+7zMain.o: 7zMain.c
+       $(CXX) $(CFLAGS) 7zMain.c
+
+7zMethodID.o: 7zMethodID.c
+       $(CXX) $(CFLAGS) 7zMethodID.c
+
+LzmaDecode.o: ../../Compress/Lzma/LzmaDecode.c
+       $(CXX) $(CFLAGS) ../../Compress/Lzma/LzmaDecode.c
+
+BranchX86.o: ../../Compress/Branch/BranchX86.c
+       $(CXX) $(CFLAGS) ../../Compress/Branch/BranchX86.c
+
+BranchX86_2.o: ../../Compress/Branch/BranchX86_2.c
+       $(CXX) $(CFLAGS) ../../Compress/Branch/BranchX86_2.c
+
+clean:
+       -$(RM) $(PROG) $(OBJS)
+
diff --git a/lzma/C/Compress/Branch/BranchARM.c b/lzma/C/Compress/Branch/BranchARM.c
new file mode 100644 (file)
index 0000000..da7db26
--- /dev/null
@@ -0,0 +1,26 @@
+/* BranchARM.c */
+
+#include "BranchARM.h"
+
+UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 4)
+  {
+    if (data[i + 3] == 0xEB)
+    {
+      UInt32 dest;
+      UInt32 src = (data[i + 2] << 16) | (data[i + 1] << 8) | (data[i + 0]);
+      src <<= 2;
+      if (encoding)
+        dest = nowPos + i + 8 + src;
+      else
+        dest = src - (nowPos + i + 8);
+      dest >>= 2;
+      data[i + 2] = (Byte)(dest >> 16);
+      data[i + 1] = (Byte)(dest >> 8);
+      data[i + 0] = (Byte)dest;
+    }
+  }
+  return i;
+}
diff --git a/lzma/C/Compress/Branch/BranchARM.h b/lzma/C/Compress/Branch/BranchARM.h
new file mode 100644 (file)
index 0000000..3b4d63e
--- /dev/null
@@ -0,0 +1,10 @@
+/* BranchARM.h */
+
+#ifndef __BRANCH_ARM_H
+#define __BRANCH_ARM_H
+
+#include "BranchTypes.h"
+
+UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchARMThumb.c b/lzma/C/Compress/Branch/BranchARMThumb.c
new file mode 100644 (file)
index 0000000..fa30e43
--- /dev/null
@@ -0,0 +1,35 @@
+/* BranchARMThumb.c */
+
+#include "BranchARMThumb.h"
+
+UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 2)
+  {
+    if ((data[i + 1] & 0xF8) == 0xF0 && 
+        (data[i + 3] & 0xF8) == 0xF8)
+    {
+      UInt32 dest;
+      UInt32 src = 
+        ((data[i + 1] & 0x7) << 19) |
+        (data[i + 0] << 11) |
+        ((data[i + 3] & 0x7) << 8) |
+        (data[i + 2]);
+      
+      src <<= 1;
+      if (encoding)
+        dest = nowPos + i + 4 + src;
+      else
+        dest = src - (nowPos + i + 4);
+      dest >>= 1;
+      
+      data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
+      data[i + 0] = (Byte)(dest >> 11);
+      data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
+      data[i + 2] = (Byte)dest;
+      i += 2;
+    }
+  }
+  return i;
+}
diff --git a/lzma/C/Compress/Branch/BranchARMThumb.h b/lzma/C/Compress/Branch/BranchARMThumb.h
new file mode 100644 (file)
index 0000000..304699c
--- /dev/null
@@ -0,0 +1,10 @@
+/* BranchARMThumb.h */
+
+#ifndef __BRANCH_ARM_THUMB_H
+#define __BRANCH_ARM_THUMB_H
+
+#include "BranchTypes.h"
+
+UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchIA64.c b/lzma/C/Compress/Branch/BranchIA64.c
new file mode 100644 (file)
index 0000000..009086b
--- /dev/null
@@ -0,0 +1,66 @@
+/* BranchIA64.c */
+
+#include "BranchIA64.h"
+
+const Byte kBranchTable[32] = 
+{ 
+  0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,
+  4, 4, 6, 6, 0, 0, 7, 7,
+  4, 4, 0, 0, 4, 4, 0, 0 
+};
+
+UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 16 <= size; i += 16)
+  {
+    UInt32 instrTemplate = data[i] & 0x1F;
+    UInt32 mask = kBranchTable[instrTemplate];
+    UInt32 bitPos = 5;
+    int slot;
+    for (slot = 0; slot < 3; slot++, bitPos += 41)
+    {
+      UInt32 bytePos, bitRes;
+      UInt64 instruction, instNorm;
+      int j;
+      if (((mask >> slot) & 1) == 0)
+        continue;
+      bytePos = (bitPos >> 3);
+      bitRes = bitPos & 0x7;
+      instruction = 0;
+      for (j = 0; j < 6; j++)
+        instruction += (UInt64)(data[i + j + bytePos]) << (8 * j);
+
+      instNorm = instruction >> bitRes;
+      if (((instNorm >> 37) & 0xF) == 0x5 
+        &&  ((instNorm >> 9) & 0x7) == 0 
+        /* &&  (instNorm & 0x3F)== 0 */
+        )
+      {
+        UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+        UInt32 dest;
+        src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+        
+        src <<= 4;
+        
+        if (encoding)
+          dest = nowPos + i + src;
+        else
+          dest = src - (nowPos + i);
+        
+        dest >>= 4;
+        
+        instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+        instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+        instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+        
+        instruction &= (1 << bitRes) - 1;
+        instruction |= (instNorm << bitRes);
+        for (j = 0; j < 6; j++)
+          data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+      }
+    }
+  }
+  return i;
+}
diff --git a/lzma/C/Compress/Branch/BranchIA64.h b/lzma/C/Compress/Branch/BranchIA64.h
new file mode 100644 (file)
index 0000000..8213cb5
--- /dev/null
@@ -0,0 +1,10 @@
+/* BranchIA64.h */
+
+#ifndef __BRANCH_IA64_H
+#define __BRANCH_IA64_H
+
+#include "BranchTypes.h"
+
+UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchPPC.c b/lzma/C/Compress/Branch/BranchPPC.c
new file mode 100644 (file)
index 0000000..b3e5703
--- /dev/null
@@ -0,0 +1,36 @@
+/* BranchPPC.c */
+
+#include "BranchPPC.h"
+
+UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 4)
+  {
+    /* PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link) */
+    if ((data[i] >> 2) == 0x12 && 
+    (
+      (data[i + 3] & 3) == 1 
+      /* || (data[i+3] & 3) == 3 */
+      )
+    )
+    {
+      UInt32 src = ((data[i + 0] & 3) << 24) |
+        (data[i + 1] << 16) |
+        (data[i + 2] << 8) |
+        (data[i + 3] & (~3));
+      
+      UInt32 dest;
+      if (encoding)
+        dest = nowPos + i + src;
+      else
+        dest = src - (nowPos + i);
+      data[i + 0] = (Byte)(0x48 | ((dest >> 24) &  0x3));
+      data[i + 1] = (Byte)(dest >> 16);
+      data[i + 2] = (Byte)(dest >> 8);
+      data[i + 3] &= 0x3;
+      data[i + 3] |= dest;
+    }
+  }
+  return i;
+}
diff --git a/lzma/C/Compress/Branch/BranchPPC.h b/lzma/C/Compress/Branch/BranchPPC.h
new file mode 100644 (file)
index 0000000..05e2a37
--- /dev/null
@@ -0,0 +1,10 @@
+/* BranchPPC.h */
+
+#ifndef __BRANCH_PPC_H
+#define __BRANCH_PPC_H
+
+#include "BranchTypes.h"
+
+UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchSPARC.c b/lzma/C/Compress/Branch/BranchSPARC.c
new file mode 100644 (file)
index 0000000..79da2ea
--- /dev/null
@@ -0,0 +1,36 @@
+/* BranchSPARC.c */
+
+#include "BranchSPARC.h"
+
+UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 4)
+  {
+    if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 || 
+        data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)
+    {
+      UInt32 src = 
+        ((UInt32)data[i + 0] << 24) |
+        ((UInt32)data[i + 1] << 16) |
+        ((UInt32)data[i + 2] << 8) |
+        ((UInt32)data[i + 3]);
+      UInt32 dest;
+      
+      src <<= 2;
+      if (encoding)
+        dest = nowPos + i + src;
+      else
+        dest = src - (nowPos + i);
+      dest >>= 2;
+      
+      dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+      data[i + 0] = (Byte)(dest >> 24);
+      data[i + 1] = (Byte)(dest >> 16);
+      data[i + 2] = (Byte)(dest >> 8);
+      data[i + 3] = (Byte)dest;
+    }
+  }
+  return i;
+}
diff --git a/lzma/C/Compress/Branch/BranchSPARC.h b/lzma/C/Compress/Branch/BranchSPARC.h
new file mode 100644 (file)
index 0000000..f3f8320
--- /dev/null
@@ -0,0 +1,10 @@
+/* BranchSPARC.h */
+
+#ifndef __BRANCH_SPARC_H
+#define __BRANCH_SPARC_H
+
+#include "BranchTypes.h"
+
+UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchTypes.h b/lzma/C/Compress/Branch/BranchTypes.h
new file mode 100644 (file)
index 0000000..1bed56a
--- /dev/null
@@ -0,0 +1,51 @@
+/* BranchTypes.h */
+
+#ifndef __BRANCHTYPES_H
+#define __BRANCHTYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif
+
+#ifndef _7ZIP_UINT64_DEFINED
+#define _7ZIP_UINT64_DEFINED
+#ifdef _SZ_NO_INT_64
+typedef unsigned long UInt64;
+#else
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 UInt64;
+#else
+typedef unsigned long long int UInt64;
+#endif
+#endif
+#endif
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchX86.c b/lzma/C/Compress/Branch/BranchX86.c
new file mode 100644 (file)
index 0000000..fd1d334
--- /dev/null
@@ -0,0 +1,84 @@
+/* BranchX86.c */
+
+#include "BranchX86.h"
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+SizeT x86_Convert(Byte *buffer, SizeT endPos, UInt32 nowPos, UInt32 *prevMaskMix, int encoding)
+{
+  SizeT bufferPos = 0, prevPosT;
+  UInt32 prevMask = *prevMaskMix & 0x7;
+  if (endPos < 5)
+    return 0;
+  nowPos += 5;
+  prevPosT = (SizeT)0 - 1;
+
+  for(;;)
+  {
+    Byte *p = buffer + bufferPos;
+    Byte *limit = buffer + endPos - 4;
+    for (; p < limit; p++)
+      if ((*p & 0xFE) == 0xE8)
+        break;
+    bufferPos = (SizeT)(p - buffer);
+    if (p >= limit)
+      break;
+    prevPosT = bufferPos - prevPosT;
+    if (prevPosT > 3)
+      prevMask = 0;
+    else
+    {
+      prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+      if (prevMask != 0)
+      {
+        Byte b = p[4 - kMaskToBitNumber[prevMask]];
+        if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+        {
+          prevPosT = bufferPos;
+          prevMask = ((prevMask << 1) & 0x7) | 1;
+          bufferPos++;
+          continue;
+        }
+      }
+    }
+    prevPosT = bufferPos;
+
+    if (Test86MSByte(p[4]))
+    {
+      UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+      UInt32 dest;
+      for (;;)
+      {
+        Byte b;
+        int index;
+        if (encoding)
+          dest = (nowPos + (UInt32)bufferPos) + src;
+        else
+          dest = src - (nowPos + (UInt32)bufferPos);
+        if (prevMask == 0)
+          break;
+        index = kMaskToBitNumber[prevMask] * 8;
+        b = (Byte)(dest >> (24 - index));
+        if (!Test86MSByte(b))
+          break;
+        src = dest ^ ((1 << (32 - index)) - 1);
+      }
+      p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
+      p[3] = (Byte)(dest >> 16);
+      p[2] = (Byte)(dest >> 8);
+      p[1] = (Byte)dest;
+      bufferPos += 5;
+    }
+    else
+    {
+      prevMask = ((prevMask << 1) & 0x7) | 1;
+      bufferPos++;
+    }
+  }
+  prevPosT = bufferPos - prevPosT;
+  *prevMaskMix = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+  return bufferPos;
+}
diff --git a/lzma/C/Compress/Branch/BranchX86.h b/lzma/C/Compress/Branch/BranchX86.h
new file mode 100644 (file)
index 0000000..5dfd02a
--- /dev/null
@@ -0,0 +1,12 @@
+/* BranchX86.h */
+
+#ifndef __BRANCHX86_H
+#define __BRANCHX86_H
+
+#include "BranchTypes.h"
+
+#define x86_Convert_Init(state) { state = 0; }
+
+SizeT x86_Convert(Byte *buffer, SizeT endPos, UInt32 nowPos, UInt32 *state, int encoding);
+
+#endif
diff --git a/lzma/C/Compress/Branch/BranchX86_2.c b/lzma/C/Compress/Branch/BranchX86_2.c
new file mode 100644 (file)
index 0000000..241789a
--- /dev/null
@@ -0,0 +1,135 @@
+// BranchX86_2.c
+
+#include "BranchX86_2.h"
+
+#include "../../Alloc.h"
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
+#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#define RC_TEST { if (Buffer == BufferLim) return BCJ2_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+// #define UpdateBit0(p) Range = bound; *(p) = (CProb)(*(p) + ((kBitModelTotal - *(p)) >> kNumMoveBits));
+// #define UpdateBit1(p) Range -= bound; Code -= bound; *(p) = (CProb)(*(p) - (*(p) >> kNumMoveBits));
+
+int x86_2_Decode(
+    const Byte *buf0, SizeT size0, 
+    const Byte *buf1, SizeT size1, 
+    const Byte *buf2, SizeT size2, 
+    const Byte *buf3, SizeT size3, 
+    Byte *outBuf, SizeT outSize)
+{
+  CProb p[256 + 2];
+  SizeT inPos = 0, outPos = 0;
+
+  const Byte *Buffer, *BufferLim;
+  UInt32 Range, Code;
+  Byte prevByte = 0;
+
+  unsigned int i;
+  for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
+    p[i] = kBitModelTotal >> 1; 
+  RC_INIT(buf3, size3);
+
+  if (outSize == 0)
+    return BCJ2_RESULT_OK;
+
+  for (;;)
+  {
+    Byte b;
+    CProb *prob;
+    UInt32 bound;
+
+    SizeT limit = size0 - inPos;
+    if (outSize - outPos < limit)
+      limit = outSize - outPos;
+    while (limit != 0)
+    {
+      Byte b = buf0[inPos];
+      outBuf[outPos++] = b;
+      if (IsJ(prevByte, b))
+        break;
+      inPos++;
+      prevByte = b;
+      limit--;
+    }
+
+    if (limit == 0 || outPos == outSize)
+      break;
+
+    b = buf0[inPos++];
+
+    if (b == 0xE8)
+      prob = p + prevByte;
+    else if (b == 0xE9)
+      prob = p + 256;
+    else
+      prob = p + 257;
+
+    IfBit0(prob)
+    {
+      UpdateBit0(prob)
+      prevByte = b;
+    }
+    else
+    {
+      UInt32 dest;
+      const Byte *v;
+      UpdateBit1(prob)
+      if (b == 0xE8)
+      {
+        v = buf1;
+        if (size1 < 4)
+          return BCJ2_RESULT_DATA_ERROR;
+        buf1 += 4;
+        size1 -= 4;
+      }
+      else
+      {
+        v = buf2;
+        if (size2 < 4)
+          return BCJ2_RESULT_DATA_ERROR;
+        buf2 += 4;
+        size2 -= 4;
+      }
+      dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | 
+          ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
+      outBuf[outPos++] = (Byte)dest;
+      if (outPos == outSize)
+        break;
+      outBuf[outPos++] = (Byte)(dest >> 8);
+      if (outPos == outSize)
+        break;
+      outBuf[outPos++] = (Byte)(dest >> 16);
+      if (outPos == outSize)
+        break;
+      outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
+    }
+  }
+  return (outPos == outSize) ? BCJ2_RESULT_OK : BCJ2_RESULT_DATA_ERROR;
+}
diff --git a/lzma/C/Compress/Branch/BranchX86_2.h b/lzma/C/Compress/Branch/BranchX86_2.h
new file mode 100644 (file)
index 0000000..4d861fa
--- /dev/null
@@ -0,0 +1,28 @@
+// BranchX86_2.h
+
+#ifndef __BRANCHX86_2_H
+#define __BRANCHX86_2_H
+
+#include "BranchTypes.h"
+
+#define BCJ2_RESULT_OK 0
+#define BCJ2_RESULT_DATA_ERROR 1
+
+/*
+Conditions:
+  outSize <= FullOutputSize, 
+  where FullOutputSize is full size of output stream of x86_2 filter.
+
+If buf0 overlaps outBuf, there are two required conditions:
+  1) (buf0 >= outBuf)
+  2) (buf0 + size0 >= outBuf + FullOutputSize).
+*/
+
+int x86_2_Decode(
+    const Byte *buf0, SizeT size0, 
+    const Byte *buf1, SizeT size1, 
+    const Byte *buf2, SizeT size2, 
+    const Byte *buf3, SizeT size3, 
+    Byte *outBuf, SizeT outSize);
+
+#endif
diff --git a/lzma/C/Compress/Huffman/HuffmanEncode.c b/lzma/C/Compress/Huffman/HuffmanEncode.c
new file mode 100644 (file)
index 0000000..f27607e
--- /dev/null
@@ -0,0 +1,146 @@
+/* Compress/HuffmanEncode.c */
+
+#include "HuffmanEncode.h"
+#include "../../Sort.h"
+
+#define kMaxLen 16
+#define NUM_BITS 10
+#define MASK ((1 << NUM_BITS) - 1)
+
+#define NUM_COUNTERS 64
+
+/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize > 1M */
+#define HUFFMAN_SPEED_OPT
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
+{
+  UInt32 num = 0;
+  /* if (maxLen > 10) maxLen = 10; */
+  {
+    UInt32 i;
+    
+    #ifdef HUFFMAN_SPEED_OPT
+    
+    UInt32 counters[NUM_COUNTERS];
+    for (i = 0; i < NUM_COUNTERS; i++) 
+      counters[i] = 0;
+    for (i = 0; i < numSymbols; i++) 
+    {
+      UInt32 freq = freqs[i];
+      counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
+    }
+    for (i = 1; i < NUM_COUNTERS; i++) 
+    {
+      UInt32 temp = counters[i];
+      counters[i] = num;
+      num += temp;
+    }
+
+    for (i = 0; i < numSymbols; i++) 
+    {
+      UInt32 freq = freqs[i];
+      if (freq == 0)
+        lens[i] = 0;
+      else
+        p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
+    }
+    counters[0] = 0;
+    HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
+    
+    #else
+
+    for (i = 0; i < numSymbols; i++) 
+    {
+      UInt32 freq = freqs[i];
+      if (freq == 0)
+        lens[i] = 0;
+      else
+        p[num++] = i | (freq << NUM_BITS);
+    }
+    HeapSort(p, num);
+
+    #endif
+  }
+
+  if (num < 2) 
+  {
+    int minCode = 0;
+    int maxCode = 1;
+    if (num == 1)
+    {
+      maxCode = p[0] & MASK;
+      if (maxCode == 0)
+        maxCode++;
+    }
+    p[minCode] = 0;
+    p[maxCode] = 1;
+    lens[minCode] = lens[maxCode] = 1;
+    return;
+  }
+  
+  {
+    UInt32 b, e, i;
+  
+    i = b = e = 0;
+    do 
+    {
+      UInt32 n, m, freq;
+      n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+      freq = (p[n] & ~MASK);
+      p[n] = (p[n] & MASK) | (e << NUM_BITS);
+      m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+      freq += (p[m] & ~MASK);
+      p[m] = (p[m] & MASK) | (e << NUM_BITS);
+      p[e] = (p[e] & MASK) | freq;
+      e++;
+    } 
+    while (num - e > 1);
+    
+    {
+      UInt32 lenCounters[kMaxLen + 1];
+      for (i = 0; i <= kMaxLen; i++) 
+        lenCounters[i] = 0;
+      
+      p[--e] &= MASK;
+      lenCounters[1] = 2;
+      while (e > 0) 
+      {
+        UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
+        p[e] = (p[e] & MASK) | (len << NUM_BITS);
+        if (len >= maxLen) 
+          for (len = maxLen - 1; lenCounters[len] == 0; len--);
+        lenCounters[len]--;
+        lenCounters[len + 1] += 2;
+      }
+      
+      {
+        UInt32 len;
+        i = 0;
+        for (len = maxLen; len != 0; len--) 
+        {
+          UInt32 num;
+          for (num = lenCounters[len]; num != 0; num--) 
+            lens[p[i++] & MASK] = (Byte)len;
+        }
+      }
+      
+      {
+        UInt32 nextCodes[kMaxLen + 1];
+        {
+          UInt32 code = 0;
+          UInt32 len;
+          for (len = 1; len <= kMaxLen; len++) 
+            nextCodes[len] = code = (code + lenCounters[len - 1]) << 1;
+        }
+        /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
+
+        {
+          UInt32 i;
+          for (i = 0; i < numSymbols; i++) 
+            p[i] = nextCodes[lens[i]]++;
+        }
+      }
+    }
+  }
+}
diff --git a/lzma/C/Compress/Huffman/HuffmanEncode.h b/lzma/C/Compress/Huffman/HuffmanEncode.h
new file mode 100644 (file)
index 0000000..c8acc28
--- /dev/null
@@ -0,0 +1,18 @@
+/* Compress/HuffmanEncode.h */
+
+#ifndef __COMPRESS_HUFFMANENCODE_H
+#define __COMPRESS_HUFFMANENCODE_H
+
+#include "../../Types.h"
+
+/*
+Conditions:
+  num <= 1024 = 2 ^ NUM_BITS
+  Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
+  maxLen <= 16 = kMaxLen
+  Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
+*/
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
+
+#endif
diff --git a/lzma/C/Compress/Lz/LzHash.h b/lzma/C/Compress/Lz/LzHash.h
new file mode 100644 (file)
index 0000000..87c2836
--- /dev/null
@@ -0,0 +1,53 @@
+/* LzHash.h */
+
+#ifndef __C_LZHASH_H
+#define __C_LZHASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)); \
+  hashValue = (hash4Value ^ (g_CrcTable[cur[4]] << 3)) & p->hashMask; \
+  hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ g_CrcTable[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ g_CrcTable[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+  hash2Value = (g_CrcTable[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/lzma/C/Compress/Lz/MatchFinder.c b/lzma/C/Compress/Lz/MatchFinder.c
new file mode 100644 (file)
index 0000000..0f530fc
--- /dev/null
@@ -0,0 +1,742 @@
+/* MatchFinder.c */
+/* Please call InitCrcTable before */
+
+#include <string.h>
+
+#include "MatchFinder.h"
+#include "LzHash.h"
+
+#include "../../7zCrc.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+  if (!p->directInput)
+  {
+    alloc->Free(p->bufferBase);
+    p->bufferBase = 0;
+  }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+  if (p->directInput)
+  {
+    p->blockSize = blockSize;
+    return 1;
+  }
+  if (p->bufferBase == 0 || p->blockSize != blockSize)
+  {
+    LzInWindow_Free(p, alloc);
+    p->blockSize = blockSize;
+    p->bufferBase = (Byte *)alloc->Alloc(blockSize);
+  }
+  return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+  p->posLimit -= subValue;
+  p->pos -= subValue;
+  p->streamPos -= subValue;
+}
+
+void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+  if (p->streamEndWasReached || p->result != SZ_OK)
+    return;
+  for (;;)
+  {
+    Byte *dest = p->buffer + (p->streamPos - p->pos);
+    UInt32 numReadBytes;
+    UInt32 size = (UInt32)(p->bufferBase + p->blockSize - dest);
+    if (size == 0)
+      return;
+    p->result = p->stream->Read(p->stream, dest, size, &numReadBytes);
+    if (p->result != SZ_OK)
+      return;
+    if (numReadBytes == 0)
+    {
+      p->streamEndWasReached = 1;
+      return;
+    }
+    p->streamPos += numReadBytes;
+    if (p->streamPos - p->pos > p->keepSizeAfter)
+      return;
+  }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+  memmove(p->bufferBase, 
+    p->buffer - p->keepSizeBefore, 
+    p->streamPos - p->pos + p->keepSizeBefore);
+  p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+  /* if (p->streamEndWasReached) return 0; */
+  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+  if (p->streamEndWasReached) 
+    return;
+  if (p->keepSizeAfter >= p->streamPos - p->pos)
+    MatchFinder_ReadBlock(p);
+}
+
+void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+  if (MatchFinder_NeedMove(p))
+    MatchFinder_MoveBlock(p);
+  MatchFinder_ReadBlock(p);
+}
+
+void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+  p->cutValue = 32;
+  p->btMode = 1;
+  p->numHashBytes = 4;
+  /* p->skipModeBits = 0; */
+  p->directInput = 0;
+  p->bigHash = 0;
+}
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+  p->bufferBase = 0;
+  p->directInput = 0;
+  p->hash = 0;
+  MatchFinder_SetDefaultSettings(p);
+}
+
+void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+  alloc->Free(p->hash);
+  p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+  MatchFinder_FreeThisClassMemory(p, alloc);
+  LzInWindow_Free(p, alloc);
+}
+
+CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+  if (sizeInBytes / sizeof(CLzRef) != num)
+    return 0;
+  return (CLzRef *)alloc->Alloc(sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
+    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+    ISzAlloc *alloc)
+{
+  UInt32 sizeReserv;
+  if (historySize > kMaxHistorySize)
+  {
+    MatchFinder_Free(p, alloc);
+    return 0;
+  }
+  sizeReserv = historySize >> 1;
+  if (historySize > ((UInt32)2 << 30))
+    sizeReserv = historySize >> 2;
+  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+  p->keepSizeBefore = historySize + keepAddBufferBefore + 1; 
+  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+  if (LzInWindow_Create(p, sizeReserv, alloc))
+  {
+    UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
+    UInt32 hs;
+    p->matchMaxLen = matchMaxLen;
+    {
+      p->fixedHashSize = 0;
+      if (p->numHashBytes == 2)
+        hs = (1 << 16) - 1;
+      else
+      {
+        hs = historySize - 1;
+        hs |= (hs >> 1);
+        hs |= (hs >> 2);
+        hs |= (hs >> 4);
+        hs |= (hs >> 8);
+        hs >>= 1;
+        /* hs >>= p->skipModeBits; */
+        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+        if (hs > (1 << 24))
+        {
+          if (p->numHashBytes == 3)
+            hs = (1 << 24) - 1;
+          else
+            hs >>= 1;
+        }
+      }
+      p->hashMask = hs;
+      hs++;
+      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+      hs += p->fixedHashSize;
+    }
+
+    {
+      UInt32 prevSize = p->hashSizeSum + p->numSons;
+      UInt32 newSize;
+      p->historySize = historySize;
+      p->hashSizeSum = hs;
+      p->cyclicBufferSize = newCyclicBufferSize;
+      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+      newSize = p->hashSizeSum + p->numSons;
+      if (p->hash != 0 && prevSize == newSize)
+        return 1;
+      MatchFinder_FreeThisClassMemory(p, alloc);
+      p->hash = AllocRefs(newSize, alloc);
+      if (p->hash != 0)
+      {
+        p->son = p->hash + p->hashSizeSum;
+        return 1;
+      }
+    }
+  }
+  MatchFinder_Free(p, alloc);
+  return 0;
+}
+
+void MatchFinder_SetLimits(CMatchFinder *p)
+{
+  UInt32 limit = kMaxValForNormalize - p->pos;
+  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+  if (limit2 < limit) 
+    limit = limit2;
+  limit2 = p->streamPos - p->pos;
+  if (limit2 <= p->keepSizeAfter)
+  {
+    if (limit2 > 0)
+      limit2 = 1;
+  }
+  else
+    limit2 -= p->keepSizeAfter;
+  if (limit2 < limit) 
+    limit = limit2;
+  {
+    UInt32 lenLimit = p->streamPos - p->pos;
+    if (lenLimit > p->matchMaxLen)
+      lenLimit = p->matchMaxLen;
+    p->lenLimit = lenLimit;
+  }
+  p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+  UInt32 i;
+  for(i = 0; i < p->hashSizeSum; i++)
+    p->hash[i] = kEmptyHashValue;
+  p->cyclicBufferPos = 0;
+  p->buffer = p->bufferBase;
+  p->pos = p->streamPos = p->cyclicBufferSize;
+  p->result = SZ_OK;
+  p->streamEndWasReached = 0;
+  MatchFinder_ReadBlock(p);
+  MatchFinder_SetLimits(p);
+}
+
+UInt32 MatchFinder_GetSubValue(CMatchFinder *p) 
+{ 
+  return (p->pos - p->historySize - 1) & kNormalizeMask; 
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+  UInt32 i;
+  for (i = 0; i < numItems; i++)
+  {
+    UInt32 value = items[i];
+    if (value <= subValue)
+      value = kEmptyHashValue;
+    else
+      value -= subValue;
+    items[i] = value;
+  }
+}
+
+void MatchFinder_Normalize(CMatchFinder *p)
+{
+  UInt32 subValue = MatchFinder_GetSubValue(p);
+  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+  MatchFinder_ReduceOffsets(p, subValue);
+}
+
+void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+  if (p->pos == kMaxValForNormalize)
+    MatchFinder_Normalize(p);
+  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+    MatchFinder_CheckAndMoveAndRead(p);
+  if (p->cyclicBufferPos == p->cyclicBufferSize)
+    p->cyclicBufferPos = 0;
+  MatchFinder_SetLimits(p);
+}
+
+UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
+    UInt32 *distances, UInt32 maxLen)
+{
+  son[_cyclicBufferPos] = curMatch;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+      return distances;
+    {
+      const Byte *pb = cur - delta;
+      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+      {
+        UInt32 len = 0;
+        while(++len != lenLimit)
+          if (pb[len] != cur[len])
+            break;
+        if (maxLen < len)
+        {
+          *distances++ = maxLen = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+            return distances;
+        }
+      }
+    }
+  }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
+    UInt32 *distances, UInt32 maxLen)
+{
+  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+  UInt32 len0 = 0, len1 = 0;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      return distances;
+    }
+    {
+      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      UInt32 len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        if (++len != lenLimit && pb[len] == cur[len])
+          while(++len != lenLimit)
+            if (pb[len] != cur[len])
+              break;
+        if (maxLen < len)
+        {
+          *distances++ = maxLen = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            return distances;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+}
+
+void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+  UInt32 len0 = 0, len1 = 0;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      return;
+    }
+    {
+      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      UInt32 len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        while(++len != lenLimit)
+          if (pb[len] != cur[len])
+            break;
+        {
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            return;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+}
+
+#define MOVE_POS \
+  ++p->cyclicBufferPos; \
+  p->buffer++; \
+  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+  cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+  distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 offset;
+  GET_MATCHES_HEADER(2)
+  HASH2_CALC;
+  curMatch = p->hash[hashValue];
+  p->hash[hashValue] = p->pos;
+  offset = 0;
+  GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 offset;
+  GET_MATCHES_HEADER(3)
+  HASH_ZIP_CALC;
+  curMatch = p->hash[hashValue];
+  p->hash[hashValue] = p->pos;
+  offset = 0;
+  GET_MATCHES_FOOTER(offset, 2)
+}
+
+UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 hash2Value, delta2, maxLen, offset;
+  GET_MATCHES_HEADER(3)
+
+  HASH3_CALC;
+
+  delta2 = p->pos - p->hash[hash2Value];
+  curMatch = p->hash[kFix3HashSize + hashValue];
+  
+  p->hash[hash2Value] = 
+  p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+  maxLen = 2;
+  offset = 0;
+  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+  {
+    for (; maxLen != lenLimit; maxLen++)
+      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+        break;
+    distances[0] = maxLen;
+    distances[1] = delta2 - 1;
+    offset = 2;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET; 
+    }
+  }
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+  GET_MATCHES_HEADER(4)
+
+  HASH4_CALC;
+
+  delta2 = p->pos - p->hash[                hash2Value];
+  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+  curMatch = p->hash[kFix4HashSize + hashValue];
+  
+  p->hash[                hash2Value] =
+  p->hash[kFix3HashSize + hash3Value] =
+  p->hash[kFix4HashSize + hashValue] = p->pos;
+
+  maxLen = 1;
+  offset = 0;
+  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+  {
+    distances[0] = maxLen = 2;
+    distances[1] = delta2 - 1;
+    offset = 2;
+  }
+  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+  {
+    maxLen = 3;
+    distances[offset + 1] = delta3 - 1;
+    offset += 2;
+    delta2 = delta3;
+  }
+  if (offset != 0)
+  {
+    for (; maxLen != lenLimit; maxLen++)
+      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+        break;
+    distances[offset - 2] = maxLen;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET; 
+    }
+  }
+  if (maxLen < 3)
+    maxLen = 3;
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+  GET_MATCHES_HEADER(4)
+
+  HASH4_CALC;
+
+  delta2 = p->pos - p->hash[                hash2Value];
+  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+  curMatch = p->hash[kFix4HashSize + hashValue];
+
+  p->hash[                hash2Value] =
+  p->hash[kFix3HashSize + hash3Value] =
+  p->hash[kFix4HashSize + hashValue] = p->pos;
+
+  maxLen = 1;
+  offset = 0;
+  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+  {
+    distances[0] = maxLen = 2;
+    distances[1] = delta2 - 1;
+    offset = 2;
+  }
+  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+  {
+    maxLen = 3;
+    distances[offset + 1] = delta3 - 1;
+    offset += 2;
+    delta2 = delta3;
+  }
+  if (offset != 0)
+  {
+    for (; maxLen != lenLimit; maxLen++)
+      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+        break;
+    distances[offset - 2] = maxLen;
+    if (maxLen == lenLimit)
+    {
+      p->son[p->cyclicBufferPos] = curMatch;
+      MOVE_POS_RET; 
+    }
+  }
+  if (maxLen < 3)
+    maxLen = 3;
+  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+    distances + offset, maxLen) - (distances));
+  MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 offset;
+  GET_MATCHES_HEADER(3)
+  HASH_ZIP_CALC;
+  curMatch = p->hash[hashValue];
+  p->hash[hashValue] = p->pos;
+  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+    distances, 2) - (distances));
+  MOVE_POS_RET
+}
+
+void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(2) 
+    HASH2_CALC;
+    curMatch = p->hash[hashValue];
+    p->hash[hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(3)
+    HASH_ZIP_CALC;
+    curMatch = p->hash[hashValue];
+    p->hash[hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 hash2Value;
+    SKIP_HEADER(3)
+    HASH3_CALC;
+    curMatch = p->hash[kFix3HashSize + hashValue];
+    p->hash[hash2Value] =
+    p->hash[kFix3HashSize + hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 hash2Value, hash3Value;
+    SKIP_HEADER(4) 
+    HASH4_CALC;
+    curMatch = p->hash[kFix4HashSize + hashValue];
+    p->hash[                hash2Value] =
+    p->hash[kFix3HashSize + hash3Value] = p->pos;
+    p->hash[kFix4HashSize + hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 hash2Value, hash3Value;
+    SKIP_HEADER(4)
+    HASH4_CALC;
+    curMatch = p->hash[kFix4HashSize + hashValue];
+    p->hash[                hash2Value] =
+    p->hash[kFix3HashSize + hash3Value] =
+    p->hash[kFix4HashSize + hashValue] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(3)
+    HASH_ZIP_CALC;
+    curMatch = p->hash[hashValue];
+    p->hash[hashValue] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+  if (!p->btMode)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 2)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 3)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+  }
+  else
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+  }
+}
diff --git a/lzma/C/Compress/Lz/MatchFinder.h b/lzma/C/Compress/Lz/MatchFinder.h
new file mode 100644 (file)
index 0000000..74f52a8
--- /dev/null
@@ -0,0 +1,106 @@
+/* MatchFinder.h */
+
+#ifndef __MATCHFINDER_H
+#define __MATCHFINDER_H
+
+#include "../../IStream.h"
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+  Byte *buffer;
+  UInt32 pos;
+  UInt32 posLimit;
+  UInt32 streamPos;
+  UInt32 lenLimit;
+
+  UInt32 cyclicBufferPos;
+  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+  UInt32 matchMaxLen;
+  CLzRef *hash;
+  CLzRef *son;
+  UInt32 hashMask;
+  UInt32 cutValue;
+
+  Byte *bufferBase;
+  ISeqInStream *stream;
+  int streamEndWasReached;
+
+  UInt32 blockSize;
+  UInt32 keepSizeBefore;
+  UInt32 keepSizeAfter;
+
+  UInt32 numHashBytes;
+  int directInput;
+  int btMode;
+  /* int skipModeBits; */
+  int bigHash;
+  UInt32 historySize;
+  UInt32 fixedHashSize;
+  UInt32 hashSizeSum;
+  UInt32 numSons;
+
+  HRes result;
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+     historySize <= 3 GB
+     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
+    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+    ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
+    UInt32 *distances, UInt32 maxLen);
+
+/* 
+Conditions:
+  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+  Mf_Init_Func Init;
+  Mf_GetIndexByte_Func GetIndexByte;
+  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+  Mf_GetMatches_Func GetMatches;
+  Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#endif
diff --git a/lzma/C/Compress/Lz/MatchFinderMt.c b/lzma/C/Compress/Lz/MatchFinderMt.c
new file mode 100644 (file)
index 0000000..ea65a6e
--- /dev/null
@@ -0,0 +1,806 @@
+/* MatchFinderMt.c */
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../7zCrc.h"
+#include "LzHash.h"
+
+#include "MatchFinderMt.h"
+
+void MtSync_Construct(CMtSync *p)
+{
+  p->wasCreated = False;
+  p->csWasInitialized = False;
+  p->csWasEntered = False;
+  Thread_Construct(&p->thread);
+  Event_Construct(&p->canStart);
+  Event_Construct(&p->wasStarted);
+  Event_Construct(&p->wasStopped);
+  Semaphore_Construct(&p->freeSemaphore);
+  Semaphore_Construct(&p->filledSemaphore);
+}
+
+void MtSync_GetNextBlock(CMtSync *p)
+{
+  if (p->needStart)
+  {
+    p->numProcessedBlocks = 1;
+    p->needStart = False;
+    p->stopWriting = False;
+    p->exit = False;
+    Event_Reset(&p->wasStarted);
+    Event_Reset(&p->wasStopped);
+
+    Event_Set(&p->canStart);
+    Event_Wait(&p->wasStarted);
+  }
+  else
+  {
+    CriticalSection_Leave(&p->cs);
+    p->csWasEntered = False;
+    p->numProcessedBlocks++;
+    Semaphore_Release1(&p->freeSemaphore);
+  }
+  Semaphore_Wait(&p->filledSemaphore);
+  CriticalSection_Enter(&p->cs);
+  p->csWasEntered = True;
+}
+
+/* MtSync_StopWriting must be called if Writing was started */
+
+void MtSync_StopWriting(CMtSync *p)
+{ 
+  UInt32 myNumBlocks = p->numProcessedBlocks;
+  if (!Thread_WasCreated(&p->thread) || p->needStart)
+    return;
+  p->stopWriting = True;
+  if (p->csWasEntered)
+  {
+    CriticalSection_Leave(&p->cs);
+    p->csWasEntered = False;
+  }
+  Semaphore_Release1(&p->freeSemaphore);
+  Event_Wait(&p->wasStopped);
+
+  while (myNumBlocks++ != p->numProcessedBlocks)
+  {
+    Semaphore_Wait(&p->filledSemaphore);
+    Semaphore_Release1(&p->freeSemaphore);
+  }
+  p->needStart = True;
+}
+
+void MtSync_Destruct(CMtSync *p)
+{
+  if (Thread_WasCreated(&p->thread))
+  {
+    MtSync_StopWriting(p);
+    p->exit = True;
+    if (p->needStart)
+      Event_Set(&p->canStart);
+    Thread_Wait(&p->thread);
+    Thread_Close(&p->thread);
+  }
+  if (p->csWasInitialized)
+  {
+    CriticalSection_Delete(&p->cs);
+    p->csWasInitialized = False;
+  }
+
+  Event_Close(&p->canStart);
+  Event_Close(&p->wasStarted);
+  Event_Close(&p->wasStopped);
+  Semaphore_Close(&p->freeSemaphore);
+  Semaphore_Close(&p->filledSemaphore);
+
+  p->wasCreated = False;
+}
+
+HRes MtSync_Create2(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+  if (p->wasCreated)
+    return SZ_OK;
+
+  RINOK(CriticalSection_Init(&p->cs));
+  p->csWasInitialized = True;
+
+  RINOK(AutoResetEvent_CreateNotSignaled(&p->canStart));
+  RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
+  RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
+  
+  RINOK(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
+  RINOK(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
+
+  p->needStart = True;
+  
+  RINOK(Thread_Create(&p->thread, startAddress, obj));
+  p->wasCreated = True;
+  return SZ_OK;
+}
+
+HRes MtSync_Create(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+  HRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
+  if (res != SZ_OK)
+    MtSync_Destruct(p);
+  return res;
+}
+
+
+void MtSync_Init(CMtSync *p) { p->needStart = True; }
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+
+#define DEF_GetHeads(name, v) \
+static void GetHeads ## name(const Byte *p, UInt32 pos, \
+UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads) { \
+for (; numHeads != 0; numHeads--) { \
+const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++;  } }
+
+DEF_GetHeads(2,  (p[0] | ((UInt32)p[1] << 8)) & hashMask)
+DEF_GetHeads(3,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
+DEF_GetHeads(4,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5)) & hashMask)
+DEF_GetHeads(4b, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
+DEF_GetHeads(5,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5) ^ (g_CrcTable[p[4]] << 3)) & hashMask)
+
+void HashThreadFunc(CMatchFinderMt *mt)
+{
+  CMtSync *p = &mt->hashSync;
+  for (;;)
+  {
+    UInt32 numProcessedBlocks = 0;
+    Event_Wait(&p->canStart);
+    Event_Set(&p->wasStarted);
+    for (;;)
+    {
+      if (p->exit)
+        return;
+      if (p->stopWriting)
+      {
+        p->numProcessedBlocks = numProcessedBlocks;
+        Event_Set(&p->wasStopped);
+        break;
+      }
+
+      {
+        CMatchFinder *mf = mt->MatchFinder;
+        if (MatchFinder_NeedMove(mf))
+        {
+          CriticalSection_Enter(&mt->btSync.cs);
+          CriticalSection_Enter(&mt->hashSync.cs);
+          {
+            const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
+            const Byte *afterPtr;
+            MatchFinder_MoveBlock(mf);
+            afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
+            mt->pointerToCurPos -= beforePtr - afterPtr;
+            mt->buffer -= beforePtr - afterPtr;
+          }
+          CriticalSection_Leave(&mt->btSync.cs);
+          CriticalSection_Leave(&mt->hashSync.cs);
+          continue;
+        }
+
+        Semaphore_Wait(&p->freeSemaphore);
+
+        MatchFinder_ReadIfRequired(mf);
+        if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
+        {
+          UInt32 subValue = (mf->pos - mf->historySize - 1);
+          MatchFinder_ReduceOffsets(mf, subValue);
+          MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
+        }
+        {
+          UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+          UInt32 num = mf->streamPos - mf->pos;
+          heads[0] = 2;
+          heads[1] = num;
+          if (num >= mf->numHashBytes)
+          {
+            num = num - mf->numHashBytes + 1;
+            if (num > kMtHashBlockSize - 2)
+              num = kMtHashBlockSize - 2;
+            mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num);
+            heads[0] += num;
+          }
+          mf->pos += num;
+          mf->buffer += num;
+        }
+      }
+
+      Semaphore_Release1(&p->filledSemaphore);
+    }
+  }
+}
+
+void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
+{
+  MtSync_GetNextBlock(&p->hashSync);
+  p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+  p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
+  p->hashNumAvail = p->hashBuf[p->hashBufPos++];
+}
+
+#define kEmptyHashValue 0
+
+/* #define MFMT_GM_INLINE */
+
+#ifdef MFMT_GM_INLINE
+
+#if _MSC_VER >= 1300
+#define NO_INLINE __declspec(noinline) __fastcall 
+#else
+#ifdef _MSC_VER
+#define NO_INLINE __fastcall 
+#endif
+#endif
+
+Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
+    UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
+{
+  do
+  {
+  UInt32 *distances = _distances + 1;
+  UInt32 curMatch = pos - *hash++;
+
+  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+  UInt32 len0 = 0, len1 = 0;
+  UInt32 cutValue = _cutValue;
+  UInt32 maxLen = _maxLen;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      break;
+    }
+    {
+      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      UInt32 len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        if (++len != lenLimit && pb[len] == cur[len])
+          while(++len != lenLimit)
+            if (pb[len] != cur[len])
+              break;
+        if (maxLen < len)
+        {
+          *distances++ = maxLen = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            break;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+  pos++;
+  _cyclicBufferPos++;
+  cur++;
+  {
+    UInt32 num = (UInt32)(distances - _distances);
+    *_distances = num - 1;
+    _distances += num;
+    limit -= num;
+  }
+  }
+  while (limit > 0 && --size != 0);
+  *posRes = pos;
+  return limit;
+}
+
+#endif
+
+void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+  UInt32 numProcessed = 0;
+  UInt32 curPos = 2;
+  UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+  distances[1] = p->hashNumAvail;
+  while (curPos < limit)
+  {
+    if (p->hashBufPos == p->hashBufPosLimit)
+    {
+      MatchFinderMt_GetNextBlock_Hash(p);
+      distances[1] = numProcessed + p->hashNumAvail;
+      if (p->hashNumAvail >= p->numHashBytes)
+        continue;
+      for (; p->hashNumAvail != 0; p->hashNumAvail--)
+        distances[curPos++] = 0;
+      break;
+    }
+    {
+      UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+      UInt32 lenLimit = p->matchMaxLen;
+      UInt32 pos = p->pos;
+      UInt32 cyclicBufferPos = p->cyclicBufferPos;
+      if (lenLimit >= p->hashNumAvail)
+        lenLimit = p->hashNumAvail;
+      {
+        UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+        if (size2 < size)
+          size = size2;
+        size2 = p->cyclicBufferSize - cyclicBufferPos;
+        if (size2 < size)
+          size = size2;
+      }
+      #ifndef MFMT_GM_INLINE
+      while (curPos < limit && size-- != 0)
+      {
+        UInt32 *startDistances = distances + curPos;
+        UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], 
+          pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, 
+          startDistances + 1, p->numHashBytes - 1) - startDistances);
+        *startDistances = num - 1;
+        curPos += num;
+        cyclicBufferPos++;
+        pos++;
+        p->buffer++;
+      }
+      #else
+      {
+        UInt32 posRes;
+        curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, 
+          distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+        p->hashBufPos += posRes - pos;
+        cyclicBufferPos += posRes - pos;
+        p->buffer += posRes - pos;
+        pos = posRes;
+      }
+      #endif
+
+      numProcessed += pos - p->pos;
+      p->hashNumAvail -= pos - p->pos;
+      p->pos = pos;
+      if (cyclicBufferPos == p->cyclicBufferSize)
+        cyclicBufferPos = 0;
+      p->cyclicBufferPos = cyclicBufferPos;
+    }
+  }
+  distances[0] = curPos;
+}
+
+void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+  CMtSync *sync = &p->hashSync;
+  if (!sync->needStart)
+  {
+    CriticalSection_Enter(&sync->cs);
+    sync->csWasEntered = True;
+  }
+  
+  BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
+
+  if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
+  {
+    UInt32 subValue = p->pos - p->cyclicBufferSize;
+    MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
+    p->pos -= subValue;
+  }
+
+  if (!sync->needStart)
+  {
+    CriticalSection_Leave(&sync->cs);
+    sync->csWasEntered = False;
+  }
+}
+
+void BtThreadFunc(CMatchFinderMt *mt)
+{
+  CMtSync *p = &mt->btSync;
+  for (;;)
+  {
+    UInt32 blockIndex = 0;
+    Event_Wait(&p->canStart);
+    Event_Set(&p->wasStarted);
+    for (;;)
+    {
+      if (p->exit)
+        return;
+      if (p->stopWriting)
+      {
+        p->numProcessedBlocks = blockIndex;
+        MtSync_StopWriting(&mt->hashSync);
+        Event_Set(&p->wasStopped);
+        break;
+      }
+      Semaphore_Wait(&p->freeSemaphore);
+      BtFillBlock(mt, blockIndex++);
+      Semaphore_Release1(&p->filledSemaphore);
+    }
+  }
+}
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+  p->hashBuf = 0;
+  MtSync_Construct(&p->hashSync);
+  MtSync_Construct(&p->btSync);
+}
+
+void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+  alloc->Free(p->hashBuf);
+  p->hashBuf = 0;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+  MtSync_Destruct(&p->hashSync);
+  MtSync_Destruct(&p->btSync);
+  MatchFinderMt_FreeMem(p, alloc);
+}
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+static unsigned StdCall HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p);  return 0; }
+static unsigned StdCall BtThreadFunc2(void *p) 
+{ 
+  #ifdef USE_ALLOCA
+  alloca(0x180);
+  #endif
+  BtThreadFunc((CMatchFinderMt *)p); 
+  return 0; 
+}
+
+HRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, 
+    UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
+{ 
+  CMatchFinder *mf = p->MatchFinder;
+  p->historySize = historySize;
+  if (kMtBtBlockSize <= matchMaxLen * 4)
+    return E_INVALIDARG;
+  if (p->hashBuf == 0)
+  {
+    p->hashBuf = (UInt32 *)alloc->Alloc((kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
+    if (p->hashBuf == 0)
+      return SZE_OUTOFMEMORY;
+    p->btBuf = p->hashBuf + kHashBufferSize;
+  }
+  keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+  keepAddBufferAfter += kMtHashBlockSize;
+  if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+    return SZE_OUTOFMEMORY;
+
+  RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
+  RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
+  return SZ_OK;
+}
+
+/* Call it after ReleaseStream / SetStream */
+void MatchFinderMt_Init(CMatchFinderMt *p)
+{ 
+  CMatchFinder *mf = p->MatchFinder;
+  p->btBufPos = p->btBufPosLimit = 0;
+  p->hashBufPos = p->hashBufPosLimit = 0;
+  MatchFinder_Init(mf);
+  p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
+  p->btNumAvailBytes = 0;
+  p->lzPos = p->historySize + 1;
+
+  p->hash = mf->hash;
+  p->fixedHashSize = mf->fixedHashSize;
+
+  p->son = mf->son;
+  p->matchMaxLen = mf->matchMaxLen;
+  p->numHashBytes = mf->numHashBytes;
+  p->pos = mf->pos;
+  p->buffer = mf->buffer;
+  p->cyclicBufferPos = mf->cyclicBufferPos;
+  p->cyclicBufferSize = mf->cyclicBufferSize;
+  p->cutValue = mf->cutValue;
+}
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{ 
+  MtSync_StopWriting(&p->btSync);
+  /* p->MatchFinder->ReleaseStream(); */
+}
+
+void MatchFinderMt_Normalize(CMatchFinderMt *p)
+{
+  MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
+  p->lzPos = p->historySize + 1;
+}
+
+void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+  UInt32 blockIndex;
+  MtSync_GetNextBlock(&p->btSync);
+  blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
+  p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
+  p->btBufPosLimit += p->btBuf[p->btBufPos++];
+  p->btNumAvailBytes = p->btBuf[p->btBufPos++];
+  if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) 
+    MatchFinderMt_Normalize(p);
+}
+
+const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+  return p->pointerToCurPos;
+}
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{ 
+  GET_NEXT_BLOCK_IF_REQUIRED;
+  return p->btNumAvailBytes;
+}
+
+Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+{ 
+  return p->pointerToCurPos[index]; 
+}
+
+UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+  UInt32 hash2Value, curMatch2;
+  UInt32 *hash = p->hash;
+  const Byte *cur = p->pointerToCurPos;
+  UInt32 lzPos = p->lzPos; 
+  MT_HASH2_CALC
+      
+  curMatch2 = hash[hash2Value];
+  hash[hash2Value] = lzPos;
+
+  if (curMatch2 >= matchMinPos) 
+    if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+    {
+      *distances++ = 2; 
+      *distances++ = lzPos - curMatch2 - 1;
+    }
+  return distances;
+}
+
+UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+  UInt32 *hash = p->hash;
+  const Byte *cur = p->pointerToCurPos;
+  UInt32 lzPos = p->lzPos; 
+  MT_HASH3_CALC
+
+  curMatch2 = hash[                hash2Value];
+  curMatch3 = hash[kFix3HashSize + hash3Value];
+  
+  hash[                hash2Value] = 
+  hash[kFix3HashSize + hash3Value] = 
+    lzPos;
+
+  if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+  { 
+    distances[1] = lzPos - curMatch2 - 1;
+    if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+    {
+      distances[0] = 3;
+      return distances + 2;
+    }
+    distances[0] = 2; 
+    distances += 2;
+  }
+  if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+  { 
+    *distances++ = 3; 
+    *distances++ = lzPos - curMatch3 - 1; 
+  }
+  return distances;
+}
+
+/*
+UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+  UInt32 *hash = p->hash;
+  const Byte *cur = p->pointerToCurPos;
+  UInt32 lzPos = p->lzPos; 
+  MT_HASH4_CALC
+      
+  curMatch2 = hash[                hash2Value];
+  curMatch3 = hash[kFix3HashSize + hash3Value];
+  curMatch4 = hash[kFix4HashSize + hash4Value];
+  
+  hash[                hash2Value] = 
+  hash[kFix3HashSize + hash3Value] = 
+  hash[kFix4HashSize + hash4Value] = 
+    lzPos;
+
+  if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+  {
+    distances[1] = lzPos - curMatch2 - 1;
+    if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+    {
+      distances[0] =  (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
+      return distances + 2;
+    }
+    distances[0] = 2;
+    distances += 2;
+  }
+  if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+  {
+    distances[1] = lzPos - curMatch3 - 1;
+    if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
+    {
+      distances[0] = 4;
+      return distances + 2;
+    }
+    distances[0] = 3;
+    distances += 2;
+  }
+
+  if (curMatch4 >= matchMinPos)
+    if (
+      cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
+      cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
+      )
+    {
+      *distances++ = 4;
+      *distances++ = lzPos - curMatch4 - 1;
+    }
+  return distances;
+}
+*/
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{ 
+  const UInt32 *btBuf = p->btBuf + p->btBufPos;
+  UInt32 len = *btBuf++;
+  p->btBufPos += 1 + len;
+  p->btNumAvailBytes--;
+  {
+    UInt32 i;
+    for (i = 0; i < len; i += 2)
+    {
+      *distances++ = *btBuf++;
+      *distances++ = *btBuf++;
+    }
+  }
+  INCREASE_LZ_POS
+  return len;
+}
+
+UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{ 
+  const UInt32 *btBuf = p->btBuf + p->btBufPos;
+  UInt32 len = *btBuf++;
+  p->btBufPos += 1 + len;
+
+  if (len == 0)
+  {
+    if (p->btNumAvailBytes-- >= 4) 
+      len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
+  }
+  else
+  {
+    /* Condition: there are matches in btBuf with length < p->numHashBytes */
+    UInt32 *distances2;
+    p->btNumAvailBytes--;
+    distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
+    do 
+    {
+      *distances2++ = *btBuf++;
+      *distances2++ = *btBuf++;
+    }
+    while ((len -= 2) != 0);
+    len  = (UInt32)(distances2 - (distances));
+  }
+  INCREASE_LZ_POS
+  return len;
+}
+
+#define SKIP_HEADER2  do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER(n) SKIP_HEADER2 if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while(--num != 0);
+
+void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER2 { p->btNumAvailBytes--;
+  SKIP_FOOTER
+}
+
+void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER(2)
+      UInt32 hash2Value;
+      MT_HASH2_CALC
+      hash[hash2Value] = p->lzPos;
+  SKIP_FOOTER
+}
+
+void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER(3)
+      UInt32 hash2Value, hash3Value;
+      MT_HASH3_CALC
+      hash[kFix3HashSize + hash3Value] = 
+      hash[                hash2Value] = 
+        p->lzPos;
+  SKIP_FOOTER
+}
+
+/*
+void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER(4)
+      UInt32 hash2Value, hash3Value, hash4Value;
+      MT_HASH4_CALC
+      hash[kFix4HashSize + hash4Value] = 
+      hash[kFix3HashSize + hash3Value] = 
+      hash[                hash2Value] = 
+        p->lzPos;
+  SKIP_FOOTER
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
+{
+  vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+  vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+  switch(p->MatchFinder->numHashBytes)
+  {
+    case 2:
+      p->GetHeadsFunc = GetHeads2;
+      p->MixMatchesFunc = (Mf_Mix_Matches)0;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+      vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+      break;
+    case 3:
+      p->GetHeadsFunc = GetHeads3;
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+      break;
+    default:
+    /* case 4: */
+      p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
+      /* p->GetHeadsFunc = GetHeads4; */
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+      break;
+    /*
+    default:
+      p->GetHeadsFunc = GetHeads5;
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
+      break;
+    */
+  }
+}
diff --git a/lzma/C/Compress/Lz/MatchFinderMt.h b/lzma/C/Compress/Lz/MatchFinderMt.h
new file mode 100644 (file)
index 0000000..e718a09
--- /dev/null
@@ -0,0 +1,95 @@
+/* MatchFinderMt.h */
+
+#ifndef __MATCHFINDERMT_H
+#define __MATCHFINDERMT_H
+
+#include "../../Threads.h"
+#include "MatchFinder.h"
+
+#define kMtHashBlockSize (1 << 13)
+#define kMtHashNumBlocks (1 << 3)
+#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)
+
+#define kMtBtBlockSize (1 << 14)
+#define kMtBtNumBlocks (1 << 6)
+#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)
+
+typedef struct _CMtSync
+{
+  Bool wasCreated;
+  Bool needStart;
+  Bool exit;
+  Bool stopWriting;
+
+  CThread thread;
+  CAutoResetEvent canStart;
+  CAutoResetEvent wasStarted;
+  CAutoResetEvent wasStopped;
+  CSemaphore freeSemaphore;
+  CSemaphore filledSemaphore;
+  Bool csWasInitialized;
+  Bool csWasEntered;
+  CCriticalSection cs;
+  UInt32 numProcessedBlocks;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+  UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads);
+
+typedef struct _CMatchFinderMt
+{
+  /* LZ */
+  const Byte *pointerToCurPos;
+  UInt32 *btBuf;
+  UInt32 btBufPos;
+  UInt32 btBufPosLimit;
+  UInt32 lzPos;
+  UInt32 btNumAvailBytes;
+
+  UInt32 *hash;
+  UInt32 fixedHashSize;
+  UInt32 historySize;
+
+  Mf_Mix_Matches MixMatchesFunc;
+  
+  /* LZ + BT */
+  CMtSync btSync;
+  Byte btDummy[kMtCacheLineDummy];
+
+  /* BT */
+  UInt32 *hashBuf;
+  UInt32 hashBufPos;
+  UInt32 hashBufPosLimit;
+  UInt32 hashNumAvail;
+
+  CLzRef *son;
+  UInt32 matchMaxLen;
+  UInt32 numHashBytes;
+  UInt32 pos;
+  Byte *buffer;
+  UInt32 cyclicBufferPos;
+  UInt32 cyclicBufferSize; /* it must be historySize + 1 */
+  UInt32 cutValue;
+
+  /* BT + Hash */
+  CMtSync hashSync;
+  /* Byte hashDummy[kMtCacheLineDummy]; */
+  
+  /* Hash */
+  Mf_GetHeads GetHeadsFunc;
+  CMatchFinder *MatchFinder;
+} CMatchFinderMt;
+
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc);
+HRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, 
+    UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+#endif
diff --git a/lzma/C/Compress/Lzma/LzmaDecode.c b/lzma/C/Compress/Lzma/LzmaDecode.c
new file mode 100644 (file)
index 0000000..cb83453
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/lzma/C/Compress/Lzma/LzmaDecode.h b/lzma/C/Compress/Lzma/LzmaDecode.h
new file mode 100644 (file)
index 0000000..2870eeb
--- /dev/null
@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/lzma/C/Compress/Lzma/LzmaDecodeSize.c b/lzma/C/Compress/Lzma/LzmaDecodeSize.c
new file mode 100644 (file)
index 0000000..a3a5eb9
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+  LzmaDecodeSize.c
+  LZMA Decoder (optimized for Size 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
+
+typedef struct _CRangeDecoder
+{
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+  #ifdef _LZMA_IN_CB
+  ILzmaInCallback *InCallback;
+  int Result;
+  #endif
+  int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+  if (rd->Buffer == rd->BufferLim)
+  {
+    #ifdef _LZMA_IN_CB
+    SizeT size;
+    rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+    rd->BufferLim = rd->Buffer + size;
+    if (size == 0)
+    #endif
+    {
+      rd->ExtraBytes = 1;
+      return 0xFF;
+    }
+  }
+  return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd
+  #ifndef _LZMA_IN_CB
+    , const Byte *stream, SizeT bufferSize
+  #endif
+    )
+{
+  int i;
+  #ifdef _LZMA_IN_CB
+  rd->Buffer = rd->BufferLim = 0;
+  #else
+  rd->Buffer = stream;
+  rd->BufferLim = stream + bufferSize;
+  #endif
+  rd->ExtraBytes = 0;
+  rd->Code = 0;
+  rd->Range = (0xFFFFFFFF);
+  for(i = 0; i < 5; i++)
+    rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;        
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+  RC_INIT_VAR
+  UInt32 result = 0;
+  int i;
+  for (i = numTotalBits; i != 0; i--)
+  {
+    /* UInt32 t; */
+    range >>= 1;
+
+    result <<= 1;
+    if (code >= range)
+    {
+      code -= range;
+      result |= 1;
+    }
+    /*
+    t = (code - range) >> 31;
+    t &= 1;
+    code -= range & (t - 1);
+    result = (result + result) | (1 - t);
+    */
+    RC_NORMALIZE
+  }
+  RC_FLUSH_VAR
+  return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+  UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+  if (rd->Code < bound)
+  {
+    rd->Range = bound;
+    *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+    if (rd->Range < kTopValue)
+    {
+      rd->Code = (rd->Code << 8) | ReadByte;
+      rd->Range <<= 8;
+    }
+    return 0;
+  }
+  else
+  {
+    rd->Range -= bound;
+    rd->Code -= bound;
+    *prob -= (*prob) >> kNumMoveBits;
+    if (rd->Range < kTopValue)
+    {
+      rd->Code = (rd->Code << 8) | ReadByte;
+      rd->Range <<= 8;
+    }
+    return 1;
+  }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+  UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+  if (code < bound) \
+    { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+  else \
+    { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+  RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)               
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+  int mi = 1;
+  int i;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  for(i = numLevels; i != 0; i--)
+  {
+    #ifdef _LZMA_LOC_OPT
+    CProb *prob = probs + mi;
+    RC_GET_BIT(prob, mi)
+    #else
+    mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+    #endif
+  }
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+  int mi = 1;
+  int i;
+  int symbol = 0;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  for(i = 0; i < numLevels; i++)
+  {
+    #ifdef _LZMA_LOC_OPT
+    CProb *prob = probs + mi;
+    RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+    #else
+    int bit = RangeDecoderBitDecode(probs + mi, rd);
+    mi = mi + mi + bit;
+    symbol |= (bit << i);
+    #endif
+  }
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{ 
+  int symbol = 1;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  do
+  {
+    #ifdef _LZMA_LOC_OPT
+    CProb *prob = probs + symbol;
+    RC_GET_BIT(prob, symbol)
+    #else
+    symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+    #endif
+  }
+  while (symbol < 0x100);
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{ 
+  int symbol = 1;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  do
+  {
+    int bit;
+    int matchBit = (matchByte >> 7) & 1;
+    matchByte <<= 1;
+    #ifdef _LZMA_LOC_OPT
+    {
+      CProb *prob = probs + 0x100 + (matchBit << 8) + symbol;
+      RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+    }
+    #else
+    bit = RangeDecoderBitDecode(probs + 0x100 + (matchBit << 8) + symbol, rd);
+    symbol = (symbol << 1) | bit;
+    #endif
+    if (matchBit != bit)
+    {
+      while (symbol < 0x100)
+      {
+        #ifdef _LZMA_LOC_OPT
+        CProb *prob = probs + symbol;
+        RC_GET_BIT(prob, symbol)
+        #else
+        symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+        #endif
+      }
+      break;
+    }
+  }
+  while (symbol < 0x100);
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return symbol;
+}
+
+#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) 
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+  if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+    return RangeDecoderBitTreeDecode(p + LenLow +
+        (posState << kLenNumLowBits), kLenNumLowBits, rd);
+  if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+    return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+        (posState << kLenNumMidBits), kLenNumMidBits, rd);
+  return kLenNumLowSymbols + kLenNumMidSymbols + 
+      RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#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;
+  CRangeDecoder rd;
+
+  #ifdef _LZMA_OUT_READ
+  
+  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];
+
+  rd.Range = vs->Range;
+  rd.Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  rd.InCallback = InCallback;
+  rd.Buffer = vs->Buffer;
+  rd.BufferLim = vs->BufferLim;
+  #else
+  rd.Buffer = inStream;
+  rd.BufferLim = inStream + inSize;
+  #endif
+
+  #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;
+      RangeDecoderInit(&rd
+          #ifndef _LZMA_IN_CB
+          , inStream, inSize
+          #endif
+          );
+      #ifdef _LZMA_IN_CB
+      if (rd.Result != LZMA_RESULT_OK)
+        return rd.Result;
+      #endif
+      if (rd.ExtraBytes != 0)
+        return LZMA_RESULT_DATA_ERROR;
+    }
+    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];
+
+  #ifdef _LZMA_IN_CB
+  rd.Result = LZMA_RESULT_OK;
+  #endif
+  rd.ExtraBytes = 0;
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+
+  #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
+  rd.InCallback = InCallback;
+  #endif
+  RangeDecoderInit(&rd
+      #ifndef _LZMA_IN_CB
+      , inStream, inSize
+      #endif
+      );
+
+  #ifdef _LZMA_IN_CB
+  if (rd.Result != LZMA_RESULT_OK)
+    return rd.Result;
+  #endif
+  if (rd.ExtraBytes != 0)
+    return LZMA_RESULT_DATA_ERROR;
+
+  #endif /* _LZMA_OUT_READ */
+
+
+  while(nowPos < outSize)
+  {
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+    #ifdef _LZMA_IN_CB
+    if (rd.Result != LZMA_RESULT_OK)
+      return rd.Result;
+    #endif
+    if (rd.ExtraBytes != 0)
+      return LZMA_RESULT_DATA_ERROR;
+    if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+    {
+      CProb *probs = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        Byte matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+      }
+      else
+        previousByte = LzmaLiteralDecode(probs, &rd);
+      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             
+    {
+      if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+      {
+        if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+        {
+          if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+      
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+
+            state = state < 7 ? 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
+        {
+          UInt32 distance;
+          if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+            distance = rep1;
+          else 
+          {
+            if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+              distance = rep2;
+            else
+            {
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+        state = state < 7 ? 8 : 11;
+      }
+      else
+      {
+        int posSlot;
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < 7 ? 7 : 10;
+        len = LzmaLenDecode(p + LenCoder, &rd, posState);
+        posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits), kNumPosSlotBits, &rd);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 += RangeDecoderReverseBitTreeDecode(
+                p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+          }
+          else
+          {
+            rep0 += RangeDecoderDecodeDirectBits(&rd, 
+                numDirectBits - kNumAlignBits) << kNumAlignBits;
+            rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+          }
+        }
+        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);
+    }
+  }
+
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = rd.Range;
+  vs->Code = rd.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 = rd.Buffer;
+  vs->BufferLim = rd.BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(rd.Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/lzma/C/Compress/Lzma/LzmaStateDecode.c b/lzma/C/Compress/Lzma/LzmaStateDecode.c
new file mode 100644 (file)
index 0000000..5dc8f0e
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+  LzmaStateDecode.c
+  LZMA Decoder (State 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 "LzmaStateDecode.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_INIT Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { Code = (Code << 8) | RC_READ_BYTE; }}
+
+#define RC_NORMALIZE if (Range < kTopValue) { 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
+
+/* kRequiredInBufferSize = number of required input bytes for worst case: 
+   longest match with longest distance.
+   kLzmaInBufferSize must be larger than kRequiredInBufferSize 
+   23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4(align) + 1 (RC_NORMALIZE)
+*/
+
+#define kRequiredInBufferSize ((23 * (kNumBitModelTotalBits - kNumMoveBits + 1) + 26 + 9) / 8)
+
+#define kLzmaStreamWasFinishedId (-1)
+
+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;
+    */
+  }
+
+  {
+    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;
+    return LZMA_RESULT_OK;
+  }
+}
+
+int LzmaDecode(
+    CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+    int finishDecoding)
+{
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+
+  unsigned char *Buffer = vs->Buffer;
+  int BufferSize = vs->BufferSize; /* don't change it to unsigned int */
+  CProb *p = vs->Probs;
+
+  int state = vs->State;
+  unsigned char previousByte;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  SizeT nowPos = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  unsigned char *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  unsigned char tempDictionary[4];
+
+  (*inSizeProcessed) = 0;
+  (*outSizeProcessed) = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+    {
+      Buffer[BufferSize++] = *inStream++;
+      (*inSizeProcessed)++;
+      inSize--;
+    }
+    if (BufferSize < 5)
+    {
+      vs->BufferSize = BufferSize;
+      return finishDecoding ? LZMA_RESULT_DATA_ERROR : LZMA_RESULT_OK;
+    }
+    {
+      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;
+      RC_INIT;
+    }
+    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];
+
+  for (;;)
+  {
+    int bufferPos = (int)(Buffer - vs->Buffer);
+    if (BufferSize - bufferPos < kRequiredInBufferSize)
+    {
+      int i;
+      BufferSize -= bufferPos;
+      if (BufferSize < 0)
+        return LZMA_RESULT_DATA_ERROR;
+      for (i = 0; i < BufferSize; i++)
+        vs->Buffer[i] = Buffer[i];
+      Buffer = vs->Buffer;
+      while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+      {
+        Buffer[BufferSize++] = *inStream++;
+        (*inSizeProcessed)++;
+        inSize--;
+      }
+      if (BufferSize < kRequiredInBufferSize && !finishDecoding)
+        break;
+    }
+    if (nowPos >= outSize)
+      break;
+    {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)((nowPos + globalPos) & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        ((((nowPos + globalPos)& literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        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 = (unsigned char)symbol;
+
+      outStream[nowPos++] = previousByte;
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      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)
+          {
+            UInt32 pos;
+            UpdateBit0(prob);
+            if (distanceLimit == 0)
+              return LZMA_RESULT_DATA_ERROR;
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            state = state < kNumLitStates ? 9 : 11;
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            outStream[nowPos++] = previousByte;
+            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;
+      if (rep0 > distanceLimit) 
+        return LZMA_RESULT_DATA_ERROR;
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+
+      do
+      {
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+    }
+  }
+  RC_NORMALIZE;
+
+  BufferSize -= (int)(Buffer - vs->Buffer);
+  if (BufferSize < 0)
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    int i;
+    for (i = 0; i < BufferSize; i++)
+      vs->Buffer[i] = Buffer[i];
+  }
+  vs->BufferSize = BufferSize;
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = (UInt32)(globalPos + 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];
+
+  (*outSizeProcessed) = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/lzma/C/Compress/Lzma/LzmaStateDecode.h b/lzma/C/Compress/Lzma/LzmaStateDecode.h
new file mode 100644 (file)
index 0000000..26490d6
--- /dev/null
@@ -0,0 +1,96 @@
+/* 
+  LzmaStateDecode.h
+  LZMA Decoder interface (State 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.
+*/
+
+#ifndef __LZMASTATEDECODE_H
+#define __LZMASTATEDECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  UInt32 DictionarySize;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(lzmaProps) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((lzmaProps)->lc + (lzmaProps)->lp)))
+
+#define kLzmaInBufferSize 64   /* don't change it. it must be larger than kRequiredInBufferSize */
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+  unsigned char *Dictionary;
+
+  unsigned char Buffer[kLzmaInBufferSize];
+  int BufferSize;
+
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;  /* -2: decoder needs internal initialization
+                     -1: stream was finished, 
+                      0: ok
+                    > 0: need to write RemainLen bytes as match Reps[0],
+                  */
+  unsigned char TempDictionary[4];  /* it's required when DictionarySize = 0 */
+} CLzmaDecoderState;
+
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; (vs)->BufferSize = 0; }
+
+/* LzmaDecode: decoding from input stream to output stream.
+  If finishDecoding != 0, then there are no more bytes in input stream
+  after inStream[inSize - 1]. */
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize,  SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+    int finishDecoding);
+
+#endif
diff --git a/lzma/C/Compress/Lzma/LzmaStateTest.c b/lzma/C/Compress/Lzma/LzmaStateTest.c
new file mode 100644 (file)
index 0000000..5df4e43
--- /dev/null
@@ -0,0 +1,195 @@
+/* 
+LzmaStateTest.c
+Test application for LZMA Decoder (State version)
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.26 (2005-08-02)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LzmaStateDecode.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+
+#define kInBufferSize (1 << 15)
+#define kOutBufferSize (1 << 15)
+
+unsigned char g_InBuffer[kInBufferSize];
+unsigned char g_OutBuffer[kOutBufferSize];
+
+size_t MyReadFile(FILE *file, void *data, size_t size)
+  { return fread(data, 1, size, file); }
+
+int MyReadFileAndCheck(FILE *file, void *data, size_t size)
+  { return (MyReadFile(file, data, size) == size); }
+
+int PrintError(char *buffer, const char *message)
+{
+  sprintf(buffer + strlen(buffer), "\nError: ");
+  sprintf(buffer + strlen(buffer), message);
+  return 1;
+}
+
+int main3(FILE *inFile, FILE *outFile, char *rs)
+{
+  /* We use two 32-bit integers to construct 64-bit integer for file size.
+     You can remove outSizeHigh, if you don't need >= 4GB supporting,
+     or you can use UInt64 outSize, if your compiler supports 64-bit integers*/
+  UInt32 outSize = 0;
+  UInt32 outSizeHigh = 0; 
+  
+  int waitEOS = 1; 
+  /* waitEOS = 1, if there is no uncompressed size in headers, 
+   so decoder will wait EOS (End of Stream Marker) in compressed stream */
+
+  int i;
+  int res = 0;
+  CLzmaDecoderState state;  /* it's about 140 bytes structure, if int is 32-bit */
+  unsigned char properties[LZMA_PROPERTIES_SIZE];
+  SizeT inAvail = 0;
+  unsigned char *inBuffer = 0;
+
+  if (sizeof(UInt32) < 4)
+    return PrintError(rs, "LZMA decoder needs correct UInt32");
+
+  /* Read LZMA properties for compressed stream */
+
+  if (!MyReadFileAndCheck(inFile, properties, sizeof(properties)))
+    return PrintError(rs, kCantReadMessage);
+
+  /* Read uncompressed size */
+  
+  for (i = 0; i < 8; i++)
+  {
+    unsigned char b;
+    if (!MyReadFileAndCheck(inFile, &b, 1))
+      return PrintError(rs, kCantReadMessage);
+    if (b != 0xFF)
+      waitEOS = 0;
+    if (i < 4)
+      outSize += (UInt32)(b) << (i * 8);
+    else
+      outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
+  }
+
+  /* Decode LZMA properties and allocate memory */
+  
+  if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+    return PrintError(rs, "Incorrect stream properties");
+  state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+  if (state.Probs == 0)
+    return PrintError(rs, kCantAllocateMessage);
+  
+  if (state.Properties.DictionarySize == 0)
+    state.Dictionary = 0;
+  else
+  {
+    state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+    if (state.Dictionary == 0)
+    {
+      free(state.Probs);
+      return PrintError(rs, kCantAllocateMessage);
+    }
+  }
+  
+  /* Decompress */
+  
+  LzmaDecoderInit(&state);
+  
+  do
+  {
+    SizeT inProcessed, outProcessed;
+    int finishDecoding;
+    UInt32 outAvail = kOutBufferSize;
+    if (!waitEOS && outSizeHigh == 0 && outAvail > outSize)
+      outAvail = outSize;
+    if (inAvail == 0)
+    {
+      inAvail = (SizeT)MyReadFile(inFile, g_InBuffer, kInBufferSize);
+      inBuffer = g_InBuffer;
+    }
+    finishDecoding = (inAvail == 0);
+    res = LzmaDecode(&state,
+        inBuffer, inAvail, &inProcessed,
+        g_OutBuffer, outAvail, &outProcessed,
+        finishDecoding);
+    if (res != 0)
+    {
+      sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+      res = 1;
+      break;
+    }
+    inAvail -= inProcessed;
+    inBuffer += inProcessed;
+    
+    if (outFile != 0)  
+      if (fwrite(g_OutBuffer, 1, outProcessed, outFile) != outProcessed)
+      {
+        PrintError(rs, kCantWriteMessage);
+        res = 1;
+        break;
+      }
+      
+    if (outSize < outProcessed)
+      outSizeHigh--;
+    outSize -= (UInt32)outProcessed;
+    outSize &= 0xFFFFFFFF;
+
+    if (outProcessed == 0 && finishDecoding)
+    {
+      if (!waitEOS && (outSize != 0 || outSizeHigh != 0))
+        res = 1;
+      break;
+    }
+  }
+  while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0  || waitEOS);
+
+  free(state.Dictionary);
+  free(state.Probs);
+  return res;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+  FILE *inFile = 0;
+  FILE *outFile = 0;
+  int res;
+
+  sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov  2005-08-02\n");
+  if (numArgs < 2 || numArgs > 3)
+  {
+    sprintf(rs + strlen(rs), "\nUsage:  lzmadec file.lzma [outFile]\n");
+    return 1;
+  }
+
+  inFile = fopen(args[1], "rb");
+  if (inFile == 0)
+    return PrintError(rs, "Can not open input file");
+
+  if (numArgs > 2)
+  {
+    outFile = fopen(args[2], "wb+");
+    if (outFile == 0)
+      return PrintError(rs, "Can not open output file");
+  }
+
+  res = main3(inFile, outFile, rs);
+
+  if (outFile != 0)
+    fclose(outFile);
+  fclose(inFile);
+  return res;
+}
+
+int main(int numArgs, const char *args[])
+{
+  char rs[800] = { 0 };
+  int res = main2(numArgs, args, rs);
+  printf(rs);
+  return res;
+}
diff --git a/lzma/C/Compress/Lzma/LzmaTest.c b/lzma/C/Compress/Lzma/LzmaTest.c
new file mode 100644 (file)
index 0000000..f95a753
--- /dev/null
@@ -0,0 +1,342 @@
+/* 
+LzmaTest.c
+Test application for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.26 (2005-08-05)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LzmaDecode.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+
+size_t MyReadFile(FILE *file, void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  return fread(data, 1, size, file); 
+}
+
+int MyReadFileAndCheck(FILE *file, void *data, size_t size)
+  { return (MyReadFile(file, data, size) == size);} 
+
+size_t MyWriteFile(FILE *file, const void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  return fwrite(data, 1, size, file); 
+}
+
+int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
+  { return (MyWriteFile(file, data, size) == size); }
+
+#ifdef _LZMA_IN_CB
+#define kInBufferSize (1 << 15)
+typedef struct _CBuffer
+{
+  ILzmaInCallback InCallback;
+  FILE *File;
+  unsigned char Buffer[kInBufferSize];
+} CBuffer;
+
+int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size)
+{
+  CBuffer *b = (CBuffer *)object;
+  *buffer = b->Buffer;
+  *size = (SizeT)MyReadFile(b->File, b->Buffer, kInBufferSize);
+  return LZMA_RESULT_OK;
+}
+CBuffer g_InBuffer;
+
+#endif
+
+#ifdef _LZMA_OUT_READ
+#define kOutBufferSize (1 << 15)
+unsigned char g_OutBuffer[kOutBufferSize];
+#endif
+
+int PrintError(char *buffer, const char *message)
+{
+  sprintf(buffer + strlen(buffer), "\nError: ");
+  sprintf(buffer + strlen(buffer), message);
+  return 1;
+}
+
+int main3(FILE *inFile, FILE *outFile, char *rs)
+{
+  /* We use two 32-bit integers to construct 64-bit integer for file size.
+     You can remove outSizeHigh, if you don't need >= 4GB supporting,
+     or you can use UInt64 outSize, if your compiler supports 64-bit integers*/
+  UInt32 outSize = 0;
+  UInt32 outSizeHigh = 0;
+  #ifndef _LZMA_OUT_READ
+  SizeT outSizeFull;
+  unsigned char *outStream;
+  #endif
+  
+  int waitEOS = 1; 
+  /* waitEOS = 1, if there is no uncompressed size in headers, 
+   so decoder will wait EOS (End of Stream Marker) in compressed stream */
+
+  #ifndef _LZMA_IN_CB
+  SizeT compressedSize;
+  unsigned char *inStream;
+  #endif
+
+  CLzmaDecoderState state;  /* it's about 24-80 bytes structure, if int is 32-bit */
+  unsigned char properties[LZMA_PROPERTIES_SIZE];
+
+  int res;
+
+  #ifdef _LZMA_IN_CB
+  g_InBuffer.File = inFile;
+  #endif
+
+  if (sizeof(UInt32) < 4)
+    return PrintError(rs, "LZMA decoder needs correct UInt32");
+
+  #ifndef _LZMA_IN_CB
+  {
+    long length;
+    fseek(inFile, 0, SEEK_END);
+    length = ftell(inFile);
+    fseek(inFile, 0, SEEK_SET);
+    if ((long)(SizeT)length != length)
+      return PrintError(rs, "Too big compressed stream");
+    compressedSize = (SizeT)(length - (LZMA_PROPERTIES_SIZE + 8));
+  }
+  #endif
+
+  /* Read LZMA properties for compressed stream */
+
+  if (!MyReadFileAndCheck(inFile, properties, sizeof(properties)))
+    return PrintError(rs, kCantReadMessage);
+
+  /* Read uncompressed size */
+
+  {
+    int i;
+    for (i = 0; i < 8; i++)
+    {
+      unsigned char b;
+      if (!MyReadFileAndCheck(inFile, &b, 1))
+        return PrintError(rs, kCantReadMessage);
+      if (b != 0xFF)
+        waitEOS = 0;
+      if (i < 4)
+        outSize += (UInt32)(b) << (i * 8);
+      else
+        outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
+    }
+    
+    #ifndef _LZMA_OUT_READ
+    if (waitEOS)
+      return PrintError(rs, "Stream with EOS marker is not supported");
+    outSizeFull = (SizeT)outSize;
+    if (sizeof(SizeT) >= 8)
+      outSizeFull |= (((SizeT)outSizeHigh << 16) << 16);
+    else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize)
+      return PrintError(rs, "Too big uncompressed stream");
+    #endif
+  }
+
+  /* Decode LZMA properties and allocate memory */
+  
+  if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+    return PrintError(rs, "Incorrect stream properties");
+  state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+
+  #ifdef _LZMA_OUT_READ
+  if (state.Properties.DictionarySize == 0)
+    state.Dictionary = 0;
+  else
+    state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+  #else
+  if (outSizeFull == 0)
+    outStream = 0;
+  else
+    outStream = (unsigned char *)malloc(outSizeFull);
+  #endif
+
+  #ifndef _LZMA_IN_CB
+  if (compressedSize == 0)
+    inStream = 0;
+  else
+    inStream = (unsigned char *)malloc(compressedSize);
+  #endif
+
+  if (state.Probs == 0 
+    #ifdef _LZMA_OUT_READ
+    || (state.Dictionary == 0 && state.Properties.DictionarySize != 0)
+    #else
+    || (outStream == 0 && outSizeFull != 0)
+    #endif
+    #ifndef _LZMA_IN_CB
+    || (inStream == 0 && compressedSize != 0)
+    #endif
+    )
+  {
+    free(state.Probs);
+    #ifdef _LZMA_OUT_READ
+    free(state.Dictionary);
+    #else
+    free(outStream);
+    #endif
+    #ifndef _LZMA_IN_CB
+    free(inStream);
+    #endif
+    return PrintError(rs, kCantAllocateMessage);
+  }
+
+  /* Decompress */
+
+  #ifdef _LZMA_IN_CB
+  g_InBuffer.InCallback.Read = LzmaReadCompressed;
+  #else
+  if (!MyReadFileAndCheck(inFile, inStream, compressedSize))
+    return PrintError(rs, kCantReadMessage);
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  {
+    #ifndef _LZMA_IN_CB
+    SizeT inAvail = compressedSize;
+    const unsigned char *inBuffer = inStream;
+    #endif
+    LzmaDecoderInit(&state);
+    do
+    {
+      #ifndef _LZMA_IN_CB
+      SizeT inProcessed;
+      #endif
+      SizeT outProcessed;
+      SizeT outAvail = kOutBufferSize;
+      if (!waitEOS && outSizeHigh == 0 && outAvail > outSize)
+        outAvail = (SizeT)outSize;
+      res = LzmaDecode(&state,
+        #ifdef _LZMA_IN_CB
+        &g_InBuffer.InCallback,
+        #else
+        inBuffer, inAvail, &inProcessed,
+        #endif
+        g_OutBuffer, outAvail, &outProcessed);
+      if (res != 0)
+      {
+        sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+        res = 1;
+        break;
+      }
+      #ifndef _LZMA_IN_CB
+      inAvail -= inProcessed;
+      inBuffer += inProcessed;
+      #endif
+      
+      if (outFile != 0)  
+        if (!MyWriteFileAndCheck(outFile, g_OutBuffer, (size_t)outProcessed))
+        {
+          PrintError(rs, kCantWriteMessage);
+          res = 1;
+          break;
+        }
+        
+      if (outSize < outProcessed)
+        outSizeHigh--;
+      outSize -= (UInt32)outProcessed;
+      outSize &= 0xFFFFFFFF;
+        
+      if (outProcessed == 0)
+      {
+        if (!waitEOS && (outSize != 0 || outSizeHigh != 0))
+          res = 1;
+        break;
+      }
+    }
+    while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0  || waitEOS);
+  }
+
+  #else
+  {
+    #ifndef _LZMA_IN_CB
+    SizeT inProcessed;
+    #endif
+    SizeT outProcessed;
+    res = LzmaDecode(&state,
+      #ifdef _LZMA_IN_CB
+      &g_InBuffer.InCallback,
+      #else
+      inStream, compressedSize, &inProcessed,
+      #endif
+      outStream, outSizeFull, &outProcessed);
+    if (res != 0)
+    {
+      sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+      res = 1;
+    }
+    else if (outFile != 0)
+    {
+      if (!MyWriteFileAndCheck(outFile, outStream, (size_t)outProcessed))
+      {
+        PrintError(rs, kCantWriteMessage);
+        res = 1;
+      }
+    }
+  }
+  #endif
+
+  free(state.Probs);
+  #ifdef _LZMA_OUT_READ
+  free(state.Dictionary);
+  #else
+  free(outStream);
+  #endif
+  #ifndef _LZMA_IN_CB
+  free(inStream);
+  #endif
+  return res;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+  FILE *inFile = 0;
+  FILE *outFile = 0;
+  int res;
+
+  sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov  2005-08-05\n");
+  if (numArgs < 2 || numArgs > 3)
+  {
+    sprintf(rs + strlen(rs), "\nUsage:  lzmadec file.lzma [outFile]\n");
+    return 1;
+  }
+
+  inFile = fopen(args[1], "rb");
+  if (inFile == 0)
+    return PrintError(rs, "Can not open input file");
+
+  if (numArgs > 2)
+  {
+    outFile = fopen(args[2], "wb+");
+    if (outFile == 0)
+      return PrintError(rs, "Can not open output file");
+  }
+
+  res = main3(inFile, outFile, rs);
+
+  if (outFile != 0)
+    fclose(outFile);
+  fclose(inFile);
+  return res;
+}
+
+int main(int numArgs, const char *args[])
+{
+  char rs[800] = { 0 };
+  int res = main2(numArgs, args, rs);
+  printf(rs);
+  return res;
+}
diff --git a/lzma/C/Compress/Lzma/LzmaTypes.h b/lzma/C/Compress/Lzma/LzmaTypes.h
new file mode 100644 (file)
index 0000000..9c27290
--- /dev/null
@@ -0,0 +1,45 @@
+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif
diff --git a/lzma/C/CpuArch.h b/lzma/C/CpuArch.h
new file mode 100644 (file)
index 0000000..26ce8b1
--- /dev/null
@@ -0,0 +1,18 @@
+/* CpuArch.h */
+
+#ifndef __CPUARCH_H
+#define __CPUARCH_H
+
+/* 
+LITTLE_ENDIAN_UNALIGN means:
+  1) CPU is LITTLE_ENDIAN
+  2) it's allowed to make unaligned memory accesses
+if LITTLE_ENDIAN_UNALIGN is not defined, it means that we don't know 
+about these properties of platform.
+*/
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
+#define LITTLE_ENDIAN_UNALIGN
+#endif
+
+#endif
diff --git a/lzma/C/IStream.h b/lzma/C/IStream.h
new file mode 100644 (file)
index 0000000..5821848
--- /dev/null
@@ -0,0 +1,19 @@
+/* IStream.h */
+
+#ifndef __C_ISTREAM_H
+#define __C_ISTREAM_H
+
+#include "Types.h"
+
+typedef struct _ISeqInStream
+{
+  HRes (*Read)(void *object, void *data, UInt32 size, UInt32 *processedSize);
+} ISeqInStream;
+
+typedef struct _ISzAlloc
+{
+  void *(*Alloc)(size_t size);
+  void (*Free)(void *address); /* address can be 0 */
+} ISzAlloc;
+
+#endif
diff --git a/lzma/C/Sort.c b/lzma/C/Sort.c
new file mode 100644 (file)
index 0000000..b30cd6a
--- /dev/null
@@ -0,0 +1,92 @@
+/* Sort.c */
+
+#include "Sort.h"
+
+#define HeapSortDown(p, k, size, temp) \
+  { for (;;) { \
+    UInt32 s = (k << 1); \
+    if (s > size) break; \
+    if (s < size && p[s + 1] > p[s]) s++; \
+    if (temp >= p[s]) break; \
+    p[k] = p[s]; k = s; \
+  } p[k] = temp; }
+
+void HeapSort(UInt32 *p, UInt32 size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    UInt32 i = size / 2;
+    do
+    {
+      UInt32 temp = p[i];
+      UInt32 k = i;
+      HeapSortDown(p, k, size, temp)
+    }
+    while(--i != 0);
+  }
+  /*
+  do
+  {
+    UInt32 k = 1;
+    UInt32 temp = p[size];
+    p[size--] = p[1];
+    HeapSortDown(p, k, size, temp)
+  }
+  while (size > 1);
+  */
+  while (size > 3)
+  {
+    UInt32 temp = p[size];
+    UInt32 k = (p[3] > p[2]) ? 3 : 2;
+    p[size--] = p[1];
+    p[1] = p[k]; 
+    HeapSortDown(p, k, size, temp)
+  }
+  {
+    UInt32 temp = p[size];
+    p[size] = p[1];
+    if (size > 2 && p[2] < temp)
+    {
+      p[1] = p[2];
+      p[2] = temp;
+    }
+    else
+      p[1] = temp;
+  }
+}
+
+/*
+#define HeapSortRefDown(p, vals, n, size, temp) \
+  { UInt32 k = n; UInt32 val = vals[temp]; for (;;) { \
+    UInt32 s = (k << 1); \
+    if (s > size) break; \
+    if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
+    if (val >= vals[p[s]]) break; \
+    p[k] = p[s]; k = s; \
+  } p[k] = temp; }
+
+void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    UInt32 i = size / 2;
+    do
+    {
+      UInt32 temp = p[i];
+      HeapSortRefDown(p, vals, i, size, temp);
+    }
+    while(--i != 0);
+  }
+  do
+  {
+    UInt32 temp = p[size];
+    p[size--] = p[1];
+    HeapSortRefDown(p, vals, 1, size, temp);
+  }
+  while (size > 1);
+}
+*/
\ No newline at end of file
diff --git a/lzma/C/Sort.h b/lzma/C/Sort.h
new file mode 100644 (file)
index 0000000..896243c
--- /dev/null
@@ -0,0 +1,11 @@
+/* Sort.h */
+
+#ifndef __7Z_Sort_H
+#define __7Z_Sort_H
+
+#include "Types.h"
+
+void HeapSort(UInt32 *p, UInt32 size);
+/* void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size); */
+
+#endif
diff --git a/lzma/C/Threads.c b/lzma/C/Threads.c
new file mode 100644 (file)
index 0000000..def4817
--- /dev/null
@@ -0,0 +1,106 @@
+/* Threads.c */
+
+#include "Threads.h"
+#include <process.h>
+
+HRes GetError()
+{
+  DWORD res = GetLastError();
+  return (res) ? (HRes)(res) : SZE_FAIL;
+}
+
+HRes BoolToHRes(int v) { return v ? SZ_OK : GetError(); }
+HRes BOOLToHRes(BOOL v) { return v ? SZ_OK : GetError(); }
+
+HRes MyCloseHandle(HANDLE *h)
+{
+  if (*h != NULL)
+    if (!CloseHandle(*h))
+      return GetError();
+  *h = NULL;
+  return SZ_OK;
+}
+
+HRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+{ 
+  unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+  thread->handle = 
+    /* CreateThread(0, 0, startAddress, parameter, 0, &threadId); */
+    (HANDLE)_beginthreadex(NULL, 0, startAddress, parameter, 0, &threadId);
+    /* maybe we must use errno here, but probably GetLastError() is also OK. */
+  return BoolToHRes(thread->handle != 0);
+}
+
+HRes WaitObject(HANDLE h)
+{
+  return (HRes)WaitForSingleObject(h, INFINITE); 
+}
+
+HRes Thread_Wait(CThread *thread)
+{
+  if (thread->handle == NULL)
+    return 1;
+  return WaitObject(thread->handle); 
+}
+
+HRes Thread_Close(CThread *thread)
+{
+  return MyCloseHandle(&thread->handle);
+}
+
+HRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
+{
+  p->handle = CreateEvent(NULL, manualReset, (initialSignaled ? TRUE : FALSE), NULL);
+  return BoolToHRes(p->handle != 0);
+}
+
+HRes ManualResetEvent_Create(CManualResetEvent *p, int initialSignaled)
+  { return Event_Create(p, TRUE, initialSignaled); }
+HRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) 
+  { return ManualResetEvent_Create(p, 0); }
+
+HRes AutoResetEvent_Create(CAutoResetEvent *p, int initialSignaled)
+  { return Event_Create(p, FALSE, initialSignaled); }
+HRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) 
+  { return AutoResetEvent_Create(p, 0); }
+
+HRes Event_Set(CEvent *p) { return BOOLToHRes(SetEvent(p->handle)); }
+HRes Event_Reset(CEvent *p) { return BOOLToHRes(ResetEvent(p->handle)); }
+HRes Event_Wait(CEvent *p) { return WaitObject(p->handle); }
+HRes Event_Close(CEvent *p) { return MyCloseHandle(&p->handle); }
+
+
+HRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
+{
+  p->handle = CreateSemaphore(NULL, (LONG)initiallyCount, (LONG)maxCount, NULL);
+  return BoolToHRes(p->handle != 0);
+}
+
+HRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) 
+{ 
+  return BOOLToHRes(ReleaseSemaphore(p->handle, releaseCount, previousCount)); 
+}
+HRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+  return Semaphore_Release(p, (LONG)releaseCount, NULL);
+}
+HRes Semaphore_Release1(CSemaphore *p)
+{
+  return Semaphore_ReleaseN(p, 1);
+}
+
+HRes Semaphore_Wait(CSemaphore *p) { return WaitObject(p->handle); }
+HRes Semaphore_Close(CSemaphore *p) { return MyCloseHandle(&p->handle); }
+
+HRes CriticalSection_Init(CCriticalSection *p)
+{
+  /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */
+  __try 
+  { 
+    InitializeCriticalSection(p); 
+    /* InitializeCriticalSectionAndSpinCount(p, 0); */
+  }  
+  __except (EXCEPTION_EXECUTE_HANDLER) { return SZE_OUTOFMEMORY; }
+  return SZ_OK;
+}
+
diff --git a/lzma/C/Threads.h b/lzma/C/Threads.h
new file mode 100644 (file)
index 0000000..c024dcc
--- /dev/null
@@ -0,0 +1,69 @@
+/* Threads.h */
+
+#ifndef __7Z_THRESDS_H
+#define __7Z_THRESDS_H
+
+#include <windows.h>
+
+#include "Types.h"
+
+typedef struct _CThread
+{
+  HANDLE handle;
+} CThread;
+
+#define Thread_Construct(thread) (thread)->handle = NULL
+#define Thread_WasCreated(thread) ((thread)->handle != NULL)
+typedef unsigned THREAD_FUNC_RET_TYPE;
+#define THREAD_FUNC_CALL_TYPE StdCall
+#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+
+HRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter);
+HRes Thread_Wait(CThread *thread);
+HRes Thread_Close(CThread *thread);
+
+typedef struct _CEvent
+{
+  HANDLE handle;
+} CEvent;
+
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+
+#define Event_Construct(event) (event)->handle = NULL
+#define Event_IsCreated(event) ((event)->handle != NULL)
+
+HRes ManualResetEvent_Create(CManualResetEvent *event, int initialSignaled);
+HRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *event);
+HRes AutoResetEvent_Create(CAutoResetEvent *event, int initialSignaled);
+HRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *event);
+HRes Event_Set(CEvent *event);
+HRes Event_Reset(CEvent *event);
+HRes Event_Wait(CEvent *event);
+HRes Event_Close(CEvent *event);
+
+
+typedef struct _CSemaphore
+{
+  HANDLE handle;
+} CSemaphore;
+
+#define Semaphore_Construct(p) (p)->handle = NULL
+
+HRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount);
+HRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+HRes Semaphore_Release1(CSemaphore *p);
+HRes Semaphore_Wait(CSemaphore *p);
+HRes Semaphore_Close(CSemaphore *p);
+
+
+typedef CRITICAL_SECTION CCriticalSection;
+
+HRes CriticalSection_Init(CCriticalSection *p);
+#define CriticalSection_Delete(p) DeleteCriticalSection(p)
+#define CriticalSection_Enter(p) EnterCriticalSection(p)
+#define CriticalSection_Leave(p) LeaveCriticalSection(p)
+
+#endif
+
diff --git a/lzma/C/Types.h b/lzma/C/Types.h
new file mode 100644 (file)
index 0000000..368cc31
--- /dev/null
@@ -0,0 +1,100 @@
+/* 7zTypes.h */
+
+#ifndef __C_TYPES_H
+#define __C_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 
+
+#ifndef _7ZIP_INT32_DEFINED
+#define _7ZIP_INT32_DEFINED
+#ifdef _LZMA_INT32_IS_ULONG
+typedef long Int32;
+#else
+typedef int Int32;
+#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
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 UInt64;
+#else
+typedef unsigned long long int UInt64;
+#endif
+#endif
+#endif
+
+
+/* #define _SZ_FILE_SIZE_32 */
+/* You can define _SZ_FILE_SIZE_32, if you don't need support for files larger than 4 GB*/
+
+#ifndef CFileSize
+#ifdef _SZ_FILE_SIZE_32
+typedef UInt32 CFileSize; 
+#else
+typedef UInt64 CFileSize; 
+#endif
+#endif
+
+#define SZ_RESULT int
+
+typedef int HRes;
+#define RES_OK (0)
+
+#define SZ_OK (0)
+#define SZE_DATA_ERROR (1)
+#define SZE_CRC_ERROR (3)
+#define SZE_ARCHIVE_ERROR (6)
+
+#define SZE_OUTOFMEMORY (0x8007000EL)
+#define SZE_NOTIMPL (0x80004001L)
+#define SZE_FAIL (0x80004005L)
+#define SZE_INVALIDARG (0x80070057L)
+
+
+#ifndef RINOK
+#define RINOK(x) { HRes __result_ = (x); if(__result_ != 0) return __result_; }
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+#ifdef _MSC_VER
+#define StdCall __stdcall 
+#else
+#define StdCall
+#endif
+
+#if _MSC_VER >= 1300
+#define MY_FAST_CALL __declspec(noinline) __fastcall 
+#elif defined( _MSC_VER)
+#define MY_FAST_CALL __fastcall 
+#else
+#define MY_FAST_CALL
+#endif
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7z.ico b/lzma/CPP/7zip/Archive/7z/7z.ico
new file mode 100755 (executable)
index 0000000..319753a
Binary files /dev/null and b/lzma/CPP/7zip/Archive/7z/7z.ico differ
diff --git a/lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp
new file mode 100644 (file)
index 0000000..6774fc4
--- /dev/null
@@ -0,0 +1,3 @@
+// CompressionMethod.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Archive/7z/7zCompressionMode.h b/lzma/CPP/7zip/Archive/7z/7zCompressionMode.h
new file mode 100644 (file)
index 0000000..5753606
--- /dev/null
@@ -0,0 +1,50 @@
+// 7zCompressionMode.h
+
+#ifndef __7Z_COMPRESSION_MODE_H
+#define __7Z_COMPRESSION_MODE_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CMethodFull: public CMethod
+{
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+  bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBind
+{
+  UInt32 InCoder;
+  UInt32 InStream;
+  UInt32 OutCoder;
+  UInt32 OutStream;
+};
+
+struct CCompressionMethodMode
+{
+  CObjectVector<CMethodFull> Methods;
+  CRecordVector<CBind> Binds;
+  #ifdef COMPRESS_MT
+  UInt32 NumThreads;
+  #endif
+  bool PasswordIsDefined;
+  UString Password;
+
+  bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+  CCompressionMethodMode(): PasswordIsDefined(false)
+      #ifdef COMPRESS_MT
+      , NumThreads(1) 
+      #endif
+  {}
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zDecode.cpp b/lzma/CPP/7zip/Archive/7z/7zDecode.cpp
new file mode 100644 (file)
index 0000000..0f81de4
--- /dev/null
@@ -0,0 +1,330 @@
+// 7zDecode.cpp
+
+#include "StdAfx.h"
+
+#include "7zDecode.h"
+
+#include "../../IPassword.h"
+#include "../../Common/LockedStream.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
+    CBindInfoEx &bindInfo)
+{
+  bindInfo.Clear();
+  int i;
+  for (i = 0; i < folder.BindPairs.Size(); i++)
+  {
+    NCoderMixer::CBindPair bindPair;
+    bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
+    bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
+    bindInfo.BindPairs.Add(bindPair);
+  }
+  UInt32 outStreamIndex = 0;
+  for (i = 0; i < folder.Coders.Size(); i++)
+  {
+    NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+    const CCoderInfo &coderInfo = folder.Coders[i];
+    coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
+    coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
+    bindInfo.Coders.Add(coderStreamsInfo);
+    bindInfo.CoderMethodIDs.Add(coderInfo.MethodID);
+    for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
+      if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
+        bindInfo.OutStreams.Add(outStreamIndex);
+  }
+  for (i = 0; i < folder.PackStreams.Size(); i++)
+    bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
+}
+
+static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, 
+    const NCoderMixer::CCoderStreamsInfo &a2)
+{
+  return (a1.NumInStreams == a2.NumInStreams) &&
+    (a1.NumOutStreams == a2.NumOutStreams);
+}
+
+static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2)
+{
+  return (a1.InIndex == a2.InIndex) &&
+    (a1.OutIndex == a2.OutIndex);
+}
+
+static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
+{
+  if (a1.Coders.Size() != a2.Coders.Size())
+    return false;
+  int i;
+  for (i = 0; i < a1.Coders.Size(); i++)
+    if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
+      return false;
+  if (a1.BindPairs.Size() != a2.BindPairs.Size())
+    return false;
+  for (i = 0; i < a1.BindPairs.Size(); i++)
+    if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
+      return false;
+  for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
+    if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
+      return false;
+  if (a1.InStreams.Size() != a2.InStreams.Size())
+    return false;
+  if (a1.OutStreams.Size() != a2.OutStreams.Size())
+    return false;
+  return true;
+}
+
+CDecoder::CDecoder(bool multiThread)
+{
+  #ifndef _ST_MODE
+  multiThread = true;
+  #endif
+  _multiThread = multiThread;
+  _bindInfoExPrevIsDefined = false;
+}
+
+HRESULT CDecoder::Decode(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    UInt64 startPos,
+    const UInt64 *packSizes,
+    const CFolder &folderInfo, 
+    ISequentialOutStream *outStream,
+    ICompressProgressInfo *compressProgress
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    #ifdef COMPRESS_MT
+    , bool mtMode, UInt32 numThreads
+    #endif
+    )
+{
+  CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+  
+  CLockedInStream lockedInStream;
+  lockedInStream.Init(inStream);
+  
+  for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
+  {
+    CLockedSequentialInStreamImp *lockedStreamImpSpec = new 
+        CLockedSequentialInStreamImp;
+    CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
+    lockedStreamImpSpec->Init(&lockedInStream, startPos);
+    startPos += packSizes[j];
+    
+    CLimitedSequentialInStream *streamSpec = new 
+        CLimitedSequentialInStream;
+    CMyComPtr<ISequentialInStream> inStream = streamSpec;
+    streamSpec->SetStream(lockedStreamImp);
+    streamSpec->Init(packSizes[j]);
+    inStreams.Add(inStream);
+  }
+  
+  int numCoders = folderInfo.Coders.Size();
+  
+  CBindInfoEx bindInfo;
+  ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
+  bool createNewCoders;
+  if (!_bindInfoExPrevIsDefined)
+    createNewCoders = true;
+  else
+    createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
+  if (createNewCoders)
+  {
+    int i;
+    _decoders.Clear();
+    // _decoders2.Clear();
+    
+    _mixerCoder.Release();
+
+    if (_multiThread)
+    {
+      _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT;
+      _mixerCoder = _mixerCoderMTSpec;
+      _mixerCoderCommon = _mixerCoderMTSpec;
+    }
+    else
+    {
+      #ifdef _ST_MODE
+      _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST;
+      _mixerCoder = _mixerCoderSTSpec;
+      _mixerCoderCommon = _mixerCoderSTSpec;
+      #endif
+    }
+    RINOK(_mixerCoderCommon->SetBindInfo(bindInfo));
+    
+    for (i = 0; i < numCoders; i++)
+    {
+      const CCoderInfo &coderInfo = folderInfo.Coders[i];
+
+  
+      CMyComPtr<ICompressCoder> decoder;
+      CMyComPtr<ICompressCoder2> decoder2;
+      RINOK(CreateCoder(
+          EXTERNAL_CODECS_LOC_VARS
+          coderInfo.MethodID, decoder, decoder2, false));
+      CMyComPtr<IUnknown> decoderUnknown;
+      if (coderInfo.IsSimpleCoder())
+      {
+        if (decoder == 0)
+          return E_NOTIMPL;
+
+        decoderUnknown = (IUnknown *)decoder;
+        
+        if (_multiThread)
+          _mixerCoderMTSpec->AddCoder(decoder);
+        #ifdef _ST_MODE
+        else
+          _mixerCoderSTSpec->AddCoder(decoder, false);
+        #endif
+      }
+      else
+      {
+        if (decoder2 == 0)
+          return E_NOTIMPL;
+        decoderUnknown = (IUnknown *)decoder2;
+        if (_multiThread)
+          _mixerCoderMTSpec->AddCoder2(decoder2);
+        #ifdef _ST_MODE
+        else
+          _mixerCoderSTSpec->AddCoder2(decoder2, false);
+        #endif
+      }
+      _decoders.Add(decoderUnknown);
+      #ifdef EXTERNAL_CODECS
+      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+      decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+      if (setCompressCodecsInfo)
+      {
+        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+      }
+      #endif
+    }
+    _bindInfoExPrev = bindInfo;
+    _bindInfoExPrevIsDefined = true;
+  }
+  int i;
+  _mixerCoderCommon->ReInit();
+  
+  UInt32 packStreamIndex = 0, unPackStreamIndex = 0;
+  UInt32 coderIndex = 0;
+  // UInt32 coder2Index = 0;
+  
+  for (i = 0; i < numCoders; i++)
+  {
+    const CCoderInfo &coderInfo = folderInfo.Coders[i];
+    CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
+    
+    {
+      CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+      decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+      if (setDecoderProperties)
+      {
+        const CByteBuffer &properties = coderInfo.Properties;
+        size_t size = properties.GetCapacity();
+        if (size > 0xFFFFFFFF)
+          return E_NOTIMPL;
+        if (size > 0)
+        {
+          RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size));
+        }
+      }
+    }
+
+    #ifdef COMPRESS_MT
+    if (mtMode)
+    {
+      CMyComPtr<ICompressSetCoderMt> setCoderMt;
+      decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+      if (setCoderMt)
+      {
+        RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+      }
+    }
+    #endif
+
+    #ifndef _NO_CRYPTO
+    {
+      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+      decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+      if (cryptoSetPassword)
+      {
+        if (getTextPassword == 0)
+          return E_FAIL;
+        CMyComBSTR password;
+        RINOK(getTextPassword->CryptoGetTextPassword(&password));
+        CByteBuffer buffer;
+        UString unicodePassword(password);
+        const UInt32 sizeInBytes = unicodePassword.Length() * 2;
+        buffer.SetCapacity(sizeInBytes);
+        for (int i = 0; i < unicodePassword.Length(); i++)
+        {
+          wchar_t c = unicodePassword[i];
+          ((Byte *)buffer)[i * 2] = (Byte)c;
+          ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+        }
+        RINOK(cryptoSetPassword->CryptoSetPassword(
+          (const Byte *)buffer, sizeInBytes));
+      }
+    }
+    #endif
+
+    coderIndex++;
+    
+    UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
+    UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
+    CRecordVector<const UInt64 *> packSizesPointers;
+    CRecordVector<const UInt64 *> unPackSizesPointers;
+    packSizesPointers.Reserve(numInStreams);
+    unPackSizesPointers.Reserve(numOutStreams);
+    UInt32 j;
+    for (j = 0; j < numOutStreams; j++, unPackStreamIndex++)
+      unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]);
+    
+    for (j = 0; j < numInStreams; j++, packStreamIndex++)
+    {
+      int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
+      if (bindPairIndex >= 0)
+        packSizesPointers.Add(
+        &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
+      else
+      {
+        int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
+        if (index < 0)
+          return E_FAIL;
+        packSizesPointers.Add(&packSizes[index]);
+      }
+    }
+    
+    _mixerCoderCommon->SetCoderInfo(i, 
+        &packSizesPointers.Front(), 
+        &unPackSizesPointers.Front());
+  }
+  UInt32 mainCoder, temp;
+  bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
+
+  if (_multiThread)
+    _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
+  /*
+  else
+    _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
+  */
+  
+  if (numCoders == 0)
+    return 0;
+  CRecordVector<ISequentialInStream *> inStreamPointers;
+  inStreamPointers.Reserve(inStreams.Size());
+  for (i = 0; i < inStreams.Size(); i++)
+    inStreamPointers.Add(inStreams[i]);
+  ISequentialOutStream *outStreamPointer = outStream;
+  return _mixerCoder->Code(&inStreamPointers.Front(), NULL, 
+    inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zDecode.h b/lzma/CPP/7zip/Archive/7z/7zDecode.h
new file mode 100644 (file)
index 0000000..7c10dfe
--- /dev/null
@@ -0,0 +1,68 @@
+// 7zDecode.h
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "../../IStream.h"
+#include "../../IPassword.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+
+#include "../../Common/CreateCoder.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CBindInfoEx: public NCoderMixer::CBindInfo
+{
+  CRecordVector<CMethodId> CoderMethodIDs;
+  void Clear()
+  {
+    CBindInfo::Clear();
+    CoderMethodIDs.Clear();
+  }
+};
+
+class CDecoder
+{
+  bool _bindInfoExPrevIsDefined;
+  CBindInfoEx _bindInfoExPrev;
+  
+  bool _multiThread;
+  #ifdef _ST_MODE
+  NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec;
+  #endif
+  NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec;
+  NCoderMixer::CCoderMixer2 *_mixerCoderCommon;
+  
+  CMyComPtr<ICompressCoder2> _mixerCoder;
+  CObjectVector<CMyComPtr<IUnknown> > _decoders;
+  // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2;
+public:
+  CDecoder(bool multiThread);
+  HRESULT Decode(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      IInStream *inStream,
+      UInt64 startPos,
+      const UInt64 *packSizes,
+      const CFolder &folder, 
+      ISequentialOutStream *outStream,
+      ICompressProgressInfo *compressProgress
+      #ifndef _NO_CRYPTO
+      , ICryptoGetTextPassword *getTextPasswordSpec
+      #endif
+      #ifdef COMPRESS_MT
+      , bool mtMode, UInt32 numThreads
+      #endif
+      );
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zEncode.cpp b/lzma/CPP/7zip/Archive/7z/7zEncode.cpp
new file mode 100644 (file)
index 0000000..3a5cfcd
--- /dev/null
@@ -0,0 +1,453 @@
+// Encode.cpp
+
+#include "StdAfx.h"
+
+#include "7zEncode.h"
+#include "7zSpecStream.h"
+
+#include "../../IPassword.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/InOutTempBuffer.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+static const UInt64 k_AES = 0x06F10701;
+static const UInt64 k_BCJ  = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
+    const CRecordVector<CMethodId> decompressionMethods,
+    CFolder &folder)
+{
+  folder.Coders.Clear();
+  // bindInfo.CoderMethodIDs.Clear();
+  // folder.OutStreams.Clear();
+  folder.PackStreams.Clear();
+  folder.BindPairs.Clear();
+  int i;
+  for (i = 0; i < bindInfo.BindPairs.Size(); i++)
+  {
+    CBindPair bindPair;
+    bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
+    bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
+    folder.BindPairs.Add(bindPair);
+  }
+  for (i = 0; i < bindInfo.Coders.Size(); i++)
+  {
+    CCoderInfo coderInfo;
+    const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
+    coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
+    coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
+    coderInfo.MethodID = decompressionMethods[i];
+    folder.Coders.Add(coderInfo);
+  }
+  for (i = 0; i < bindInfo.InStreams.Size(); i++)
+    folder.PackStreams.Add(bindInfo.InStreams[i]);
+}
+
+HRESULT CEncoder::CreateMixerCoder(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    const UInt64 *inSizeForReduce)
+{
+  _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
+  _mixerCoder = _mixerCoderSpec;
+  RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
+  for (int i = 0; i < _options.Methods.Size(); i++)
+  {
+    const CMethodFull &methodFull = _options.Methods[i];
+    _codersInfo.Add(CCoderInfo());
+    CCoderInfo &encodingInfo = _codersInfo.Back();
+    encodingInfo.MethodID = methodFull.Id;
+    CMyComPtr<ICompressCoder> encoder;
+    CMyComPtr<ICompressCoder2> encoder2;
+    
+
+    RINOK(CreateCoder(
+        EXTERNAL_CODECS_LOC_VARS
+        methodFull.Id, encoder, encoder2, true));
+
+    if (!encoder && !encoder2)
+      return E_FAIL;
+
+    CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
+   
+    #ifdef COMPRESS_MT
+    {
+      CMyComPtr<ICompressSetCoderMt> setCoderMt;
+      encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+      if (setCoderMt)
+      {
+        RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
+      }
+    }
+    #endif
+        
+
+    RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon));
+
+    /*
+    CMyComPtr<ICryptoResetSalt> resetSalt;
+    encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
+    if (resetSalt != NULL)
+    {
+      resetSalt->ResetSalt();
+    }
+    */
+
+    #ifdef EXTERNAL_CODECS
+    CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+    encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+    if (setCompressCodecsInfo)
+    {
+      RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+    }
+    #endif
+    
+    CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+    encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+
+    if (cryptoSetPassword)
+    {
+      CByteBuffer buffer;
+      const UInt32 sizeInBytes = _options.Password.Length() * 2;
+      buffer.SetCapacity(sizeInBytes);
+      for (int i = 0; i < _options.Password.Length(); i++)
+      {
+        wchar_t c = _options.Password[i];
+        ((Byte *)buffer)[i * 2] = (Byte)c;
+        ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+      }
+      RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+    }
+
+    if (encoder)
+      _mixerCoderSpec->AddCoder(encoder);
+    else
+      _mixerCoderSpec->AddCoder2(encoder2);
+  }
+  return S_OK;
+}
+
+HRESULT CEncoder::Encode(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    ISequentialInStream *inStream,
+    const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+    CFolder &folderItem,
+    ISequentialOutStream *outStream,
+    CRecordVector<UInt64> &packSizes,
+    ICompressProgressInfo *compressProgress)
+{
+  RINOK(EncoderConstr());
+
+  if (_mixerCoderSpec == NULL)
+  {
+    RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
+  }
+  _mixerCoderSpec->ReInit();
+  // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
+
+  CObjectVector<CInOutTempBuffer> inOutTempBuffers;
+  CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
+  CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+  int numMethods = _bindInfo.Coders.Size();
+  int i;
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    inOutTempBuffers.Add(CInOutTempBuffer());
+    inOutTempBuffers.Back().Create();
+    inOutTempBuffers.Back().InitWriting();
+  }
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    CSequentialOutTempBufferImp *tempBufferSpec = 
+        new CSequentialOutTempBufferImp;
+    CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
+    tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
+    tempBuffers.Add(tempBuffer);
+    tempBufferSpecs.Add(tempBufferSpec);
+  }
+
+  for (i = 0; i < numMethods; i++)
+    _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
+
+  if (_bindInfo.InStreams.IsEmpty())
+    return E_FAIL;
+  UInt32 mainCoderIndex, mainStreamIndex;
+  _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
+  
+  if (inStreamSize != NULL)
+  {
+    CRecordVector<const UInt64 *> sizePointers;
+    for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
+      if (i == mainStreamIndex)
+        sizePointers.Add(inStreamSize);
+      else
+        sizePointers.Add(NULL);
+    _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
+  }
+
+  
+  // UInt64 outStreamStartPos;
+  // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
+  
+  CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = 
+      new CSequentialInStreamSizeCount2;
+  CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+  CSequentialOutStreamSizeCount *outStreamSizeCountSpec = 
+      new CSequentialOutStreamSizeCount;
+  CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
+
+  inStreamSizeCountSpec->Init(inStream);
+  outStreamSizeCountSpec->SetStream(outStream);
+  outStreamSizeCountSpec->Init();
+
+  CRecordVector<ISequentialInStream *> inStreamPointers;
+  CRecordVector<ISequentialOutStream *> outStreamPointers;
+  inStreamPointers.Add(inStreamSizeCount);
+  outStreamPointers.Add(outStreamSizeCount);
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+    outStreamPointers.Add(tempBuffers[i - 1]);
+
+  for (i = 0; i < _codersInfo.Size(); i++)
+  {
+    CCoderInfo &encodingInfo = _codersInfo[i];
+    
+    CMyComPtr<ICryptoResetInitVector> resetInitVector;
+    _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
+    if (resetInitVector != NULL)
+    {
+      resetInitVector->ResetInitVector();
+    }
+
+    CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+    _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+    if (writeCoderProperties != NULL)
+    {
+      CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
+      CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+      outStreamSpec->Init();
+      writeCoderProperties->WriteCoderProperties(outStream);
+      size_t size = outStreamSpec->GetSize();
+      encodingInfo.Properties.SetCapacity(size);
+      memmove(encodingInfo.Properties, outStreamSpec->GetBuffer(), size);
+    }
+  }
+
+  UInt32 progressIndex = mainCoderIndex;
+
+  for (i = 0; i < _codersInfo.Size(); i++)
+  {
+    const CCoderInfo &e = _codersInfo[i];
+    if ((e.MethodID == k_BCJ || e.MethodID == k_BCJ2) && i + 1 < _codersInfo.Size())
+      progressIndex = i + 1;
+  }
+
+  _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
+  
+  RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
+    &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
+  
+  ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods,
+      folderItem);
+  
+  packSizes.Add(outStreamSizeCountSpec->GetSize());
+  
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
+    inOutTempBuffer.FlushWrite();
+    inOutTempBuffer.InitReading();
+    inOutTempBuffer.WriteToStream(outStream);
+    packSizes.Add(inOutTempBuffer.GetDataSize());
+  }
+  
+  for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
+  {
+    int binder = _bindInfo.FindBinderForInStream(
+        _bindReverseConverter->DestOutToSrcInMap[i]);
+    UInt64 streamSize;
+    if (binder < 0)
+      streamSize = inStreamSizeCountSpec->GetSize();
+    else
+      streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
+    folderItem.UnPackSizes.Add(streamSize);
+  }
+  for (i = numMethods - 1; i >= 0; i--)
+    folderItem.Coders[numMethods - 1 - i].Properties = _codersInfo[i].Properties;
+  return S_OK;
+}
+
+
+CEncoder::CEncoder(const CCompressionMethodMode &options):
+  _bindReverseConverter(0),
+  _constructed(false)
+{
+  if (options.IsEmpty())
+    throw 1;
+
+  _options = options;
+  _mixerCoderSpec = NULL;
+}
+
+HRESULT CEncoder::EncoderConstr()
+{
+  if (_constructed)
+    return S_OK;
+  if (_options.Methods.IsEmpty())
+  {
+    // it has only password method;
+    if (!_options.PasswordIsDefined)
+      throw 1;
+    if (!_options.Binds.IsEmpty())
+      throw 1;
+    NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+    CMethodFull method;
+    
+    method.NumInStreams = 1;
+    method.NumOutStreams = 1;
+    coderStreamsInfo.NumInStreams = 1;
+    coderStreamsInfo.NumOutStreams = 1;
+    method.Id = k_AES;
+    
+    _options.Methods.Add(method);
+    _bindInfo.Coders.Add(coderStreamsInfo);
+  
+    _bindInfo.InStreams.Add(0);
+    _bindInfo.OutStreams.Add(0);
+  }
+  else
+  {
+
+  UInt32 numInStreams = 0, numOutStreams = 0;
+  int i;
+  for (i = 0; i < _options.Methods.Size(); i++)
+  {
+    const CMethodFull &methodFull = _options.Methods[i];
+    NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+    coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
+    coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
+    if (_options.Binds.IsEmpty())
+    {
+      if (i < _options.Methods.Size() - 1)
+      {
+        NCoderMixer::CBindPair bindPair;
+        bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
+        bindPair.OutIndex = numOutStreams;
+        _bindInfo.BindPairs.Add(bindPair);
+      }
+      else
+        _bindInfo.OutStreams.Insert(0, numOutStreams);
+      for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
+        _bindInfo.OutStreams.Add(numOutStreams + j);
+    }
+    
+    numInStreams += coderStreamsInfo.NumInStreams;
+    numOutStreams += coderStreamsInfo.NumOutStreams;
+
+    _bindInfo.Coders.Add(coderStreamsInfo);
+  }
+
+  if (!_options.Binds.IsEmpty())
+  {
+    for (i = 0; i < _options.Binds.Size(); i++)
+    {
+      NCoderMixer::CBindPair bindPair;
+      const CBind &bind = _options.Binds[i];
+      bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
+      bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
+      _bindInfo.BindPairs.Add(bindPair);
+    }
+    for (i = 0; i < (int)numOutStreams; i++)
+      if (_bindInfo.FindBinderForOutStream(i) == -1)
+        _bindInfo.OutStreams.Add(i);
+  }
+
+  for (i = 0; i < (int)numInStreams; i++)
+    if (_bindInfo.FindBinderForInStream(i) == -1)
+      _bindInfo.InStreams.Add(i);
+
+  if (_bindInfo.InStreams.IsEmpty())
+    throw 1; // this is error
+
+  // Make main stream first in list
+  int inIndex = _bindInfo.InStreams[0];
+  for (;;)
+  {
+    UInt32 coderIndex, coderStreamIndex;
+    _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
+    UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+    int binder = _bindInfo.FindBinderForOutStream(outIndex);
+    if (binder >= 0)
+    {
+      inIndex = _bindInfo.BindPairs[binder].InIndex;
+      continue;
+    }
+    for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+      if (_bindInfo.OutStreams[i] == outIndex)
+      {
+        _bindInfo.OutStreams.Delete(i);
+        _bindInfo.OutStreams.Insert(0, outIndex);
+        break;
+      }
+    break;
+  }
+
+  if (_options.PasswordIsDefined)
+  {
+    int numCryptoStreams = _bindInfo.OutStreams.Size();
+
+    for (i = 0; i < numCryptoStreams; i++)
+    {
+      NCoderMixer::CBindPair bindPair;
+      bindPair.InIndex = numInStreams + i;
+      bindPair.OutIndex = _bindInfo.OutStreams[i];
+      _bindInfo.BindPairs.Add(bindPair);
+    }
+    _bindInfo.OutStreams.Clear();
+
+    /*
+    if (numCryptoStreams == 0)
+      numCryptoStreams = 1;
+    */
+
+    for (i = 0; i < numCryptoStreams; i++)
+    {
+      NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+      CMethodFull method;
+      method.NumInStreams = 1;
+      method.NumOutStreams = 1;
+      coderStreamsInfo.NumInStreams = method.NumOutStreams;
+      coderStreamsInfo.NumOutStreams = method.NumInStreams;
+      method.Id = k_AES;
+
+      _options.Methods.Add(method);
+      _bindInfo.Coders.Add(coderStreamsInfo);
+      _bindInfo.OutStreams.Add(numOutStreams + i);
+    }
+  }
+
+  }
+
+  for (int i = _options.Methods.Size() - 1; i >= 0; i--)
+  {
+    const CMethodFull &methodFull = _options.Methods[i];
+    _decompressionMethods.Add(methodFull.Id);
+  }
+
+  _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
+  _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
+  _constructed = true;
+  return S_OK;
+}
+
+CEncoder::~CEncoder()
+{
+  delete _bindReverseConverter;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zEncode.h b/lzma/CPP/7zip/Archive/7z/7zEncode.h
new file mode 100644 (file)
index 0000000..4909a6e
--- /dev/null
@@ -0,0 +1,55 @@
+// 7zEncode.h
+
+#ifndef __7Z_ENCODE_H
+#define __7Z_ENCODE_H
+
+// #include "../../Common/StreamObjects.h"
+
+#include "7zCompressionMode.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+#include "7zItem.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CEncoder
+{
+  NCoderMixer::CCoderMixer2MT *_mixerCoderSpec;
+  CMyComPtr<ICompressCoder2> _mixerCoder;
+
+  CObjectVector<CCoderInfo> _codersInfo;
+
+  CCompressionMethodMode _options;
+  NCoderMixer::CBindInfo _bindInfo;
+  NCoderMixer::CBindInfo _decompressBindInfo;
+  NCoderMixer::CBindReverseConverter *_bindReverseConverter;
+  CRecordVector<CMethodId> _decompressionMethods;
+
+  HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
+      const UInt64 *inSizeForReduce);
+
+  bool _constructed;
+public:
+  CEncoder(const CCompressionMethodMode &options);
+  ~CEncoder();
+  HRESULT EncoderConstr();
+  HRESULT Encode(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      ISequentialInStream *inStream,
+      const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+      CFolder &folderItem,
+      ISequentialOutStream *outStream,
+      CRecordVector<UInt64> &packSizes,
+      ICompressProgressInfo *compressProgress);
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zExtract.cpp b/lzma/CPP/7zip/Archive/7z/7zExtract.cpp
new file mode 100644 (file)
index 0000000..4297709
--- /dev/null
@@ -0,0 +1,269 @@
+// 7zExtract.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zFolderOutStream.h"
+#include "7zDecode.h"
+// #include "7z1Decode.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CExtractFolderInfo
+{
+  #ifdef _7Z_VOL
+  int VolumeIndex;
+  #endif
+  CNum FileIndex;
+  CNum FolderIndex;
+  CBoolVector ExtractStatuses;
+  UInt64 UnPackSize;
+  CExtractFolderInfo(
+    #ifdef _7Z_VOL
+    int volumeIndex, 
+    #endif
+    CNum fileIndex, CNum folderIndex): 
+    #ifdef _7Z_VOL
+    VolumeIndex(volumeIndex),
+    #endif
+    FileIndex(fileIndex),
+    FolderIndex(folderIndex), 
+    UnPackSize(0) 
+  {
+    if (fileIndex != kNumNoIndex)
+    {
+      ExtractStatuses.Reserve(1);
+      ExtractStatuses.Add(true);
+    }
+  };
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
+    Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
+{
+  COM_TRY_BEGIN
+  bool testMode = (testModeSpec != 0);
+  CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+  UInt64 importantTotalUnPacked = 0;
+
+  bool allFilesMode = (numItems == UInt32(-1));
+  if (allFilesMode)
+    numItems = 
+    #ifdef _7Z_VOL
+    _refs.Size();
+    #else
+    _database.Files.Size();
+    #endif
+
+  if(numItems == 0)
+    return S_OK;
+
+  /*
+  if(_volumes.Size() != 1)
+    return E_FAIL;
+  const CVolume &volume = _volumes.Front();
+  const CArchiveDatabaseEx &_database = volume.Database;
+  IInStream *_inStream = volume.Stream;
+  */
+  
+  CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
+  for(UInt32 ii = 0; ii < numItems; ii++)
+  {
+    // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
+    UInt32 ref2Index = allFilesMode ? ii : indices[ii];
+    // const CRef2 &ref2 = _refs[ref2Index];
+
+    // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
+    {
+      #ifdef _7Z_VOL
+      // const CRef &ref = ref2.Refs[ri];
+      const CRef &ref = _refs[ref2Index];
+
+      int volumeIndex = ref.VolumeIndex;
+      const CVolume &volume = _volumes[volumeIndex];
+      const CArchiveDatabaseEx &database = volume.Database;
+      UInt32 fileIndex = ref.ItemIndex;
+      #else
+      const CArchiveDatabaseEx &database = _database;
+      UInt32 fileIndex = ref2Index;
+      #endif
+
+      CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex];
+      if (folderIndex == kNumNoIndex)
+      {
+        extractFolderInfoVector.Add(CExtractFolderInfo(
+            #ifdef _7Z_VOL
+            volumeIndex, 
+            #endif
+            fileIndex, kNumNoIndex));
+        continue;
+      }
+      if (extractFolderInfoVector.IsEmpty() || 
+        folderIndex != extractFolderInfoVector.Back().FolderIndex 
+        #ifdef _7Z_VOL
+        || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
+        #endif
+        )
+      {
+        extractFolderInfoVector.Add(CExtractFolderInfo(
+            #ifdef _7Z_VOL
+            volumeIndex, 
+            #endif
+            kNumNoIndex, folderIndex));
+        const CFolder &folderInfo = database.Folders[folderIndex];
+        UInt64 unPackSize = folderInfo.GetUnPackSize();
+        importantTotalUnPacked += unPackSize;
+        extractFolderInfoVector.Back().UnPackSize = unPackSize;
+      }
+      
+      CExtractFolderInfo &efi = extractFolderInfoVector.Back();
+      
+      // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
+      CNum startIndex = database.FolderStartFileIndex[folderIndex];
+      for (CNum index = efi.ExtractStatuses.Size();
+          index <= fileIndex - startIndex; index++)
+      {
+        // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize;
+        // Count partial_folder_size
+        // efi.UnPackSize += unPackSize;
+        // importantTotalUnPacked += unPackSize;
+        efi.ExtractStatuses.Add(index == fileIndex - startIndex);
+      }
+    }
+  }
+
+  extractCallback->SetTotal(importantTotalUnPacked);
+
+  CDecoder decoder(
+    #ifdef _ST_MODE
+    false
+    #else
+    true
+    #endif
+    );
+  // CDecoder1 decoder;
+
+  UInt64 currentTotalPacked = 0;
+  UInt64 currentTotalUnPacked = 0;
+  UInt64 totalFolderUnPacked;
+  UInt64 totalFolderPacked;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for(int i = 0; i < extractFolderInfoVector.Size(); i++, 
+      currentTotalUnPacked += totalFolderUnPacked,
+      currentTotalPacked += totalFolderPacked)
+  {
+    lps->OutSize = currentTotalUnPacked;
+    lps->InSize = currentTotalPacked;
+    RINOK(lps->SetCur());
+    
+    const CExtractFolderInfo &efi = extractFolderInfoVector[i];
+    totalFolderUnPacked = efi.UnPackSize;
+
+    totalFolderPacked = 0;
+
+    CFolderOutStream *folderOutStream = new CFolderOutStream;
+    CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+    #ifdef _7Z_VOL
+    const CVolume &volume = _volumes[efi.VolumeIndex];
+    const CArchiveDatabaseEx &database = volume.Database;
+    #else
+    const CArchiveDatabaseEx &database = _database;
+    #endif
+
+    CNum startIndex;
+    if (efi.FileIndex != kNumNoIndex)
+      startIndex = efi.FileIndex;
+    else
+      startIndex = database.FolderStartFileIndex[efi.FolderIndex];
+
+
+    HRESULT result = folderOutStream->Init(&database, 
+        #ifdef _7Z_VOL
+        volume.StartRef2Index, 
+        #else
+        0,
+        #endif
+        startIndex, 
+        &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
+
+    RINOK(result);
+
+    if (efi.FileIndex != kNumNoIndex)
+      continue;
+
+    CNum folderIndex = efi.FolderIndex;
+    const CFolder &folderInfo = database.Folders[folderIndex];
+
+    totalFolderPacked = _database.GetFolderFullPackSize(folderIndex);
+
+    CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex];
+    UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0);
+
+    #ifndef _NO_CRYPTO
+    CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+    if (extractCallback)
+      extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+    #endif
+
+    try
+    {
+      HRESULT result = decoder.Decode(
+          EXTERNAL_CODECS_VARS
+          #ifdef _7Z_VOL
+          volume.Stream,
+          #else
+          _inStream,
+          #endif
+          folderStartPackPos, 
+          &database.PackSizes[packStreamIndex],
+          folderInfo,
+          outStream,
+          progress
+          #ifndef _NO_CRYPTO
+          , getTextPassword
+          #endif
+          #ifdef COMPRESS_MT
+          , true, _numThreads
+          #endif
+          );
+
+      if (result == S_FALSE)
+      {
+        RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
+        continue;
+      }
+      if (result == E_NOTIMPL)
+      {
+        RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
+        continue;
+      }
+      if (result != S_OK)
+        return result;
+      if (folderOutStream->WasWritingFinished() != S_OK)
+      {
+        RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
+        continue;
+      }
+    }
+    catch(...)
+    {
+      RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
+      continue;
+    }
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp
new file mode 100644 (file)
index 0000000..f60a717
--- /dev/null
@@ -0,0 +1,130 @@
+// 7zFolderInStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderInStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderInStream::CFolderInStream()
+{
+  _inStreamWithHashSpec = new CSequentialInStreamWithCRC;
+  _inStreamWithHash = _inStreamWithHashSpec;
+}
+
+void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, 
+    const UInt32 *fileIndices, UInt32 numFiles)
+{
+  _updateCallback = updateCallback;
+  _numFiles = numFiles;
+  _fileIndex = 0;
+  _fileIndices = fileIndices;
+  Processed.Clear();
+  CRCs.Clear();
+  Sizes.Clear();
+  _fileIsOpen = false;
+  _currentSizeIsDefined = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+  _filePos = 0;
+  while (_fileIndex < _numFiles)
+  {
+    _currentSizeIsDefined = false;
+    CMyComPtr<ISequentialInStream> stream;
+    HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
+    if (result != S_OK && result != S_FALSE)
+      return result;
+    _fileIndex++;
+    _inStreamWithHashSpec->SetStream(stream);
+    _inStreamWithHashSpec->Init();
+    if (!stream)
+    {
+      RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+      Sizes.Add(0);
+      Processed.Add(result == S_OK);
+      AddDigest();
+      continue;
+    }
+    CMyComPtr<IStreamGetSize> streamGetSize;
+    if (stream.QueryInterface(IID_IStreamGetSize, &streamGetSize) == S_OK)
+    {
+      if(streamGetSize)
+      {
+        _currentSizeIsDefined = true;
+        RINOK(streamGetSize->GetSize(&_currentSize));
+      }
+    }
+
+    _fileIsOpen = true;
+    return S_OK;
+  }
+  return S_OK;
+}
+
+void CFolderInStream::AddDigest()
+{
+  CRCs.Add(_inStreamWithHashSpec->GetCRC());
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+  RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+  _inStreamWithHashSpec->ReleaseStream();
+  _fileIsOpen = false;
+  Processed.Add(true);
+  Sizes.Add(_filePos);
+  AddDigest();
+  return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize = 0;
+  while ((_fileIndex < _numFiles || _fileIsOpen) && size > 0)
+  {
+    if (_fileIsOpen)
+    {
+      UInt32 localProcessedSize;
+      RINOK(_inStreamWithHash->Read(
+          ((Byte *)data) + realProcessedSize, size, &localProcessedSize));
+      if (localProcessedSize == 0)
+      {
+        RINOK(CloseStream());
+        continue;
+      }
+      realProcessedSize += localProcessedSize;
+      _filePos += localProcessedSize;
+      size -= localProcessedSize;
+      break;
+    }
+    else
+    {
+      RINOK(OpenStream());
+    }
+  }
+  if (processedSize != 0)
+    *processedSize = realProcessedSize;
+  return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+  *value = 0;
+  int subStreamIndex = (int)subStream;
+  if (subStreamIndex < 0 || subStream > Sizes.Size())
+    return E_FAIL;
+  if (subStreamIndex < Sizes.Size())
+  {
+    *value= Sizes[subStreamIndex];
+    return S_OK;
+  }
+  if (!_currentSizeIsDefined)
+    return S_FALSE;
+  *value = _currentSize;
+  return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderInStream.h b/lzma/CPP/7zip/Archive/7z/7zFolderInStream.h
new file mode 100644 (file)
index 0000000..9a720c8
--- /dev/null
@@ -0,0 +1,66 @@
+// 7z/FolderInStream.h
+
+#ifndef __7Z_FOLDERINSTREAM_H
+#define __7Z_FOLDERINSTREAM_H
+
+#include "7zItem.h"
+#include "7zHeader.h"
+
+#include "../IArchive.h"
+#include "../Common/InStreamWithCRC.h"
+#include "../../IStream.h"
+#include "../../ICoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderInStream: 
+  public ISequentialInStream,
+  public ICompressGetSubStreamSize,
+  public CMyUnknownImp
+{
+public:
+
+  MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+  CFolderInStream();
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+private:
+  CSequentialInStreamWithCRC *_inStreamWithHashSpec;
+  CMyComPtr<ISequentialInStream> _inStreamWithHash;
+  CMyComPtr<IArchiveUpdateCallback> _updateCallback;
+
+  bool _currentSizeIsDefined;
+  UInt64 _currentSize;
+
+  bool _fileIsOpen;
+  UInt64 _filePos;
+
+  const UInt32 *_fileIndices;
+  UInt32 _numFiles;
+  UInt32 _fileIndex;
+
+  HRESULT OpenStream();
+  HRESULT CloseStream();
+  void AddDigest();
+public:
+  void Init(IArchiveUpdateCallback *updateCallback, 
+      const UInt32 *fileIndices, UInt32 numFiles);
+  CRecordVector<bool> Processed;
+  CRecordVector<UInt32> CRCs;
+  CRecordVector<UInt64> Sizes;
+  UInt64 GetFullSize() const
+  {
+    UInt64 size = 0;
+    for (int i = 0; i < Sizes.Size(); i++)      
+      size += Sizes[i];
+    return size;
+  }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
new file mode 100644 (file)
index 0000000..6206ffe
--- /dev/null
@@ -0,0 +1,165 @@
+// 7zFolderOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderOutStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderOutStream::CFolderOutStream()
+{
+  _outStreamWithHashSpec = new COutStreamWithCRC;
+  _outStreamWithHash = _outStreamWithHashSpec;
+}
+
+HRESULT CFolderOutStream::Init(
+    const CArchiveDatabaseEx *archiveDatabase,
+    UInt32 ref2Offset,
+    UInt32 startIndex,
+    const CBoolVector *extractStatuses, 
+    IArchiveExtractCallback *extractCallback,
+    bool testMode,
+    bool checkCrc)
+{
+  _archiveDatabase = archiveDatabase;
+  _ref2Offset = ref2Offset;
+  _startIndex = startIndex;
+
+  _extractStatuses = extractStatuses;
+  _extractCallback = extractCallback;
+  _testMode = testMode;
+
+  _checkCrc = checkCrc;
+
+  _currentIndex = 0;
+  _fileIsOpen = false;
+  return WriteEmptyFiles();
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+  Int32 askMode;
+  if((*_extractStatuses)[_currentIndex])
+    askMode = _testMode ? 
+        NArchive::NExtract::NAskMode::kTest :
+        NArchive::NExtract::NAskMode::kExtract;
+  else
+    askMode = NArchive::NExtract::NAskMode::kSkip;
+  CMyComPtr<ISequentialOutStream> realOutStream;
+
+  UInt32 index = _startIndex + _currentIndex;
+  RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
+
+  _outStreamWithHashSpec->SetStream(realOutStream);
+  _outStreamWithHashSpec->Init(_checkCrc);
+  if (askMode == NArchive::NExtract::NAskMode::kExtract &&
+      (!realOutStream)) 
+  {
+    const CFileItem &fileInfo = _archiveDatabase->Files[index];
+    if (!fileInfo.IsAnti && !fileInfo.IsDirectory)
+      askMode = NArchive::NExtract::NAskMode::kSkip;
+  }
+  return _extractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::WriteEmptyFiles()
+{
+  for(;_currentIndex < _extractStatuses->Size(); _currentIndex++)
+  {
+    UInt32 index = _startIndex + _currentIndex;
+    const CFileItem &fileInfo = _archiveDatabase->Files[index];
+    if (!fileInfo.IsAnti && !fileInfo.IsDirectory && fileInfo.UnPackSize != 0)
+      return S_OK;
+    RINOK(OpenFile());
+    RINOK(_extractCallback->SetOperationResult(
+        NArchive::NExtract::NOperationResult::kOK));
+    _outStreamWithHashSpec->ReleaseStream();
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, 
+    UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize = 0;
+  while(_currentIndex < _extractStatuses->Size())
+  {
+    if (_fileIsOpen)
+    {
+      UInt32 index = _startIndex + _currentIndex;
+      const CFileItem &fileInfo = _archiveDatabase->Files[index];
+      UInt64 fileSize = fileInfo.UnPackSize;
+      
+      UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - _filePos, 
+          UInt64(size - realProcessedSize));
+      
+      UInt32 processedSizeLocal;
+      RINOK(_outStreamWithHash->Write((const Byte *)data + realProcessedSize, 
+            numBytesToWrite, &processedSizeLocal));
+
+      _filePos += processedSizeLocal;
+      realProcessedSize += processedSizeLocal;
+      if (_filePos == fileSize)
+      {
+        bool digestsAreEqual;
+        if (fileInfo.IsFileCRCDefined && _checkCrc)
+          digestsAreEqual = fileInfo.FileCRC == _outStreamWithHashSpec->GetCRC();
+        else
+          digestsAreEqual = true;
+
+        RINOK(_extractCallback->SetOperationResult(
+            digestsAreEqual ? 
+            NArchive::NExtract::NOperationResult::kOK :
+            NArchive::NExtract::NOperationResult::kCRCError));
+        _outStreamWithHashSpec->ReleaseStream();
+        _fileIsOpen = false;
+        _currentIndex++;
+      }
+      if (realProcessedSize == size)
+      {
+        if (processedSize != NULL)
+          *processedSize = realProcessedSize;
+        return WriteEmptyFiles();
+      }
+    }
+    else
+    {
+      RINOK(OpenFile());
+      _fileIsOpen = true;
+      _filePos = 0;
+    }
+  }
+  if (processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
+
+HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
+{
+  while(_currentIndex < _extractStatuses->Size())
+  {
+    if (_fileIsOpen)
+    {
+      RINOK(_extractCallback->SetOperationResult(resultEOperationResult));
+      _outStreamWithHashSpec->ReleaseStream();
+      _fileIsOpen = false;
+      _currentIndex++;
+    }
+    else
+    {
+      RINOK(OpenFile());
+      _fileIsOpen = true;
+    }
+  }
+  return S_OK;
+}
+
+HRESULT CFolderOutStream::WasWritingFinished()
+{
+  if (_currentIndex == _extractStatuses->Size())
+    return S_OK;
+  return E_FAIL;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h b/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h
new file mode 100644 (file)
index 0000000..8ca91e6
--- /dev/null
@@ -0,0 +1,60 @@
+// 7zFolderOutStream.h
+
+#ifndef __7Z_FOLDEROUTSTREAM_H
+#define __7Z_FOLDEROUTSTREAM_H
+
+#include "7zIn.h"
+
+#include "../../IStream.h"
+#include "../IArchive.h"
+#include "../Common/OutStreamWithCRC.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderOutStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+  
+  CFolderOutStream();
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+private:
+
+  COutStreamWithCRC *_outStreamWithHashSpec;
+  CMyComPtr<ISequentialOutStream> _outStreamWithHash;
+  const CArchiveDatabaseEx *_archiveDatabase;
+  const CBoolVector *_extractStatuses;
+  UInt32 _startIndex;
+  UInt32 _ref2Offset;
+  int _currentIndex;
+  // UInt64 _currentDataPos;
+  CMyComPtr<IArchiveExtractCallback> _extractCallback;
+  bool _testMode;
+
+  bool _fileIsOpen;
+
+  bool _checkCrc;
+  UInt64 _filePos;
+
+  HRESULT OpenFile();
+  HRESULT WriteEmptyFiles();
+public:
+  HRESULT Init(
+      const CArchiveDatabaseEx *archiveDatabase,
+      UInt32 ref2Offset,
+      UInt32 startIndex,
+      const CBoolVector *extractStatuses, 
+      IArchiveExtractCallback *extractCallback,
+      bool testMode,
+      bool checkCrc);
+  HRESULT FlushCorrupted(Int32 resultEOperationResult);
+  HRESULT WasWritingFinished();
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zHandler.cpp b/lzma/CPP/7zip/Archive/7z/7zHandler.cpp
new file mode 100644 (file)
index 0000000..bbef1ea
--- /dev/null
@@ -0,0 +1,793 @@
+// 7zHandler.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zProperties.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Windows/Defs.h"
+
+#include "../Common/ItemNameUtils.h"
+#ifdef _7Z_VOL
+#include "../Common/MultiStream.h"
+#endif
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+#include "../Common/ParseProperties.h"
+#endif
+#endif
+
+#ifdef COMPRESS_MT
+#include "../../../Windows/System.h"
+#endif
+
+using namespace NWindows;
+
+extern UString ConvertMethodIdToString(UInt64 id);
+
+namespace NArchive {
+namespace N7z {
+
+CHandler::CHandler()
+{
+  _crcSize = 4;
+
+  #ifdef EXTRACT_ONLY
+  #ifdef COMPRESS_MT
+  _numThreads = NWindows::NSystem::GetNumberOfProcessors();
+  #endif
+  #else
+  Init();
+  #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+  *numItems = 
+  #ifdef _7Z_VOL
+  _refs.Size();
+  #else
+  *numItems = _database.Files.Size();
+  #endif
+  return S_OK;
+}
+
+#ifdef _SFX
+
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
+{
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,     
+      BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
+{
+  return E_NOTIMPL;
+}
+
+
+#else
+
+STATPROPSTG kArcProps[] = 
+{
+  { NULL, kpidMethod, VT_BSTR},
+  { NULL, kpidSolid, VT_BOOL},
+  { NULL, kpidNumBlocks, VT_UI4}
+};
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+  COM_TRY_BEGIN
+  NWindows::NCOM::CPropVariant prop;
+  switch(propID)
+  {
+    case kpidMethod:
+    {
+      UString resString;
+      CRecordVector<UInt64> ids;
+      int i;
+      for (i = 0; i < _database.Folders.Size(); i++)
+      {
+        const CFolder &f = _database.Folders[i];
+        for (int j = f.Coders.Size() - 1; j >= 0; j--)
+          ids.AddToUniqueSorted(f.Coders[j].MethodID);
+      }
+
+      for (i = 0; i < ids.Size(); i++)
+      {
+        UInt64 id = ids[i];
+        UString methodName;
+        /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
+        if (methodName.IsEmpty())
+          methodName = ConvertMethodIdToString(id);
+        if (!resString.IsEmpty())
+          resString += L' ';
+        resString += methodName;
+      }
+      prop = resString; 
+      break;
+    }
+    case kpidSolid: prop = _database.IsSolid(); break;
+    case kpidNumBlocks: prop = (UInt32)_database.Folders.Size(); break;
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+#endif
+
+static void MySetFileTime(bool timeDefined, FILETIME unixTime, NWindows::NCOM::CPropVariant &prop)
+{
+  if (timeDefined)
+    prop = unixTime;
+}
+
+#ifndef _SFX
+
+static UString ConvertUInt32ToString(UInt32 value)
+{
+  wchar_t buffer[32];
+  ConvertUInt64ToString(value, buffer);
+  return buffer;
+}
+
+static UString GetStringForSizeValue(UInt32 value)
+{
+  for (int i = 31; i >= 0; i--)
+    if ((UInt32(1) << i) == value)
+      return ConvertUInt32ToString(i);
+  UString result;
+  if (value % (1 << 20) == 0)
+  {
+    result += ConvertUInt32ToString(value >> 20);
+    result += L"m";
+  }
+  else if (value % (1 << 10) == 0)
+  {
+    result += ConvertUInt32ToString(value >> 10);
+    result += L"k";
+  }
+  else
+  {
+    result += ConvertUInt32ToString(value);
+    result += L"b";
+  }
+  return result;
+}
+
+static const UInt64 k_Copy = 0x0;
+static const UInt64 k_LZMA  = 0x030101;
+static const UInt64 k_PPMD  = 0x030401;
+
+static wchar_t GetHex(Byte value)
+{
+  return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
+}
+static inline UString GetHex2(Byte value)
+{
+  UString result;
+  result += GetHex((Byte)(value >> 4));
+  result += GetHex((Byte)(value & 0xF));
+  return result;
+}
+
+#endif
+
+static const UInt64 k_AES  = 0x06F10701;
+
+#ifndef _SFX
+static inline UInt32 GetUInt32FromMemLE(const Byte *p)
+{
+  return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24);
+}
+#endif
+
+bool CHandler::IsEncrypted(UInt32 index2) const
+{
+  CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+  if (folderIndex != kNumNoIndex)
+  {
+    const CFolder &folderInfo = _database.Folders[folderIndex];
+    for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
+      if (folderInfo.Coders[i].MethodID == k_AES)
+        return true;
+  }
+  return false;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
+{
+  COM_TRY_BEGIN
+  NWindows::NCOM::CPropVariant prop;
+  
+  /*
+  const CRef2 &ref2 = _refs[index];
+  if (ref2.Refs.IsEmpty())
+    return E_FAIL;
+  const CRef &ref = ref2.Refs.Front();
+  */
+  
+  #ifdef _7Z_VOL
+  const CRef &ref = _refs[index];
+  const CVolume &volume = _volumes[ref.VolumeIndex];
+  const CArchiveDatabaseEx &_database = volume.Database;
+  UInt32 index2 = ref.ItemIndex;
+  const CFileItem &item = _database.Files[index2];
+  #else
+  const CFileItem &item = _database.Files[index];
+  UInt32 index2 = index;
+  #endif
+
+  switch(propID)
+  {
+    case kpidPath:
+    {
+      if (!item.Name.IsEmpty())
+        prop = NItemName::GetOSName(item.Name);
+      break;
+    }
+    case kpidIsFolder:
+      prop = item.IsDirectory;
+      break;
+    case kpidSize:
+    {
+      prop = item.UnPackSize;
+      // prop = ref2.UnPackSize;
+      break;
+    }
+    case kpidPosition:
+    {
+      /*
+      if (ref2.Refs.Size() > 1)
+        prop = ref2.StartPos;
+      else
+      */
+        if (item.IsStartPosDefined)
+          prop = item.StartPos;
+      break;
+    }
+    case kpidPackedSize:
+    {
+      // prop = ref2.PackSize;
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+        {
+          if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2)
+            prop = _database.GetFolderFullPackSize(folderIndex);
+          /*
+          else
+            prop = (UInt64)0;
+          */
+        }
+        else
+          prop = (UInt64)0;
+      }
+      break;
+    }
+    case kpidLastAccessTime:
+      MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, prop);
+      break;
+    case kpidCreationTime:
+      MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, prop);
+      break;
+    case kpidLastWriteTime:
+      MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, prop);
+      break;
+    case kpidAttributes:
+      if (item.AreAttributesDefined)
+        prop = item.Attributes;
+      break;
+    case kpidCRC:
+      if (item.IsFileCRCDefined)
+        prop = item.FileCRC;
+      break;
+    case kpidEncrypted:
+    {
+      prop = IsEncrypted(index2);
+      break;
+    }
+    #ifndef _SFX
+    case kpidMethod:
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+        {
+          const CFolder &folderInfo = _database.Folders[folderIndex];
+          UString methodsString;
+          for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
+          {
+            const CCoderInfo &coderInfo = folderInfo.Coders[i];
+            if (!methodsString.IsEmpty())
+              methodsString += L' ';
+
+            {
+              UString methodName;
+              bool methodIsKnown = FindMethod(
+                  EXTERNAL_CODECS_VARS 
+                  coderInfo.MethodID, methodName);
+
+              if (methodIsKnown)
+              {
+                methodsString += methodName;
+                if (coderInfo.MethodID == k_LZMA)
+                {
+                  if (coderInfo.Properties.GetCapacity() >= 5)
+                  {
+                    methodsString += L":";
+                    UInt32 dicSize = GetUInt32FromMemLE(
+                      ((const Byte *)coderInfo.Properties + 1));
+                    methodsString += GetStringForSizeValue(dicSize);
+                  }
+                }
+                else if (coderInfo.MethodID == k_PPMD)
+                {
+                  if (coderInfo.Properties.GetCapacity() >= 5)
+                  {
+                    Byte order = *(const Byte *)coderInfo.Properties;
+                    methodsString += L":o";
+                    methodsString += ConvertUInt32ToString(order);
+                    methodsString += L":mem";
+                    UInt32 dicSize = GetUInt32FromMemLE(
+                      ((const Byte *)coderInfo.Properties + 1));
+                    methodsString += GetStringForSizeValue(dicSize);
+                  }
+                }
+                else if (coderInfo.MethodID == k_AES)
+                {
+                  if (coderInfo.Properties.GetCapacity() >= 1)
+                  {
+                    methodsString += L":";
+                    const Byte *data = (const Byte *)coderInfo.Properties;
+                    Byte firstByte = *data++;
+                    UInt32 numCyclesPower = firstByte & 0x3F;
+                    methodsString += ConvertUInt32ToString(numCyclesPower);
+                    /*
+                    if ((firstByte & 0xC0) != 0)
+                    {
+                      methodsString += L":";
+                      return S_OK;
+                      UInt32 saltSize = (firstByte >> 7) & 1;
+                      UInt32 ivSize = (firstByte >> 6) & 1;
+                      if (coderInfo.Properties.GetCapacity() >= 2)
+                      {
+                        Byte secondByte = *data++;
+                        saltSize += (secondByte >> 4);
+                        ivSize += (secondByte & 0x0F);
+                      }
+                    }
+                    */
+                  }
+                }
+                else
+                {
+                  if (coderInfo.Properties.GetCapacity() > 0)
+                  {
+                    methodsString += L":[";
+                    for (size_t bi = 0; bi < coderInfo.Properties.GetCapacity(); bi++)
+                    {
+                      if (bi > 5 && bi + 1 < coderInfo.Properties.GetCapacity())
+                      {
+                        methodsString += L"..";
+                        break;
+                      }
+                      else
+                        methodsString += GetHex2(coderInfo.Properties[bi]);
+                    }
+                    methodsString += L"]";
+                  }
+                }
+              }
+              else
+              {
+                methodsString += ConvertMethodIdToString(coderInfo.MethodID);
+              }
+            }
+          }
+          prop = methodsString;
+        }
+      }
+      break;
+    case kpidBlock:
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+          prop = (UInt32)folderIndex;
+      }
+      break;
+    case kpidPackedSize0:
+    case kpidPackedSize1:
+    case kpidPackedSize2:
+    case kpidPackedSize3:
+    case kpidPackedSize4:
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+        {
+          const CFolder &folderInfo = _database.Folders[folderIndex];
+          if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
+              folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
+          {
+            prop = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
+          }
+          else
+            prop = (UInt64)0;
+        }
+        else
+          prop = (UInt64)0;
+      }
+      break;
+    #endif
+    case kpidIsAnti:
+      prop = item.IsAnti;
+      break;
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+#ifdef _7Z_VOL
+
+static const wchar_t *kExt = L"7z";
+static const wchar_t *kAfterPart = L".7z";
+
+class CVolumeName
+{
+  bool _first;
+  UString _unchangedPart;
+  UString _changedPart;    
+  UString _afterPart;    
+public:
+  bool InitName(const UString &name)
+  {
+    _first = true;
+    int dotPos = name.ReverseFind('.');
+    UString basePart = name;
+    if (dotPos >= 0)
+    {
+      UString ext = name.Mid(dotPos + 1);
+      if (ext.CompareNoCase(kExt)==0 || 
+        ext.CompareNoCase(L"EXE") == 0)
+      {
+        _afterPart = kAfterPart;
+        basePart = name.Left(dotPos);
+      }
+    }
+
+    int numLetters = 1;
+    bool splitStyle = false;
+    if (basePart.Right(numLetters) == L"1")
+    {
+      while (numLetters < basePart.Length())
+      {
+        if (basePart[basePart.Length() - numLetters - 1] != '0')
+          break;
+        numLetters++;
+      }
+    }
+    else 
+      return false;
+    _unchangedPart = basePart.Left(basePart.Length() - numLetters);
+    _changedPart = basePart.Right(numLetters);
+    return true;
+  }
+
+  UString GetNextName()
+  {
+    UString newName; 
+    // if (_newStyle || !_first)
+    {
+      int i;
+      int numLetters = _changedPart.Length();
+      for (i = numLetters - 1; i >= 0; i--)
+      {
+        wchar_t c = _changedPart[i];
+        if (c == L'9')
+        {
+          c = L'0';
+          newName = c + newName;
+          if (i == 0)
+            newName = UString(L'1') + newName;
+          continue;
+        }
+        c++;
+        newName = UString(c) + newName;
+        i--;
+        for (; i >= 0; i--)
+          newName = _changedPart[i] + newName;
+        break;
+      }
+      _changedPart = newName;
+    }
+    _first = false;
+    return _unchangedPart + _changedPart + _afterPart;
+  }
+};
+
+#endif
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+    const UInt64 *maxCheckStartPosition, 
+    IArchiveOpenCallback *openArchiveCallback)
+{
+  COM_TRY_BEGIN
+  Close();
+  #ifndef _SFX
+  _fileInfoPopIDs.Clear();
+  #endif
+  try
+  {
+    CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
+    #ifdef _7Z_VOL
+    CVolumeName seqName;
+
+    CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+    #endif
+
+    #ifndef _NO_CRYPTO
+    CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+    if (openArchiveCallback)
+    {
+      openArchiveCallbackTemp.QueryInterface(
+          IID_ICryptoGetTextPassword, &getTextPassword);
+    }
+    #endif
+    #ifdef _7Z_VOL
+    if (openArchiveCallback)
+    {
+      openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
+    }
+    for (;;)
+    {
+      CMyComPtr<IInStream> inStream;
+      if (!_volumes.IsEmpty())
+      {
+        if (!openVolumeCallback)
+          break;
+        if(_volumes.Size() == 1)
+        {
+          UString baseName;
+          {
+            NCOM::CPropVariant prop;
+            RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+            if (prop.vt != VT_BSTR)
+              break;
+            baseName = prop.bstrVal;
+          }
+          seqName.InitName(baseName);
+        }
+
+        UString fullName = seqName.GetNextName();
+        HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
+        if (result == S_FALSE)
+          break;
+        if (result != S_OK)
+          return result;
+        if (!stream)
+          break;
+      }
+      else
+        inStream = stream;
+
+      CInArchive archive;
+      RINOK(archive.Open(inStream, maxCheckStartPosition));
+
+      _volumes.Add(CVolume());
+      CVolume &volume = _volumes.Back();
+      CArchiveDatabaseEx &database = volume.Database;
+      volume.Stream = inStream;
+      volume.StartRef2Index = _refs.Size();
+
+      HRESULT result = archive.ReadDatabase(database
+          #ifndef _NO_CRYPTO
+          , getTextPassword
+          #endif
+          );
+      if (result != S_OK)
+      {
+        _volumes.Clear();
+        return result;
+      }
+      database.Fill();
+      for(int i = 0; i < database.Files.Size(); i++)
+      {
+        CRef refNew;
+        refNew.VolumeIndex = _volumes.Size() - 1;
+        refNew.ItemIndex = i;
+        _refs.Add(refNew);
+        /*
+        const CFileItem &file = database.Files[i];
+        int j;
+        */
+        /*
+        for (j = _refs.Size() - 1; j >= 0; j--)
+        {
+          CRef2 &ref2 = _refs[j];
+          const CRef &ref = ref2.Refs.Back();
+          const CVolume &volume2 = _volumes[ref.VolumeIndex];
+          const CArchiveDatabaseEx &database2 = volume2.Database;
+          const CFileItem &file2 = database2.Files[ref.ItemIndex];
+          if (file2.Name.CompareNoCase(file.Name) == 0)
+          {
+            if (!file.IsStartPosDefined)
+              continue;
+            if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
+              continue;
+            ref2.Refs.Add(refNew);
+            break;
+          }
+        }
+        */
+        /*
+        j = -1;
+        if (j < 0)
+        {
+          CRef2 ref2New;
+          ref2New.Refs.Add(refNew);
+          j = _refs.Add(ref2New);
+        }
+        CRef2 &ref2 = _refs[j];
+        ref2.UnPackSize += file.UnPackSize;
+        ref2.PackSize += database.GetFilePackSize(i);
+        if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
+          ref2.StartPos = file.StartPos;
+        */
+      }
+      if (database.Files.Size() != 1)
+        break;
+      const CFileItem &file = database.Files.Front();
+      if (!file.IsStartPosDefined)
+        break;
+    }
+    #else
+    CInArchive archive;
+    RINOK(archive.Open(stream, maxCheckStartPosition));
+    HRESULT result = archive.ReadDatabase(
+      EXTERNAL_CODECS_VARS
+      _database
+      #ifndef _NO_CRYPTO
+      , getTextPassword
+      #endif
+      );
+    RINOK(result);
+    _database.Fill();
+    _inStream = stream;
+    #endif
+  }
+  catch(...)
+  {
+    Close();
+    return S_FALSE;
+  }
+  // _inStream = stream;
+  #ifndef _SFX
+  FillPopIDs();
+  #endif
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+  COM_TRY_BEGIN
+  #ifdef _7Z_VOL
+  _volumes.Clear();
+  _refs.Clear();
+  #else
+  _inStream.Release();
+  _database.Clear();
+  #endif
+  return S_OK;
+  COM_TRY_END
+}
+
+#ifdef _7Z_VOL
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+  if (index != 0)
+    return E_INVALIDARG;
+  *stream = 0;
+  CMultiStream *streamSpec = new CMultiStream;
+  CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+  
+  UInt64 pos = 0;
+  const UString *fileName;
+  for (int i = 0; i < _refs.Size(); i++)
+  {
+    const CRef &ref = _refs[i];
+    const CVolume &volume = _volumes[ref.VolumeIndex];
+    const CArchiveDatabaseEx &database = volume.Database;
+    const CFileItem &file = database.Files[ref.ItemIndex];
+    if (i == 0)
+      fileName = &file.Name;
+    else
+      if (fileName->Compare(file.Name) != 0)
+        return S_FALSE;
+    if (!file.IsStartPosDefined)
+      return S_FALSE;
+    if (file.StartPos != pos)
+      return S_FALSE;
+    CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex];
+    if (folderIndex == kNumNoIndex)
+    {
+      if (file.UnPackSize != 0)
+        return E_FAIL;
+      continue;
+    }
+    if (database.NumUnPackStreamsVector[folderIndex] != 1)
+      return S_FALSE;
+    const CFolder &folder = database.Folders[folderIndex];
+    if (folder.Coders.Size() != 1)
+      return S_FALSE;
+    const CCoderInfo &coder = folder.Coders.Front();
+    if (coder.NumInStreams != 1 || coder.NumOutStreams != 1)
+      return S_FALSE;
+    if (coder.MethodID != k_Copy)
+      return S_FALSE;
+
+    pos += file.UnPackSize;
+    CMultiStream::CSubStreamInfo subStreamInfo;
+    subStreamInfo.Stream = volume.Stream;
+    subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0);
+    subStreamInfo.Size = file.UnPackSize;
+    streamSpec->Streams.Add(subStreamInfo);
+  }
+  streamSpec->Init();
+  *stream = streamTemp.Detach();
+  return S_OK;
+}
+#endif
+
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+  COM_TRY_BEGIN
+  #ifdef COMPRESS_MT
+  const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+  _numThreads = numProcessors;
+  #endif
+
+  for (int i = 0; i < numProperties; i++)
+  {
+    UString name = names[i];
+    name.MakeUpper();
+    if (name.IsEmpty())
+      return E_INVALIDARG;
+    const PROPVARIANT &value = values[i];
+    UInt32 number;
+    int index = ParseStringToUInt32(name, number);
+    if (index == 0)
+    {
+      if(name.Left(2).CompareNoCase(L"MT") == 0)
+      {
+        #ifdef COMPRESS_MT
+        RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+        #endif
+        continue;
+      }
+      else
+        return E_INVALIDARG;
+    }
+  }
+  return S_OK;
+  COM_TRY_END
+}  
+
+#endif
+#endif
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zHandler.h b/lzma/CPP/7zip/Archive/7z/7zHandler.h
new file mode 100644 (file)
index 0000000..ad4df41
--- /dev/null
@@ -0,0 +1,146 @@
+// 7z/Handler.h
+
+#ifndef __7Z_HANDLER_H
+#define __7Z_HANDLER_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+#include "7zIn.h"
+
+#include "7zCompressionMode.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifndef EXTRACT_ONLY
+#include "../Common/HandlerOut.h"
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+#ifdef _7Z_VOL
+struct CRef
+{
+  int VolumeIndex;
+  int ItemIndex;
+};
+
+struct CVolume
+{
+  int StartRef2Index;
+  CMyComPtr<IInStream> Stream;
+  CArchiveDatabaseEx Database;
+};
+#endif
+
+#ifndef __7Z_SET_PROPERTIES
+
+#ifdef EXTRACT_ONLY
+#ifdef COMPRESS_MT
+#define __7Z_SET_PROPERTIES
+#endif
+#else 
+#define __7Z_SET_PROPERTIES
+#endif
+
+#endif
+
+
+class CHandler: 
+  #ifndef EXTRACT_ONLY
+  public NArchive::COutHandler,
+  #endif
+  public IInArchive,
+  #ifdef _7Z_VOL
+  public IInArchiveGetStream,
+  #endif
+  #ifdef __7Z_SET_PROPERTIES
+  public ISetProperties, 
+  #endif
+  #ifndef EXTRACT_ONLY
+  public IOutArchive, 
+  #endif
+  PUBLIC_ISetCompressCodecsInfo
+  public CMyUnknownImp
+{
+public:
+  MY_QUERYINTERFACE_BEGIN2(IInArchive)
+  #ifdef _7Z_VOL
+  MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
+  #endif
+  #ifdef __7Z_SET_PROPERTIES
+  MY_QUERYINTERFACE_ENTRY(ISetProperties)
+  #endif
+  #ifndef EXTRACT_ONLY
+  MY_QUERYINTERFACE_ENTRY(IOutArchive)
+  #endif
+  QUERY_ENTRY_ISetCompressCodecsInfo
+  MY_QUERYINTERFACE_END
+  MY_ADDREF_RELEASE
+
+  INTERFACE_IInArchive(;)
+
+  #ifdef _7Z_VOL
+  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);  
+  #endif
+
+  #ifdef __7Z_SET_PROPERTIES
+  STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+  #endif
+
+  #ifndef EXTRACT_ONLY
+  INTERFACE_IOutArchive(;)
+  #endif
+
+  DECL_ISetCompressCodecsInfo
+
+  CHandler();
+
+private:
+  #ifdef _7Z_VOL
+  CObjectVector<CVolume> _volumes;
+  CObjectVector<CRef> _refs;
+  #else
+  CMyComPtr<IInStream> _inStream;
+  NArchive::N7z::CArchiveDatabaseEx _database;
+  #endif
+
+  #ifdef EXTRACT_ONLY
+  
+  #ifdef COMPRESS_MT
+  UInt32 _numThreads;
+  #endif
+
+  UInt32 _crcSize;
+
+  #else
+  
+  CRecordVector<CBind> _binds;
+
+  HRESULT SetPassword(CCompressionMethodMode &methodMode, IArchiveUpdateCallback *updateCallback);
+
+  HRESULT SetCompressionMethod(CCompressionMethodMode &method,
+      CObjectVector<COneMethodInfo> &methodsInfo
+      #ifdef COMPRESS_MT
+      , UInt32 numThreads
+      #endif
+      );
+
+  HRESULT SetCompressionMethod(
+      CCompressionMethodMode &method,
+      CCompressionMethodMode &headerMethod);
+
+  #endif
+
+  bool IsEncrypted(UInt32 index2) const;
+  #ifndef _SFX
+
+  CRecordVector<UInt64> _fileInfoPopIDs;
+  void FillPopIDs();
+
+  #endif
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp
new file mode 100644 (file)
index 0000000..af4b942
--- /dev/null
@@ -0,0 +1,464 @@
+// 7zHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringToInt.h"
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const UInt32 kLzmaAlgorithmX5 = 1;
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders = 1 << 20;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;
+
+static inline bool IsCopyMethod(const UString &methodName)
+  { return (methodName.CompareNoCase(kCopyMethod) == 0); }
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+  *type = NFileTimeType::kWindows;
+  return S_OK;
+}
+
+HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
+    IArchiveUpdateCallback *updateCallback)
+{
+  CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
+  if (!getTextPassword)
+  {
+    CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
+    udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
+  }
+  
+  if (getTextPassword)
+  {
+    CMyComBSTR password;
+    Int32 passwordIsDefined;
+    RINOK(getTextPassword->CryptoGetTextPassword2(
+        &passwordIsDefined, &password));
+    methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
+    if (methodMode.PasswordIsDefined)
+      methodMode.Password = password;
+  }
+  else
+    methodMode.PasswordIsDefined = false;
+  return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+    CCompressionMethodMode &methodMode,
+    CCompressionMethodMode &headerMethod)
+{
+  HRESULT res = SetCompressionMethod(methodMode, _methods
+  #ifdef COMPRESS_MT
+  , _numThreads
+  #endif
+  );
+  RINOK(res);
+  methodMode.Binds = _binds;
+
+  if (_compressHeaders)
+  {
+    // headerMethod.Methods.Add(methodMode.Methods.Back());
+
+    CObjectVector<COneMethodInfo> headerMethodInfoVector;
+    COneMethodInfo oneMethodInfo;
+    oneMethodInfo.MethodName = kLZMAMethodName;
+    {
+      CProp property;
+      property.Id = NCoderPropID::kMatchFinder;
+      property.Value = kLzmaMatchFinderForHeaders;
+      oneMethodInfo.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kAlgorithm;
+      property.Value = kAlgorithmForHeaders;
+      oneMethodInfo.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kNumFastBytes;
+      property.Value = UInt32(kNumFastBytesForHeaders);
+      oneMethodInfo.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kDictionarySize;
+      property.Value = UInt32(kDictionaryForHeaders);
+      oneMethodInfo.Properties.Add(property);
+    }
+    headerMethodInfoVector.Add(oneMethodInfo);
+    HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
+      #ifdef COMPRESS_MT
+      ,1
+      #endif
+    );
+    RINOK(res);
+  }
+  return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+    CCompressionMethodMode &methodMode,
+    CObjectVector<COneMethodInfo> &methodsInfo
+    #ifdef COMPRESS_MT
+    , UInt32 numThreads
+    #endif
+    )
+{
+  UInt32 level = _level;
+  
+  if (methodsInfo.IsEmpty())
+  {
+    COneMethodInfo oneMethodInfo;
+    oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
+    methodsInfo.Add(oneMethodInfo);
+  }
+
+  bool needSolid = false;
+  for(int i = 0; i < methodsInfo.Size(); i++)
+  {
+    COneMethodInfo &oneMethodInfo = methodsInfo[i];
+    SetCompressionMethod2(oneMethodInfo
+      #ifdef COMPRESS_MT
+      , numThreads
+      #endif
+      );
+
+    if (!IsCopyMethod(oneMethodInfo.MethodName))
+      needSolid = true;
+
+    CMethodFull methodFull;
+
+    if (!FindMethod(
+        EXTERNAL_CODECS_VARS
+        oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams))
+      return E_INVALIDARG;
+    methodFull.Properties = oneMethodInfo.Properties;
+    methodMode.Methods.Add(methodFull);
+
+    if (!_numSolidBytesDefined)
+    {
+      for (int j = 0; j < methodFull.Properties.Size(); j++)
+      {
+        const CProp &prop = methodFull.Properties[j];
+        if ((prop.Id == NCoderPropID::kDictionarySize || 
+             prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
+        {
+          _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
+          const UInt64 kMinSize = (1 << 24);
+          if (_numSolidBytes < kMinSize)
+            _numSolidBytes = kMinSize;
+          _numSolidBytesDefined = true;
+          break;
+        }
+      }
+    }
+  }
+
+  if (!needSolid && !_numSolidBytesDefined)
+  {
+    _numSolidBytesDefined = true;
+    _numSolidBytes  = 0;
+  }
+  return S_OK;
+}
+
+static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, CArchiveFileTime &filetime, bool &filetimeIsDefined)
+{
+  filetimeIsDefined = false;
+  NCOM::CPropVariant propVariant;
+  RINOK(updateCallback->GetProperty(index, propID, &propVariant));
+  if (propVariant.vt == VT_FILETIME)
+  {
+    filetime = propVariant.filetime;
+    filetimeIsDefined = true;
+  }
+  else if (propVariant.vt != VT_EMPTY)
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+    IArchiveUpdateCallback *updateCallback)
+{
+  COM_TRY_BEGIN
+
+  const CArchiveDatabaseEx *database = 0;
+  #ifdef _7Z_VOL
+  if(_volumes.Size() > 1)
+    return E_FAIL;
+  const CVolume *volume = 0;
+  if (_volumes.Size() == 1)
+  {
+    volume = &_volumes.Front();
+    database = &volume->Database;
+  }
+  #else
+  if (_inStream != 0)
+    database = &_database;
+  #endif
+
+  // CRecordVector<bool> compressStatuses;
+  CObjectVector<CUpdateItem> updateItems;
+  // CRecordVector<UInt32> copyIndices;
+  
+  // CMyComPtr<IUpdateCallback2> updateCallback2;
+  // updateCallback->QueryInterface(&updateCallback2);
+
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    Int32 newData;
+    Int32 newProperties;
+    UInt32 indexInArchive;
+    if (!updateCallback)
+      return E_FAIL;
+    RINOK(updateCallback->GetUpdateItemInfo(i,
+        &newData, &newProperties, &indexInArchive));
+    CUpdateItem updateItem;
+    updateItem.NewProperties = IntToBool(newProperties);
+    updateItem.NewData = IntToBool(newData);
+    updateItem.IndexInArchive = indexInArchive;
+    updateItem.IndexInClient = i;
+    updateItem.IsAnti = false;
+    updateItem.Size = 0;
+
+    if (updateItem.IndexInArchive != -1)
+    {
+      const CFileItem &fileItem = database->Files[updateItem.IndexInArchive];
+      updateItem.Name = fileItem.Name;
+      updateItem.IsDirectory = fileItem.IsDirectory;
+      updateItem.Size = fileItem.UnPackSize;
+      updateItem.IsAnti = fileItem.IsAnti;
+      
+      updateItem.CreationTime = fileItem.CreationTime;
+      updateItem.IsCreationTimeDefined = fileItem.IsCreationTimeDefined;
+      updateItem.LastWriteTime = fileItem.LastWriteTime;
+      updateItem.IsLastWriteTimeDefined = fileItem.IsLastWriteTimeDefined;
+      updateItem.LastAccessTime = fileItem.LastAccessTime;
+      updateItem.IsLastAccessTimeDefined = fileItem.IsLastAccessTimeDefined;
+    }
+
+    if (updateItem.NewProperties)
+    {
+      bool nameIsDefined;
+      bool folderStatusIsDefined;
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          updateItem.AttributesAreDefined = false;
+        else if (propVariant.vt != VT_UI4)
+          return E_INVALIDARG;
+        else
+        {
+          updateItem.Attributes = propVariant.ulVal;
+          updateItem.AttributesAreDefined = true;
+        }
+      }
+      
+      RINOK(GetTime(updateCallback, i, kpidCreationTime, updateItem.CreationTime, updateItem.IsCreationTimeDefined));
+      RINOK(GetTime(updateCallback, i, kpidLastWriteTime, updateItem.LastWriteTime , updateItem.IsLastWriteTimeDefined));
+      RINOK(GetTime(updateCallback, i, kpidLastAccessTime, updateItem.LastAccessTime, updateItem.IsLastAccessTimeDefined));
+
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          nameIsDefined = false;
+        else if (propVariant.vt != VT_BSTR)
+          return E_INVALIDARG;
+        else
+        {
+          updateItem.Name = NItemName::MakeLegalName(propVariant.bstrVal);
+          nameIsDefined = true;
+        }
+      }
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          folderStatusIsDefined = false;
+        else if (propVariant.vt != VT_BOOL)
+          return E_INVALIDARG;
+        else
+        {
+          updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE);
+          folderStatusIsDefined = true;
+        }
+      }
+
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidIsAnti, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          updateItem.IsAnti = false;
+        else if (propVariant.vt != VT_BOOL)
+          return E_INVALIDARG;
+        else
+          updateItem.IsAnti = (propVariant.boolVal != VARIANT_FALSE);
+      }
+
+      if (updateItem.IsAnti)
+      {
+        updateItem.AttributesAreDefined = false;
+
+        updateItem.IsCreationTimeDefined = false;
+        updateItem.IsLastWriteTimeDefined = false;
+        updateItem.IsLastAccessTimeDefined = false;
+        
+        updateItem.Size = 0;
+      }
+
+      if (!folderStatusIsDefined && updateItem.AttributesAreDefined)
+        updateItem.SetDirectoryStatusFromAttributes();
+    }
+
+    if (updateItem.NewData)
+    {
+      NCOM::CPropVariant propVariant;
+      RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant));
+      if (propVariant.vt != VT_UI8)
+        return E_INVALIDARG;
+      updateItem.Size = (UInt64)propVariant.uhVal.QuadPart;
+      if (updateItem.Size != 0 && updateItem.IsAnti)
+        return E_INVALIDARG;
+    }
+    updateItems.Add(updateItem);
+  }
+
+  CCompressionMethodMode methodMode, headerMethod;
+  RINOK(SetCompressionMethod(methodMode, headerMethod));
+  #ifdef COMPRESS_MT
+  methodMode.NumThreads = _numThreads;
+  headerMethod.NumThreads = 1;
+  #endif
+
+  RINOK(SetPassword(methodMode, updateCallback));
+
+  bool compressMainHeader = _compressHeaders;  // check it
+
+  if (methodMode.PasswordIsDefined)
+  {
+    compressMainHeader = true; 
+    if(_encryptHeaders)
+      RINOK(SetPassword(headerMethod, updateCallback));
+  }
+
+  if (numItems < 2)
+    compressMainHeader = false;
+
+  CUpdateOptions options;
+  options.Method = &methodMode;
+  options.HeaderMethod = (_compressHeaders || 
+      (methodMode.PasswordIsDefined && _encryptHeaders)) ? 
+      &headerMethod : 0;
+  options.UseFilters = _level != 0 && _autoFilter;
+  options.MaxFilter = _level >= 8;
+
+  options.HeaderOptions.CompressMainHeader = compressMainHeader;
+  options.HeaderOptions.WriteModified = WriteModified;
+  options.HeaderOptions.WriteCreated = WriteCreated;
+  options.HeaderOptions.WriteAccessed = WriteAccessed;
+  
+  options.NumSolidFiles = _numSolidFiles;
+  options.NumSolidBytes = _numSolidBytes;
+  options.SolidExtension = _solidExtension;
+  options.RemoveSfxBlock = _removeSfxBlock;
+  options.VolumeMode = _volumeMode;
+  return Update(
+      EXTERNAL_CODECS_VARS
+      #ifdef _7Z_VOL
+      volume ? volume->Stream: 0, 
+      volume ? database: 0, 
+      #else
+      _inStream, 
+      database,
+      #endif
+      updateItems, outStream, updateCallback, options);
+  COM_TRY_END
+}
+
+static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
+{
+  stream = 0;
+  int index = ParseStringToUInt32(srcString, coder);
+  if (index == 0)
+    return E_INVALIDARG;
+  srcString.Delete(0, index);
+  if (srcString[0] == 'S')
+  {
+    srcString.Delete(0);
+    int index = ParseStringToUInt32(srcString, stream);
+    if (index == 0)
+      return E_INVALIDARG;
+    srcString.Delete(0, index);
+  }
+  return S_OK;
+}
+
+static HRESULT GetBindInfo(UString &srcString, CBind &bind)
+{
+  RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
+  if (srcString[0] != ':')
+    return E_INVALIDARG;
+  srcString.Delete(0);
+  RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
+  if (!srcString.IsEmpty())
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+  COM_TRY_BEGIN
+  _binds.Clear();
+  BeforeSetProperty();
+
+  for (int i = 0; i < numProperties; i++)
+  {
+    UString name = names[i];
+    name.MakeUpper();
+    if (name.IsEmpty())
+      return E_INVALIDARG;
+
+    const PROPVARIANT &value = values[i];
+
+    if (name[0] == 'B')
+    {
+      name.Delete(0);
+      CBind bind;
+      RINOK(GetBindInfo(name, bind));
+      _binds.Add(bind);
+      continue;
+    }
+
+    RINOK(SetProperty(name, value));
+  }
+
+  return S_OK;
+  COM_TRY_END
+}  
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zHeader.cpp b/lzma/CPP/7zip/Archive/7z/7zHeader.cpp
new file mode 100644 (file)
index 0000000..425231f
--- /dev/null
@@ -0,0 +1,27 @@
+// 7z/Header.cpp
+
+#include "StdAfx.h"
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+Byte kSignature[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C};
+#ifdef _7Z_VOL
+Byte kFinishSignature[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C + 1};
+#endif
+
+class SignatureInitializer
+{
+public:
+  SignatureInitializer() 
+  { 
+    kSignature[0]--; 
+    #ifdef _7Z_VOL
+    kFinishSignature[0]--;
+    #endif
+  };
+} g_SignatureInitializer;
+
+}}
+
diff --git a/lzma/CPP/7zip/Archive/7z/7zHeader.h b/lzma/CPP/7zip/Archive/7z/7zHeader.h
new file mode 100644 (file)
index 0000000..e239ab2
--- /dev/null
@@ -0,0 +1,96 @@
+// 7z/7zHeader.h
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "../../../Common/Types.h"
+
+namespace NArchive {
+namespace N7z {
+
+const int kSignatureSize = 6;
+extern Byte kSignature[kSignatureSize];
+
+// #define _7Z_VOL
+// 7z-MultiVolume is not finished yet.
+// It can work already, but I still do not like some 
+// things of that new multivolume format.
+// So please keep it commented.
+
+#ifdef _7Z_VOL
+extern Byte kFinishSignature[kSignatureSize];
+#endif
+
+struct CArchiveVersion
+{
+  Byte Major;
+  Byte Minor;
+};
+
+const Byte kMajorVersion = 0;
+
+struct CStartHeader
+{
+  UInt64 NextHeaderOffset;
+  UInt64 NextHeaderSize;
+  UInt32 NextHeaderCRC;
+};
+
+const UInt32 kStartHeaderSize = 20;
+
+#ifdef _7Z_VOL
+struct CFinishHeader: public CStartHeader
+{
+  UInt64 ArchiveStartOffset;  // data offset from end if that struct
+  UInt64 AdditionalStartBlockSize; // start  signature & start header size
+};
+
+const UInt32 kFinishHeaderSize = kStartHeaderSize + 16;
+#endif
+
+namespace NID
+{
+  enum EEnum
+  {
+    kEnd,
+
+    kHeader,
+
+    kArchiveProperties,
+    
+    kAdditionalStreamsInfo,
+    kMainStreamsInfo,
+    kFilesInfo,
+    
+    kPackInfo,
+    kUnPackInfo,
+    kSubStreamsInfo,
+
+    kSize,
+    kCRC,
+
+    kFolder,
+
+    kCodersUnPackSize,
+    kNumUnPackStream,
+
+    kEmptyStream,
+    kEmptyFile,
+    kAnti,
+
+    kName,
+    kCreationTime,
+    kLastAccessTime,
+    kLastWriteTime,
+    kWinAttributes,
+    kComment,
+
+    kEncodedHeader,
+
+    kStartPos
+  };
+}
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zIn.cpp b/lzma/CPP/7zip/Archive/7z/7zIn.cpp
new file mode 100644 (file)
index 0000000..a429254
--- /dev/null
@@ -0,0 +1,1206 @@
+// 7zIn.cpp
+
+#include "StdAfx.h"
+
+#include "7zIn.h"
+#include "7zDecode.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+extern "C" 
+{ 
+#include "../../../../C/7zCrc.h"
+}
+
+// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader 
+#ifndef _SFX
+#define FORMAT_7Z_RECOVERY
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+class CInArchiveException {};
+
+static void ThrowException() { throw CInArchiveException(); }
+static inline void ThrowEndOfData()   { ThrowException(); }
+static inline void ThrowUnsupported() { ThrowException(); }
+static inline void ThrowIncorrect()   { ThrowException(); }
+static inline void ThrowUnsupportedVersion() { ThrowException(); }
+
+/*
+class CInArchiveException
+{
+public:
+  enum CCauseType
+  {
+    kUnsupportedVersion = 0,
+    kUnsupported,
+    kIncorrect, 
+    kEndOfData,
+  } Cause;
+  CInArchiveException(CCauseType cause): Cause(cause) {};
+};
+
+static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
+static void ThrowEndOfData()   { ThrowException(CInArchiveException::kEndOfData); }
+static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
+static void ThrowIncorrect()   { ThrowException(CInArchiveException::kIncorrect); }
+static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
+*/
+
+class CStreamSwitch
+{
+  CInArchive *_archive;
+  bool _needRemove;
+public:
+  CStreamSwitch(): _needRemove(false) {}
+  ~CStreamSwitch() { Remove(); }
+  void Remove();
+  void Set(CInArchive *archive, const Byte *data, size_t size);
+  void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
+  void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
+};
+
+void CStreamSwitch::Remove()
+{
+  if (_needRemove)
+  {
+    _archive->DeleteByteStream();
+    _needRemove = false;
+  }
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
+{
+  Remove();
+  _archive = archive;
+  _archive->AddByteStream(data, size);
+  _needRemove = true;
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
+{
+  Set(archive, byteBuffer, byteBuffer.GetCapacity());
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
+{
+  Remove();
+  Byte external = archive->ReadByte();
+  if (external != 0)
+  {
+    int dataIndex = (int)archive->ReadNum();
+    if (dataIndex < 0 || dataIndex >= dataVector->Size())
+      ThrowIncorrect();
+    Set(archive, (*dataVector)[dataIndex]);
+  }
+}
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
+#define SZ_LITTLE_ENDIAN_UNALIGN
+#endif
+
+#ifdef SZ_LITTLE_ENDIAN_UNALIGN
+static inline UInt16 GetUInt16FromMem(const Byte *p) { return *(const UInt16 *)p; }
+static inline UInt32 GetUInt32FromMem(const Byte *p) { return *(const UInt32 *)p; }
+static inline UInt64 GetUInt64FromMem(const Byte *p) { return *(const UInt64 *)p; }
+#else
+static inline UInt16 GetUInt16FromMem(const Byte *p) { return p[0] | ((UInt16)p[1] << 8); }
+static inline UInt32 GetUInt32FromMem(const Byte *p) { return p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24); }
+static inline UInt64 GetUInt64FromMem(const Byte *p) { return GetUInt32FromMem(p) | ((UInt64)GetUInt32FromMem(p + 4) << 32); }
+#endif
+
+Byte CInByte2::ReadByte()
+{
+  if (_pos >= _size)
+    ThrowEndOfData();
+  return _buffer[_pos++];
+}
+
+void CInByte2::ReadBytes(Byte *data, size_t size)
+{
+  if (size > _size - _pos)
+    ThrowEndOfData();
+  for (size_t i = 0; i < size; i++)
+    data[i] = _buffer[_pos++];
+}
+
+void CInByte2::SkeepData(UInt64 size)
+{
+  if (size > _size - _pos)
+    ThrowEndOfData();
+}
+
+void CInByte2::SkeepData()
+{
+  SkeepData(ReadNumber());
+}
+
+UInt64 CInByte2::ReadNumber()
+{
+  if (_pos >= _size)
+    ThrowEndOfData();
+  Byte firstByte = _buffer[_pos++];
+  Byte mask = 0x80;
+  UInt64 value = 0;
+  for (int i = 0; i < 8; i++)
+  {
+    if ((firstByte & mask) == 0)
+    {
+      UInt64 highPart = firstByte & (mask - 1);
+      value += (highPart << (i * 8));
+      return value;
+    }
+    if (_pos >= _size)
+      ThrowEndOfData();
+    value |= ((UInt64)_buffer[_pos++] << (8 * i));
+    mask >>= 1;
+  }
+  return value;
+}
+
+CNum CInByte2::ReadNum()
+{ 
+  UInt64 value = ReadNumber(); 
+  if (value > kNumMax)
+    ThrowUnsupported();
+  return (CNum)value;
+}
+
+UInt32 CInByte2::ReadUInt32()
+{
+  if (_pos + 4 > _size)
+    ThrowEndOfData();
+  UInt32 res = GetUInt32FromMem(_buffer + _pos);
+  _pos += 4;
+  return res;
+}
+
+UInt64 CInByte2::ReadUInt64()
+{
+  if (_pos + 8 > _size)
+    ThrowEndOfData();
+  UInt64 res = GetUInt64FromMem(_buffer + _pos);
+  _pos += 8;
+  return res;
+}
+
+void CInByte2::ReadString(UString &s)
+{
+  const Byte *buf = _buffer + _pos;
+  size_t rem = (_size - _pos) / 2 * 2;
+  {
+    size_t i;
+    for (i = 0; i < rem; i += 2)
+      if (buf[i] == 0 && buf[i + 1] == 0)
+        break;
+    if (i == rem)
+      ThrowEndOfData();
+    rem = i;
+  }
+  int len = (int)(rem / 2);
+  if (len < 0 || (size_t)len * 2 != rem)
+    ThrowUnsupported();
+  wchar_t *p = s.GetBuffer(len);
+  int i;
+  for (i = 0; i < len; i++, buf += 2) 
+    p[i] = (wchar_t)GetUInt16FromMem(buf);
+  p[i] = 0;
+  s.ReleaseBuffer(len);
+  _pos += rem + 2;
+}
+
+static inline bool TestSignatureCandidate(const Byte *p)
+{
+  for (int i = 0; i < kSignatureSize; i++)
+    if (p[i] != kSignature[i])
+      return false;
+  return (p[0x1A] == 0 && p[0x1B] == 0);
+}
+
+HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+  UInt32 processedSize; 
+  RINOK(ReadStream(stream, _header, kHeaderSize, &processedSize));
+  if (processedSize != kHeaderSize)
+    return S_FALSE;
+  if (TestSignatureCandidate(_header))
+    return S_OK;
+
+  CByteBuffer byteBuffer;
+  const UInt32 kBufferSize = (1 << 16);
+  byteBuffer.SetCapacity(kBufferSize);
+  Byte *buffer = byteBuffer;
+  UInt32 numPrevBytes = kHeaderSize - 1;
+  memcpy(buffer, _header + 1, numPrevBytes);
+  UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
+  for (;;)
+  {
+    if (searchHeaderSizeLimit != NULL)
+      if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
+        break;
+    UInt32 numReadBytes = kBufferSize - numPrevBytes;
+    RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
+    UInt32 numBytesInBuffer = numPrevBytes + processedSize;
+    if (numBytesInBuffer < kHeaderSize)
+      break;
+    UInt32 numTests = numBytesInBuffer - kHeaderSize + 1;
+    for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++)
+    { 
+      if (TestSignatureCandidate(buffer + pos))
+      {
+        memcpy(_header, buffer + pos, kHeaderSize);
+        _arhiveBeginStreamPosition = curTestPos;
+        return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
+      }
+    }
+    numPrevBytes = numBytesInBuffer - numTests;
+    memmove(buffer, buffer + numTests, numPrevBytes);
+  }
+  return S_FALSE;
+}
+
+// S_FALSE means that file is not archive
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+  Close();
+  RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
+  RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
+  _stream = stream;
+  return S_OK;
+}
+  
+void CInArchive::Close()
+{
+  _stream.Release();
+}
+
+void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
+{
+  for (;;)
+  {
+    if (ReadID() == NID::kEnd)
+      break;
+    SkeepData();
+  }
+}
+
+void CInArchive::GetNextFolderItem(CFolder &folder)
+{
+  CNum numCoders = ReadNum();
+
+  folder.Coders.Clear();
+  folder.Coders.Reserve((int)numCoders);
+  CNum numInStreams = 0;
+  CNum numOutStreams = 0;
+  CNum i;
+  for (i = 0; i < numCoders; i++)
+  {
+    folder.Coders.Add(CCoderInfo());
+    CCoderInfo &coder = folder.Coders.Back();
+
+    {
+      Byte mainByte = ReadByte();
+      int idSize = (mainByte & 0xF);
+      Byte longID[15];
+      ReadBytes(longID, idSize);
+      if (idSize > 8)
+        ThrowUnsupported();
+      UInt64 id = 0;
+      for (int j = 0; j < idSize; j++)
+        id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
+      coder.MethodID = id;
+
+      if ((mainByte & 0x10) != 0)
+      {
+        coder.NumInStreams = ReadNum();
+        coder.NumOutStreams = ReadNum();
+      }
+      else
+      {
+        coder.NumInStreams = 1;
+        coder.NumOutStreams = 1;
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        CNum propertiesSize = ReadNum();
+        coder.Properties.SetCapacity((size_t)propertiesSize);
+        ReadBytes((Byte *)coder.Properties, (size_t)propertiesSize);
+      }
+      if ((mainByte & 0x80) != 0)
+        ThrowUnsupported();
+    }
+    numInStreams += coder.NumInStreams;
+    numOutStreams += coder.NumOutStreams;
+  }
+
+  CNum numBindPairs;
+  numBindPairs = numOutStreams - 1;
+  folder.BindPairs.Clear();
+  folder.BindPairs.Reserve(numBindPairs);
+  for (i = 0; i < numBindPairs; i++)
+  {
+    CBindPair bindPair;
+    bindPair.InIndex = ReadNum();
+    bindPair.OutIndex = ReadNum(); 
+    folder.BindPairs.Add(bindPair);
+  }
+
+  CNum numPackedStreams = numInStreams - numBindPairs;
+  folder.PackStreams.Reserve(numPackedStreams);
+  if (numPackedStreams == 1)
+  {
+    for (CNum j = 0; j < numInStreams; j++)
+      if (folder.FindBindPairForInStream(j) < 0)
+      {
+        folder.PackStreams.Add(j);
+        break;
+      }
+  }
+  else
+    for(i = 0; i < numPackedStreams; i++)
+      folder.PackStreams.Add(ReadNum());
+}
+
+void CInArchive::WaitAttribute(UInt64 attribute)
+{
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == attribute)
+      return;
+    if (type == NID::kEnd)
+      ThrowIncorrect();
+    SkeepData();
+  }
+}
+
+void CInArchive::ReadHashDigests(int numItems,
+    CRecordVector<bool> &digestsDefined, 
+    CRecordVector<UInt32> &digests)
+{
+  ReadBoolVector2(numItems, digestsDefined);
+  digests.Clear();
+  digests.Reserve(numItems);
+  for(int i = 0; i < numItems; i++)
+  {
+    UInt32 crc = 0;
+    if (digestsDefined[i])
+      crc = ReadUInt32();
+    digests.Add(crc);
+  }
+}
+
+void CInArchive::ReadPackInfo(
+    UInt64 &dataOffset,
+    CRecordVector<UInt64> &packSizes,
+    CRecordVector<bool> &packCRCsDefined,
+    CRecordVector<UInt32> &packCRCs)
+{
+  dataOffset = ReadNumber();
+  CNum numPackStreams = ReadNum();
+
+  WaitAttribute(NID::kSize);
+  packSizes.Clear();
+  packSizes.Reserve(numPackStreams);
+  for (CNum i = 0; i < numPackStreams; i++)
+    packSizes.Add(ReadNumber());
+
+  UInt64 type;
+  for (;;)
+  {
+    type = ReadID();
+    if (type == NID::kEnd)
+      break;
+    if (type == NID::kCRC)
+    {
+      ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); 
+      continue;
+    }
+    SkeepData();
+  }
+  if (packCRCsDefined.IsEmpty())
+  {
+    packCRCsDefined.Reserve(numPackStreams);
+    packCRCsDefined.Clear();
+    packCRCs.Reserve(numPackStreams);
+    packCRCs.Clear();
+    for(CNum i = 0; i < numPackStreams; i++)
+    {
+      packCRCsDefined.Add(false);
+      packCRCs.Add(0);
+    }
+  }
+}
+
+void CInArchive::ReadUnPackInfo(
+    const CObjectVector<CByteBuffer> *dataVector,
+    CObjectVector<CFolder> &folders)
+{
+  WaitAttribute(NID::kFolder);
+  CNum numFolders = ReadNum();
+
+  {
+    CStreamSwitch streamSwitch;
+    streamSwitch.Set(this, dataVector);
+    folders.Clear();
+    folders.Reserve(numFolders);
+    for(CNum i = 0; i < numFolders; i++)
+    {
+      folders.Add(CFolder());
+      GetNextFolderItem(folders.Back());
+    }
+  }
+
+  WaitAttribute(NID::kCodersUnPackSize);
+
+  CNum i;
+  for (i = 0; i < numFolders; i++)
+  {
+    CFolder &folder = folders[i];
+    CNum numOutStreams = folder.GetNumOutStreams();
+    folder.UnPackSizes.Reserve(numOutStreams);
+    for (CNum j = 0; j < numOutStreams; j++)
+      folder.UnPackSizes.Add(ReadNumber());
+  }
+
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == NID::kEnd)
+      return;
+    if (type == NID::kCRC)
+    {
+      CRecordVector<bool> crcsDefined;
+      CRecordVector<UInt32> crcs;
+      ReadHashDigests(numFolders, crcsDefined, crcs); 
+      for(i = 0; i < numFolders; i++)
+      {
+        CFolder &folder = folders[i];
+        folder.UnPackCRCDefined = crcsDefined[i];
+        folder.UnPackCRC = crcs[i];
+      }
+      continue;
+    }
+    SkeepData();
+  }
+}
+
+void CInArchive::ReadSubStreamsInfo(
+    const CObjectVector<CFolder> &folders,
+    CRecordVector<CNum> &numUnPackStreamsInFolders,
+    CRecordVector<UInt64> &unPackSizes,
+    CRecordVector<bool> &digestsDefined, 
+    CRecordVector<UInt32> &digests)
+{
+  numUnPackStreamsInFolders.Clear();
+  numUnPackStreamsInFolders.Reserve(folders.Size());
+  UInt64 type;
+  for (;;)
+  {
+    type = ReadID();
+    if (type == NID::kNumUnPackStream)
+    {
+      for(int i = 0; i < folders.Size(); i++)
+        numUnPackStreamsInFolders.Add(ReadNum());
+      continue;
+    }
+    if (type == NID::kCRC || type == NID::kSize)
+      break;
+    if (type == NID::kEnd)
+      break;
+    SkeepData();
+  }
+
+  if (numUnPackStreamsInFolders.IsEmpty())
+    for(int i = 0; i < folders.Size(); i++)
+      numUnPackStreamsInFolders.Add(1);
+
+  int i;
+  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+  {
+    // v3.13 incorrectly worked with empty folders
+    // v4.07: we check that folder is empty
+    CNum numSubstreams = numUnPackStreamsInFolders[i];
+    if (numSubstreams == 0)
+      continue;
+    UInt64 sum = 0;
+    for (CNum j = 1; j < numSubstreams; j++)
+      if (type == NID::kSize)
+      {
+        UInt64 size = ReadNumber();
+        unPackSizes.Add(size);
+        sum += size;
+      }
+    unPackSizes.Add(folders[i].GetUnPackSize() - sum);
+  }
+  if (type == NID::kSize)
+    type = ReadID();
+
+  int numDigests = 0;
+  int numDigestsTotal = 0;
+  for(i = 0; i < folders.Size(); i++)
+  {
+    CNum numSubstreams = numUnPackStreamsInFolders[i];
+    if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
+      numDigests += numSubstreams;
+    numDigestsTotal += numSubstreams;
+  }
+
+  for (;;)
+  {
+    if (type == NID::kCRC)
+    {
+      CRecordVector<bool> digestsDefined2; 
+      CRecordVector<UInt32> digests2;
+      ReadHashDigests(numDigests, digestsDefined2, digests2);
+      int digestIndex = 0;
+      for (i = 0; i < folders.Size(); i++)
+      {
+        CNum numSubstreams = numUnPackStreamsInFolders[i];
+        const CFolder &folder = folders[i];
+        if (numSubstreams == 1 && folder.UnPackCRCDefined)
+        {
+          digestsDefined.Add(true);
+          digests.Add(folder.UnPackCRC);
+        }
+        else
+          for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
+          {
+            digestsDefined.Add(digestsDefined2[digestIndex]);
+            digests.Add(digests2[digestIndex]);
+          }
+      }
+    }
+    else if (type == NID::kEnd)
+    {
+      if (digestsDefined.IsEmpty())
+      {
+        digestsDefined.Clear();
+        digests.Clear();
+        for (int i = 0; i < numDigestsTotal; i++)
+        {
+          digestsDefined.Add(false);
+          digests.Add(0);
+        }
+      }
+      return;
+    }
+    else
+      SkeepData();
+    type = ReadID();
+  }
+}
+
+void CInArchive::ReadStreamsInfo(
+    const CObjectVector<CByteBuffer> *dataVector,
+    UInt64 &dataOffset,
+    CRecordVector<UInt64> &packSizes,
+    CRecordVector<bool> &packCRCsDefined,
+    CRecordVector<UInt32> &packCRCs,
+    CObjectVector<CFolder> &folders,
+    CRecordVector<CNum> &numUnPackStreamsInFolders,
+    CRecordVector<UInt64> &unPackSizes,
+    CRecordVector<bool> &digestsDefined, 
+    CRecordVector<UInt32> &digests)
+{
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type > ((UInt32)1 << 30))
+      ThrowIncorrect();
+    switch((UInt32)type)
+    {
+      case NID::kEnd:
+        return;
+      case NID::kPackInfo:
+      {
+        ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
+        break;
+      }
+      case NID::kUnPackInfo:
+      {
+        ReadUnPackInfo(dataVector, folders);
+        break;
+      }
+      case NID::kSubStreamsInfo:
+      {
+        ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
+            unPackSizes, digestsDefined, digests);
+        break;
+      }
+      default:
+        ThrowIncorrect();
+    }
+  }
+}
+
+void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
+{
+  v.Clear();
+  v.Reserve(numItems);
+  Byte b = 0;
+  Byte mask = 0;
+  for(int i = 0; i < numItems; i++)
+  {
+    if (mask == 0)
+    {
+      b = ReadByte();
+      mask = 0x80;
+    }
+    v.Add((b & mask) != 0);
+    mask >>= 1;
+  }
+}
+
+void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
+{
+  Byte allAreDefined = ReadByte();
+  if (allAreDefined == 0)
+  {
+    ReadBoolVector(numItems, v);
+    return;
+  }
+  v.Clear();
+  v.Reserve(numItems);
+  for (int i = 0; i < numItems; i++)
+    v.Add(true);
+}
+
+void CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector,
+    CObjectVector<CFileItem> &files, UInt32 type)
+{
+  CBoolVector boolVector;
+  ReadBoolVector2(files.Size(), boolVector);
+
+  CStreamSwitch streamSwitch;
+  streamSwitch.Set(this, &dataVector);
+
+  for(int i = 0; i < files.Size(); i++)
+  {
+    CFileItem &file = files[i];
+    CArchiveFileTime fileTime;
+    fileTime.dwLowDateTime = 0;
+    fileTime.dwHighDateTime = 0;
+    bool defined = boolVector[i];
+    if (defined)
+    {
+      fileTime.dwLowDateTime = ReadUInt32();
+      fileTime.dwHighDateTime = ReadUInt32();
+    }
+    switch(type)
+    {
+      case NID::kCreationTime:
+        file.IsCreationTimeDefined = defined;
+        if (defined)
+          file.CreationTime = fileTime;
+        break;
+      case NID::kLastWriteTime:
+        file.IsLastWriteTimeDefined = defined;
+        if (defined)
+          file.LastWriteTime = fileTime;
+        break;
+      case NID::kLastAccessTime:
+        file.IsLastAccessTimeDefined = defined;
+        if (defined)
+          file.LastAccessTime = fileTime;
+        break;
+    }
+  }
+}
+
+HRESULT CInArchive::ReadAndDecodePackedStreams(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    UInt64 baseOffset, 
+    UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  CRecordVector<UInt64> packSizes;
+  CRecordVector<bool> packCRCsDefined;
+  CRecordVector<UInt32> packCRCs;
+  CObjectVector<CFolder> folders;
+  
+  CRecordVector<CNum> numUnPackStreamsInFolders;
+  CRecordVector<UInt64> unPackSizes;
+  CRecordVector<bool> digestsDefined;
+  CRecordVector<UInt32> digests;
+  
+  ReadStreamsInfo(NULL, 
+    dataOffset,
+    packSizes, 
+    packCRCsDefined, 
+    packCRCs, 
+    folders,
+    numUnPackStreamsInFolders,
+    unPackSizes,
+    digestsDefined, 
+    digests);
+  
+  // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
+  
+  CNum packIndex = 0;
+  CDecoder decoder(
+    #ifdef _ST_MODE
+    false
+    #else
+    true
+    #endif
+    );
+  UInt64 dataStartPos = baseOffset + dataOffset;
+  for(int i = 0; i < folders.Size(); i++)
+  {
+    const CFolder &folder = folders[i];
+    dataVector.Add(CByteBuffer());
+    CByteBuffer &data = dataVector.Back();
+    UInt64 unPackSize64 = folder.GetUnPackSize();
+    size_t unPackSize = (size_t)unPackSize64;
+    if (unPackSize != unPackSize64)
+      ThrowUnsupported();
+    data.SetCapacity(unPackSize);
+    
+    CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
+    CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+    outStreamSpec->Init(data, unPackSize);
+    
+    HRESULT result = decoder.Decode(
+      EXTERNAL_CODECS_LOC_VARS
+      _stream, dataStartPos, 
+      &packSizes[packIndex], folder, outStream, NULL
+      #ifndef _NO_CRYPTO
+      , getTextPassword
+      #endif
+      #ifdef COMPRESS_MT
+      , false, 1
+      #endif
+      );
+    RINOK(result);
+    
+    if (folder.UnPackCRCDefined)
+      if (CrcCalc(data, unPackSize) != folder.UnPackCRC)
+        ThrowIncorrect();
+      for (int j = 0; j < folder.PackStreams.Size(); j++)
+        dataStartPos += packSizes[packIndex++];
+  }
+  return S_OK;
+}
+
+HRESULT CInArchive::ReadHeader(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CArchiveDatabaseEx &database
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  UInt64 type = ReadID();
+
+  if (type == NID::kArchiveProperties)
+  {
+    ReadArchiveProperties(database.ArchiveInfo);
+    type = ReadID();
+  }
+  CObjectVector<CByteBuffer> dataVector;
+  
+  if (type == NID::kAdditionalStreamsInfo)
+  {
+    HRESULT result = ReadAndDecodePackedStreams(
+        EXTERNAL_CODECS_LOC_VARS
+        database.ArchiveInfo.StartPositionAfterHeader, 
+        database.ArchiveInfo.DataStartPosition2,
+        dataVector
+        #ifndef _NO_CRYPTO
+        , getTextPassword
+        #endif
+        );
+    RINOK(result);
+    database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
+    type = ReadID();
+  }
+
+  CRecordVector<UInt64> unPackSizes;
+  CRecordVector<bool> digestsDefined;
+  CRecordVector<UInt32> digests;
+  
+  if (type == NID::kMainStreamsInfo)
+  {
+    ReadStreamsInfo(&dataVector,
+        database.ArchiveInfo.DataStartPosition,
+        database.PackSizes, 
+        database.PackCRCsDefined, 
+        database.PackCRCs, 
+        database.Folders,
+        database.NumUnPackStreamsVector,
+        unPackSizes,
+        digestsDefined,
+        digests);
+    database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
+    type = ReadID();
+  }
+  else
+  {
+    for(int i = 0; i < database.Folders.Size(); i++)
+    {
+      database.NumUnPackStreamsVector.Add(1);
+      CFolder &folder = database.Folders[i];
+      unPackSizes.Add(folder.GetUnPackSize());
+      digestsDefined.Add(folder.UnPackCRCDefined);
+      digests.Add(folder.UnPackCRC);
+    }
+  }
+
+  database.Files.Clear();
+
+  if (type == NID::kEnd)
+    return S_OK;
+  if (type != NID::kFilesInfo)
+    ThrowIncorrect();
+  
+  CNum numFiles = ReadNum();
+  database.Files.Reserve(numFiles);
+  CNum i;
+  for(i = 0; i < numFiles; i++)
+    database.Files.Add(CFileItem());
+
+  database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
+  if (!database.PackSizes.IsEmpty())
+    database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
+  if (numFiles > 0  && !digests.IsEmpty())
+    database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
+
+  CBoolVector emptyStreamVector;
+  emptyStreamVector.Reserve((int)numFiles);
+  for(i = 0; i < numFiles; i++)
+    emptyStreamVector.Add(false);
+  CBoolVector emptyFileVector;
+  CBoolVector antiFileVector;
+  CNum numEmptyStreams = 0;
+
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == NID::kEnd)
+      break;
+    UInt64 size = ReadNumber();
+    bool isKnownType = true;
+    if (type > ((UInt32)1 << 30))
+      isKnownType = false;
+    else switch((UInt32)type)
+    {
+      case NID::kName:
+      {
+        CStreamSwitch streamSwitch;
+        streamSwitch.Set(this, &dataVector);
+        for(int i = 0; i < database.Files.Size(); i++)
+          _inByteBack->ReadString(database.Files[i].Name);
+        break;
+      }
+      case NID::kWinAttributes:
+      {
+        CBoolVector boolVector;
+        ReadBoolVector2(database.Files.Size(), boolVector);
+        CStreamSwitch streamSwitch;
+        streamSwitch.Set(this, &dataVector);
+        for(i = 0; i < numFiles; i++)
+        {
+          CFileItem &file = database.Files[i];
+          file.AreAttributesDefined = boolVector[i];
+          if (file.AreAttributesDefined)
+            file.Attributes = ReadUInt32();
+        }
+        break;
+      }
+      case NID::kStartPos:
+      {
+        CBoolVector boolVector;
+        ReadBoolVector2(database.Files.Size(), boolVector);
+        CStreamSwitch streamSwitch;
+        streamSwitch.Set(this, &dataVector);
+        for(i = 0; i < numFiles; i++)
+        {
+          CFileItem &file = database.Files[i];
+          file.IsStartPosDefined = boolVector[i];
+          if (file.IsStartPosDefined)
+            file.StartPos = ReadUInt64();
+        }
+        break;
+      }
+      case NID::kEmptyStream:
+      {
+        ReadBoolVector(numFiles, emptyStreamVector);
+        for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
+          if (emptyStreamVector[i])
+            numEmptyStreams++;
+        emptyFileVector.Reserve(numEmptyStreams);
+        antiFileVector.Reserve(numEmptyStreams);
+        for (i = 0; i < numEmptyStreams; i++)
+        {
+          emptyFileVector.Add(false);
+          antiFileVector.Add(false);
+        }
+        break;
+      }
+      case NID::kEmptyFile:
+      {
+        ReadBoolVector(numEmptyStreams, emptyFileVector);
+        break;
+      }
+      case NID::kAnti:
+      {
+        ReadBoolVector(numEmptyStreams, antiFileVector);
+        break;
+      }
+      case NID::kCreationTime:
+      case NID::kLastWriteTime:
+      case NID::kLastAccessTime:
+      {
+        ReadTime(dataVector, database.Files, (UInt32)type);
+        break;
+      }
+      default:
+        isKnownType = false;
+    }
+    if (isKnownType)
+      database.ArchiveInfo.FileInfoPopIDs.Add(type);
+    else
+      SkeepData(size);
+  }
+
+  CNum emptyFileIndex = 0;
+  CNum sizeIndex = 0;
+  for(i = 0; i < numFiles; i++)
+  {
+    CFileItem &file = database.Files[i];
+    file.HasStream = !emptyStreamVector[i];
+    if(file.HasStream)
+    {
+      file.IsDirectory = false;
+      file.IsAnti = false;
+      file.UnPackSize = unPackSizes[sizeIndex];
+      file.FileCRC = digests[sizeIndex];
+      file.IsFileCRCDefined = digestsDefined[sizeIndex];
+      sizeIndex++;
+    }
+    else
+    {
+      file.IsDirectory = !emptyFileVector[emptyFileIndex];
+      file.IsAnti = antiFileVector[emptyFileIndex];
+      emptyFileIndex++;
+      file.UnPackSize = 0;
+      file.IsFileCRCDefined = false;
+    }
+  }
+  return S_OK;
+}
+
+
+void CArchiveDatabaseEx::FillFolderStartPackStream()
+{
+  FolderStartPackStreamIndex.Clear();
+  FolderStartPackStreamIndex.Reserve(Folders.Size());
+  CNum startPos = 0;
+  for(int i = 0; i < Folders.Size(); i++)
+  {
+    FolderStartPackStreamIndex.Add(startPos);
+    startPos += (CNum)Folders[i].PackStreams.Size();
+  }
+}
+
+void CArchiveDatabaseEx::FillStartPos()
+{
+  PackStreamStartPositions.Clear();
+  PackStreamStartPositions.Reserve(PackSizes.Size());
+  UInt64 startPos = 0;
+  for(int i = 0; i < PackSizes.Size(); i++)
+  {
+    PackStreamStartPositions.Add(startPos);
+    startPos += PackSizes[i];
+  }
+}
+
+void CArchiveDatabaseEx::FillFolderStartFileIndex()
+{
+  FolderStartFileIndex.Clear();
+  FolderStartFileIndex.Reserve(Folders.Size());
+  FileIndexToFolderIndexMap.Clear();
+  FileIndexToFolderIndexMap.Reserve(Files.Size());
+  
+  int folderIndex = 0;
+  CNum indexInFolder = 0;
+  for (int i = 0; i < Files.Size(); i++)
+  {
+    const CFileItem &file = Files[i];
+    bool emptyStream = !file.HasStream;
+    if (emptyStream && indexInFolder == 0)
+    {
+      FileIndexToFolderIndexMap.Add(kNumNoIndex);
+      continue;
+    }
+    if (indexInFolder == 0)
+    {
+      // v3.13 incorrectly worked with empty folders
+      // v4.07: Loop for skipping empty folders
+      for (;;)
+      {
+        if (folderIndex >= Folders.Size())
+          ThrowIncorrect();
+        FolderStartFileIndex.Add(i); // check it
+        if (NumUnPackStreamsVector[folderIndex] != 0)
+          break;
+        folderIndex++;
+      }
+    }
+    FileIndexToFolderIndexMap.Add(folderIndex);
+    if (emptyStream)
+      continue;
+    indexInFolder++;
+    if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
+    {
+      folderIndex++;
+      indexInFolder = 0;
+    }
+  }
+}
+
+HRESULT CInArchive::ReadDatabase2(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CArchiveDatabaseEx &database
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  database.Clear();
+  database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+
+  database.ArchiveInfo.Version.Major = _header[6];
+  database.ArchiveInfo.Version.Minor = _header[7];
+
+  if (database.ArchiveInfo.Version.Major != kMajorVersion)
+    ThrowUnsupportedVersion();
+
+  UInt32 crcFromArchive = GetUInt32FromMem(_header + 8);
+  UInt64 nextHeaderOffset = GetUInt64FromMem(_header + 0xC);
+  UInt64 nextHeaderSize = GetUInt64FromMem(_header + 0x14);
+  UInt32 nextHeaderCRC =  GetUInt32FromMem(_header + 0x1C);
+  UInt32 crc = CrcCalc(_header + 0xC, 20);
+
+  #ifdef FORMAT_7Z_RECOVERY
+  if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
+  {
+    UInt64 cur, cur2;
+    RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
+    const int kCheckSize = 500;
+    Byte buf[kCheckSize];
+    RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
+    int checkSize = kCheckSize;
+    if (cur2 - cur < kCheckSize)
+      checkSize = (int)(cur2 - cur);
+    RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
+    
+    UInt32 realProcessedSize;
+    RINOK(_stream->Read(buf, (UInt32)kCheckSize, &realProcessedSize));
+
+    int i;
+    for (i = (int)realProcessedSize - 2; i >= 0; i--)
+      if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
+        break;
+    if (i < 0)
+      return S_FALSE;
+    nextHeaderSize = realProcessedSize - i;
+    nextHeaderOffset = cur2 - cur + i;
+    nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
+    RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
+  }
+  #endif
+
+  #ifdef FORMAT_7Z_RECOVERY
+  crcFromArchive = crc;
+  #endif
+
+  database.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
+
+  if (crc != crcFromArchive)
+    ThrowIncorrect();
+
+  if (nextHeaderSize == 0)
+    return S_OK;
+
+  if (nextHeaderSize > (UInt64)0xFFFFFFFF)
+    return S_FALSE;
+
+  RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
+
+  CByteBuffer buffer2;
+  buffer2.SetCapacity((size_t)nextHeaderSize);
+
+  UInt32 realProcessedSize;
+  RINOK(_stream->Read(buffer2, (UInt32)nextHeaderSize, &realProcessedSize));
+  if (realProcessedSize != (UInt32)nextHeaderSize)
+    return S_FALSE;
+  if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
+    ThrowIncorrect();
+  
+  CStreamSwitch streamSwitch;
+  streamSwitch.Set(this, buffer2);
+  
+  CObjectVector<CByteBuffer> dataVector;
+  
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == NID::kHeader)
+      break;
+    if (type != NID::kEncodedHeader)
+      ThrowIncorrect();
+    HRESULT result = ReadAndDecodePackedStreams(
+        EXTERNAL_CODECS_LOC_VARS
+        database.ArchiveInfo.StartPositionAfterHeader, 
+        database.ArchiveInfo.DataStartPosition2,
+        dataVector
+        #ifndef _NO_CRYPTO
+        , getTextPassword
+        #endif
+        );
+    RINOK(result);
+    if (dataVector.Size() == 0)
+      return S_OK;
+    if (dataVector.Size() > 1)
+      ThrowIncorrect();
+    streamSwitch.Remove();
+    streamSwitch.Set(this, dataVector.Front());
+  }
+
+  return ReadHeader(
+    EXTERNAL_CODECS_LOC_VARS
+    database
+    #ifndef _NO_CRYPTO
+    , getTextPassword
+    #endif
+    );
+}
+
+HRESULT CInArchive::ReadDatabase(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CArchiveDatabaseEx &database
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  try
+  {
+    return ReadDatabase2(
+      EXTERNAL_CODECS_LOC_VARS database
+      #ifndef _NO_CRYPTO
+      , getTextPassword
+      #endif
+      );
+  }
+  catch(CInArchiveException &) { return S_FALSE; }
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zIn.h b/lzma/CPP/7zip/Archive/7z/7zIn.h
new file mode 100644 (file)
index 0000000..aae4350
--- /dev/null
@@ -0,0 +1,235 @@
+// 7zIn.h
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "../../../Common/MyCom.h"
+#include "../../IStream.h"
+#include "../../IPassword.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/InBuffer.h"
+
+#include "7zItem.h"
+namespace NArchive {
+namespace N7z {
+  
+struct CInArchiveInfo
+{
+  CArchiveVersion Version;
+  UInt64 StartPosition;
+  UInt64 StartPositionAfterHeader;
+  UInt64 DataStartPosition;
+  UInt64 DataStartPosition2;
+  CRecordVector<UInt64> FileInfoPopIDs;
+  void Clear()
+  {
+    FileInfoPopIDs.Clear();
+  }
+};
+
+struct CArchiveDatabaseEx: public CArchiveDatabase
+{
+  CInArchiveInfo ArchiveInfo;
+  CRecordVector<UInt64> PackStreamStartPositions;
+  CRecordVector<CNum> FolderStartPackStreamIndex;
+  CRecordVector<CNum> FolderStartFileIndex;
+  CRecordVector<CNum> FileIndexToFolderIndexMap;
+
+  void Clear()
+  {
+    CArchiveDatabase::Clear();
+    ArchiveInfo.Clear();
+    PackStreamStartPositions.Clear();
+    FolderStartPackStreamIndex.Clear();
+    FolderStartFileIndex.Clear();
+    FileIndexToFolderIndexMap.Clear();
+  }
+
+  void FillFolderStartPackStream();
+  void FillStartPos();
+  void FillFolderStartFileIndex();
+
+  void Fill()
+  {
+    FillFolderStartPackStream();
+    FillStartPos();
+    FillFolderStartFileIndex();
+  }
+  
+  UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const
+  {
+    return ArchiveInfo.DataStartPosition +
+        PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+  }
+  
+  UInt64 GetFolderFullPackSize(int folderIndex) const 
+  {
+    CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex];
+    const CFolder &folder = Folders[folderIndex];
+    UInt64 size = 0;
+    for (int i = 0; i < folder.PackStreams.Size(); i++)
+      size += PackSizes[packStreamIndex + i];
+    return size;
+  }
+  
+  UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const 
+  {
+    return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+  }
+
+  UInt64 GetFilePackSize(CNum fileIndex) const
+  {
+    CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
+    if (folderIndex != kNumNoIndex)
+      if (FolderStartFileIndex[folderIndex] == fileIndex)
+        return GetFolderFullPackSize(folderIndex);
+    return 0;
+  }
+};
+
+class CInByte2
+{
+  const Byte *_buffer;
+  size_t _size;
+  size_t _pos;
+public:
+  void Init(const Byte *buffer, size_t size)
+  {
+    _buffer = buffer;
+    _size = size;
+    _pos = 0;
+  }
+  Byte ReadByte();
+  void ReadBytes(Byte *data, size_t size);
+  void SkeepData(UInt64 size);
+  void SkeepData();
+  UInt64 ReadNumber();
+  CNum ReadNum();
+  UInt32 ReadUInt32();
+  UInt64 ReadUInt64();
+  void ReadString(UString &s);
+};
+
+class CStreamSwitch;
+
+const UInt32 kHeaderSize = 32;
+
+class CInArchive
+{
+  friend class CStreamSwitch;
+
+  CMyComPtr<IInStream> _stream;
+
+  CObjectVector<CInByte2> _inByteVector;
+  CInByte2 *_inByteBack;
+  UInt64 _arhiveBeginStreamPosition;
+
+  Byte _header[kHeaderSize];
+
+  void AddByteStream(const Byte *buffer, size_t size)
+  {
+    _inByteVector.Add(CInByte2());
+    _inByteBack = &_inByteVector.Back();
+    _inByteBack->Init(buffer, size);
+  }
+  
+  void DeleteByteStream()
+  {
+    _inByteVector.DeleteBack();
+    if (!_inByteVector.IsEmpty())
+      _inByteBack = &_inByteVector.Back();
+  }
+
+private:
+  HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+  
+  void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
+  Byte ReadByte() { return _inByteBack->ReadByte(); }
+  UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
+  CNum ReadNum() { return _inByteBack->ReadNum(); }
+  UInt64 ReadID() { return _inByteBack->ReadNumber(); }
+  UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
+  UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
+  void SkeepData(UInt64 size) { _inByteBack->SkeepData(size); }
+  void SkeepData() { _inByteBack->SkeepData(); }
+  void WaitAttribute(UInt64 attribute);
+
+  void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
+  void GetNextFolderItem(CFolder &itemInfo);
+  void ReadHashDigests(int numItems,
+      CRecordVector<bool> &digestsDefined, CRecordVector<UInt32> &digests);
+  
+  void ReadPackInfo(
+      UInt64 &dataOffset,
+      CRecordVector<UInt64> &packSizes,
+      CRecordVector<bool> &packCRCsDefined,
+      CRecordVector<UInt32> &packCRCs);
+  
+  void ReadUnPackInfo(
+      const CObjectVector<CByteBuffer> *dataVector,
+      CObjectVector<CFolder> &folders);
+  
+  void ReadSubStreamsInfo(
+      const CObjectVector<CFolder> &folders,
+      CRecordVector<CNum> &numUnPackStreamsInFolders,
+      CRecordVector<UInt64> &unPackSizes,
+      CRecordVector<bool> &digestsDefined, 
+      CRecordVector<UInt32> &digests);
+
+  void ReadStreamsInfo(
+      const CObjectVector<CByteBuffer> *dataVector,
+      UInt64 &dataOffset,
+      CRecordVector<UInt64> &packSizes,
+      CRecordVector<bool> &packCRCsDefined,
+      CRecordVector<UInt32> &packCRCs,
+      CObjectVector<CFolder> &folders,
+      CRecordVector<CNum> &numUnPackStreamsInFolders,
+      CRecordVector<UInt64> &unPackSizes,
+      CRecordVector<bool> &digestsDefined, 
+      CRecordVector<UInt32> &digests);
+
+
+  void ReadBoolVector(int numItems, CBoolVector &v);
+  void ReadBoolVector2(int numItems, CBoolVector &v);
+  void ReadTime(const CObjectVector<CByteBuffer> &dataVector,
+      CObjectVector<CFileItem> &files, UInt32 type);
+  HRESULT ReadAndDecodePackedStreams(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      UInt64 baseOffset, UInt64 &dataOffset,
+      CObjectVector<CByteBuffer> &dataVector
+      #ifndef _NO_CRYPTO
+      , ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+  HRESULT ReadHeader(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CArchiveDatabaseEx &database
+      #ifndef _NO_CRYPTO
+      ,ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+  HRESULT ReadDatabase2(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CArchiveDatabaseEx &database 
+      #ifndef _NO_CRYPTO
+      ,ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+public:
+  HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
+  void Close();
+
+  HRESULT ReadDatabase(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CArchiveDatabaseEx &database 
+      #ifndef _NO_CRYPTO
+      ,ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+};
+  
+}}
+  
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zItem.h b/lzma/CPP/7zip/Archive/7z/7zItem.h
new file mode 100644 (file)
index 0000000..31c5ce2
--- /dev/null
@@ -0,0 +1,184 @@
+// 7zItem.h
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "../../../Common/Buffer.h"
+#include "../../../Common/MyString.h"
+#include "../../Common/MethodId.h"
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+typedef UInt32 CNum;
+const CNum kNumMax     = 0x7FFFFFFF;
+const CNum kNumNoIndex = 0xFFFFFFFF;
+
+struct CCoderInfo
+{
+  CMethodId MethodID;
+  CByteBuffer Properties;
+  CNum NumInStreams;
+  CNum NumOutStreams;
+  bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBindPair
+{
+  CNum InIndex;
+  CNum OutIndex;
+};
+
+struct CFolder
+{
+  CObjectVector<CCoderInfo> Coders;
+  CRecordVector<CBindPair> BindPairs;
+  CRecordVector<CNum> PackStreams;
+  CRecordVector<UInt64> UnPackSizes;
+  UInt32 UnPackCRC;
+  bool UnPackCRCDefined;
+
+  CFolder(): UnPackCRCDefined(false) {}
+
+  UInt64 GetUnPackSize() const // test it
+  { 
+    if (UnPackSizes.IsEmpty())
+      return 0;
+    for (int i = UnPackSizes.Size() - 1; i >= 0; i--)
+      if (FindBindPairForOutStream(i) < 0)
+        return UnPackSizes[i];
+    throw 1;
+  }
+
+  CNum GetNumOutStreams() const
+  {
+    CNum result = 0;
+    for (int i = 0; i < Coders.Size(); i++)
+      result += Coders[i].NumOutStreams;
+    return result;
+  }
+
+  int FindBindPairForInStream(CNum inStreamIndex) const
+  {
+    for(int i = 0; i < BindPairs.Size(); i++)
+      if (BindPairs[i].InIndex == inStreamIndex)
+        return i;
+    return -1;
+  }
+  int FindBindPairForOutStream(CNum outStreamIndex) const
+  {
+    for(int i = 0; i < BindPairs.Size(); i++)
+      if (BindPairs[i].OutIndex == outStreamIndex)
+        return i;
+    return -1;
+  }
+  int FindPackStreamArrayIndex(CNum inStreamIndex) const
+  {
+    for(int i = 0; i < PackStreams.Size(); i++)
+      if (PackStreams[i] == inStreamIndex)
+        return i;
+    return -1;
+  }
+};
+
+typedef FILETIME CArchiveFileTime;
+
+class CFileItem
+{
+public:
+  CArchiveFileTime CreationTime;
+  CArchiveFileTime LastWriteTime;
+  CArchiveFileTime LastAccessTime;
+  UInt64 UnPackSize;
+  UInt64 StartPos;
+  UInt32 Attributes;
+  UInt32 FileCRC;
+  UString Name;
+
+  bool HasStream; // Test it !!! it means that there is 
+                  // stream in some folder. It can be empty stream
+  bool IsDirectory;
+  bool IsAnti;
+  bool IsFileCRCDefined;
+  bool AreAttributesDefined;
+  bool IsCreationTimeDefined;
+  bool IsLastWriteTimeDefined;
+  bool IsLastAccessTimeDefined;
+  bool IsStartPosDefined;
+
+  /*
+  const bool HasStream() const { 
+      return !IsDirectory && !IsAnti && UnPackSize != 0; }
+  */
+  CFileItem(): 
+    HasStream(true),
+    IsDirectory(false),
+    IsAnti(false),
+    IsFileCRCDefined(false),
+    AreAttributesDefined(false), 
+    IsCreationTimeDefined(false), 
+    IsLastWriteTimeDefined(false), 
+    IsLastAccessTimeDefined(false),
+    IsStartPosDefined(false)
+      {}
+  void SetAttributes(UInt32 attributes) 
+  { 
+    AreAttributesDefined = true;
+    Attributes = attributes;
+  }
+  void SetCreationTime(const CArchiveFileTime &creationTime) 
+  { 
+    IsCreationTimeDefined = true;
+    CreationTime = creationTime;
+  }
+  void SetLastWriteTime(const CArchiveFileTime &lastWriteTime) 
+  {
+    IsLastWriteTimeDefined = true;
+    LastWriteTime = lastWriteTime;
+  }
+  void SetLastAccessTime(const CArchiveFileTime &lastAccessTime) 
+  { 
+    IsLastAccessTimeDefined = true;
+    LastAccessTime = lastAccessTime;
+  }
+};
+
+struct CArchiveDatabase
+{
+  CRecordVector<UInt64> PackSizes;
+  CRecordVector<bool> PackCRCsDefined;
+  CRecordVector<UInt32> PackCRCs;
+  CObjectVector<CFolder> Folders;
+  CRecordVector<CNum> NumUnPackStreamsVector;
+  CObjectVector<CFileItem> Files;
+  void Clear()
+  {
+    PackSizes.Clear();
+    PackCRCsDefined.Clear();
+    PackCRCs.Clear();
+    Folders.Clear();
+    NumUnPackStreamsVector.Clear();
+    Files.Clear();
+  }
+  bool IsEmpty() const
+  {
+    return (PackSizes.IsEmpty() && 
+      PackCRCsDefined.IsEmpty() && 
+      PackCRCs.IsEmpty() && 
+      Folders.IsEmpty() && 
+      NumUnPackStreamsVector.IsEmpty() && 
+      Files.IsEmpty());
+  }
+  bool IsSolid() const
+  {
+    for (int i = 0; i < NumUnPackStreamsVector.Size(); i++)
+      if (NumUnPackStreamsVector[i] > 1)
+        return true;
+    return false;
+  }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zOut.cpp b/lzma/CPP/7zip/Archive/7z/7zOut.cpp
new file mode 100644 (file)
index 0000000..a00cdf5
--- /dev/null
@@ -0,0 +1,1026 @@
+// 7zOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/AutoPtr.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zOut.h"
+
+extern "C" 
+{ 
+#include "../../../../C/7zCrc.h"
+}
+
+static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
+{
+  while (size > 0)
+  {
+    UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
+    UInt32 processedSize;
+    RINOK(stream->Write(data, curSize, &processedSize));
+    if(processedSize == 0)
+      return E_FAIL;
+    data = (const void *)((const Byte *)data + processedSize);
+    size -= processedSize;
+  }
+  return S_OK;
+}
+
+namespace NArchive {
+namespace N7z {
+
+HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
+{
+  return ::WriteBytes(SeqStream, data, size);
+}
+
+UInt32 CrcUpdateUInt32(UInt32 crc, UInt32 value)
+{
+  for (int i = 0; i < 4; i++, value >>= 8)
+    crc = CRC_UPDATE_BYTE(crc, (Byte)value);
+  return crc;
+}
+
+UInt32 CrcUpdateUInt64(UInt32 crc, UInt64 value)
+{
+  for (int i = 0; i < 8; i++, value >>= 8)
+    crc = CRC_UPDATE_BYTE(crc, (Byte)value);
+  return crc;
+}
+
+HRESULT COutArchive::WriteDirectUInt32(UInt32 value)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    RINOK(WriteDirectByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteDirectUInt64(UInt64 value)
+{
+  for (int i = 0; i < 8; i++)
+  {
+    RINOK(WriteDirectByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteSignature()
+{
+  RINOK(WriteDirect(kSignature, kSignatureSize));
+  RINOK(WriteDirectByte(kMajorVersion));
+  return WriteDirectByte(2);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishSignature()
+{
+  RINOK(WriteDirect(kFinishSignature, kSignatureSize));
+  CArchiveVersion av;
+  av.Major = kMajorVersion;
+  av.Minor = 2;
+  RINOK(WriteDirectByte(av.Major));
+  return WriteDirectByte(av.Minor);
+}
+#endif
+
+HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
+{
+  UInt32 crc = CRC_INIT_VAL;
+  crc = CrcUpdateUInt64(crc, h.NextHeaderOffset);
+  crc = CrcUpdateUInt64(crc, h.NextHeaderSize);
+  crc = CrcUpdateUInt32(crc, h.NextHeaderCRC);
+  RINOK(WriteDirectUInt32(CRC_GET_DIGEST(crc)));
+  RINOK(WriteDirectUInt64(h.NextHeaderOffset));
+  RINOK(WriteDirectUInt64(h.NextHeaderSize));
+  return WriteDirectUInt32(h.NextHeaderCRC);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
+{
+  CCRC crc;
+  crc.UpdateUInt64(h.NextHeaderOffset);
+  crc.UpdateUInt64(h.NextHeaderSize);
+  crc.UpdateUInt32(h.NextHeaderCRC);
+  crc.UpdateUInt64(h.ArchiveStartOffset);
+  crc.UpdateUInt64(h.AdditionalStartBlockSize);
+  RINOK(WriteDirectUInt32(crc.GetDigest()));
+  RINOK(WriteDirectUInt64(h.NextHeaderOffset));
+  RINOK(WriteDirectUInt64(h.NextHeaderSize));
+  RINOK(WriteDirectUInt32(h.NextHeaderCRC));
+  RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
+  return WriteDirectUInt64(h.AdditionalStartBlockSize);
+}
+#endif
+
+HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
+{
+  Close();
+  #ifdef _7Z_VOL
+  // endMarker = false;
+  _endMarker = endMarker;
+  #endif
+  SeqStream = stream;
+  if (!endMarker)
+  {
+    SeqStream.QueryInterface(IID_IOutStream, &Stream);
+    if (!Stream)
+    {
+      return E_NOTIMPL;
+      // endMarker = true;
+    }
+  }
+  #ifdef _7Z_VOL
+  if (endMarker)
+  {
+    /*
+    CStartHeader sh;
+    sh.NextHeaderOffset = (UInt32)(Int32)-1;
+    sh.NextHeaderSize = (UInt32)(Int32)-1;
+    sh.NextHeaderCRC = 0;
+    WriteStartHeader(sh);
+    */
+  }
+  else
+  #endif
+  {
+    if (!Stream)
+      return E_FAIL;
+    RINOK(WriteSignature());
+    RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
+  }
+  return S_OK;
+}
+
+void COutArchive::Close()
+{
+  SeqStream.Release();
+  Stream.Release();
+}
+
+HRESULT COutArchive::SkeepPrefixArchiveHeader()
+{
+  #ifdef _7Z_VOL
+  if (_endMarker)
+    return S_OK;
+  #endif
+  return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
+}
+
+HRESULT COutArchive::WriteBytes(const void *data, size_t size)
+{
+  if (_mainMode)
+  {
+    if (_dynamicMode)
+      _dynamicBuffer.Write(data, size);
+    else
+      _outByte.WriteBytes(data, size);
+    _crc = CrcUpdate(_crc, data, size);
+  }
+  else
+  {
+    if (_countMode)
+      _countSize += size;
+    else
+      RINOK(_outByte2.Write(data, size));
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteBytes(const CByteBuffer &data)
+{
+  return WriteBytes(data, data.GetCapacity());
+}
+
+HRESULT COutArchive::WriteByte(Byte b)
+{
+  return WriteBytes(&b, 1);
+}
+
+HRESULT COutArchive::WriteUInt32(UInt32 value)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    RINOK(WriteByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteNumber(UInt64 value)
+{
+  Byte firstByte = 0;
+  Byte mask = 0x80;
+  int i;
+  for (i = 0; i < 8; i++)
+  {
+    if (value < ((UInt64(1) << ( 7  * (i + 1)))))
+    {
+      firstByte |= Byte(value >> (8 * i));
+      break;
+    }
+    firstByte |= mask;
+    mask >>= 1;
+  }
+  RINOK(WriteByte(firstByte));
+  for (;i > 0; i--)
+  {
+    RINOK(WriteByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+#ifdef _7Z_VOL
+static UInt32 GetBigNumberSize(UInt64 value)
+{
+  int i;
+  for (i = 0; i < 8; i++)
+    if (value < ((UInt64(1) << ( 7  * (i + 1)))))
+      break;
+  return 1 + i;
+}
+
+UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
+{
+  UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
+  if (nameLength != 0)
+  {
+    nameLength = (nameLength + 1) * 2;
+    result += nameLength + GetBigNumberSize(nameLength) + 2;
+  }
+  if (props)
+  {
+    result += 20;
+  }
+  if (result >= 128)
+    result++;
+  result += kSignatureSize + 2 + kFinishHeaderSize;
+  return result;
+}
+
+UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
+{
+  UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
+  int testSize;
+  if (volSize > headersSizeBase)
+    testSize = volSize - headersSizeBase;
+  else
+    testSize = 1;
+  UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
+  UInt64 pureSize = 1;
+  if (volSize > headersSize)
+    pureSize = volSize - headersSize;
+  return pureSize;
+}
+#endif
+
+HRESULT COutArchive::WriteFolder(const CFolder &folder)
+{
+  RINOK(WriteNumber(folder.Coders.Size()));
+  int i;
+  for (i = 0; i < folder.Coders.Size(); i++)
+  {
+    const CCoderInfo &coder = folder.Coders[i];
+    {
+      size_t propertiesSize = coder.Properties.GetCapacity();
+      
+      UInt64 id = coder.MethodID; 
+      int idSize;
+      for (idSize = 1; idSize < sizeof(id); idSize++)
+        if ((id >> (8 * idSize)) == 0)
+          break;
+      BYTE longID[15];
+      for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
+        longID[t] = (Byte)(id & 0xFF);
+      Byte b;
+      b = (Byte)(idSize & 0xF);
+      bool isComplex = !coder.IsSimpleCoder();
+      b |= (isComplex ? 0x10 : 0);
+      b |= ((propertiesSize != 0) ? 0x20 : 0 );
+      RINOK(WriteByte(b));
+      RINOK(WriteBytes(longID, idSize));
+      if (isComplex)
+      {
+        RINOK(WriteNumber(coder.NumInStreams));
+        RINOK(WriteNumber(coder.NumOutStreams));
+      }
+      if (propertiesSize == 0)
+        continue;
+      RINOK(WriteNumber(propertiesSize));
+      RINOK(WriteBytes(coder.Properties, propertiesSize));
+    }
+  }
+  for (i = 0; i < folder.BindPairs.Size(); i++)
+  {
+    const CBindPair &bindPair = folder.BindPairs[i];
+    RINOK(WriteNumber(bindPair.InIndex));
+    RINOK(WriteNumber(bindPair.OutIndex));
+  }
+  if (folder.PackStreams.Size() > 1)
+    for (i = 0; i < folder.PackStreams.Size(); i++)
+    {
+      RINOK(WriteNumber(folder.PackStreams[i]));
+    }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteBoolVector(const CBoolVector &boolVector)
+{
+  Byte b = 0;
+  Byte mask = 0x80;
+  for(int i = 0; i < boolVector.Size(); i++)
+  {
+    if (boolVector[i])
+      b |= mask;
+    mask >>= 1;
+    if (mask == 0)
+    {
+      RINOK(WriteByte(b));
+      mask = 0x80;
+      b = 0;
+    }
+  }
+  if (mask != 0x80)
+  {
+    RINOK(WriteByte(b));
+  }
+  return S_OK;
+}
+
+
+HRESULT COutArchive::WriteHashDigests(
+    const CRecordVector<bool> &digestsDefined,
+    const CRecordVector<UInt32> &digests)
+{
+  int numDefined = 0;
+  int i;
+  for(i = 0; i < digestsDefined.Size(); i++)
+    if (digestsDefined[i])
+      numDefined++;
+  if (numDefined == 0)
+    return S_OK;
+
+  RINOK(WriteByte(NID::kCRC));
+  if (numDefined == digestsDefined.Size())
+  {
+    RINOK(WriteByte(1));
+  }
+  else
+  {
+    RINOK(WriteByte(0));
+    RINOK(WriteBoolVector(digestsDefined));
+  }
+  for(i = 0; i < digests.Size(); i++)
+  {
+    if(digestsDefined[i])
+      RINOK(WriteUInt32(digests[i]));
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WritePackInfo(
+    UInt64 dataOffset,
+    const CRecordVector<UInt64> &packSizes,
+    const CRecordVector<bool> &packCRCsDefined,
+    const CRecordVector<UInt32> &packCRCs)
+{
+  if (packSizes.IsEmpty())
+    return S_OK;
+  RINOK(WriteByte(NID::kPackInfo));
+  RINOK(WriteNumber(dataOffset));
+  RINOK(WriteNumber(packSizes.Size()));
+  RINOK(WriteByte(NID::kSize));
+  for(int i = 0; i < packSizes.Size(); i++)
+    RINOK(WriteNumber(packSizes[i]));
+
+  RINOK(WriteHashDigests(packCRCsDefined, packCRCs));
+  
+  return WriteByte(NID::kEnd);
+}
+
+HRESULT COutArchive::WriteUnPackInfo(const CObjectVector<CFolder> &folders)
+{
+  if (folders.IsEmpty())
+    return S_OK;
+
+  RINOK(WriteByte(NID::kUnPackInfo));
+
+  RINOK(WriteByte(NID::kFolder));
+  RINOK(WriteNumber(folders.Size()));
+  {
+    RINOK(WriteByte(0));
+    for(int i = 0; i < folders.Size(); i++)
+      RINOK(WriteFolder(folders[i]));
+  }
+  
+  RINOK(WriteByte(NID::kCodersUnPackSize));
+  int i;
+  for(i = 0; i < folders.Size(); i++)
+  {
+    const CFolder &folder = folders[i];
+    for (int j = 0; j < folder.UnPackSizes.Size(); j++)
+      RINOK(WriteNumber(folder.UnPackSizes[j]));
+  }
+
+  CRecordVector<bool> unPackCRCsDefined;
+  CRecordVector<UInt32> unPackCRCs;
+  for(i = 0; i < folders.Size(); i++)
+  {
+    const CFolder &folder = folders[i];
+    unPackCRCsDefined.Add(folder.UnPackCRCDefined);
+    unPackCRCs.Add(folder.UnPackCRC);
+  }
+  RINOK(WriteHashDigests(unPackCRCsDefined, unPackCRCs));
+
+  return WriteByte(NID::kEnd);
+}
+
+HRESULT COutArchive::WriteSubStreamsInfo(
+    const CObjectVector<CFolder> &folders,
+    const CRecordVector<CNum> &numUnPackStreamsInFolders,
+    const CRecordVector<UInt64> &unPackSizes,
+    const CRecordVector<bool> &digestsDefined,
+    const CRecordVector<UInt32> &digests)
+{
+  RINOK(WriteByte(NID::kSubStreamsInfo));
+
+  int i;
+  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+  {
+    if (numUnPackStreamsInFolders[i] != 1)
+    {
+      RINOK(WriteByte(NID::kNumUnPackStream));
+      for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+        RINOK(WriteNumber(numUnPackStreamsInFolders[i]));
+      break;
+    }
+  }
+
+  bool needFlag = true;
+  CNum index = 0;
+  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+    for (CNum j = 0; j < numUnPackStreamsInFolders[i]; j++)
+    {
+      if (j + 1 != numUnPackStreamsInFolders[i])
+      {
+        if (needFlag)
+          RINOK(WriteByte(NID::kSize));
+        needFlag = false;
+        RINOK(WriteNumber(unPackSizes[index]));
+      }
+      index++;
+    }
+
+  CRecordVector<bool> digestsDefined2;
+  CRecordVector<UInt32> digests2;
+
+  int digestIndex = 0;
+  for (i = 0; i < folders.Size(); i++)
+  {
+    int numSubStreams = (int)numUnPackStreamsInFolders[i];
+    if (numSubStreams == 1 && folders[i].UnPackCRCDefined)
+      digestIndex++;
+    else
+      for (int j = 0; j < numSubStreams; j++, digestIndex++)
+      {
+        digestsDefined2.Add(digestsDefined[digestIndex]);
+        digests2.Add(digests[digestIndex]);
+      }
+  }
+  RINOK(WriteHashDigests(digestsDefined2, digests2));
+  return WriteByte(NID::kEnd);
+}
+
+HRESULT COutArchive::WriteTime(
+    const CObjectVector<CFileItem> &files, Byte type)
+{
+  /////////////////////////////////////////////////
+  // CreationTime
+  CBoolVector boolVector;
+  boolVector.Reserve(files.Size());
+  bool thereAreDefined = false;
+  bool allDefined = true;
+  int i;
+  for(i = 0; i < files.Size(); i++)
+  {
+    const CFileItem &item = files[i];
+    bool defined;
+    switch(type)
+    {
+      case NID::kCreationTime:
+        defined = item.IsCreationTimeDefined;
+        break;
+      case NID::kLastWriteTime:
+        defined = item.IsLastWriteTimeDefined;
+        break;
+      case NID::kLastAccessTime:
+        defined = item.IsLastAccessTimeDefined;
+        break;
+      default:
+        throw 1;
+    }
+    boolVector.Add(defined);
+    thereAreDefined = (thereAreDefined || defined);
+    allDefined = (allDefined && defined);
+  }
+  if (!thereAreDefined)
+    return S_OK;
+  RINOK(WriteByte(type));
+  size_t dataSize = 1 + 1;
+    dataSize += files.Size() * 8;
+  if (allDefined)
+  {
+    RINOK(WriteNumber(dataSize));
+    WriteByte(1);
+  }
+  else
+  {
+    RINOK(WriteNumber(1 + (boolVector.Size() + 7) / 8 + dataSize));
+    WriteByte(0);
+    RINOK(WriteBoolVector(boolVector));
+  }
+  RINOK(WriteByte(0));
+  for(i = 0; i < files.Size(); i++)
+  {
+    if (boolVector[i])
+    {
+      const CFileItem &item = files[i];
+      CArchiveFileTime timeValue;
+      timeValue.dwLowDateTime = 0;
+      timeValue.dwHighDateTime = 0;
+      switch(type)
+      {
+        case NID::kCreationTime:
+          timeValue = item.CreationTime;
+          break;
+        case NID::kLastWriteTime:
+          timeValue = item.LastWriteTime;
+          break;
+        case NID::kLastAccessTime:
+          timeValue = item.LastAccessTime;
+          break;
+      }
+      RINOK(WriteUInt32(timeValue.dwLowDateTime));
+      RINOK(WriteUInt32(timeValue.dwHighDateTime));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::EncodeStream(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CEncoder &encoder, const Byte *data, size_t dataSize,
+    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+{
+  CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp;
+  CMyComPtr<ISequentialInStream> stream = streamSpec;
+  streamSpec->Init(data, dataSize);
+  CFolder folderItem;
+  folderItem.UnPackCRCDefined = true;
+  folderItem.UnPackCRC = CrcCalc(data, dataSize);
+  UInt64 dataSize64 = dataSize;
+  RINOK(encoder.Encode(
+      EXTERNAL_CODECS_LOC_VARS
+      stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
+  folders.Add(folderItem);
+  return S_OK;
+}
+
+HRESULT COutArchive::EncodeStream(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CEncoder &encoder, const CByteBuffer &data, 
+    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+{
+  return EncodeStream(
+      EXTERNAL_CODECS_LOC_VARS
+      encoder, data, data.GetCapacity(), packSizes, folders);
+}
+
+static void WriteUInt32ToBuffer(Byte *data, UInt32 value)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    *data++ = (Byte)value;
+    value >>= 8;
+  }
+}
+
+static void WriteUInt64ToBuffer(Byte *data, UInt64 value)
+{
+  for (int i = 0; i < 8; i++)
+  {
+    *data++ = (Byte)value;
+    value >>= 8;
+  }
+}
+
+
+HRESULT COutArchive::WriteHeader(
+    const CArchiveDatabase &database,
+    const CHeaderOptions &headerOptions,
+    UInt64 &headerOffset)
+{
+  int i;
+  
+  /////////////////////////////////
+  // Names
+
+  CNum numDefinedNames = 0;
+  size_t namesDataSize = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+  {
+    const UString &name = database.Files[i].Name;
+    if (!name.IsEmpty())
+      numDefinedNames++;
+    namesDataSize += (name.Length() + 1) * 2;
+  }
+
+  CByteBuffer namesData;
+  if (numDefinedNames > 0)
+  {
+    namesData.SetCapacity((size_t)namesDataSize);
+    size_t pos = 0;
+    for(int i = 0; i < database.Files.Size(); i++)
+    {
+      const UString &name = database.Files[i].Name;
+      for (int t = 0; t < name.Length(); t++)
+      {
+        wchar_t c = name[t];
+        namesData[pos++] = Byte(c);
+        namesData[pos++] = Byte(c >> 8);
+      }
+      namesData[pos++] = 0;
+      namesData[pos++] = 0;
+    }
+  }
+
+  /////////////////////////////////
+  // Write Attributes
+  CBoolVector attributesBoolVector;
+  attributesBoolVector.Reserve(database.Files.Size());
+  int numDefinedAttributes = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+  {
+    bool defined = database.Files[i].AreAttributesDefined;
+    attributesBoolVector.Add(defined);
+    if (defined)
+      numDefinedAttributes++;
+  }
+
+  CByteBuffer attributesData;
+  if (numDefinedAttributes > 0)
+  {
+    attributesData.SetCapacity(numDefinedAttributes * 4);
+    size_t pos = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (file.AreAttributesDefined)
+      {
+        WriteUInt32ToBuffer(attributesData + pos, file.Attributes);
+        pos += 4;
+      }
+    }
+  }
+
+  /////////////////////////////////
+  // Write StartPos
+  CBoolVector startsBoolVector;
+  startsBoolVector.Reserve(database.Files.Size());
+  int numDefinedStarts = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+  {
+    bool defined = database.Files[i].IsStartPosDefined;
+    startsBoolVector.Add(defined);
+    if (defined)
+      numDefinedStarts++;
+  }
+
+  CByteBuffer startsData;
+  if (numDefinedStarts > 0)
+  {
+    startsData.SetCapacity(numDefinedStarts * 8);
+    size_t pos = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (file.IsStartPosDefined)
+      {
+        WriteUInt64ToBuffer(startsData + pos, file.StartPos);
+        pos += 8;
+      }
+    }
+  }
+  
+  /////////////////////////////////
+  // Write Last Write Time
+  // /*
+  CNum numDefinedLastWriteTimes = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+    if (database.Files[i].IsLastWriteTimeDefined)
+      numDefinedLastWriteTimes++;
+
+  if (numDefinedLastWriteTimes > 0)
+  {
+    CByteBuffer lastWriteTimeData;
+    lastWriteTimeData.SetCapacity(numDefinedLastWriteTimes * 8);
+    size_t pos = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (file.IsLastWriteTimeDefined)
+      {
+        WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwLowDateTime);
+        pos += 4;
+        WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwHighDateTime);
+        pos += 4;
+      }
+    }
+  }
+  // */
+  
+
+  UInt64 packedSize = 0;
+  for(i = 0; i < database.PackSizes.Size(); i++)
+    packedSize += database.PackSizes[i];
+
+  headerOffset = packedSize;
+
+  _mainMode = true;
+
+  _outByte.SetStream(SeqStream);
+  _outByte.Init();
+  _crc = CRC_INIT_VAL;
+
+
+  RINOK(WriteByte(NID::kHeader));
+
+  // Archive Properties
+
+  if (database.Folders.Size() > 0)
+  {
+    RINOK(WriteByte(NID::kMainStreamsInfo));
+    RINOK(WritePackInfo(0, database.PackSizes, 
+        database.PackCRCsDefined,
+        database.PackCRCs));
+
+    RINOK(WriteUnPackInfo(database.Folders));
+
+    CRecordVector<UInt64> unPackSizes;
+    CRecordVector<bool> digestsDefined;
+    CRecordVector<UInt32> digests;
+    for (i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (!file.HasStream)
+        continue;
+      unPackSizes.Add(file.UnPackSize);
+      digestsDefined.Add(file.IsFileCRCDefined);
+      digests.Add(file.FileCRC);
+    }
+
+    RINOK(WriteSubStreamsInfo(
+        database.Folders,
+        database.NumUnPackStreamsVector,
+        unPackSizes,
+        digestsDefined,
+        digests));
+    RINOK(WriteByte(NID::kEnd));
+  }
+
+  if (database.Files.IsEmpty())
+  {
+    RINOK(WriteByte(NID::kEnd));
+    return _outByte.Flush();
+  }
+
+  RINOK(WriteByte(NID::kFilesInfo));
+  RINOK(WriteNumber(database.Files.Size()));
+
+  CBoolVector emptyStreamVector;
+  emptyStreamVector.Reserve(database.Files.Size());
+  int numEmptyStreams = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+    if (database.Files[i].HasStream)
+      emptyStreamVector.Add(false);
+    else
+    {
+      emptyStreamVector.Add(true);
+      numEmptyStreams++;
+    }
+  if (numEmptyStreams > 0)
+  {
+    RINOK(WriteByte(NID::kEmptyStream));
+    RINOK(WriteNumber((emptyStreamVector.Size() + 7) / 8));
+    RINOK(WriteBoolVector(emptyStreamVector));
+
+    CBoolVector emptyFileVector, antiVector;
+    emptyFileVector.Reserve(numEmptyStreams);
+    antiVector.Reserve(numEmptyStreams);
+    CNum numEmptyFiles = 0, numAntiItems = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (!file.HasStream)
+      {
+        emptyFileVector.Add(!file.IsDirectory);
+        if (!file.IsDirectory)
+          numEmptyFiles++;
+        antiVector.Add(file.IsAnti);
+        if (file.IsAnti)
+          numAntiItems++;
+      }
+    }
+
+    if (numEmptyFiles > 0)
+    {
+      RINOK(WriteByte(NID::kEmptyFile));
+      RINOK(WriteNumber((emptyFileVector.Size() + 7) / 8));
+      RINOK(WriteBoolVector(emptyFileVector));
+    }
+
+    if (numAntiItems > 0)
+    {
+      RINOK(WriteByte(NID::kAnti));
+      RINOK(WriteNumber((antiVector.Size() + 7) / 8));
+      RINOK(WriteBoolVector(antiVector));
+    }
+  }
+
+  if (numDefinedNames > 0)
+  {
+    /////////////////////////////////////////////////
+    RINOK(WriteByte(NID::kName));
+    {
+      RINOK(WriteNumber(1 + namesData.GetCapacity()));
+      RINOK(WriteByte(0));
+      RINOK(WriteBytes(namesData));
+    }
+
+  }
+
+  if (headerOptions.WriteCreated)
+  {
+    RINOK(WriteTime(database.Files, NID::kCreationTime));
+  }
+  if (headerOptions.WriteModified)
+  {
+    RINOK(WriteTime(database.Files, NID::kLastWriteTime));
+  }
+  if (headerOptions.WriteAccessed)
+  {
+    RINOK(WriteTime(database.Files, NID::kLastAccessTime));
+  }
+
+  if (numDefinedAttributes > 0)
+  {
+    RINOK(WriteByte(NID::kWinAttributes));
+    size_t size = 2;
+    if (numDefinedAttributes != database.Files.Size())
+      size += (attributesBoolVector.Size() + 7) / 8 + 1;
+      size += attributesData.GetCapacity();
+
+    RINOK(WriteNumber(size));
+    if (numDefinedAttributes == database.Files.Size())
+    {
+      RINOK(WriteByte(1));
+    }
+    else
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBoolVector(attributesBoolVector));
+    }
+
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBytes(attributesData));
+    }
+  }
+
+  if (numDefinedStarts > 0)
+  {
+    RINOK(WriteByte(NID::kStartPos));
+    size_t size = 2;
+    if (numDefinedStarts != database.Files.Size())
+      size += (startsBoolVector.Size() + 7) / 8 + 1;
+      size += startsData.GetCapacity();
+
+    RINOK(WriteNumber(size));
+    if (numDefinedStarts == database.Files.Size())
+    {
+      RINOK(WriteByte(1));
+    }
+    else
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBoolVector(startsBoolVector));
+    }
+
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBytes(startsData));
+    }
+  }
+
+  RINOK(WriteByte(NID::kEnd)); // for files
+  RINOK(WriteByte(NID::kEnd)); // for headers
+
+  return _outByte.Flush();
+}
+
+HRESULT COutArchive::WriteDatabase(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    const CArchiveDatabase &database,
+    const CCompressionMethodMode *options, 
+    const CHeaderOptions &headerOptions)
+{
+  UInt64 headerOffset;
+  UInt32 headerCRC;
+  UInt64 headerSize;
+  if (database.IsEmpty())
+  {
+    headerSize = 0;
+    headerOffset = 0;
+    headerCRC = CrcCalc(0, 0);
+  }
+  else
+  {
+    _dynamicBuffer.Init();
+    _dynamicMode = false;
+
+    if (options != 0)
+      if (options->IsEmpty())
+        options = 0;
+    if (options != 0)
+      if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
+        _dynamicMode = true;
+    RINOK(WriteHeader(database, headerOptions, headerOffset));
+
+    if (_dynamicMode)
+    {
+      CCompressionMethodMode encryptOptions;
+      encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
+      encryptOptions.Password = options->Password;
+      CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
+      CRecordVector<UInt64> packSizes;
+      CObjectVector<CFolder> folders;
+      RINOK(EncodeStream(
+          EXTERNAL_CODECS_LOC_VARS
+          encoder, _dynamicBuffer, 
+          _dynamicBuffer.GetSize(), packSizes, folders));
+      _dynamicMode = false;
+      _mainMode = true;
+      
+      _outByte.SetStream(SeqStream);
+      _outByte.Init();
+      _crc = CRC_INIT_VAL;
+      
+      if (folders.Size() == 0)
+        throw 1;
+
+      RINOK(WriteID(NID::kEncodedHeader));
+      RINOK(WritePackInfo(headerOffset, packSizes, 
+        CRecordVector<bool>(), CRecordVector<UInt32>()));
+      RINOK(WriteUnPackInfo(folders));
+      RINOK(WriteByte(NID::kEnd));
+      for (int i = 0; i < packSizes.Size(); i++)
+        headerOffset += packSizes[i];
+      RINOK(_outByte.Flush());
+    }
+    headerCRC = CRC_GET_DIGEST(_crc);
+    headerSize = _outByte.GetProcessedSize();
+  }
+  #ifdef _7Z_VOL
+  if (_endMarker)
+  {
+    CFinishHeader h;
+    h.NextHeaderSize = headerSize;
+    h.NextHeaderCRC = headerCRC;
+    h.NextHeaderOffset = 
+        UInt64(0) - (headerSize + 
+        4 + kFinishHeaderSize);
+    h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
+    h.AdditionalStartBlockSize = 0;
+    RINOK(WriteFinishHeader(h));
+    return WriteFinishSignature();
+  }
+  else
+  #endif
+  {
+    CStartHeader h;
+    h.NextHeaderSize = headerSize;
+    h.NextHeaderCRC = headerCRC;
+    h.NextHeaderOffset = headerOffset;
+    RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
+    return WriteStartHeader(h);
+  }
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zOut.h b/lzma/CPP/7zip/Archive/7z/7zOut.h
new file mode 100644 (file)
index 0000000..fd79818
--- /dev/null
@@ -0,0 +1,193 @@
+// 7z/Out.h
+
+#ifndef __7Z_OUT_H
+#define __7Z_OUT_H
+
+#include "7zHeader.h"
+#include "7zItem.h"
+#include "7zCompressionMode.h"
+#include "7zEncode.h"
+
+#include "../../Common/OutBuffer.h"
+#include "../../../Common/DynamicBuffer.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CWriteBufferLoc
+{
+  Byte *_data;
+  size_t _size;
+  size_t _pos;
+public:
+  CWriteBufferLoc(): _size(0), _pos(0) {}
+  void Init(Byte *data, size_t size)  
+  { 
+    _pos = 0;
+    _data = data;
+    _size = size; 
+  }
+  HRESULT Write(const void *data, size_t size)
+  {
+    if (_pos + size > _size)
+      return E_FAIL;
+    memmove(_data + _pos, data, size);
+    _pos += size;
+    return S_OK; 
+  }
+};
+
+class CWriteDynamicBuffer
+{
+  CByteDynamicBuffer _buffer;
+  size_t _pos;
+public:
+  CWriteDynamicBuffer(): _pos(0) {}
+  void Init()  
+  { 
+    _pos = 0;
+  }
+  void Write(const void *data, size_t size)
+  {
+    if (_pos + size > _buffer.GetCapacity())
+      _buffer.EnsureCapacity(_pos + size);
+    memmove(((Byte *)_buffer) +_pos, data, size);
+    _pos += size;
+  }
+  operator Byte *() { return (Byte *)_buffer; };
+  operator const Byte *() const { return (const Byte *)_buffer; };
+  size_t GetSize() const { return _pos; }
+};
+
+struct CHeaderOptions
+{
+  // bool UseAdditionalHeaderStreams;
+  bool CompressMainHeader;
+  bool WriteModified;
+  bool WriteCreated;
+  bool WriteAccessed;
+
+  CHeaderOptions(): 
+      // UseAdditionalHeaderStreams(false), 
+      CompressMainHeader(true),
+      WriteModified(true),
+      WriteCreated(false),
+      WriteAccessed(false) {} 
+};
+
+class COutArchive
+{
+  UInt64 _prefixHeaderPos;
+
+  HRESULT WriteDirect(const void *data, UInt32 size);
+  HRESULT WriteDirectByte(Byte b) { return WriteDirect(&b, 1); }
+  HRESULT WriteDirectUInt32(UInt32 value);
+  HRESULT WriteDirectUInt64(UInt64 value);
+  
+  HRESULT WriteBytes(const void *data, size_t size);
+  HRESULT WriteBytes(const CByteBuffer &data);
+  HRESULT WriteByte(Byte b);
+  HRESULT WriteUInt32(UInt32 value);
+  HRESULT WriteNumber(UInt64 value);
+  HRESULT WriteID(UInt64 value) { return WriteNumber(value); }
+
+  HRESULT WriteFolder(const CFolder &folder);
+  HRESULT WriteFileHeader(const CFileItem &itemInfo);
+  HRESULT WriteBoolVector(const CBoolVector &boolVector);
+  HRESULT WriteHashDigests(
+      const CRecordVector<bool> &digestsDefined,
+      const CRecordVector<UInt32> &hashDigests);
+
+  HRESULT WritePackInfo(
+      UInt64 dataOffset,
+      const CRecordVector<UInt64> &packSizes,
+      const CRecordVector<bool> &packCRCsDefined,
+      const CRecordVector<UInt32> &packCRCs);
+
+  HRESULT WriteUnPackInfo(const CObjectVector<CFolder> &folders);
+
+  HRESULT WriteSubStreamsInfo(
+      const CObjectVector<CFolder> &folders,
+      const CRecordVector<CNum> &numUnPackStreamsInFolders,
+      const CRecordVector<UInt64> &unPackSizes,
+      const CRecordVector<bool> &digestsDefined,
+      const CRecordVector<UInt32> &hashDigests);
+
+  /*
+  HRESULT WriteStreamsInfo(
+      UInt64 dataOffset,
+      const CRecordVector<UInt64> &packSizes,
+      const CRecordVector<bool> &packCRCsDefined,
+      const CRecordVector<UInt32> &packCRCs,
+      bool externalFolders,
+      UInt64 externalFoldersStreamIndex,
+      const CObjectVector<CFolder> &folders,
+      const CRecordVector<CNum> &numUnPackStreamsInFolders,
+      const CRecordVector<UInt64> &unPackSizes,
+      const CRecordVector<bool> &digestsDefined,
+      const CRecordVector<UInt32> &hashDigests);
+  */
+
+
+  HRESULT WriteTime(const CObjectVector<CFileItem> &files, Byte type);
+
+  HRESULT EncodeStream(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CEncoder &encoder, const Byte *data, size_t dataSize,
+      CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+  HRESULT EncodeStream(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CEncoder &encoder, const CByteBuffer &data, 
+      CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+  HRESULT WriteHeader(
+      const CArchiveDatabase &database,
+      const CHeaderOptions &headerOptions,
+      UInt64 &headerOffset);
+  
+  bool _mainMode;
+
+  bool _dynamicMode;
+
+  bool _countMode;
+  size_t _countSize;
+  COutBuffer _outByte;
+  CWriteBufferLoc _outByte2;
+  CWriteDynamicBuffer _dynamicBuffer;
+  UInt32 _crc;
+
+  #ifdef _7Z_VOL
+  bool _endMarker;
+  #endif
+
+  HRESULT WriteSignature();
+  #ifdef _7Z_VOL
+  HRESULT WriteFinishSignature();
+  #endif
+  HRESULT WriteStartHeader(const CStartHeader &h);
+  #ifdef _7Z_VOL
+  HRESULT WriteFinishHeader(const CFinishHeader &h);
+  #endif
+  CMyComPtr<IOutStream> Stream;
+public:
+
+  COutArchive() { _outByte.Create(1 << 16); }
+  CMyComPtr<ISequentialOutStream> SeqStream;
+  HRESULT Create(ISequentialOutStream *stream, bool endMarker);
+  void Close();
+  HRESULT SkeepPrefixArchiveHeader();
+  HRESULT WriteDatabase(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      const CArchiveDatabase &database,
+      const CCompressionMethodMode *options, 
+      const CHeaderOptions &headerOptions);
+
+  #ifdef _7Z_VOL
+  static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false);
+  static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false);
+  #endif
+
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zProperties.cpp b/lzma/CPP/7zip/Archive/7z/7zProperties.cpp
new file mode 100644 (file)
index 0000000..3452a03
--- /dev/null
@@ -0,0 +1,162 @@
+// 7zProperties.cpp
+
+#include "StdAfx.h"
+
+#include "7zProperties.h"
+#include "7zHeader.h"
+#include "7zHandler.h"
+
+// #define _MULTI_PACK
+
+namespace NArchive {
+namespace N7z {
+
+struct CPropMap
+{
+  UInt64 FilePropID;
+  STATPROPSTG StatPROPSTG;
+};
+
+CPropMap kPropMap[] = 
+{
+  { NID::kName, NULL, kpidPath, VT_BSTR},
+  { NID::kSize, NULL, kpidSize, VT_UI8},
+  { NID::kPackInfo, NULL, kpidPackedSize, VT_UI8},
+  
+  #ifdef _MULTI_PACK
+  { 100, L"Pack0", kpidPackedSize0, VT_UI8},
+  { 101, L"Pack1", kpidPackedSize1, VT_UI8},
+  { 102, L"Pack2", kpidPackedSize2, VT_UI8},
+  { 103, L"Pack3", kpidPackedSize3, VT_UI8},
+  { 104, L"Pack4", kpidPackedSize4, VT_UI8},
+  #endif
+
+  { NID::kCreationTime, NULL, kpidCreationTime, VT_FILETIME},
+  { NID::kLastWriteTime, NULL, kpidLastWriteTime, VT_FILETIME},
+  { NID::kLastAccessTime, NULL, kpidLastAccessTime, VT_FILETIME},
+  { NID::kWinAttributes, NULL, kpidAttributes, VT_UI4},
+  { NID::kStartPos, NULL, kpidPosition, VT_UI4},
+
+  { NID::kCRC, NULL, kpidCRC, VT_UI4},
+  
+  { NID::kAnti, NULL, kpidIsAnti, VT_BOOL},
+  // { 97, NULL, kpidSolid, VT_BOOL},
+  #ifndef _SFX
+  { 98, NULL, kpidMethod, VT_BSTR},
+  { 99, NULL, kpidBlock, VT_UI4}
+  #endif
+};
+
+static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]);
+
+static int FindPropInMap(UInt64 filePropID)
+{
+  for (int i = 0; i < kPropMapSize; i++)
+    if (kPropMap[i].FilePropID == filePropID)
+      return i;
+  return -1;
+}
+
+static void CopyOneItem(CRecordVector<UInt64> &src, 
+    CRecordVector<UInt64> &dest, UInt32 item)
+{
+  for (int i = 0; i < src.Size(); i++)
+    if (src[i] == item)
+    {
+      dest.Add(item);
+      src.Delete(i);
+      return;
+    }
+}
+
+static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
+{
+  for (int i = 0; i < src.Size(); i++)
+    if (src[i] == item)
+    {
+      src.Delete(i);
+      return;
+    }
+}
+
+static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
+{
+  for (int i = 0; i < dest.Size(); i++)
+    if (dest[i] == item)
+    {
+      dest.Delete(i);
+      break;
+    }
+  dest.Insert(0, item);
+}
+
+void CHandler::FillPopIDs()
+{ 
+  _fileInfoPopIDs.Clear();
+
+  #ifdef _7Z_VOL
+  if(_volumes.Size() < 1)
+    return;
+  const CVolume &volume = _volumes.Front();
+  const CArchiveDatabaseEx &_database = volume.Database;
+  #endif
+
+  CRecordVector<UInt64> fileInfoPopIDs = _database.ArchiveInfo.FileInfoPopIDs;
+
+  RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
+  RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
+
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCreationTime);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kLastWriteTime);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kLastAccessTime);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment);
+  _fileInfoPopIDs += fileInfoPopIDs; 
+  #ifndef _SFX
+  _fileInfoPopIDs.Add(98);
+  _fileInfoPopIDs.Add(99);
+  #endif
+  #ifdef _MULTI_PACK
+  _fileInfoPopIDs.Add(100);
+  _fileInfoPopIDs.Add(101);
+  _fileInfoPopIDs.Add(102);
+  _fileInfoPopIDs.Add(103);
+  _fileInfoPopIDs.Add(104);
+  #endif
+
+  #ifndef _SFX
+  InsertToHead(_fileInfoPopIDs, NID::kLastWriteTime);
+  InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
+  InsertToHead(_fileInfoPopIDs, NID::kSize);
+  InsertToHead(_fileInfoPopIDs, NID::kName);
+  #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
+{
+  *numProperties = _fileInfoPopIDs.Size();
+  return S_OK;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,     
+      BSTR *name, PROPID *propID, VARTYPE *varType)
+{
+  if((int)index >= _fileInfoPopIDs.Size())
+    return E_INVALIDARG;
+  int indexInMap = FindPropInMap(_fileInfoPopIDs[index]);
+  if (indexInMap == -1)
+    return E_INVALIDARG;
+  const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG;
+  *propID = srcItem.propid;
+  *varType = srcItem.vt;
+  *name = 0;
+  return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zProperties.h b/lzma/CPP/7zip/Archive/7z/7zProperties.h
new file mode 100644 (file)
index 0000000..4da85f0
--- /dev/null
@@ -0,0 +1,22 @@
+// 7zProperties.h
+
+#ifndef __7Z_PROPERTIES_H
+#define __7Z_PROPERTIES_H
+
+#include "../../PropID.h"
+
+namespace NArchive {
+namespace N7z {
+
+enum
+{
+  kpidPackedSize0 = kpidUserDefined,
+  kpidPackedSize1, 
+  kpidPackedSize2,
+  kpidPackedSize3,
+  kpidPackedSize4
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zRegister.cpp b/lzma/CPP/7zip/Archive/7z/7zRegister.cpp
new file mode 100644 (file)
index 0000000..e18c4d7
--- /dev/null
@@ -0,0 +1,18 @@
+// 7zRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "7zHandler.h"
+static IInArchive *CreateArc() { return new NArchive::N7z::CHandler;  }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler;  }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+  { L"7z", L"7z", 0, 7, {'7' + 1 , 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC_DEC_SIG(7z)
diff --git a/lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp b/lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp
new file mode 100644 (file)
index 0000000..80d303a
--- /dev/null
@@ -0,0 +1,24 @@
+// 7zSpecStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zSpecStream.h"
+
+STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result = _stream->Read(data, size, &realProcessedSize);
+  _size += realProcessedSize;
+  if (processedSize != 0)
+    *processedSize = realProcessedSize;
+  return result; 
+}
+
+STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(
+    UInt64 subStream, UInt64 *value)
+{
+  if (_getSubStreamSize == NULL)
+    return E_NOTIMPL;
+  return  _getSubStreamSize->GetSubStreamSize(subStream, value);
+}
+
diff --git a/lzma/CPP/7zip/Archive/7z/7zSpecStream.h b/lzma/CPP/7zip/Archive/7z/7zSpecStream.h
new file mode 100644 (file)
index 0000000..0253c42
--- /dev/null
@@ -0,0 +1,35 @@
+// 7zSpecStream.h
+
+#ifndef __7Z_SPEC_STREAM_H
+#define __7Z_SPEC_STREAM_H
+
+#include "../../IStream.h"
+#include "../../ICoder.h"
+#include "../../../Common/MyCom.h"
+
+class CSequentialInStreamSizeCount2: 
+  public ISequentialInStream,
+  public ICompressGetSubStreamSize,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialInStream> _stream;
+  CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+  UInt64 _size;
+public:
+  void Init(ISequentialInStream *stream)
+  {
+    _stream = stream;
+    _getSubStreamSize = 0;
+    _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
+    _size = 0;
+  }
+  UInt64 GetSize() const { return _size; }
+
+  MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zUpdate.cpp b/lzma/CPP/7zip/Archive/7z/7zUpdate.cpp
new file mode 100644 (file)
index 0000000..68f4604
--- /dev/null
@@ -0,0 +1,1029 @@
+// UpdateMain.cpp
+
+#include "StdAfx.h"
+
+#include "7zUpdate.h"
+#include "7zFolderInStream.h"
+#include "7zEncode.h"
+#include "7zHandler.h"
+#include "7zOut.h"
+
+#include "../../Compress/Copy/CopyCoder.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/LimitedStreams.h"
+#include "../Common/ItemNameUtils.h"
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2";
+static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20;
+static const UInt32 kAlgorithmForBCJ2_LZMA = 1;
+static const UInt32 kNumFastBytesForBCJ2_LZMA = 64;
+
+static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, 
+    UInt64 position, UInt64 size, ICompressProgressInfo *progress)
+{
+  RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+  streamSpec->SetStream(inStream);
+  streamSpec->Init(size);
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+  RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+  return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL);
+}
+
+static int GetReverseSlashPos(const UString &name)
+{
+  int slashPos = name.ReverseFind(L'/');
+  #ifdef _WIN32
+  int slash1Pos = name.ReverseFind(L'\\');
+  slashPos = MyMax(slashPos, slash1Pos);
+  #endif
+  return slashPos;
+}
+
+int CUpdateItem::GetExtensionPos() const
+{
+  int slashPos = GetReverseSlashPos(Name);
+  int dotPos = Name.ReverseFind(L'.');
+  if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+    return Name.Length();
+  return dotPos + 1;
+}
+
+UString CUpdateItem::GetExtension() const
+{
+  return Name.Mid(GetExtensionPos());
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)
+{
+  size_t c1 = a1.GetCapacity();
+  size_t c2 = a2.GetCapacity();
+  RINOZ(MyCompare(c1, c2));
+  for (size_t i = 0; i < c1; i++)
+    RINOZ(MyCompare(a1[i], a2[i]));
+  return 0;
+}
+
+static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)
+{
+  RINOZ(MyCompare(c1.NumInStreams, c2.NumInStreams));
+  RINOZ(MyCompare(c1.NumOutStreams, c2.NumOutStreams));
+  RINOZ(MyCompare(c1.MethodID, c2.MethodID));
+  return CompareBuffers(c1.Properties, c2.Properties);
+}
+
+static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
+{
+  RINOZ(MyCompare(b1.InIndex, b2.InIndex));
+  return MyCompare(b1.OutIndex, b2.OutIndex);
+}
+
+static int CompareFolders(const CFolder &f1, const CFolder &f2)
+{
+  int s1 = f1.Coders.Size();
+  int s2 = f2.Coders.Size();
+  RINOZ(MyCompare(s1, s2));
+  int i;
+  for (i = 0; i < s1; i++)
+    RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));
+  s1 = f1.BindPairs.Size();
+  s2 = f2.BindPairs.Size();
+  RINOZ(MyCompare(s1, s2));
+  for (i = 0; i < s1; i++)
+    RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
+  return 0;
+}
+
+static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
+{
+  return MyStringCompareNoCase(f1.Name, f2.Name);
+}
+
+static int CompareFolderRefs(const int *p1, const int *p2, void *param)
+{
+  int i1 = *p1;
+  int i2 = *p2;
+  const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param;
+  RINOZ(CompareFolders(
+      db.Folders[i1],
+      db.Folders[i2]));
+  RINOZ(MyCompare(
+      db.NumUnPackStreamsVector[i1],
+      db.NumUnPackStreamsVector[i2]));
+  if (db.NumUnPackStreamsVector[i1] == 0)
+    return 0;
+  return CompareFiles(
+      db.Files[db.FolderStartFileIndex[i1]],
+      db.Files[db.FolderStartFileIndex[i2]]);
+}
+
+////////////////////////////////////////////////////////////
+
+static int CompareEmptyItems(const int *p1, const int *p2, void *param)
+{
+  const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
+  const CUpdateItem &u1 = updateItems[*p1];
+  const CUpdateItem &u2 = updateItems[*p2];
+  if (u1.IsDirectory != u2.IsDirectory)
+    return (u1.IsDirectory) ? 1 : -1;
+  if (u1.IsDirectory)
+  {
+    if (u1.IsAnti != u2.IsAnti)
+      return (u1.IsAnti ? 1 : -1);
+    int n = MyStringCompareNoCase(u1.Name, u2.Name);
+    return -n;
+  }
+  if (u1.IsAnti != u2.IsAnti)
+    return (u1.IsAnti ? 1 : -1);
+  return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+static const char *g_Exts = 
+  " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo" 
+  " zip jar ear war msi"
+  " 3gp avi mov mpeg mpg mpe wmv"
+  " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
+  " swf "
+  " chm hxi hxs"
+  " gif jpeg jpg jp2 png tiff  bmp ico psd psp"
+  " awg ps eps cgm dxf svg vrml wmf emf ai md"
+  " cad dwg pps key sxi"
+  " max 3ds"
+  " iso bin nrg mdf img pdi tar cpio xpi"
+  " vfd vhd vud vmc vsv"
+  " vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
+  " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" 
+  " f77 f f90 f95"
+  " asm sql manifest dep "
+  " mak clw csproj vcproj sln dsp dsw "
+  " class "
+  " bat cmd"
+  " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+  " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs"
+  " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf"
+  " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf"
+  " abw afp cwk lwp wpd wps wpt wrf wri"
+  " abf afm bdf fon mgf otf pcf pfa snf ttf"
+  " dbf mdb nsf ntf wdb db fdb gdb"
+  " exe dll ocx vbx sfx sys tlb awx com obj lib out o so "
+  " pdb pch idb ncb opt";
+
+int GetExtIndex(const char *ext)
+{
+  int extIndex = 1;
+  const char *p = g_Exts;
+  for (;;)
+  {
+    char c = *p++;
+    if (c == 0)
+      return extIndex;
+    if (c == ' ')
+      continue;
+    int pos = 0;
+    for (;;)
+    {
+      char c2 = ext[pos++];
+      if (c2 == 0 && (c == 0 || c == ' '))
+        return extIndex;
+      if (c != c2)
+        break;
+      c = *p++;
+    }
+    extIndex++;
+    for (;;)
+    {
+      if (c == 0)
+        return extIndex;
+      if (c == ' ')
+        break;
+      c = *p++;
+    }
+  }
+}
+
+struct CRefItem
+{
+  UInt32 Index;
+  const CUpdateItem *UpdateItem;
+  UInt32 ExtensionPos;
+  UInt32 NamePos;
+  int ExtensionIndex;
+  CRefItem(UInt32 index, const CUpdateItem &updateItem, bool sortByType):
+    Index(index),
+    UpdateItem(&updateItem),
+    ExtensionPos(0),
+    NamePos(0),
+    ExtensionIndex(0)
+  {
+    if (sortByType)
+    {
+      int slashPos = GetReverseSlashPos(updateItem.Name);
+      NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0);
+      int dotPos = updateItem.Name.ReverseFind(L'.');
+      if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+        ExtensionPos = updateItem.Name.Length();
+      else 
+      {
+        ExtensionPos = dotPos + 1;
+        UString us = updateItem.Name.Mid(ExtensionPos);
+        if (!us.IsEmpty())
+        {
+          us.MakeLower();
+          int i;
+          AString s;
+          for (i = 0; i < us.Length(); i++)
+          {
+            wchar_t c = us[i];
+            if (c >= 0x80)
+              break;
+            s += (char)c;
+          }
+          if (i == us.Length())
+            ExtensionIndex = GetExtIndex(s);
+          else
+            ExtensionIndex = 0;
+        }
+      }
+    }
+  }
+};
+
+static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param)
+{
+  const CRefItem &a1 = *p1;
+  const CRefItem &a2 = *p2;
+  const CUpdateItem &u1 = *a1.UpdateItem;
+  const CUpdateItem &u2 = *a2.UpdateItem;
+  int n;
+  if (u1.IsDirectory != u2.IsDirectory)
+    return (u1.IsDirectory) ? 1 : -1;
+  if (u1.IsDirectory)
+  {
+    if (u1.IsAnti != u2.IsAnti)
+      return (u1.IsAnti ? 1 : -1);
+    n = MyStringCompareNoCase(u1.Name, u2.Name);
+    return -n;
+  }
+  bool sortByType = *(bool *)param;
+  if (sortByType)
+  {
+    RINOZ(MyCompare(a1.ExtensionIndex, a2.ExtensionIndex))
+    RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
+    RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
+    if (u1.IsLastWriteTimeDefined && u2.IsLastWriteTimeDefined)
+      RINOZ(CompareFileTime(&u1.LastWriteTime, &u2.LastWriteTime));
+    RINOZ(MyCompare(u1.Size, u2.Size))
+  }
+  return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+struct CSolidGroup
+{
+  CCompressionMethodMode Method;
+  CRecordVector<UInt32> Indices;
+};
+
+static wchar_t *g_ExeExts[] =
+{
+  L"dll",
+  L"exe",
+  L"ocx",
+  L"sfx",
+  L"sys"
+};
+
+static bool IsExeFile(const UString &ext)
+{
+  for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
+    if (ext.CompareNoCase(g_ExeExts[i]) == 0)
+      return true;
+  return false;
+}
+
+static const UInt64 k_LZMA  = 0x030101;
+static const UInt64 k_BCJ   = 0x03030103;
+static const UInt64 k_BCJ2  = 0x0303011B;
+
+static bool GetMethodFull(UInt64 methodID, 
+    UInt32 numInStreams, CMethodFull &methodResult)
+{
+  methodResult.Id = methodID;
+  methodResult.NumInStreams = numInStreams;
+  methodResult.NumOutStreams = 1;
+  return true;
+}
+
+static bool MakeExeMethod(const CCompressionMethodMode &method, 
+    bool bcj2Filter, CCompressionMethodMode &exeMethod)
+{
+  exeMethod = method;
+  if (bcj2Filter)
+  {
+    CMethodFull methodFull;
+    if (!GetMethodFull(k_BCJ2, 4, methodFull))
+      return false;
+    exeMethod.Methods.Insert(0, methodFull);
+    if (!GetMethodFull(k_LZMA, 1, methodFull))
+      return false;
+    {
+      CProp property;
+      property.Id = NCoderPropID::kAlgorithm;
+      property.Value = kAlgorithmForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kMatchFinder;
+      property.Value = kMatchFinderForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kDictionarySize;
+      property.Value = kDictionaryForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kNumFastBytes;
+      property.Value = kNumFastBytesForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+
+    exeMethod.Methods.Add(methodFull);
+    exeMethod.Methods.Add(methodFull);
+    CBind bind;
+
+    bind.OutCoder = 0;
+    bind.InStream = 0;
+
+    bind.InCoder = 1;
+    bind.OutStream = 0;
+    exeMethod.Binds.Add(bind);
+
+    bind.InCoder = 2;
+    bind.OutStream = 1;
+    exeMethod.Binds.Add(bind);
+
+    bind.InCoder = 3;
+    bind.OutStream = 2;
+    exeMethod.Binds.Add(bind);
+  }
+  else
+  {
+    CMethodFull methodFull;
+    if (!GetMethodFull(k_BCJ, 1, methodFull))
+      return false;
+    exeMethod.Methods.Insert(0, methodFull);
+    CBind bind;
+    bind.OutCoder = 0;
+    bind.InStream = 0;
+    bind.InCoder = 1;
+    bind.OutStream = 0;
+    exeMethod.Binds.Add(bind);
+  }
+  return true;
+}   
+
+static void SplitFilesToGroups(
+    const CCompressionMethodMode &method, 
+    bool useFilters, bool maxFilter,
+    const CObjectVector<CUpdateItem> &updateItems,
+    CObjectVector<CSolidGroup> &groups)
+{
+  if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
+    useFilters = false;
+  groups.Clear();
+  groups.Add(CSolidGroup());
+  groups.Add(CSolidGroup());
+  CSolidGroup &generalGroup = groups[0];
+  CSolidGroup &exeGroup = groups[1];
+  generalGroup.Method = method;
+  int i;
+  for (i = 0; i < updateItems.Size(); i++)
+  {
+    const CUpdateItem &updateItem = updateItems[i];
+    if (!updateItem.NewData)
+      continue;
+    if (!updateItem.HasStream())
+      continue;
+    if (useFilters)
+    {
+      const UString name = updateItem.Name;
+      int dotPos = name.ReverseFind(L'.');
+      if (dotPos >= 0)
+      {
+        UString ext = name.Mid(dotPos + 1);
+        if (IsExeFile(ext))
+        {
+          exeGroup.Indices.Add(i);
+          continue;
+        }
+      }
+    }
+    generalGroup.Indices.Add(i);
+  }
+  if (exeGroup.Indices.Size() > 0)
+    if (!MakeExeMethod(method, maxFilter, exeGroup.Method))
+      exeGroup.Method = method;
+  for (i = 0; i < groups.Size();)
+    if (groups[i].Indices.Size() == 0)
+      groups.Delete(i);
+    else
+      i++;
+}
+
+static void FromUpdateItemToFileItem(const CUpdateItem &updateItem, 
+    CFileItem &file)
+{
+  file.Name = NItemName::MakeLegalName(updateItem.Name);
+  if (updateItem.AttributesAreDefined)
+    file.SetAttributes(updateItem.Attributes);
+  
+  if (updateItem.IsCreationTimeDefined)
+    file.SetCreationTime(updateItem.CreationTime);
+  if (updateItem.IsLastWriteTimeDefined)
+    file.SetLastWriteTime(updateItem.LastWriteTime);
+  if (updateItem.IsLastAccessTimeDefined)
+    file.SetLastAccessTime(updateItem.LastAccessTime);
+  
+  file.UnPackSize = updateItem.Size;
+  file.IsDirectory = updateItem.IsDirectory;
+  file.IsAnti = updateItem.IsAnti;
+  file.HasStream = updateItem.HasStream();
+}
+
+static HRESULT Update2(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    const CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options)
+{
+  UInt64 numSolidFiles = options.NumSolidFiles;
+  if (numSolidFiles == 0)
+    numSolidFiles = 1;
+  /*
+  CMyComPtr<IOutStream> outStream;
+  RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+  if (!outStream)
+    return E_NOTIMPL;
+  */
+
+  UInt64 startBlockSize = database != 0 ? database->ArchiveInfo.StartPosition: 0;
+  if (startBlockSize > 0 && !options.RemoveSfxBlock)
+  {
+    RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
+  }
+
+  CRecordVector<int> fileIndexToUpdateIndexMap;
+  if (database != 0)
+  {
+    fileIndexToUpdateIndexMap.Reserve(database->Files.Size());
+    for (int i = 0; i < database->Files.Size(); i++)
+      fileIndexToUpdateIndexMap.Add(-1);
+  }
+  int i;
+  for(i = 0; i < updateItems.Size(); i++)
+  {
+    int index = updateItems[i].IndexInArchive;
+    if (index != -1)
+      fileIndexToUpdateIndexMap[index] = i;
+  }
+
+  CRecordVector<int> folderRefs;
+  if (database != 0)
+  {
+    for(i = 0; i < database->Folders.Size(); i++)
+    {
+      CNum indexInFolder = 0;
+      CNum numCopyItems = 0;
+      CNum numUnPackStreams = database->NumUnPackStreamsVector[i];
+      for (CNum fileIndex = database->FolderStartFileIndex[i];
+      indexInFolder < numUnPackStreams; fileIndex++)
+      {
+        if (database->Files[fileIndex].HasStream)
+        {
+          indexInFolder++;
+          int updateIndex = fileIndexToUpdateIndexMap[fileIndex];
+          if (updateIndex >= 0)
+            if (!updateItems[updateIndex].NewData)
+              numCopyItems++;
+        }
+      }
+      if (numCopyItems != numUnPackStreams && numCopyItems != 0)
+        return E_NOTIMPL; // It needs repacking !!!
+      if (numCopyItems > 0)
+        folderRefs.Add(i);
+    }
+    folderRefs.Sort(CompareFolderRefs, (void *)database);
+  }
+
+  CArchiveDatabase newDatabase;
+
+  ////////////////////////////
+
+  COutArchive archive;
+  RINOK(archive.Create(seqOutStream, false));
+  RINOK(archive.SkeepPrefixArchiveHeader());
+  UInt64 complexity = 0;
+  for(i = 0; i < folderRefs.Size(); i++)
+    complexity += database->GetFolderFullPackSize(folderRefs[i]);
+  UInt64 inSizeForReduce = 0;
+  for(i = 0; i < updateItems.Size(); i++)
+  {
+    const CUpdateItem &updateItem = updateItems[i];
+    if (updateItem.NewData)
+    {
+      complexity += updateItem.Size;
+      if (numSolidFiles == 1)
+      {
+        if (updateItem.Size > inSizeForReduce)
+          inSizeForReduce = updateItem.Size;
+      }
+      else
+        inSizeForReduce += updateItem.Size;
+    }
+  }
+  RINOK(updateCallback->SetTotal(complexity));
+  complexity = 0;
+  RINOK(updateCallback->SetCompleted(&complexity));
+
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+
+  /////////////////////////////////////////
+  // Write Copy Items
+
+  for(i = 0; i < folderRefs.Size(); i++)
+  {
+    int folderIndex = folderRefs[i];
+    
+    lps->ProgressOffset = complexity;
+    UInt64 packSize = database->GetFolderFullPackSize(folderIndex);
+    RINOK(WriteRange(inStream, archive.SeqStream,
+        database->GetFolderStreamPos(folderIndex, 0), packSize, progress));
+    complexity += packSize;
+    
+    const CFolder &folder = database->Folders[folderIndex];
+    CNum startIndex = database->FolderStartPackStreamIndex[folderIndex];
+    for (int j = 0; j < folder.PackStreams.Size(); j++)
+    {
+      newDatabase.PackSizes.Add(database->PackSizes[startIndex + j]);
+      // newDatabase.PackCRCsDefined.Add(database.PackCRCsDefined[startIndex + j]);
+      // newDatabase.PackCRCs.Add(database.PackCRCs[startIndex + j]);
+    }
+    newDatabase.Folders.Add(folder);
+
+    CNum numUnPackStreams = database->NumUnPackStreamsVector[folderIndex];
+    newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
+
+    CNum indexInFolder = 0;
+    for (CNum fi = database->FolderStartFileIndex[folderIndex];
+        indexInFolder < numUnPackStreams; fi++)
+    {
+      CFileItem file = database->Files[fi];
+      if (file.HasStream)
+      {
+        indexInFolder++;
+        int updateIndex = fileIndexToUpdateIndexMap[fi];
+        if (updateIndex >= 0)
+        {
+          const CUpdateItem &updateItem = updateItems[updateIndex];
+          if (updateItem.NewProperties)
+          {
+            CFileItem file2;
+            FromUpdateItemToFileItem(updateItem, file2);
+            file2.UnPackSize = file.UnPackSize;
+            file2.FileCRC = file.FileCRC;
+            file2.IsFileCRCDefined = file.IsFileCRCDefined;
+            file2.HasStream = file.HasStream;
+            file = file2;
+          }
+        }
+        newDatabase.Files.Add(file);
+      }
+    }
+  }
+
+  /////////////////////////////////////////
+  // Compress New Files
+
+  CObjectVector<CSolidGroup> groups;
+  SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter, 
+      updateItems, groups);
+
+  const UInt32 kMinReduceSize = (1 << 16);
+  if (inSizeForReduce < kMinReduceSize)
+    inSizeForReduce = kMinReduceSize;
+
+  for (int groupIndex = 0; groupIndex < groups.Size(); groupIndex++)
+  {
+    const CSolidGroup &group = groups[groupIndex];
+    int numFiles = group.Indices.Size();
+    if (numFiles == 0)
+      continue;
+    CRecordVector<CRefItem> refItems;
+    refItems.Reserve(numFiles);
+    bool sortByType = (numSolidFiles > 1);
+    for (i = 0; i < numFiles; i++)
+      refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType));
+    refItems.Sort(CompareUpdateItems, (void *)&sortByType);
+    
+    CRecordVector<UInt32> indices;
+    indices.Reserve(numFiles);
+
+    for (i = 0; i < numFiles; i++)
+    {
+      UInt32 index = refItems[i].Index;
+      indices.Add(index);
+      /*
+      const CUpdateItem &updateItem = updateItems[index];
+      CFileItem file;
+      if (updateItem.NewProperties)
+        FromUpdateItemToFileItem(updateItem, file);
+      else
+        file = database.Files[updateItem.IndexInArchive];
+      if (file.IsAnti || file.IsDirectory)
+        return E_FAIL;
+      newDatabase.Files.Add(file);
+      */
+    }
+    
+    CEncoder encoder(group.Method);
+
+    for (i = 0; i < numFiles;)
+    {
+      UInt64 totalSize = 0;
+      int numSubFiles;
+      UString prevExtension;
+      for (numSubFiles = 0; i + numSubFiles < numFiles && 
+          numSubFiles < numSolidFiles; numSubFiles++)
+      {
+        const CUpdateItem &updateItem = updateItems[indices[i + numSubFiles]];
+        totalSize += updateItem.Size;
+        if (totalSize > options.NumSolidBytes)
+          break;
+        if (options.SolidExtension)
+        {
+          UString ext = updateItem.GetExtension();
+          if (numSubFiles == 0)
+            prevExtension = ext;
+          else
+            if (ext.CompareNoCase(prevExtension) != 0)
+              break;
+        }
+      }
+      if (numSubFiles < 1)
+        numSubFiles = 1;
+
+      CFolderInStream *inStreamSpec = new CFolderInStream;
+      CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+      inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
+      
+      CFolder folderItem;
+
+      int startPackIndex = newDatabase.PackSizes.Size();
+      RINOK(encoder.Encode(
+          EXTERNAL_CODECS_LOC_VARS
+          solidInStream, NULL, &inSizeForReduce, folderItem, 
+          archive.SeqStream, newDatabase.PackSizes, progress));
+
+      for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+        lps->OutSize += newDatabase.PackSizes[startPackIndex];
+
+      lps->InSize += folderItem.GetUnPackSize();
+      // for()
+      // newDatabase.PackCRCsDefined.Add(false);
+      // newDatabase.PackCRCs.Add(0);
+      
+      newDatabase.Folders.Add(folderItem);
+      
+      CNum numUnPackStreams = 0;
+      for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
+      {
+        const CUpdateItem &updateItem = updateItems[indices[i + subIndex]];
+        CFileItem file;
+        if (updateItem.NewProperties)
+          FromUpdateItemToFileItem(updateItem, file);
+        else
+          file = database->Files[updateItem.IndexInArchive];
+        if (file.IsAnti || file.IsDirectory)
+          return E_FAIL;
+        
+        /*
+        CFileItem &file = newDatabase.Files[
+              startFileIndexInDatabase + i + subIndex];
+        */
+        if (!inStreamSpec->Processed[subIndex])
+        {
+          continue;
+          // file.Name += L".locked";
+        }
+
+        file.FileCRC = inStreamSpec->CRCs[subIndex];
+        file.UnPackSize = inStreamSpec->Sizes[subIndex];
+        if (file.UnPackSize != 0)
+        {
+          file.IsFileCRCDefined = true;
+          file.HasStream = true;
+          numUnPackStreams++;
+        }
+        else
+        {
+          file.IsFileCRCDefined = false;
+          file.HasStream = false;
+        }
+        newDatabase.Files.Add(file);
+      }
+      // numUnPackStreams = 0 is very bad case for locked files
+      // v3.13 doesn't understand it.
+      newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
+      i += numSubFiles;
+    }
+  }
+
+  {
+    /////////////////////////////////////////
+    // Write Empty Files & Folders
+    
+    CRecordVector<int> emptyRefs;
+    for(i = 0; i < updateItems.Size(); i++)
+    {
+      const CUpdateItem &updateItem = updateItems[i];
+      if (updateItem.NewData)
+      {
+        if (updateItem.HasStream())
+          continue;
+      }
+      else
+        if (updateItem.IndexInArchive != -1)
+          if (database->Files[updateItem.IndexInArchive].HasStream)
+            continue;
+      emptyRefs.Add(i);
+    }
+    emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
+    for(i = 0; i < emptyRefs.Size(); i++)
+    {
+      const CUpdateItem &updateItem = updateItems[emptyRefs[i]];
+      CFileItem file;
+      if (updateItem.NewProperties)
+        FromUpdateItemToFileItem(updateItem, file);
+      else
+        file = database->Files[updateItem.IndexInArchive];
+      newDatabase.Files.Add(file);
+    }
+  }
+    
+  /*
+  if (newDatabase.Files.Size() != updateItems.Size())
+    return E_FAIL;
+  */
+
+  return archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS
+      newDatabase, options.HeaderMethod, options.HeaderOptions);
+}
+
+#ifdef _7Z_VOL
+
+static const UInt64 k_Copy = 0x0;
+
+static HRESULT WriteVolumeHeader(COutArchive &archive, CFileItem &file, const CUpdateOptions &options)
+{
+  CCoderInfo coder;
+  coder.NumInStreams = coder.NumOutStreams = 1;
+  coder.MethodID = k_Copy;
+  
+  CFolder folder;
+  folder.Coders.Add(coder);
+  folder.PackStreams.Add(0);
+  
+  CNum numUnPackStreams = 0;
+  if (file.UnPackSize != 0)
+  {
+    file.IsFileCRCDefined = true;
+    file.HasStream = true;
+    numUnPackStreams++;
+  }
+  else
+  {
+    throw 1;
+    file.IsFileCRCDefined = false;
+    file.HasStream = false;
+  }
+  folder.UnPackSizes.Add(file.UnPackSize);
+  
+  CArchiveDatabase newDatabase;
+  newDatabase.Files.Add(file);
+  newDatabase.Folders.Add(folder);
+  newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
+  newDatabase.PackSizes.Add(file.UnPackSize);
+  newDatabase.PackCRCsDefined.Add(false);
+  newDatabase.PackCRCs.Add(file.FileCRC);
+  
+  return archive.WriteDatabase(newDatabase, 
+      options.HeaderMethod, 
+      false, 
+      false);
+}
+
+HRESULT UpdateVolume(
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options)
+{
+  if (updateItems.Size() != 1)
+    return E_NOTIMPL;
+
+  CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
+  RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
+  if (!volumeCallback)
+    return E_NOTIMPL;
+
+  CMyComPtr<ISequentialInStream> fileStream;
+  HRESULT result = updateCallback->GetStream(0, &fileStream);
+  if (result != S_OK && result != S_FALSE)
+    return result;
+  if (result == S_FALSE)
+    return E_FAIL;
+  
+  CFileItem file;
+  
+  const CUpdateItem &updateItem = updateItems[0];
+  if (updateItem.NewProperties)
+    FromUpdateItemToFileItem(updateItem, file);
+  else
+    file = database->Files[updateItem.IndexInArchive];
+  if (file.IsAnti || file.IsDirectory)
+    return E_FAIL;
+
+  UInt64 complexity = 0;
+  file.IsStartPosDefined = true;
+  file.StartPos = 0;
+  for (UInt64 volumeIndex = 0; true; volumeIndex++)
+  { 
+    UInt64 volSize;
+    RINOK(volumeCallback->GetVolumeSize(volumeIndex, &volSize));
+    UInt64 pureSize = COutArchive::GetVolPureSize(volSize, file.Name.Length(), true);
+    CMyComPtr<ISequentialOutStream> volumeStream;
+    RINOK(volumeCallback->GetVolumeStream(volumeIndex, &volumeStream));
+   
+    COutArchive archive;
+    RINOK(archive.Create(volumeStream, true));
+    RINOK(archive.SkeepPrefixArchiveHeader());
+        
+    CSequentialInStreamWithCRC *inCrcStreamSpec = new CSequentialInStreamWithCRC;
+    CMyComPtr<ISequentialInStream> inCrcStream = inCrcStreamSpec;
+    inCrcStreamSpec->Init(fileStream);
+
+    RINOK(WriteRange(inCrcStream, volumeStream, pureSize, updateCallback, complexity));
+    file.UnPackSize = inCrcStreamSpec->GetSize();
+    if (file.UnPackSize == 0)
+      break;
+    file.FileCRC = inCrcStreamSpec->GetCRC();
+    RINOK(WriteVolumeHeader(archive, file, options));
+    file.StartPos += file.UnPackSize;
+    if (file.UnPackSize < pureSize)
+      break;
+  }
+  return S_OK;
+}
+
+class COutVolumeStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  int _volIndex;
+  UInt64 _volSize;
+  UInt64 _curPos;
+  CMyComPtr<ISequentialOutStream> _volumeStream;
+  COutArchive _archive;
+  CCRC _crc;
+
+public:
+  MY_UNKNOWN_IMP
+
+  CFileItem _file;
+  CUpdateOptions _options;
+  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+  void Init(IArchiveUpdateCallback2 *volumeCallback, 
+      const UString &name)  
+  { 
+    _file.Name = name;
+    _file.IsStartPosDefined = true;
+    _file.StartPos = 0;
+    
+    VolumeCallback = volumeCallback;
+    _volIndex = 0;
+    _volSize = 0;
+  }
+  
+  HRESULT Flush();
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT COutVolumeStream::Flush()
+{
+  if (_volumeStream)
+  {
+    _file.UnPackSize = _curPos;
+    _file.FileCRC = _crc.GetDigest();
+    RINOK(WriteVolumeHeader(_archive, _file, _options));
+    _archive.Close();
+    _volumeStream.Release();
+    _file.StartPos += _file.UnPackSize;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP COutVolumeStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if(processedSize != NULL)
+    *processedSize = 0;
+  while(size > 0)
+  {
+    if (!_volumeStream)
+    {
+      RINOK(VolumeCallback->GetVolumeSize(_volIndex, &_volSize));
+      RINOK(VolumeCallback->GetVolumeStream(_volIndex, &_volumeStream));
+      _volIndex++;
+      _curPos = 0;
+      RINOK(_archive.Create(_volumeStream, true));
+      RINOK(_archive.SkeepPrefixArchiveHeader());
+      _crc.Init();
+      continue;
+    }
+    UInt64 pureSize = COutArchive::GetVolPureSize(_volSize, _file.Name.Length());
+    UInt32 curSize = (UInt32)MyMin(UInt64(size), pureSize - _curPos);
+
+    _crc.Update(data, curSize);
+    UInt32 realProcessed;
+    RINOK(_volumeStream->Write(data, curSize, &realProcessed))
+    data = (void *)((Byte *)data + realProcessed);
+    size -= realProcessed;
+    if(processedSize != NULL)
+      *processedSize += realProcessed;
+    _curPos += realProcessed;
+    if (realProcessed != curSize && realProcessed == 0)
+      return E_FAIL;
+    if (_curPos == pureSize)
+    {
+      RINOK(Flush());
+    }
+  }
+  return S_OK;
+}
+
+#endif
+
+HRESULT Update(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    const CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options)
+{
+  #ifdef _7Z_VOL
+  if (seqOutStream)
+  #endif
+    return Update2(
+        EXTERNAL_CODECS_LOC_VARS
+        inStream, database, updateItems,
+        seqOutStream, updateCallback, options);
+  #ifdef _7Z_VOL
+  if (options.VolumeMode)
+    return UpdateVolume(inStream, database, updateItems,
+      seqOutStream, updateCallback, options);
+  COutVolumeStream *volStreamSpec = new COutVolumeStream;
+  CMyComPtr<ISequentialOutStream> volStream = volStreamSpec;
+  CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
+  RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
+  if (!volumeCallback)
+    return E_NOTIMPL;
+  volStreamSpec->Init(volumeCallback, L"a.7z");
+  volStreamSpec->_options = options;
+  RINOK(Update2(inStream, database, updateItems,
+    volStream, updateCallback, options));
+  return volStreamSpec->Flush();
+  #endif
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zUpdate.h b/lzma/CPP/7zip/Archive/7z/7zUpdate.h
new file mode 100644 (file)
index 0000000..ac1b5b6
--- /dev/null
@@ -0,0 +1,80 @@
+// 7zUpdate.h
+
+#ifndef __7Z_UPDATE_H
+#define __7Z_UPDATE_H
+
+#include "7zIn.h"
+#include "7zOut.h"
+#include "7zCompressionMode.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CUpdateItem
+{
+  bool NewData;
+  bool NewProperties;
+  int IndexInArchive;
+  int IndexInClient;
+  
+  UInt32 Attributes;
+  FILETIME CreationTime;
+  FILETIME LastWriteTime;
+  FILETIME LastAccessTime;
+
+  UInt64 Size;
+  UString Name;
+  
+  bool IsAnti;
+  bool IsDirectory;
+
+  bool IsCreationTimeDefined;
+  bool IsLastWriteTimeDefined;
+  bool IsLastAccessTimeDefined;
+  bool AttributesAreDefined;
+
+  bool HasStream() const 
+    { return !IsDirectory && !IsAnti && Size != 0; }
+  CUpdateItem():  
+      IsAnti(false), 
+      AttributesAreDefined(false), 
+      IsCreationTimeDefined(false), 
+      IsLastWriteTimeDefined(false), 
+      IsLastAccessTimeDefined(false)
+      {}
+  void SetDirectoryStatusFromAttributes()
+    { IsDirectory = ((Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0); };
+
+  int GetExtensionPos() const;
+  UString GetExtension() const;
+};
+
+struct CUpdateOptions
+{
+  const CCompressionMethodMode *Method;
+  const CCompressionMethodMode *HeaderMethod;
+  bool UseFilters;
+  bool MaxFilter;
+
+  CHeaderOptions HeaderOptions;
+
+  UInt64 NumSolidFiles;
+  UInt64 NumSolidBytes;
+  bool SolidExtension;
+  bool RemoveSfxBlock;
+  bool VolumeMode;
+};
+
+HRESULT Update(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    const CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options);
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/StdAfx.cpp b/lzma/CPP/7zip/Archive/7z/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Archive/7z/StdAfx.h b/lzma/CPP/7zip/Archive/7z/StdAfx.h
new file mode 100644 (file)
index 0000000..2e4be10
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Archive.def b/lzma/CPP/7zip/Archive/Archive.def
new file mode 100644 (file)
index 0000000..55b530b
--- /dev/null
@@ -0,0 +1,6 @@
+EXPORTS
+  CreateObject PRIVATE
+  GetHandlerProperty PRIVATE
+  GetNumberOfFormats PRIVATE
+  GetHandlerProperty2 PRIVATE
+  CreateObject PRIVATE
diff --git a/lzma/CPP/7zip/Archive/Archive2.def b/lzma/CPP/7zip/Archive/Archive2.def
new file mode 100644 (file)
index 0000000..885d39d
--- /dev/null
@@ -0,0 +1,9 @@
+EXPORTS
+  CreateObject PRIVATE
+  GetHandlerProperty PRIVATE
+  GetNumberOfFormats PRIVATE
+  GetHandlerProperty2 PRIVATE
+  CreateObject PRIVATE
+  GetNumberOfMethods PRIVATE
+  GetMethodProperty PRIVATE
+  SetLargePageMode PRIVATE
diff --git a/lzma/CPP/7zip/Archive/ArchiveExports.cpp b/lzma/CPP/7zip/Archive/ArchiveExports.cpp
new file mode 100644 (file)
index 0000000..a60303a
--- /dev/null
@@ -0,0 +1,130 @@
+// ArchiveExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Types.h"
+#include "../../Windows/PropVariant.h"
+#include "../Common/RegisterArc.h"
+
+#include "IArchive.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+static const unsigned int kNumArcsMax = 32;
+static unsigned int g_NumArcs = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax]; 
+void RegisterArc(const CArcInfo *arcInfo) 
+{ 
+  if (g_NumArcs < kNumArcsMax)
+    g_Arcs[g_NumArcs++] = arcInfo; 
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler, 
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+  if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+    value->vt = VT_BSTR;
+  return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+  return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+int FindFormatCalssId(const GUID *clsID)
+{
+  GUID cls = *clsID;
+  CLS_ARC_ID_ITEM(cls) = 0;
+  if (cls != CLSID_CArchiveHandler)
+    return -1;
+  Byte id = CLS_ARC_ID_ITEM(*clsID);
+  for (UInt32 i = 0; i < g_NumArcs; i++)
+    if (g_Arcs[i]->ClassId == id)
+      return i;
+  return -1;
+}
+
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
+{
+  COM_TRY_BEGIN
+  {
+    int needIn = (*iid == IID_IInArchive);
+    int needOut = (*iid == IID_IOutArchive);
+    if (!needIn && !needOut)
+      return E_NOINTERFACE;
+    int formatIndex = FindFormatCalssId(clsid);
+    if (formatIndex < 0)
+      return CLASS_E_CLASSNOTAVAILABLE;
+    
+    const CArcInfo &arc = *g_Arcs[formatIndex];
+    if (needIn)
+    {
+      *outObject = arc.CreateInArchive();
+      ((IInArchive *)*outObject)->AddRef();
+    }
+    else
+    {
+      if (!arc.CreateOutArchive)
+        return CLASS_E_CLASSNOTAVAILABLE;
+      *outObject = arc.CreateOutArchive();
+      ((IOutArchive *)*outObject)->AddRef();
+    }
+  }
+  COM_TRY_END
+  return S_OK;
+}
+
+STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
+{
+  if (formatIndex >= g_NumArcs)
+    return E_INVALIDARG;
+  const CArcInfo &arc = *g_Arcs[formatIndex];
+  NWindows::NCOM::CPropVariant prop;
+  switch(propID)
+  {
+    case NArchive::kName:
+      prop = arc.Name;
+      break;
+    case NArchive::kClassID:
+    {
+      GUID clsId = CLSID_CArchiveHandler;
+      CLS_ARC_ID_ITEM(clsId) = arc.ClassId;
+      return SetPropGUID(clsId, value);
+    }
+    case NArchive::kExtension:
+      if (arc.Ext != 0)
+        prop = arc.Ext;
+      break;
+    case NArchive::kAddExtension:
+      if (arc.AddExt != 0)
+        prop = arc.AddExt;
+      break;
+    case NArchive::kUpdate:
+      prop = (bool)(arc.CreateOutArchive != 0);
+      break;
+    case NArchive::kKeepName:
+      prop = arc.KeepName;
+      break;
+    case NArchive::kStartSignature:
+      return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
+  }
+  prop.Detach(value);
+  return S_OK;
+}
+
+STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
+{
+  return GetHandlerProperty2(0, propID, value);
+}
+
+STDAPI GetNumberOfFormats(UINT32 *numFormats)
+{
+  *numFormats = g_NumArcs;
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp b/lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp
new file mode 100644 (file)
index 0000000..d11e9e6
--- /dev/null
@@ -0,0 +1,121 @@
+// CoderMixer2.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2.h"
+
+namespace NCoderMixer {
+
+CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
+  _srcBindInfo(srcBindInfo)
+{
+  srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams);
+
+  UInt32  j;
+  for (j = 0; j < NumSrcInStreams; j++)
+  {
+    _srcInToDestOutMap.Add(0);
+    DestOutToSrcInMap.Add(0);
+  }
+  for (j = 0; j < _numSrcOutStreams; j++)
+  {
+    _srcOutToDestInMap.Add(0);
+    _destInToSrcOutMap.Add(0);
+  }
+
+  UInt32 destInOffset = 0;
+  UInt32 destOutOffset = 0;
+  UInt32 srcInOffset = NumSrcInStreams;
+  UInt32 srcOutOffset = _numSrcOutStreams;
+
+  for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+  {
+    const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i];
+
+    srcInOffset -= srcCoderInfo.NumInStreams;
+    srcOutOffset -= srcCoderInfo.NumOutStreams;
+    
+    UInt32 j;
+    for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++)
+    {
+      UInt32 index = srcInOffset + j;
+      _srcInToDestOutMap[index] = destOutOffset;
+      DestOutToSrcInMap[destOutOffset] = index;
+    }
+    for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++)
+    {
+      UInt32 index = srcOutOffset + j;
+      _srcOutToDestInMap[index] = destInOffset;
+      _destInToSrcOutMap[destInOffset] = index;
+    }
+  }
+}
+
+void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo)
+{
+  destBindInfo.Coders.Clear();
+  destBindInfo.BindPairs.Clear();
+  destBindInfo.InStreams.Clear();
+  destBindInfo.OutStreams.Clear();
+
+  int i;
+  for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+  {
+    const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i];
+    CCoderStreamsInfo destCoderInfo;
+    destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams;
+    destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams;
+    destBindInfo.Coders.Add(destCoderInfo);
+  }
+  for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--)
+  {
+    const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i];
+    CBindPair destBindPair;
+    destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex];
+    destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex];
+    destBindInfo.BindPairs.Add(destBindPair);
+  }
+  for (i = 0; i < _srcBindInfo.InStreams.Size(); i++)
+    destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
+  for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++)
+    destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
+}
+
+CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): 
+    NumInStreams(numInStreams),
+    NumOutStreams(numOutStreams)
+{
+  InSizes.Reserve(NumInStreams);
+  InSizePointers.Reserve(NumInStreams);
+  OutSizePointers.Reserve(NumOutStreams);
+  OutSizePointers.Reserve(NumOutStreams);
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, 
+    CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+  sizes.Clear();
+  sizePointers.Clear();
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    if (srcSizes == 0 || srcSizes[i] == NULL)
+    {
+      sizes.Add(0);
+      sizePointers.Add(NULL);
+    }
+    else
+    {
+      sizes.Add(*srcSizes[i]);
+      sizePointers.Add(&sizes.Back());
+    }
+  }
+}
+
+void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes,
+      const UInt64 **outSizes)
+{
+  SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+  SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+}  
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2.h b/lzma/CPP/7zip/Archive/Common/CoderMixer2.h
new file mode 100644 (file)
index 0000000..be68c68
--- /dev/null
@@ -0,0 +1,174 @@
+// CoderMixer2.h
+
+#ifndef __CODER_MIXER2_H
+#define __CODER_MIXER2_H
+
+#include "../../../Common/MyVector.h"
+#include "../../../Common/Types.h"
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+namespace NCoderMixer {
+
+struct CBindPair
+{
+  UInt32 InIndex;
+  UInt32 OutIndex;
+};
+
+struct CCoderStreamsInfo
+{
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+};
+
+struct CBindInfo
+{
+  CRecordVector<CCoderStreamsInfo> Coders;
+  CRecordVector<CBindPair> BindPairs;
+  CRecordVector<UInt32> InStreams;
+  CRecordVector<UInt32> OutStreams;
+
+  void Clear()
+  {
+    Coders.Clear();
+    BindPairs.Clear();
+    InStreams.Clear();
+    OutStreams.Clear();
+  }
+
+  /*
+  UInt32 GetCoderStartOutStream(UInt32 coderIndex) const
+  {
+    UInt32 numOutStreams = 0;
+    for (UInt32 i = 0; i < coderIndex; i++)
+      numOutStreams += Coders[i].NumOutStreams;
+    return numOutStreams;
+  }
+  */
+
+
+  void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const
+  {
+    numInStreams = 0;
+    numOutStreams = 0;
+    for (int i = 0; i < Coders.Size(); i++)
+    {
+      const CCoderStreamsInfo &coderStreamsInfo = Coders[i];
+      numInStreams += coderStreamsInfo.NumInStreams;
+      numOutStreams += coderStreamsInfo.NumOutStreams;
+    }
+  }
+
+  int FindBinderForInStream(UInt32 inStream) const
+  {
+    for (int i = 0; i < BindPairs.Size(); i++)
+      if (BindPairs[i].InIndex == inStream)
+        return i;
+    return -1;
+  }
+  int FindBinderForOutStream(UInt32 outStream) const
+  {
+    for (int i = 0; i < BindPairs.Size(); i++)
+      if (BindPairs[i].OutIndex == outStream)
+        return i;
+    return -1;
+  }
+
+  UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const
+  {
+    UInt32 streamIndex = 0;
+    for (UInt32 i = 0; i < coderIndex; i++)
+      streamIndex += Coders[i].NumInStreams;
+    return streamIndex;
+  }
+
+  UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const
+  {
+    UInt32 streamIndex = 0;
+    for (UInt32 i = 0; i < coderIndex; i++)
+      streamIndex += Coders[i].NumOutStreams;
+    return streamIndex;
+  }
+
+
+  void FindInStream(UInt32 streamIndex, UInt32 &coderIndex, 
+      UInt32 &coderStreamIndex) const
+  {
+    for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+    {
+      UInt32 curSize = Coders[coderIndex].NumInStreams;
+      if (streamIndex < curSize)
+      {
+        coderStreamIndex = streamIndex;
+        return;
+      }
+      streamIndex -= curSize;
+    }
+    throw 1;
+  }
+  void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex, 
+      UInt32 &coderStreamIndex) const
+  {
+    for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+    {
+      UInt32 curSize = Coders[coderIndex].NumOutStreams;
+      if (streamIndex < curSize)
+      {
+        coderStreamIndex = streamIndex;
+        return;
+      }
+      streamIndex -= curSize;
+    }
+    throw 1;
+  }
+};
+
+class CBindReverseConverter
+{
+  UInt32 _numSrcOutStreams;
+  NCoderMixer::CBindInfo _srcBindInfo;
+  CRecordVector<UInt32> _srcInToDestOutMap;
+  CRecordVector<UInt32> _srcOutToDestInMap;
+  CRecordVector<UInt32> _destInToSrcOutMap;
+public:
+  UInt32 NumSrcInStreams;
+  CRecordVector<UInt32> DestOutToSrcInMap;
+
+  CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo);
+  void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo);
+};
+
+struct CCoderInfo2
+{
+  CMyComPtr<ICompressCoder> Coder;
+  CMyComPtr<ICompressCoder2> Coder2;
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+
+  CRecordVector<UInt64> InSizes;
+  CRecordVector<UInt64> OutSizes;
+  CRecordVector<const UInt64 *> InSizePointers;
+  CRecordVector<const UInt64 *> OutSizePointers;
+
+  CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams);
+  void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+
+  HRESULT QueryInterface(REFGUID iid, void** pp) const
+  {
+    IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
+    return p->QueryInterface(iid, pp);
+  }
+};
+
+class CCoderMixer2
+{
+public:
+  virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0;
+  virtual void ReInit() = 0;
+  virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0;
+};
+
+}
+#endif
+
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
new file mode 100644 (file)
index 0000000..2ef1fa9
--- /dev/null
@@ -0,0 +1,228 @@
+// CoderMixer2MT.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2MT.h"
+
+namespace NCoderMixer {
+
+CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams): 
+    CCoderInfo2(numInStreams, numOutStreams)
+{
+  InStreams.Reserve(NumInStreams);
+  InStreamPointers.Reserve(NumInStreams);
+  OutStreams.Reserve(NumOutStreams);
+  OutStreamPointers.Reserve(NumOutStreams);
+}
+
+void CCoder2::Execute() { Code(NULL); }
+
+void CCoder2::Code(ICompressProgressInfo *progress)
+{
+  InStreamPointers.Clear();
+  OutStreamPointers.Clear();
+  UInt32 i;
+  for (i = 0; i < NumInStreams; i++)
+  {
+    if (InSizePointers[i] != NULL)
+      InSizePointers[i] = &InSizes[i];
+    InStreamPointers.Add((ISequentialInStream *)InStreams[i]);
+  }
+  for (i = 0; i < NumOutStreams; i++)
+  {
+    if (OutSizePointers[i] != NULL)
+      OutSizePointers[i] = &OutSizes[i];
+    OutStreamPointers.Add((ISequentialOutStream *)OutStreams[i]);
+  }
+  if (Coder)
+    Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], 
+        InSizePointers[0], OutSizePointers[0], progress);
+  else
+    Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams,
+      &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress);
+  {
+    int i;
+    for (i = 0; i < InStreams.Size(); i++)
+      InStreams[i].Release();
+    for (i = 0; i < OutStreams.Size(); i++)
+      OutStreams[i].Release();
+  }
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, 
+    CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+  sizes.Clear();
+  sizePointers.Clear();
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    if (srcSizes == 0 || srcSizes[i] == NULL)
+    {
+      sizes.Add(0);
+      sizePointers.Add(NULL);
+    }
+    else
+    {
+      sizes.Add(*srcSizes[i]);
+      sizePointers.Add(&sizes.Back());
+    }
+  }
+}
+
+
+void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
+{
+  SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+  SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+//////////////////////////////////////
+// CCoderMixer2MT
+
+HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo)
+{  
+  _bindInfo = bindInfo; 
+  _streamBinders.Clear();
+  for(int i = 0; i < _bindInfo.BindPairs.Size(); i++)
+  {
+    _streamBinders.Add(CStreamBinder());
+    RINOK(_streamBinders.Back().CreateEvents());
+  }
+  return S_OK;
+}
+
+void CCoderMixer2MT::AddCoderCommon()
+{
+  const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()];
+  CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams);
+  _coders.Add(threadCoderInfo);
+}
+
+void CCoderMixer2MT::AddCoder(ICompressCoder *coder)
+{
+  AddCoderCommon();
+  _coders.Back().Coder = coder;
+}
+
+void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder)
+{
+  AddCoderCommon();
+  _coders.Back().Coder2 = coder;
+}
+
+
+void CCoderMixer2MT::ReInit()
+{
+  for(int i = 0; i < _streamBinders.Size(); i++)
+    _streamBinders[i].ReInit();
+}
+
+
+HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams) 
+{
+  /*
+  if (_coders.Size() != _bindInfo.Coders.Size())
+    throw 0;
+  */
+  int i;
+  for(i = 0; i < _coders.Size(); i++)
+  {
+    CCoder2 &coderInfo = _coders[i];
+    const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i];
+    coderInfo.InStreams.Clear();
+    UInt32 j;
+    for(j = 0; j < coderStreamsInfo.NumInStreams; j++)
+      coderInfo.InStreams.Add(NULL);
+    coderInfo.OutStreams.Clear();
+    for(j = 0; j < coderStreamsInfo.NumOutStreams; j++)
+      coderInfo.OutStreams.Add(NULL);
+  }
+
+  for(i = 0; i < _bindInfo.BindPairs.Size(); i++)
+  {
+    const CBindPair &bindPair = _bindInfo.BindPairs[i];
+    UInt32 inCoderIndex, inCoderStreamIndex;
+    UInt32 outCoderIndex, outCoderStreamIndex;
+    _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex);
+    _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex);
+
+    _streamBinders[i].CreateStreams(
+        &_coders[inCoderIndex].InStreams[inCoderStreamIndex],
+        &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]);
+  }
+
+  for(i = 0; i < _bindInfo.InStreams.Size(); i++)
+  {
+    UInt32 inCoderIndex, inCoderStreamIndex;
+    _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex);
+    _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i];
+  }
+  
+  for(i = 0; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    UInt32 outCoderIndex, outCoderStreamIndex;
+    _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex);
+    _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i];
+  }
+  return S_OK;
+}
+
+HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code)
+{
+  for (int i = 0; i < _coders.Size(); i++)
+    if (_coders[i].Result == code)
+      return code;
+  return S_OK;
+}
+
+STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams,
+      const UInt64 ** /* inSizes */, 
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams, 
+      const UInt64 ** /* outSizes */,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress)
+{
+  if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
+      numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
+    return E_INVALIDARG;
+
+  Init(inStreams, outStreams);
+
+  int i;
+  for (i = 0; i < _coders.Size(); i++)
+    if (i != _progressCoderIndex)
+    {
+      RINOK(_coders[i].Create());
+    }
+
+  for (i = 0; i < _coders.Size(); i++)
+    if (i != _progressCoderIndex)
+      _coders[i].Start();
+
+  _coders[_progressCoderIndex].Code(progress);
+
+  for (i = 0; i < _coders.Size(); i++)
+    if (i != _progressCoderIndex)
+      _coders[i].WaitFinish();
+
+  RINOK(ReturnIfError(E_ABORT));
+  RINOK(ReturnIfError(E_OUTOFMEMORY));
+  RINOK(ReturnIfError(S_FALSE));
+
+  for (i = 0; i < _coders.Size(); i++)
+  {
+    HRESULT result = _coders[i].Result;
+    if (result != S_OK && result != E_FAIL)
+      return result;
+  }
+  for (i = 0; i < _coders.Size(); i++)
+  {
+    HRESULT result = _coders[i].Result;
+    if (result != S_OK)
+      return result;
+  }
+  return S_OK;
+}
+
+}  
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.h b/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.h
new file mode 100644 (file)
index 0000000..505f1a8
--- /dev/null
@@ -0,0 +1,80 @@
+// CoderMixer2MT.h
+
+#ifndef __CODER_MIXER2_MT_H
+#define __CODER_MIXER2_MT_H
+
+#include "CoderMixer2.h"
+#include "../../../Common/MyCom.h"
+#include "../../Common/StreamBinder.h"
+#include "../../Common/VirtThread.h"
+
+namespace NCoderMixer {
+
+struct CCoder2: public CCoderInfo2, public CVirtThread
+{
+  HRESULT Result;
+  CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
+  CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
+  CRecordVector<ISequentialInStream*> InStreamPointers;
+  CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+  CCoder2(UInt32 numInStreams, UInt32 numOutStreams);
+  void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+  virtual void Execute();
+  void Code(ICompressProgressInfo *progress);
+};
+
+
+/*
+  SetBindInfo()
+  for each coder
+    AddCoder[2]()
+  SetProgressIndex(UInt32 coderIndex);
+  for each file
+  {
+    ReInit()
+    for each coder
+      SetCoderInfo  
+    Code
+  }
+*/
+
+class CCoderMixer2MT:
+  public ICompressCoder2,
+  public CCoderMixer2,
+  public CMyUnknownImp
+{
+  CBindInfo _bindInfo;
+  CObjectVector<CStreamBinder> _streamBinders;
+  int _progressCoderIndex;
+
+  void AddCoderCommon();
+  HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams);
+  HRESULT ReturnIfError(HRESULT code);
+public:
+  CObjectVector<CCoder2> _coders;
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Code)(ISequentialInStream **inStreams,
+      const UInt64 **inSizes, 
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams, 
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress);
+
+  HRESULT SetBindInfo(const CBindInfo &bindInfo);
+  void AddCoder(ICompressCoder *coder);
+  void AddCoder2(ICompressCoder2 *coder);
+  void SetProgressCoderIndex(int coderIndex) {  _progressCoderIndex = coderIndex; }
+
+  void ReInit();
+  void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
+    {  _coders[coderIndex].SetCoderInfo(inSizes, outSizes); }
+  UInt64 GetWriteProcessedSize(UInt32 binderIndex) const
+    {  return _streamBinders[binderIndex].ProcessedSize; }
+};
+
+}
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
new file mode 100644 (file)
index 0000000..a974b54
--- /dev/null
@@ -0,0 +1,15 @@
+// CrossThreadProgress.cpp
+
+#include "StdAfx.h"
+
+#include "CrossThreadProgress.h"
+
+STDMETHODIMP CCrossThreadProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+  InSize = inSize;
+  OutSize = outSize;
+  ProgressEvent.Set();
+  WaitEvent.Lock();
+  return Result;
+}
+
diff --git a/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.h b/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.h
new file mode 100644 (file)
index 0000000..b5422a3
--- /dev/null
@@ -0,0 +1,37 @@
+// CrossThreadProgress.h
+
+#ifndef __CROSSTHREADPROGRESS_H
+#define __CROSSTHREADPROGRESS_H
+
+#include "../../ICoder.h"
+#include "../../../Windows/Synchronization.h"
+#include "../../../Common/MyCom.h"
+
+class CCrossThreadProgress: 
+  public ICompressProgressInfo,
+  public CMyUnknownImp
+{
+public:
+  const UInt64 *InSize;
+  const UInt64 *OutSize;
+  HRESULT Result;
+  NWindows::NSynchronization::CAutoResetEvent ProgressEvent;
+  NWindows::NSynchronization::CAutoResetEvent WaitEvent;
+
+  HRes Create()
+  {
+    RINOK(ProgressEvent.CreateIfNotCreated());
+    return WaitEvent.CreateIfNotCreated();
+  }
+  void Init()
+  {
+    ProgressEvent.Reset();
+    WaitEvent.Reset();
+  }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/DummyOutStream.cpp b/lzma/CPP/7zip/Archive/Common/DummyOutStream.cpp
new file mode 100644 (file)
index 0000000..54bcfec
--- /dev/null
@@ -0,0 +1,22 @@
+// DummyOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "DummyOutStream.h"
+
+STDMETHODIMP CDummyOutStream::Write(const void *data,  UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result;
+  if(!_stream)
+  {
+    realProcessedSize = size;
+    result = S_OK;
+  }
+  else
+    result = _stream->Write(data, size, &realProcessedSize);
+  _size += realProcessedSize;
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return result;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/DummyOutStream.h b/lzma/CPP/7zip/Archive/Common/DummyOutStream.h
new file mode 100644 (file)
index 0000000..d19b311
--- /dev/null
@@ -0,0 +1,23 @@
+// DummyOutStream.h
+
+#ifndef __DUMMYOUTSTREAM_H
+#define __DUMMYOUTSTREAM_H
+
+#include "../../IStream.h"
+#include "Common/MyCom.h"
+
+class CDummyOutStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt64 _size;
+public:
+  void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
+  void Init() { _size = 0; }
+  MY_UNKNOWN_IMP
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  UInt64 GetSize() const { return _size; }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/HandlerOut.cpp b/lzma/CPP/7zip/Archive/Common/HandlerOut.cpp
new file mode 100644 (file)
index 0000000..0dcf449
--- /dev/null
@@ -0,0 +1,618 @@
+// HandlerOutCommon.cpp
+
+#include "StdAfx.h"
+
+#include "HandlerOut.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Common/StringToInt.h"
+#include "../../ICoder.h"
+#include "../Common/ParseProperties.h"
+
+#ifdef COMPRESS_MT
+#include "../../../Windows/System.h"
+#endif
+
+using namespace NWindows;
+
+namespace NArchive {
+
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kLZMA2MethodName = L"LZMA2";
+static const wchar_t *kBZip2MethodName = L"BZip2";
+static const wchar_t *kPpmdMethodName = L"PPMd";
+static const wchar_t *kDeflateMethodName = L"Deflate";
+static const wchar_t *kDeflate64MethodName = L"Deflate64";
+
+static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
+static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
+
+static const UInt32 kLzmaAlgoX1 = 0;
+static const UInt32 kLzmaAlgoX5 = 1;
+
+static const UInt32 kLzmaDicSizeX1 = 1 << 16;
+static const UInt32 kLzmaDicSizeX3 = 1 << 20;
+static const UInt32 kLzmaDicSizeX5 = 1 << 24;
+static const UInt32 kLzmaDicSizeX7 = 1 << 25;
+static const UInt32 kLzmaDicSizeX9 = 1 << 26;
+
+static const UInt32 kLzmaFastBytesX1 = 32;
+static const UInt32 kLzmaFastBytesX7 = 64;
+
+static const UInt32 kPpmdMemSizeX1 = (1 << 22);
+static const UInt32 kPpmdMemSizeX5 = (1 << 24);
+static const UInt32 kPpmdMemSizeX7 = (1 << 26);
+static const UInt32 kPpmdMemSizeX9 = (192 << 20);
+
+static const UInt32 kPpmdOrderX1 = 4;
+static const UInt32 kPpmdOrderX5 = 6;
+static const UInt32 kPpmdOrderX7 = 16;
+static const UInt32 kPpmdOrderX9 = 32;
+
+static const UInt32 kDeflateAlgoX1 = 0;
+static const UInt32 kDeflateAlgoX5 = 1;
+
+static const UInt32 kDeflateFastBytesX1 = 32;
+static const UInt32 kDeflateFastBytesX7 = 64;
+static const UInt32 kDeflateFastBytesX9 = 128;
+
+static const UInt32 kDeflatePassesX1 = 1;
+static const UInt32 kDeflatePassesX7 = 3;
+static const UInt32 kDeflatePassesX9 = 10;
+
+static const UInt32 kBZip2NumPassesX1 = 1;
+static const UInt32 kBZip2NumPassesX7 = 2;
+static const UInt32 kBZip2NumPassesX9 = 7;
+
+static const UInt32 kBZip2DicSizeX1 = 100000;
+static const UInt32 kBZip2DicSizeX3 = 500000;
+static const UInt32 kBZip2DicSizeX5 = 900000;
+
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders = 1 << 20;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
+
+static bool AreEqual(const UString &methodName, const wchar_t *s)
+  { return (methodName.CompareNoCase(s) == 0); }
+
+static inline bool IsLZMAMethod(const UString &methodName)
+{ 
+  return 
+    AreEqual(methodName, kLZMAMethodName) || 
+    AreEqual(methodName, kLZMA2MethodName); 
+}
+
+static inline bool IsBZip2Method(const UString &methodName)
+  { return AreEqual(methodName, kBZip2MethodName); }
+
+static inline bool IsPpmdMethod(const UString &methodName)
+  { return AreEqual(methodName, kPpmdMethodName); }
+
+static inline bool IsDeflateMethod(const UString &methodName)
+{ 
+  return 
+    AreEqual(methodName, kDeflateMethodName) || 
+    AreEqual(methodName, kDeflate64MethodName); 
+}
+
+struct CNameToPropID
+{
+  PROPID PropID;
+  VARTYPE VarType;
+  const wchar_t *Name;
+};
+
+CNameToPropID g_NameToPropID[] = 
+{
+  { NCoderPropID::kOrder, VT_UI4, L"O" },
+  { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
+  { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
+  { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
+  { NCoderPropID::kEndMarker, VT_BOOL, L"eos" },
+
+  { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
+  { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
+  { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
+  { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
+  { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
+  { NCoderPropID::kNumThreads, VT_UI4, L"mt" }
+};
+
+static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
+{
+  if (varType == srcProp.vt)
+  {
+    destProp = srcProp;
+    return true;
+  }
+  if (varType == VT_UI1)
+  {
+    if (srcProp.vt == VT_UI4)
+    {
+      UInt32 value = srcProp.ulVal;
+      if (value > 0xFF)
+        return false;
+      destProp = (Byte)value;
+      return true;
+    }
+  }
+  else if (varType == VT_BOOL)
+  {
+    bool res;
+    if (SetBoolProperty(res, srcProp) != S_OK)
+      return false;
+    destProp = res;
+    return true;
+  }
+  return false;
+}
+    
+static int FindPropIdFromStringName(const UString &name)
+{
+  for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
+    if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
+      return i;
+  return -1;
+}
+
+static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID, 
+    const NWindows::NCOM::CPropVariant &value)
+{
+  for (int j = 0; j < oneMethodInfo.Properties.Size(); j++)
+    if (oneMethodInfo.Properties[j].Id == propID)
+      return;
+  CProp property;
+  property.Id = propID;
+  property.Value = value;
+  oneMethodInfo.Properties.Add(property);
+}
+
+void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
+    #ifdef COMPRESS_MT
+    , UInt32 numThreads
+    #endif
+    )
+{
+  UInt32 level = _level;
+  if (oneMethodInfo.MethodName.IsEmpty())
+    oneMethodInfo.MethodName = kDefaultMethodName;
+  
+  if (IsLZMAMethod(oneMethodInfo.MethodName))
+  {
+    UInt32 dicSize = 
+      (level >= 9 ? kLzmaDicSizeX9 : 
+      (level >= 7 ? kLzmaDicSizeX7 : 
+      (level >= 5 ? kLzmaDicSizeX5 : 
+      (level >= 3 ? kLzmaDicSizeX3 : 
+                    kLzmaDicSizeX1)))); 
+    
+    UInt32 algo = 
+      (level >= 5 ? kLzmaAlgoX5 : 
+                    kLzmaAlgoX1); 
+    
+    UInt32 fastBytes = 
+      (level >= 7 ? kLzmaFastBytesX7 : 
+                    kLzmaFastBytesX1); 
+    
+    const wchar_t *matchFinder = 
+      (level >= 5 ? kLzmaMatchFinderX5 : 
+                    kLzmaMatchFinderX1); 
+    
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
+    #ifdef COMPRESS_MT
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+    #endif
+  }
+  else if (IsDeflateMethod(oneMethodInfo.MethodName))
+  {
+    UInt32 fastBytes = 
+      (level >= 9 ? kDeflateFastBytesX9 : 
+      (level >= 7 ? kDeflateFastBytesX7 : 
+                    kDeflateFastBytesX1));
+    
+    UInt32 numPasses = 
+      (level >= 9 ? kDeflatePassesX9 :  
+      (level >= 7 ? kDeflatePassesX7 : 
+                    kDeflatePassesX1));
+    
+    UInt32 algo = 
+      (level >= 5 ? kDeflateAlgoX5 : 
+                    kDeflateAlgoX1); 
+    
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
+  }
+  else if (IsBZip2Method(oneMethodInfo.MethodName))
+  {
+    UInt32 numPasses = 
+      (level >= 9 ? kBZip2NumPassesX9 : 
+      (level >= 7 ? kBZip2NumPassesX7 :  
+                    kBZip2NumPassesX1));
+    
+    UInt32 dicSize = 
+      (level >= 5 ? kBZip2DicSizeX5 : 
+      (level >= 3 ? kBZip2DicSizeX3 : 
+                    kBZip2DicSizeX1));
+    
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
+    #ifdef COMPRESS_MT
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+    #endif
+  }
+  else if (IsPpmdMethod(oneMethodInfo.MethodName))
+  {
+    UInt32 useMemSize = 
+      (level >= 9 ? kPpmdMemSizeX9 : 
+      (level >= 7 ? kPpmdMemSizeX7 : 
+      (level >= 5 ? kPpmdMemSizeX5 : 
+                    kPpmdMemSizeX1)));
+    
+    UInt32 order = 
+      (level >= 9 ? kPpmdOrderX9 : 
+      (level >= 7 ? kPpmdOrderX7 : 
+      (level >= 5 ? kPpmdOrderX5 : 
+                    kPpmdOrderX1)));
+    
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
+    SetOneMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
+  }
+}
+
+static void SplitParams(const UString &srcString, UStringVector &subStrings)
+{
+  subStrings.Clear();
+  UString name;
+  int len = srcString.Length();
+  if (len == 0)
+    return;
+  for (int i = 0; i < len; i++)
+  {
+    wchar_t c = srcString[i];
+    if (c == L':')
+    {
+      subStrings.Add(name);
+      name.Empty();
+    }
+    else
+      name += c;
+  }
+  subStrings.Add(name);
+}
+
+static void SplitParam(const UString &param, UString &name, UString &value)
+{
+  int eqPos = param.Find(L'=');
+  if (eqPos >= 0)
+  {
+    name = param.Left(eqPos);
+    value = param.Mid(eqPos + 1);
+    return;
+  }
+  for(int i = 0; i < param.Length(); i++)
+  {
+    wchar_t c = param[i];
+    if (c >= L'0' && c <= L'9')
+    {
+      name = param.Left(i);
+      value = param.Mid(i);
+      return;
+    }
+  }
+  name = param;
+}
+
+HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
+{
+  CProp property;
+  if (
+    name.CompareNoCase(L"D") == 0 || 
+    name.CompareNoCase(L"MEM") == 0)
+  {
+    UInt32 dicSize;
+    RINOK(ParsePropDictionaryValue(value, dicSize));
+    if (name.CompareNoCase(L"D") == 0)
+      property.Id = NCoderPropID::kDictionarySize;
+    else
+      property.Id = NCoderPropID::kUsedMemorySize;
+    property.Value = dicSize;
+    oneMethodInfo.Properties.Add(property);
+  }
+  else
+  {
+    int index = FindPropIdFromStringName(name);
+    if (index < 0)
+      return E_INVALIDARG;
+    
+    const CNameToPropID &nameToPropID = g_NameToPropID[index];
+    property.Id = nameToPropID.PropID;
+    
+    NCOM::CPropVariant propValue;
+    
+    if (nameToPropID.VarType == VT_BSTR)
+      propValue = value;
+    else if (nameToPropID.VarType == VT_BOOL)
+    {
+      bool res;
+      if (!StringToBool(value, res))
+        return E_INVALIDARG;
+      propValue = res;
+    }
+    else
+    {
+      UInt32 number;
+      if (ParseStringToUInt32(value, number) == value.Length())
+        propValue = number;
+      else
+        propValue = value;
+    }
+    
+    if (!ConvertProperty(propValue, nameToPropID.VarType, property.Value))
+      return E_INVALIDARG;
+    
+    oneMethodInfo.Properties.Add(property);
+  }
+  return S_OK;
+}
+
+HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
+{
+  UStringVector params;
+  SplitParams(srcString, params);
+  if (params.Size() > 0)
+    oneMethodInfo.MethodName = params[0];
+  for (int i = 1; i < params.Size(); i++)
+  {
+    const UString &param = params[i];
+    UString name, value;
+    SplitParam(param, name, value);
+    RINOK(SetParam(oneMethodInfo, name, value));
+  }
+  return S_OK;
+}
+
+HRESULT COutHandler::SetSolidSettings(const UString &s)
+{
+  bool res;
+  if (StringToBool(s, res))
+  {
+    if (res)
+      InitSolid();
+    else
+      _numSolidFiles = 1;
+    return S_OK;
+  }
+  UString s2 = s;
+  s2.MakeUpper();
+  for (int i = 0; i < s2.Length();)
+  {
+    const wchar_t *start = ((const wchar_t *)s2) + i;
+    const wchar_t *end;
+    UInt64 v = ConvertStringToUInt64(start, &end);
+    if (start == end)
+    {
+      if (s2[i++] != 'E')
+        return E_INVALIDARG;
+      _solidExtension = true;
+      continue;
+    }
+    i += (int)(end - start);
+    if (i == s2.Length())
+      return E_INVALIDARG;
+    wchar_t c = s2[i++];
+    switch(c)
+    {
+      case 'F':
+        if (v < 1)
+          v = 1;
+        _numSolidFiles = v;
+        break;
+      case 'B':
+        _numSolidBytes = v;
+        _numSolidBytesDefined = true;
+        break;
+      case 'K':
+        _numSolidBytes = (v << 10);
+        _numSolidBytesDefined = true;
+        break;
+      case 'M':
+        _numSolidBytes = (v << 20);
+        _numSolidBytesDefined = true;
+        break;
+      case 'G':
+        _numSolidBytes = (v << 30);
+        _numSolidBytesDefined = true;
+        break;
+      default:
+        return E_INVALIDARG;
+    }
+  }
+  return S_OK;
+}
+
+HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value)
+{
+  switch(value.vt)
+  {
+    case VT_EMPTY:
+      InitSolid();
+      return S_OK;
+    case VT_BSTR:
+      return SetSolidSettings(value.bstrVal);
+    default:
+      return E_INVALIDARG;
+  }
+}
+
+void COutHandler::Init()
+{
+  _removeSfxBlock = false;
+  _compressHeaders = true;
+  _encryptHeaders = false;
+  
+  WriteModified = true;
+  WriteCreated = false;
+  WriteAccessed = false;
+  
+  #ifdef COMPRESS_MT
+  _numThreads = NWindows::NSystem::GetNumberOfProcessors();
+  #endif
+  
+  _level = 5;
+  _autoFilter = true;
+  _volumeMode = false;
+  _crcSize = 4;
+  InitSolid();
+}
+
+void COutHandler::BeforeSetProperty()
+{
+  Init();
+  #ifdef COMPRESS_MT
+  numProcessors = NSystem::GetNumberOfProcessors();
+  #endif
+
+  mainDicSize = 0xFFFFFFFF;
+  mainDicMethodIndex = 0xFFFFFFFF;
+  minNumber = 0;
+  _crcSize = 4;
+}
+
+HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+  UString name = nameSpec;
+  name.MakeUpper();
+  if (name.IsEmpty())
+    return E_INVALIDARG;
+  
+  if (name[0] == 'X')
+  {
+    name.Delete(0);
+    _level = 9;
+    return ParsePropValue(name, value, _level);
+  }
+  
+  if (name[0] == L'S')
+  {
+    name.Delete(0);
+    if (name.IsEmpty())
+      return SetSolidSettings(value);
+    if (value.vt != VT_EMPTY)
+      return E_INVALIDARG;
+    return SetSolidSettings(name);
+  }
+  
+  if (name == L"CRC")
+  {
+    _crcSize = 4;
+    name.Delete(0, 3);
+    return ParsePropValue(name, value, _crcSize);
+  }
+  
+  UInt32 number;
+  int index = ParseStringToUInt32(name, number);
+  UString realName = name.Mid(index);
+  if (index == 0)
+  {
+    if(name.Left(2).CompareNoCase(L"MT") == 0)
+    {
+      #ifdef COMPRESS_MT
+      RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+      #endif
+      return S_OK;
+    }
+    if (name.CompareNoCase(L"RSFX") == 0)
+      return SetBoolProperty(_removeSfxBlock, value);
+    if (name.CompareNoCase(L"F") == 0)
+      return SetBoolProperty(_autoFilter, value);
+    if (name.CompareNoCase(L"HC") == 0)
+      return SetBoolProperty(_compressHeaders, value);
+    if (name.CompareNoCase(L"HCF") == 0)
+    {
+      bool compressHeadersFull = true;
+      RINOK(SetBoolProperty(compressHeadersFull, value));
+      if (!compressHeadersFull)
+        return E_INVALIDARG;
+      return S_OK;
+    }
+    if (name.CompareNoCase(L"HE") == 0)
+      return SetBoolProperty(_encryptHeaders, value);
+    if (name.CompareNoCase(L"TM") == 0)
+      return SetBoolProperty(WriteModified, value);
+    if (name.CompareNoCase(L"TC") == 0)
+      return SetBoolProperty(WriteCreated, value);
+    if (name.CompareNoCase(L"TA") == 0)
+      return SetBoolProperty(WriteAccessed, value);
+    if (name.CompareNoCase(L"V") == 0)
+      return SetBoolProperty(_volumeMode, value);
+    number = 0;
+  }
+  if (number > 10000)
+    return E_FAIL;
+  if (number < minNumber)
+    return E_INVALIDARG;
+  number -= minNumber;
+  for(int j = _methods.Size(); j <= (int)number; j++)
+  {
+    COneMethodInfo oneMethodInfo;
+    _methods.Add(oneMethodInfo);
+  }
+  
+  COneMethodInfo &oneMethodInfo = _methods[number];
+  
+  if (realName.Length() == 0)
+  {
+    if (value.vt != VT_BSTR)
+      return E_INVALIDARG;
+    
+    RINOK(SetParams(oneMethodInfo, value.bstrVal));
+  }
+  else
+  {
+    CProp property;
+    if (realName.Left(1).CompareNoCase(L"D") == 0)
+    {
+      UInt32 dicSize;
+      RINOK(ParsePropDictionaryValue(realName.Mid(1), value, dicSize));
+      property.Id = NCoderPropID::kDictionarySize;
+      property.Value = dicSize;
+      oneMethodInfo.Properties.Add(property);
+      if (number <= mainDicMethodIndex)
+        mainDicSize = dicSize;
+    }
+    else if (realName.Left(3).CompareNoCase(L"MEM") == 0)
+    {
+      UInt32 dicSize;
+      RINOK(ParsePropDictionaryValue(realName.Mid(3), value, dicSize));
+      property.Id = NCoderPropID::kUsedMemorySize;
+      property.Value = dicSize;
+      oneMethodInfo.Properties.Add(property);
+      if (number <= mainDicMethodIndex)
+        mainDicSize = dicSize;
+    }
+    else
+    {
+      int index = FindPropIdFromStringName(realName);
+      if (index < 0)
+        return E_INVALIDARG;
+      
+      const CNameToPropID &nameToPropID = g_NameToPropID[index];
+      property.Id = nameToPropID.PropID;
+      
+      if (!ConvertProperty(value, nameToPropID.VarType, property.Value))
+        return E_INVALIDARG;
+      
+      oneMethodInfo.Properties.Add(property);
+    }
+  }
+  return S_OK;
+}  
+
+}
diff --git a/lzma/CPP/7zip/Archive/Common/HandlerOut.h b/lzma/CPP/7zip/Archive/Common/HandlerOut.h
new file mode 100644 (file)
index 0000000..ab925cc
--- /dev/null
@@ -0,0 +1,86 @@
+// HandlerOut.h
+
+#ifndef __HANDLER_OUT_H
+#define __HANDLER_OUT_H
+
+#include "../../Common/MethodProps.h"
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+
+struct COneMethodInfo
+{
+  CObjectVector<CProp> Properties;
+  UString MethodName;
+};
+
+class COutHandler
+{
+public:
+  HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+  
+  HRESULT SetSolidSettings(const UString &s);
+  HRESULT SetSolidSettings(const PROPVARIANT &value);
+
+  #ifdef COMPRESS_MT
+  UInt32 _numThreads;
+  #endif
+
+  UInt32 _crcSize;
+
+  CObjectVector<COneMethodInfo> _methods;
+  bool _removeSfxBlock;
+  
+  UInt64 _numSolidFiles; 
+  UInt64 _numSolidBytes;
+  bool _numSolidBytesDefined;
+  bool _solidExtension;
+
+  bool _compressHeaders;
+  bool _encryptHeaders;
+
+  bool WriteModified;
+  bool WriteCreated;
+  bool WriteAccessed;
+
+  bool _autoFilter;
+  UInt32 _level;
+
+  bool _volumeMode;
+
+  HRESULT SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value);
+  HRESULT SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString);
+
+  void SetCompressionMethod2(COneMethodInfo &oneMethodInfo
+      #ifdef COMPRESS_MT
+      , UInt32 numThreads
+      #endif
+      );
+
+  void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
+  void InitSolidSize()  { _numSolidBytes = (UInt64)(Int64)(-1); }
+  void InitSolid()
+  {
+    InitSolidFiles();
+    InitSolidSize();
+    _solidExtension = false;
+    _numSolidBytesDefined = false;
+  }
+
+  void Init();
+
+  COutHandler() { Init(); }
+
+  void BeforeSetProperty();
+
+  UInt32 minNumber;
+  UInt32 numProcessors;
+  UInt32 mainDicSize;
+  UInt32 mainDicMethodIndex;
+
+  DECL_EXTERNAL_CODECS_VARS
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
new file mode 100644 (file)
index 0000000..1d9e555
--- /dev/null
@@ -0,0 +1,40 @@
+// InStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "InStreamWithCRC.h"
+
+STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result = _stream->Read(data, size, &realProcessedSize);
+  _size += realProcessedSize;
+  if (size > 0 && realProcessedSize == 0)
+    _wasFinished = true;
+  _crc = CrcUpdate(_crc, data, realProcessedSize);
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return result;
+}
+
+STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result = _stream->Read(data, size, &realProcessedSize);
+  if (size > 0 && realProcessedSize == 0)
+    _wasFinished = true;
+  _size += realProcessedSize;
+  _crc = CrcUpdate(_crc, data, realProcessedSize);
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return result;
+}
+
+STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+  if (seekOrigin != STREAM_SEEK_SET || offset != 0)
+    return E_FAIL;
+  _size = 0;
+  _crc = CRC_INIT_VAL;
+  return _stream->Seek(offset, seekOrigin, newPosition);
+}
diff --git a/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.h b/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.h
new file mode 100644 (file)
index 0000000..96bea9b
--- /dev/null
@@ -0,0 +1,69 @@
+// InStreamWithCRC.h
+
+#ifndef __INSTREAMWITHCRC_H
+#define __INSTREAMWITHCRC_H
+
+#include "../../../Common/MyCom.h"
+#include "../../IStream.h"
+
+extern "C" 
+{ 
+#include "../../../../C/7zCrc.h"
+}
+
+class CSequentialInStreamWithCRC: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+private:
+  CMyComPtr<ISequentialInStream> _stream;
+  UInt64 _size;
+  UInt32 _crc;
+  bool _wasFinished;
+public:
+  void SetStream(ISequentialInStream *stream) { _stream = stream;  }
+  void Init()
+  {
+    _size = 0;
+    _wasFinished = false;
+    _crc = CRC_INIT_VAL;
+  }
+  void ReleaseStream() { _stream.Release(); }
+  UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+  UInt64 GetSize() const { return _size; }
+  bool WasFinished() const { return _wasFinished; }
+};
+
+class CInStreamWithCRC: 
+  public IInStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP1(IInStream)
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+private:
+  CMyComPtr<IInStream> _stream;
+  UInt64 _size;
+  UInt32 _crc;
+  bool _wasFinished;
+public:
+  void SetStream(IInStream *stream) { _stream = stream;  }
+  void Init()
+  {
+    _size = 0;
+    _wasFinished = false;
+    _crc = CRC_INIT_VAL;
+  }
+  void ReleaseStream() { _stream.Release(); }
+  UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+  UInt64 GetSize() const { return _size; }
+  bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/lzma/CPP/7zip/Archive/Common/ItemNameUtils.cpp
new file mode 100644 (file)
index 0000000..f7c3fcd
--- /dev/null
@@ -0,0 +1,59 @@
+// Archive/Common/ItemNameUtils.cpp
+
+#include "StdAfx.h"
+
+#include "ItemNameUtils.h"
+
+namespace NArchive {
+namespace NItemName {
+
+static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR;
+static const wchar_t kDirDelimiter = L'/';
+
+UString MakeLegalName(const UString &name)
+{
+  UString zipName = name;
+  zipName.Replace(kOSDirDelimiter, kDirDelimiter);
+  return zipName;
+}
+
+UString GetOSName(const UString &name)
+{
+  UString newName = name;
+  newName.Replace(kDirDelimiter, kOSDirDelimiter);
+  return newName;
+}
+
+UString GetOSName2(const UString &name)
+{
+  if (name.IsEmpty())
+    return UString();
+  UString newName = GetOSName(name);
+  if (newName[newName.Length() - 1] == kOSDirDelimiter)
+    newName.Delete(newName.Length() - 1);
+  return newName;
+}
+
+bool HasTailSlash(const AString &name, UINT codePage)
+{
+  if (name.IsEmpty())
+    return false;
+  LPCSTR prev = 
+  #ifdef _WIN32
+    CharPrevExA((WORD)codePage, name, &name[name.Length()], 0);
+  #else
+    (LPCSTR)(name) + (name.Length() - 1);
+  #endif
+  return (*prev == '/');
+}
+
+#ifndef _WIN32
+UString WinNameToOSName(const UString &name)
+{
+  UString newName = name;
+  newName.Replace(L'\\', kOSDirDelimiter);
+  return newName;
+}
+#endif
+
+}}
diff --git a/lzma/CPP/7zip/Archive/Common/ItemNameUtils.h b/lzma/CPP/7zip/Archive/Common/ItemNameUtils.h
new file mode 100644 (file)
index 0000000..5eafacb
--- /dev/null
@@ -0,0 +1,24 @@
+// Archive/Common/ItemNameUtils.h
+
+#ifndef __ARCHIVE_ITEMNAMEUTILS_H
+#define __ARCHIVE_ITEMNAMEUTILS_H
+
+#include "../../../Common/MyString.h"
+
+namespace NArchive {
+namespace NItemName {
+
+  UString MakeLegalName(const UString &name);
+  UString GetOSName(const UString &name);
+  UString GetOSName2(const UString &name);
+  bool HasTailSlash(const AString &name, UINT codePage);
+
+  #ifdef _WIN32
+  inline UString WinNameToOSName(const UString &name)  { return name; }
+  #else
+  UString WinNameToOSName(const UString &name);
+  #endif
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/MultiStream.cpp b/lzma/CPP/7zip/Archive/Common/MultiStream.cpp
new file mode 100644 (file)
index 0000000..a8cb333
--- /dev/null
@@ -0,0 +1,201 @@
+// MultiStream.cpp
+
+#include "StdAfx.h"
+
+#include "MultiStream.h"
+
+STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  if(processedSize != NULL)
+    *processedSize = 0;
+  while(_streamIndex < Streams.Size() && size > 0)
+  {
+    CSubStreamInfo &s = Streams[_streamIndex];
+    if (_pos == s.Size)
+    {
+      _streamIndex++;
+      _pos = 0;
+      continue;
+    }
+    RINOK(s.Stream->Seek(s.Pos + _pos, STREAM_SEEK_SET, 0));
+    UInt32 sizeToRead = UInt32(MyMin((UInt64)size, s.Size - _pos));
+    UInt32 realProcessed;
+    HRESULT result = s.Stream->Read(data, sizeToRead, &realProcessed);
+    data = (void *)((Byte *)data + realProcessed);
+    size -= realProcessed;
+    if(processedSize != NULL)
+      *processedSize += realProcessed;
+    _pos += realProcessed;
+    _seekPos += realProcessed;
+    RINOK(result);
+    break;
+  }
+  return S_OK;
+}
+  
+STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, 
+    UInt64 *newPosition)
+{
+  UInt64 newPos;
+  switch(seekOrigin)
+  {
+    case STREAM_SEEK_SET:
+      newPos = offset;
+      break;
+    case STREAM_SEEK_CUR:
+      newPos = _seekPos + offset;
+      break;
+    case STREAM_SEEK_END:
+      newPos = _totalLength + offset;
+      break;
+    default:
+      return STG_E_INVALIDFUNCTION;
+  }
+  _seekPos = 0;
+  for (_streamIndex = 0; _streamIndex < Streams.Size(); _streamIndex++)
+  {
+    UInt64 size = Streams[_streamIndex].Size;
+    if (newPos < _seekPos + size)
+    {
+      _pos = newPos - _seekPos;
+      _seekPos += _pos;
+      if (newPosition != 0)
+        *newPosition = newPos;
+      return S_OK;
+    }
+    _seekPos += size;
+  }
+  if (newPos == _seekPos)
+  {
+    if (newPosition != 0)
+      *newPosition = newPos;
+    return S_OK;
+  }
+  return E_FAIL;
+}
+
+
+/*
+class COutVolumeStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  int _volIndex;
+  UInt64 _volSize;
+  UInt64 _curPos;
+  CMyComPtr<ISequentialOutStream> _volumeStream;
+  COutArchive _archive;
+  CCRC _crc;
+
+public:
+  MY_UNKNOWN_IMP
+
+  CFileItem _file;
+  CUpdateOptions _options;
+  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+  void Init(IArchiveUpdateCallback2 *volumeCallback, 
+      const UString &name)  
+  { 
+    _file.Name = name;
+    _file.IsStartPosDefined = true;
+    _file.StartPos = 0;
+    
+    VolumeCallback = volumeCallback;
+    _volIndex = 0;
+    _volSize = 0;
+  }
+  
+  HRESULT Flush();
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT COutVolumeStream::Flush()
+{
+  if (_volumeStream)
+  {
+    _file.UnPackSize = _curPos;
+    _file.FileCRC = _crc.GetDigest();
+    RINOK(WriteVolumeHeader(_archive, _file, _options));
+    _archive.Close();
+    _volumeStream.Release();
+    _file.StartPos += _file.UnPackSize;
+  }
+  return S_OK;
+}
+*/
+
+/*
+STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if(processedSize != NULL)
+    *processedSize = 0;
+  while(size > 0)
+  {
+    if (_streamIndex >= Streams.Size())
+    {
+      CSubStreamInfo subStream;
+      RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));
+      RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));
+      subStream.Pos = 0;
+      Streams.Add(subStream);
+      continue;
+    }
+    CSubStreamInfo &subStream = Streams[_streamIndex];
+    if (_offsetPos >= subStream.Size)
+    {
+      _offsetPos -= subStream.Size;
+      _streamIndex++;
+      continue;
+    }
+    if (_offsetPos != subStream.Pos)
+    {
+      CMyComPtr<IOutStream> outStream;
+      RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+      RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+      subStream.Pos = _offsetPos;
+    }
+
+    UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
+    UInt32 realProcessed;
+    RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+    data = (void *)((Byte *)data + realProcessed);
+    size -= realProcessed;
+    subStream.Pos += realProcessed;
+    _offsetPos += realProcessed;
+    _absPos += realProcessed;
+    if (_absPos > _length)
+      _length = _absPos;
+    if(processedSize != NULL)
+      *processedSize += realProcessed;
+    if (subStream.Pos == subStream.Size)
+    {
+      _streamIndex++;
+      _offsetPos = 0;
+    }
+    if (realProcessed != curSize && realProcessed == 0)
+      return E_FAIL;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+  if(seekOrigin >= 3)
+    return STG_E_INVALIDFUNCTION;
+  switch(seekOrigin)
+  {
+    case STREAM_SEEK_SET:
+      _absPos = offset;
+      break;
+    case STREAM_SEEK_CUR:
+      _absPos += offset;
+      break;
+    case STREAM_SEEK_END:
+      _absPos = _length + offset;
+      break;
+  }
+  _offsetPos = _absPos;
+  _streamIndex = 0;
+  return S_OK;
+}
+*/
diff --git a/lzma/CPP/7zip/Archive/Common/MultiStream.h b/lzma/CPP/7zip/Archive/Common/MultiStream.h
new file mode 100644 (file)
index 0000000..b0fe41d
--- /dev/null
@@ -0,0 +1,76 @@
+// MultiStream.h
+
+#ifndef __MULTISTREAM_H
+#define __MULTISTREAM_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+#include "../../Archive/IArchive.h"
+
+class CMultiStream: 
+  public IInStream,
+  public CMyUnknownImp
+{
+  int _streamIndex;
+  UInt64 _pos;
+  UInt64 _seekPos;
+  UInt64 _totalLength;
+public:
+  struct CSubStreamInfo
+  {
+    CMyComPtr<IInStream> Stream;
+    UInt64 Pos;
+    UInt64 Size;
+  };
+  CObjectVector<CSubStreamInfo> Streams;
+  void Init()
+  {
+    _streamIndex = 0;
+    _pos = 0;
+    _seekPos = 0;
+    _totalLength = 0;
+    for (int i = 0; i < Streams.Size(); i++)
+      _totalLength += Streams[i].Size;
+  }
+
+  MY_UNKNOWN_IMP1(IInStream)
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+/*
+class COutMultiStream: 
+  public IOutStream,
+  public CMyUnknownImp
+{
+  int _streamIndex; // required stream
+  UInt64 _offsetPos; // offset from start of _streamIndex index
+  UInt64 _absPos;
+  UInt64 _length;
+
+  struct CSubStreamInfo
+  {
+    CMyComPtr<ISequentialOutStream> Stream;
+    UInt64 Size;
+    UInt64 Pos;
+ };
+  CObjectVector<CSubStreamInfo> Streams;
+public:
+  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+  void Init()
+  {
+    _streamIndex = 0;
+    _offsetPos = 0;
+    _absPos = 0;
+    _length = 0;
+  }
+
+  MY_UNKNOWN_IMP1(IOutStream)
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+*/
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
new file mode 100644 (file)
index 0000000..2ab2da6
--- /dev/null
@@ -0,0 +1,24 @@
+// OutStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithCRC.h"
+
+STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result;
+  if(!_stream)
+  {
+    realProcessedSize = size;
+    result = S_OK;
+  }
+  else
+    result = _stream->Write(data, size, &realProcessedSize);
+  if (_calculate)
+    _crc = CrcUpdate(_crc, data, realProcessedSize);
+  _size += realProcessedSize;
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return result;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.h
new file mode 100644 (file)
index 0000000..eaeecde
--- /dev/null
@@ -0,0 +1,38 @@
+// OutStreamWithCRC.h
+
+#ifndef __OUTSTREAMWITHCRC_H
+#define __OUTSTREAMWITHCRC_H
+
+#include "../../../Common/MyCom.h"
+#include "../../IStream.h"
+
+extern "C" 
+{ 
+#include "../../../../C/7zCrc.h"
+}
+
+class COutStreamWithCRC: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt64 _size;
+  UInt32 _crc;
+  bool _calculate;
+public:
+  MY_UNKNOWN_IMP
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+  void ReleaseStream() { _stream.Release(); }
+  void Init(bool calculate = true)
+  {
+    _size = 0;
+    _calculate = calculate;
+    _crc = CRC_INIT_VAL;
+  }
+  void InitCRC() { _crc = CRC_INIT_VAL; }
+  UInt64 GetSize() const { return _size; }
+  UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/ParseProperties.cpp b/lzma/CPP/7zip/Archive/Common/ParseProperties.cpp
new file mode 100644 (file)
index 0000000..f0d4e29
--- /dev/null
@@ -0,0 +1,174 @@
+// ParseProperties.cpp
+
+#include "StdAfx.h"
+
+#include "ParseProperties.h"
+
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+  if (prop.vt == VT_UI4)
+  {
+    if (!name.IsEmpty())
+      return E_INVALIDARG;
+    resValue = prop.ulVal;
+  }
+  else if (prop.vt == VT_EMPTY)
+  {
+    if(!name.IsEmpty())
+    {
+      const wchar_t *start = name;
+      const wchar_t *end;
+      UInt64 v = ConvertStringToUInt64(start, &end);
+      if (end - start != name.Length())
+        return E_INVALIDARG;
+      resValue = (UInt32)v;
+    }
+  }
+  else
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+static const int kLogarithmicSizeLimit = 32;
+static const wchar_t kByteSymbol = L'B';
+static const wchar_t kKiloByteSymbol = L'K';
+static const wchar_t kMegaByteSymbol = L'M';
+
+HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize)
+{
+  UString srcString = srcStringSpec;
+  srcString.MakeUpper();
+
+  const wchar_t *start = srcString;
+  const wchar_t *end;
+  UInt64 number = ConvertStringToUInt64(start, &end);
+  int numDigits = (int)(end - start);
+  if (numDigits == 0 || srcString.Length() > numDigits + 1)
+    return E_INVALIDARG;
+  if (srcString.Length() == numDigits)
+  {
+    if (number >= kLogarithmicSizeLimit)
+      return E_INVALIDARG;
+    dicSize = (UInt32)1 << (int)number;
+    return S_OK;
+  }
+  switch (srcString[numDigits])
+  {
+    case kByteSymbol:
+      if (number >= ((UInt64)1 << kLogarithmicSizeLimit))
+        return E_INVALIDARG;
+      dicSize = (UInt32)number;
+      break;
+    case kKiloByteSymbol:
+      if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 10)))
+        return E_INVALIDARG;
+      dicSize = (UInt32)(number << 10);
+      break;
+    case kMegaByteSymbol:
+      if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 20)))
+        return E_INVALIDARG;
+      dicSize = (UInt32)(number << 20);
+      break;
+    default:
+      return E_INVALIDARG;
+  }
+  return S_OK;
+}
+
+HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+  if (name.IsEmpty())
+  {
+    if (prop.vt == VT_UI4)
+    {
+      UInt32 logDicSize = prop.ulVal;
+      if (logDicSize >= 32)
+        return E_INVALIDARG;
+      resValue = (UInt32)1 << logDicSize;
+      return S_OK;
+    }
+    if (prop.vt == VT_BSTR)
+      return ParsePropDictionaryValue(prop.bstrVal, resValue);
+    return E_INVALIDARG;
+  }
+  return ParsePropDictionaryValue(name, resValue);
+}
+
+bool StringToBool(const UString &s, bool &res)
+{
+  if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0)
+  {
+    res = true;
+    return true;
+  }
+  if (s.CompareNoCase(L"OFF") == 0)
+  {
+    res = false;
+    return true;
+  }
+  return false;
+}
+
+HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value)
+{
+  switch(value.vt)
+  {
+    case VT_EMPTY:
+      dest = true;
+      return S_OK;
+    /*
+    case VT_UI4:
+      dest = (value.ulVal != 0);
+      break;
+    */
+    case VT_BSTR:
+      return StringToBool(value.bstrVal, dest) ?  S_OK : E_INVALIDARG;
+  }
+  return E_INVALIDARG;
+}
+
+int ParseStringToUInt32(const UString &srcString, UInt32 &number)
+{
+  const wchar_t *start = srcString;
+  const wchar_t *end;
+  UInt64 number64 = ConvertStringToUInt64(start, &end);
+  if (number64 > 0xFFFFFFFF) 
+  {
+    number = 0;
+    return 0;
+  }
+  number = (UInt32)number64;
+  return (int)(end - start);
+}
+
+HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
+{
+  if (name.IsEmpty())
+  {
+    switch(prop.vt)
+    {
+      case VT_UI4:
+        numThreads = prop.ulVal;
+        break;
+      default:
+      {
+        bool val; 
+        RINOK(SetBoolProperty(val, prop));
+        numThreads = (val ? defaultNumThreads : 1);
+        break;
+      }
+    }
+  }
+  else
+  {
+    UInt32 number;
+    int index = ParseStringToUInt32(name, number);
+    if (index != name.Length())
+      return E_INVALIDARG;
+    numThreads = number;
+  }
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/ParseProperties.h b/lzma/CPP/7zip/Archive/Common/ParseProperties.h
new file mode 100644 (file)
index 0000000..6f80f63
--- /dev/null
@@ -0,0 +1,18 @@
+// ParseProperties.h
+
+#ifndef __PARSEPROPERTIES_H
+#define __PARSEPROPERTIES_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize);
+HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+
+bool StringToBool(const UString &s, bool &res);
+HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value);
+int ParseStringToUInt32(const UString &srcString, UInt32 &number);
+HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads);
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/DllExports2.cpp b/lzma/CPP/7zip/Archive/DllExports2.cpp
new file mode 100644 (file)
index 0000000..d3b15f0
--- /dev/null
@@ -0,0 +1,82 @@
+// DLLExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/Types.h"
+#include "../../Windows/PropVariant.h"
+#if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+extern "C" 
+{ 
+#include "../../../C/Alloc.h"
+}
+#endif
+
+#include "IArchive.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+HINSTANCE g_hInstance;
+#ifndef _UNICODE
+#ifdef _WIN32
+bool g_IsNT = false;
+static bool IsItWindowsNT()
+{
+  OSVERSIONINFO versionInfo;
+  versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+  if (!::GetVersionEx(&versionInfo)) 
+    return false;
+  return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+#endif
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+  if (dwReason == DLL_PROCESS_ATTACH)
+  {
+    g_hInstance = hInstance;
+    #ifndef _UNICODE
+    #ifdef _WIN32
+    g_IsNT = IsItWindowsNT();
+    #endif
+    #endif
+  }
+  return TRUE;
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler, 
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec, 
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+  // COM_TRY_BEGIN
+  *outObject = 0;
+  if (*iid == IID_ICompressCoder || *iid == IID_ICompressCoder2 || *iid == IID_ICompressFilter)
+  {
+    return CreateCoder(clsid, iid, outObject);
+  }
+  else
+  {
+    return CreateArchiver(clsid, iid, outObject);
+  }
+  // COM_TRY_END
+}
+
+STDAPI SetLargePageMode()
+{
+  #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+  SetLargePageSize();
+  #endif
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Archive/IArchive.h b/lzma/CPP/7zip/Archive/IArchive.h
new file mode 100644 (file)
index 0000000..e0ae7aa
--- /dev/null
@@ -0,0 +1,207 @@
+// IArchive.h
+
+#ifndef __IARCHIVE_H
+#define __IARCHIVE_H
+
+#include "../IStream.h"
+#include "../IProgress.h"
+#include "../PropID.h"
+
+#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
+#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
+
+namespace NFileTimeType
+{
+  enum EEnum
+  {
+    kWindows,
+    kUnix,
+    kDOS
+  };
+}
+
+namespace NArchive
+{
+  enum 
+  {
+    kName = 0,
+    kClassID,
+    kExtension,
+    kAddExtension,
+    kUpdate,
+    kKeepName,
+    kStartSignature,
+    kFinishSignature,
+    kAssociate
+  };
+
+  namespace NExtract
+  {
+    namespace NAskMode
+    {
+      enum 
+      {
+        kExtract = 0,
+        kTest,
+        kSkip
+      };
+    }
+    namespace NOperationResult
+    {
+      enum 
+      {
+        kOK = 0,
+        kUnSupportedMethod,
+        kDataError,
+        kCRCError
+      };
+    }
+  }
+  namespace NUpdate
+  {
+    namespace NOperationResult
+    {
+      enum 
+      {
+        kOK = 0,
+        kError
+      };
+    }
+  }
+}
+
+ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
+{
+  STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) PURE;
+  STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) PURE;
+};
+
+
+ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
+{
+  STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, 
+      Int32 askExtractMode) PURE;
+  // GetStream OUT: S_OK - OK, S_FALSE - skeep this file
+  STDMETHOD(PrepareOperation)(Int32 askExtractMode) PURE;
+  STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) PURE;
+};
+
+
+ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
+{
+  STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) PURE;
+  STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) PURE;
+};
+
+
+ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
+{
+  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;  
+};
+
+
+ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
+{
+  STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
+};
+
+
+/*
+IInArchive::Extract:
+  indices must be sorted 
+  numItems = 0xFFFFFFFF means "all files"
+  testMode != 0 means "test files without writing to outStream"
+*/
+
+#define INTERFACE_IInArchive(x) \
+  STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) x; \
+  STDMETHOD(Close)() x; \
+  STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \
+  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
+  STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) x; \
+  STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) x; \
+  STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \
+  STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \
+  STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) x; \
+  STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x;
+
+ARCHIVE_INTERFACE(IInArchive, 0x60)
+{
+  INTERFACE_IInArchive(PURE)
+};
+
+
+ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
+{
+  STDMETHOD(GetUpdateItemInfo)(UInt32 index, 
+      Int32 *newData, // 1 - new data, 0 - old data
+      Int32 *newProperties, // 1 - new properties, 0 - old properties
+      UInt32 *indexInArchive // -1 if there is no in archive, or if doesn't matter
+      ) PURE;
+  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;
+  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) PURE;
+  STDMETHOD(SetOperationResult)(Int32 operationResult) PURE;
+};
+
+
+ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
+{
+  STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) PURE;
+  STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) PURE;
+};
+
+
+#define INTERFACE_IOutArchive(x) \
+  STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \
+  STDMETHOD(GetFileTimeType)(UInt32 *type) x;
+
+ARCHIVE_INTERFACE(IOutArchive, 0xA0)
+{
+  INTERFACE_IOutArchive(PURE)
+};
+
+
+ARCHIVE_INTERFACE(ISetProperties, 0x03)
+{
+  STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE;
+};
+
+
+#define IMP_IInArchive_GetProp(k) \
+  (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+    { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+    const STATPROPSTG &srcItem = k[index]; \
+    *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \
+
+#define IMP_IInArchive_GetProp_WITH_NAME(k) \
+  (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+    { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+    const STATPROPSTG &srcItem = k[index]; \
+    *propID = srcItem.propid; *varType = srcItem.vt; \
+    if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \
+
+#define IMP_IInArchive_Props \
+  STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
+    { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+  STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)
+
+#define IMP_IInArchive_Props_WITH_NAME \
+  STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
+    { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+  STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)
+
+
+#define IMP_IInArchive_ArcProps \
+  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+    { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+  STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)
+
+#define IMP_IInArchive_ArcProps_NO \
+  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+    { *numProperties = 0; return S_OK; } \
+  STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
+    { return E_NOTIMPL; } \
+  STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
+    { value->vt = VT_EMPTY; return S_OK; } 
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsp b/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsp
new file mode 100644 (file)
index 0000000..b9f389b
--- /dev/null
@@ -0,0 +1,1453 @@
+# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Alone - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "Alone.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "COMPRESS_MT" /D "_NO_CRYPTO" /D "BREAK_HANDLER" /D "BENCH_MT" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "COMPRESS_MT" /D "_NO_CRYPTO" /D "BREAK_HANDLER" /D "BENCH_MT" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "FORMAT_BZIP2" /D "FORMAT_ZIP" /D "FORMAT_TAR" /D "FORMAT_GZIP" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "COMPRESS_MF_PAT" /D "COMPRESS_MF_BT" /D "COMPRESS_PPMD" /D "COMPRESS_DEFLATE" /D "COMPRESS_IMPLODE" /D "COMPRESS_BZIP2" /D "CRYPTO_ZIP" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "COMPRESS_MT" /D "_NO_CRYPTO" /D "BREAK_HANDLER" /D "BENCH_MT" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "FORMAT_BZIP2" /D "FORMAT_ZIP" /D "FORMAT_TAR" /D "FORMAT_GZIP" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "COMPRESS_MF_PAT" /D "COMPRESS_MF_BT" /D "COMPRESS_PPMD" /D "COMPRESS_DEFLATE" /D "COMPRESS_IMPLODE" /D "COMPRESS_BZIP2" /D "CRYPTO_ZIP" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gz /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "COMPRESS_MT" /D "_NO_CRYPTO" /D "BREAK_HANDLER" /D "BENCH_MT" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "Alone - Win32 Release"
+# Name "Alone - Win32 Debug"
+# Name "Alone - Win32 ReleaseU"
+# Name "Alone - Win32 DebugU"
+# Begin Group "Console"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ArError.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\CompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\Main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\MainAr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UpdateCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.h
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\AutoPtr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyException.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyGuidDef.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Device.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Error.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Error.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConversions.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConversions.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Time.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LSBFDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LSBFDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LSBFEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LSBFEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MSBFDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MSBFEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressMt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterCodec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Group "Branch"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\x86.cpp
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\x86.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\x86_2.cpp
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\x86_2.h
+# End Source File
+# End Group
+# Begin Group "Copy"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Copy\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Copy\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Copy\CopyRegister.cpp
+# End Source File
+# End Group
+# Begin Group "LZ"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\LZ\LZOutWindow.cpp
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O1
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O1
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZ\LZOutWindow.h
+# End Source File
+# End Group
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA\LZMA.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA\LZMADecoder.cpp
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA\LZMADecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA\LZMAEncoder.cpp
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA\LZMAEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA\LZMARegister.cpp
+# End Source File
+# End Group
+# Begin Group "RangeCoder"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoder\RangeCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoder\RangeCoderBit.cpp
+
+!IF  "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O1
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O1
+
+!ELSEIF  "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoder\RangeCoderBit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoder\RangeCoderBitTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoder\RangeCoderOpt.h
+# End Source File
+# End Group
+# Begin Group "LZMA_Alone"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA_Alone\LzmaBench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA_Alone\LzmaBench.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA_Alone\LzmaBenchCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA_Alone\LzmaBenchCon.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "Archive"
+
+# PROP Default_Filter ""
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.h
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2MT.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2MT.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.h
+# End Source File
+# End Group
+# Begin Group "split"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Split\SplitHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Split\SplitHandler.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveCommandLine.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\WorkDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\WorkDir.h
+# End Source File
+# End Group
+# Begin Group "7-zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IMyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Group "C Branch"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchARM.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchARM.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchARMThumb.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchARMThumb.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchIA64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchIA64.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchPPC.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchPPC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchSPARC.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchSPARC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchX86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchX86.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinder.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinderMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinderMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Types.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsw b/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsw
new file mode 100644 (file)
index 0000000..65eca43
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Alone"=.\Alone.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.cpp b/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.h b/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.h
new file mode 100644 (file)
index 0000000..2e4be10
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/makefile b/lzma/CPP/7zip/Bundles/Alone7z/makefile
new file mode 100644 (file)
index 0000000..1feb1fb
--- /dev/null
@@ -0,0 +1,236 @@
+PROG = 7za.exe
+LIBS = $(LIBS) user32.lib oleaut32.lib Advapi32.lib
+
+CFLAGS = $(CFLAGS) -I ../../../ \
+  -D_NO_CRYPTO \
+  -DWIN_LONG_PATH \
+  -DCOMPRESS_MT \
+  -DCOMPRESS_MF_MT \
+  -D_NO_CRYPTO \
+  -DBREAK_HANDLER \
+  -DBENCH_MT \
+
+
+CONSOLE_OBJS = \
+  $O\ConsoleClose.obj \
+  $O\ExtractCallbackConsole.obj \
+  $O\List.obj \
+  $O\Main.obj \
+  $O\MainAr.obj \
+  $O\OpenCallbackConsole.obj \
+  $O\PercentPrinter.obj \
+  $O\UpdateCallbackConsole.obj \
+  $O\UserInputUtils.obj \
+
+COMMON_OBJS = \
+  $O\CommandLineParser.obj \
+  $O\CRC.obj \
+  $O\IntToString.obj \
+  $O\ListFileUtils.obj \
+  $O\NewHandler.obj \
+  $O\StdInStream.obj \
+  $O\StdOutStream.obj \
+  $O\MyString.obj \
+  $O\StringConvert.obj \
+  $O\StringToInt.obj \
+  $O\UTFConvert.obj \
+  $O\MyVector.obj \
+  $O\Wildcard.obj \
+
+WIN_OBJS = \
+  $O\DLL.obj \
+  $O\Error.obj \
+  $O\FileDir.obj \
+  $O\FileFind.obj \
+  $O\FileIO.obj \
+  $O\FileName.obj \
+  $O\MemoryLock.obj \
+  $O\PropVariant.obj \
+  $O\PropVariantConversions.obj \
+  $O\Synchronization.obj \
+  $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+  $O\CreateCoder.obj \
+  $O\FilePathAutoRename.obj \
+  $O\FileStreams.obj \
+  $O\InBuffer.obj \
+  $O\InOutTempBuffer.obj \
+  $O\FilterCoder.obj \
+  $O\LimitedStreams.obj \
+  $O\LockedStream.obj \
+  $O\MethodId.obj \
+  $O\MethodProps.obj \
+  $O\OffsetStream.obj \
+  $O\OutBuffer.obj \
+  $O\ProgressUtils.obj \
+  $O\StreamBinder.obj \
+  $O\StreamObjects.obj \
+  $O\StreamUtils.obj \
+  $O\VirtThread.obj \
+
+UI_COMMON_OBJS = \
+  $O\ArchiveCommandLine.obj \
+  $O\ArchiveExtractCallback.obj \
+  $O\ArchiveOpenCallback.obj \
+  $O\DefaultName.obj \
+  $O\EnumDirItems.obj \
+  $O\Extract.obj \
+  $O\ExtractingFilePath.obj \
+  $O\LoadCodecs.obj \
+  $O\OpenArchive.obj \
+  $O\PropIDUtils.obj \
+  $O\SetProperties.obj \
+  $O\SortUtils.obj \
+  $O\TempFiles.obj \
+  $O\Update.obj \
+  $O\UpdateAction.obj \
+  $O\UpdateCallback.obj \
+  $O\UpdatePair.obj \
+  $O\UpdateProduce.obj \
+  $O\WorkDir.obj \
+
+AR_COMMON_OBJS = \
+  $O\CoderMixer2.obj \
+  $O\CoderMixer2MT.obj \
+  $O\CrossThreadProgress.obj \
+  $O\DummyOutStream.obj \
+  $O\HandlerOut.obj \
+  $O\InStreamWithCRC.obj \
+  $O\ItemNameUtils.obj \
+  $O\MultiStream.obj \
+  $O\OutStreamWithCRC.obj \
+  $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+  $O\7zCompressionMode.obj \
+  $O\7zDecode.obj \
+  $O\7zEncode.obj \
+  $O\7zExtract.obj \
+  $O\7zFolderInStream.obj \
+  $O\7zFolderOutStream.obj \
+  $O\7zHandler.obj \
+  $O\7zHandlerOut.obj \
+  $O\7zHeader.obj \
+  $O\7zIn.obj \
+  $O\7zOut.obj \
+  $O\7zProperties.obj \
+  $O\7zRegister.obj \
+  $O\7zSpecStream.obj \
+  $O\7zUpdate.obj \
+
+
+BRANCH_OPT_OBJS = \
+  $O\BranchCoder.obj \
+  $O\x86.obj \
+  $O\x86_2.obj \
+  $O\ARM.obj \
+  $O\ARMThumb.obj \
+  $O\IA64.obj \
+  $O\PPC.obj \
+  $O\SPARC.obj \
+  $O\BranchRegister.obj \
+  $O\BCJRegister.obj \
+  $O\BCJ2Register.obj \
+
+SWAP_OPT_OBJS = \
+  $O\ByteSwap.obj \
+  $O\ByteSwapRegister.obj \
+
+COPY_OBJS = \
+  $O\CopyCoder.obj \
+  $O\CopyRegister.obj \
+
+LZ_OBJS = \
+  $O\LZOutWindow.obj \
+
+LZMA_OPT_OBJS = \
+  $O\LZMADecoder.obj \
+  $O\LZMAEncoder.obj \
+  $O\LZMARegister.obj \
+
+LZMA_BENCH_OBJS = \
+  $O\LzmaBench.obj \
+  $O\LzmaBenchCon.obj \
+
+C_OBJS = \
+  $O\Alloc.obj \
+  $O\7zCrc.obj \
+  $O\Sort.obj \
+  $O\Threads.obj \
+
+C_LZ_OBJS = \
+  $O\MatchFinder.obj \
+  $O\MatchFinderMt.obj \
+
+C_BRANCH_OBJS = \
+  $O\BranchARM.obj \
+  $O\BranchARMThumb.obj \
+  $O\BranchIA64.obj \
+  $O\BranchPPC.obj \
+  $O\BranchSPARC.obj \
+  $O\BranchX86.obj \
+
+OBJS = \
+  $O\StdAfx.obj \
+  $(CONSOLE_OBJS) \
+  $(COMMON_OBJS) \
+  $(WIN_OBJS) \
+  $(7ZIP_COMMON_OBJS) \
+  $(UI_COMMON_OBJS) \
+  $(AR_COMMON_OBJS) \
+  $(7Z_OBJS) \
+  $(BRANCH_OPT_OBJS) \
+  $(SWAP_OPT_OBJS) \
+  $(COPY_OBJS) \
+  $(LZ_OBJS) \
+  $(LZMA_OPT_OBJS) \
+  $(LZMA_BENCH_OBJS) \
+  $(C_OBJS) \
+  $(C_LZ_OBJS) \
+  $(C_BRANCH_OBJS) \
+  $O\RangeCoderBit.obj \
+  $(CRC_OBJS) \
+  $O\resource.res
+
+
+!include "../../../Build.mak"
+
+$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp
+       $(COMPL)
+
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+       $(COMPL)
+$(WIN_OBJS): ../../../Windows/$(*B).cpp
+       $(COMPL)
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+       $(COMPL)
+$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp
+       $(COMPL)
+$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
+       $(COMPL)
+
+$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
+       $(COMPL)
+$(BRANCH_OPT_OBJS): ../../Compress/Branch/$(*B).cpp
+       $(COMPL_O2)
+$(SWAP_OPT_OBJS): ../../Compress/ByteSwap/$(*B).cpp
+       $(COMPL_O2)
+$(COPY_OBJS): ../../Compress/Copy/$(*B).cpp
+       $(COMPL)
+$(LZ_OBJS): ../../Compress/LZ/$(*B).cpp
+       $(COMPL)
+$(LZMA_OPT_OBJS): ../../Compress/LZMA/$(*B).cpp
+       $(COMPL_O2)
+$(LZMA_BENCH_OBJS): ../../Compress/LZMA_Alone/$(*B).cpp
+       $(COMPL)
+$O\RangeCoderBit.obj: ../../Compress/RangeCoder/$(*B).cpp
+       $(COMPL)
+
+$(C_OBJS): ../../../../C/$(*B).c
+       $(COMPL_O2)
+$(C_LZ_OBJS): ../../../../C/Compress/Lz/$(*B).c
+       $(COMPL_O2)
+$(C_BRANCH_OBJS): ../../../../C/Compress/Branch/$(*B).c
+       $(COMPL_O2)
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/resource.rc b/lzma/CPP/7zip/Bundles/Alone7z/resource.rc
new file mode 100644 (file)
index 0000000..fc9063c
--- /dev/null
@@ -0,0 +1,3 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7-Zip Standalone Console", "7za")
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp b/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h b/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
new file mode 100644 (file)
index 0000000..2e4be10
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/makefile b/lzma/CPP/7zip/Bundles/Format7zExtractR/makefile
new file mode 100644 (file)
index 0000000..0632e71
--- /dev/null
@@ -0,0 +1,165 @@
+PROG = 7zxr.dll
+DEF_FILE = ../../Archive/Archive2.def
+LIBS = $(LIBS) user32.lib oleaut32.lib
+CFLAGS = $(CFLAGS) -I ../../../ \
+  -DEXTRACT_ONLY \
+  -DCOMPRESS_MT \
+  -D_NO_CRYPTO
+
+COMMON_OBJS = \
+  $O\CRC.obj \
+  $O\IntToString.obj \
+  $O\NewHandler.obj \
+  $O\MyString.obj \
+  $O\StringConvert.obj \
+  $O\StringToInt.obj \
+  $O\MyVector.obj \
+  $O\Wildcard.obj \
+
+WIN_OBJS = \
+  $O\FileDir.obj \
+  $O\FileFind.obj \
+  $O\FileIO.obj \
+  $O\PropVariant.obj \
+  $O\Synchronization.obj \
+  $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+  $O\CreateCoder.obj \
+  $O\InBuffer.obj \
+  $O\InOutTempBuffer.obj \
+  $O\FilterCoder.obj \
+  $O\LimitedStreams.obj \
+  $O\LockedStream.obj \
+  $O\MethodId.obj \
+  $O\MethodProps.obj \
+  $O\OutBuffer.obj \
+  $O\ProgressUtils.obj \
+  $O\StreamBinder.obj \
+  $O\StreamObjects.obj \
+  $O\StreamUtils.obj \
+  $O\VirtThread.obj \
+
+AR_OBJS = \
+  $O\ArchiveExports.obj \
+  $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+  $O\CoderMixer2.obj \
+  $O\CoderMixer2MT.obj \
+  $O\CrossThreadProgress.obj \
+  $O\HandlerOut.obj \
+  $O\ItemNameUtils.obj \
+  $O\OutStreamWithCRC.obj \
+  $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+  $O\7zCompressionMode.obj \
+  $O\7zDecode.obj \
+  $O\7zExtract.obj \
+  $O\7zFolderOutStream.obj \
+  $O\7zHandler.obj \
+  $O\7zHeader.obj \
+  $O\7zIn.obj \
+  $O\7zProperties.obj \
+  $O\7zRegister.obj \
+
+
+COMPRESS_OBJS = \
+  $O\CodecExports.obj \
+
+SWAP_OPT_OBJS = \
+  $O\ByteSwap.obj \
+  $O\ByteSwapRegister.obj \
+
+BRANCH_OPT_OBJS = \
+  $O\BranchCoder.obj \
+  $O\x86.obj \
+  $O\x86_2.obj \
+  $O\ARM.obj \
+  $O\ARMThumb.obj \
+  $O\IA64.obj \
+  $O\PPC.obj \
+  $O\SPARC.obj \
+  $O\BranchRegister.obj \
+  $O\BCJRegister.obj \
+  $O\BCJ2Register.obj \
+
+COPY_OBJS = \
+  $O\CopyCoder.obj \
+  $O\CopyRegister.obj \
+
+LZ_OBJS = \
+  $O\LZOutWindow.obj \
+
+LZMA_OPT_OBJS = \
+  $O\LZMADecoder.obj \
+  $O\LZMARegister.obj \
+
+C_OBJS = \
+  $O\Alloc.obj \
+  $O\7zCrc.obj \
+  $O\Threads.obj \
+
+C_BRANCH_OBJS = \
+  $O\BranchARM.obj \
+  $O\BranchARMThumb.obj \
+  $O\BranchIA64.obj \
+  $O\BranchPPC.obj \
+  $O\BranchSPARC.obj \
+  $O\BranchX86.obj \
+
+OBJS = \
+  $O\StdAfx.obj \
+  $(CONSOLE_OBJS) \
+  $(COMMON_OBJS) \
+  $(WIN_OBJS) \
+  $(7ZIP_COMMON_OBJS) \
+  $(AR_OBJS) \
+  $(AR_COMMON_OBJS) \
+  $(7Z_OBJS) \
+  $(COMPRESS_OBJS) \
+  $(BRANCH_OPT_OBJS) \
+  $(SWAP_OPT_OBJS) \
+  $(COPY_OBJS) \
+  $(LZ_OBJS) \
+  $(LZMA_OPT_OBJS) \
+  $(C_OBJS) \
+  $(C_BRANCH_OBJS) \
+  $O\resource.res
+
+
+!include "../../../Build.mak"
+
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+       $(COMPL)
+$(WIN_OBJS): ../../../Windows/$(*B).cpp
+       $(COMPL)
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+       $(COMPL)
+$(AR_OBJS): ../../Archive/$(*B).cpp
+       $(COMPL)
+$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
+       $(COMPL)
+
+$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
+       $(COMPL)
+
+$(COMPRESS_OBJS): ../../Compress/$(*B).cpp
+       $(COMPL)
+$(BRANCH_OPT_OBJS): ../../Compress/Branch/$(*B).cpp
+       $(COMPL_O2)
+$(SWAP_OPT_OBJS): ../../Compress/ByteSwap/$(*B).cpp
+       $(COMPL_O2)
+$(COPY_OBJS): ../../Compress/Copy/$(*B).cpp
+       $(COMPL)
+$(LZ_OBJS): ../../Compress/LZ/$(*B).cpp
+       $(COMPL)
+$(LZMA_OPT_OBJS): ../../Compress/LZMA/$(*B).cpp
+       $(COMPL_O2)
+
+$(C_OBJS): ../../../../C/$(*B).c
+       $(COMPL_O2)
+$(C_BRANCH_OBJS): ../../../../C/Compress/Branch/$(*B).c
+       $(COMPL_O2)
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/resource.rc b/lzma/CPP/7zip/Bundles/Format7zExtractR/resource.rc
new file mode 100644 (file)
index 0000000..09708cf
--- /dev/null
@@ -0,0 +1,5 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7z Standalone Extracting Plugin", "7zxr")
+
+101  ICON  "../../Archive/7z/7z.ico"
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.cpp b/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.h b/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.h
new file mode 100644 (file)
index 0000000..2e4be10
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/makefile b/lzma/CPP/7zip/Bundles/Format7zR/makefile
new file mode 100644 (file)
index 0000000..6e96a8a
--- /dev/null
@@ -0,0 +1,188 @@
+PROG = 7zra.dll
+DEF_FILE = ../../Archive/Archive2.def
+LIBS = $(LIBS) user32.lib oleaut32.lib
+CFLAGS = $(CFLAGS) -I ../../../ \
+  -DCOMPRESS_MT \
+  -DCOMPRESS_MF_MT \
+  -D_NO_CRYPTO
+
+COMMON_OBJS = \
+  $O\CRC.obj \
+  $O\IntToString.obj \
+  $O\NewHandler.obj \
+  $O\MyString.obj \
+  $O\StringConvert.obj \
+  $O\StringToInt.obj \
+  $O\MyVector.obj \
+  $O\Wildcard.obj \
+
+WIN_OBJS = \
+  $O\FileDir.obj \
+  $O\FileFind.obj \
+  $O\FileIO.obj \
+  $O\PropVariant.obj \
+  $O\Synchronization.obj \
+  $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+  $O\CreateCoder.obj \
+  $O\InBuffer.obj \
+  $O\InOutTempBuffer.obj \
+  $O\FilterCoder.obj \
+  $O\LimitedStreams.obj \
+  $O\LockedStream.obj \
+  $O\MethodId.obj \
+  $O\MethodProps.obj \
+  $O\OutBuffer.obj \
+  $O\ProgressUtils.obj \
+  $O\StreamBinder.obj \
+  $O\StreamObjects.obj \
+  $O\StreamUtils.obj \
+  $O\VirtThread.obj \
+
+AR_OBJS = \
+  $O\ArchiveExports.obj \
+  $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+  $O\CoderMixer2.obj \
+  $O\CoderMixer2MT.obj \
+  $O\CrossThreadProgress.obj \
+  $O\HandlerOut.obj \
+  $O\InStreamWithCRC.obj \
+  $O\ItemNameUtils.obj \
+  $O\OutStreamWithCRC.obj \
+  $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+  $O\7zCompressionMode.obj \
+  $O\7zDecode.obj \
+  $O\7zEncode.obj \
+  $O\7zExtract.obj \
+  $O\7zFolderInStream.obj \
+  $O\7zFolderOutStream.obj \
+  $O\7zHandler.obj \
+  $O\7zHandlerOut.obj \
+  $O\7zHeader.obj \
+  $O\7zIn.obj \
+  $O\7zOut.obj \
+  $O\7zProperties.obj \
+  $O\7zSpecStream.obj \
+  $O\7zUpdate.obj \
+  $O\7zRegister.obj \
+
+
+COMPRESS_OBJS = \
+  $O\CodecExports.obj \
+
+BRANCH_OPT_OBJS = \
+  $O\BranchCoder.obj \
+  $O\x86.obj \
+  $O\x86_2.obj \
+  $O\ARM.obj \
+  $O\ARMThumb.obj \
+  $O\IA64.obj \
+  $O\PPC.obj \
+  $O\SPARC.obj \
+  $O\BranchRegister.obj \
+  $O\BCJRegister.obj \
+  $O\BCJ2Register.obj \
+
+SWAP_OPT_OBJS = \
+  $O\ByteSwap.obj \
+  $O\ByteSwapRegister.obj \
+
+COPY_OBJS = \
+  $O\CopyCoder.obj \
+  $O\CopyRegister.obj \
+
+LZ_OBJS = \
+  $O\LZOutWindow.obj \
+
+LZMA_OPT_OBJS = \
+  $O\LZMADecoder.obj \
+  $O\LZMAEncoder.obj \
+  $O\LZMARegister.obj \
+
+C_OBJS = \
+  $O\Alloc.obj \
+  $O\7zCrc.obj \
+  $O\Sort.obj \
+  $O\Threads.obj \
+
+C_LZ_OBJS = \
+  $O\MatchFinder.obj \
+  $O\MatchFinderMt.obj \
+
+C_BRANCH_OBJS = \
+  $O\BranchARM.obj \
+  $O\BranchARMThumb.obj \
+  $O\BranchIA64.obj \
+  $O\BranchPPC.obj \
+  $O\BranchSPARC.obj \
+  $O\BranchX86.obj \
+
+OBJS = \
+  $O\StdAfx.obj \
+  $(CONSOLE_OBJS) \
+  $(COMMON_OBJS) \
+  $(WIN_OBJS) \
+  $(7ZIP_COMMON_OBJS) \
+  $(AR_OBJS) \
+  $(AR_COMMON_OBJS) \
+  $(7Z_OBJS) \
+  $(BZIP2_OBJS) \
+  $(BZIP2_OPT_OBJS) \
+  $(COMPRESS_OBJS) \
+  $(BRANCH_OPT_OBJS) \
+  $(SWAP_OPT_OBJS) \
+  $(COPY_OBJS) \
+  $(DEFLATE_OPT_OBJS) \
+  $(LZ_OBJS) \
+  $(LZMA_OPT_OBJS) \
+  $(PPMD_OPT_OBJS) \
+  $(C_OBJS) \
+  $(C_LZ_OBJS) \
+  $(C_BRANCH_OBJS) \
+  $O\RangeCoderBit.obj \
+  $O\resource.res
+
+
+!include "../../../Build.mak"
+
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+       $(COMPL)
+$(WIN_OBJS): ../../../Windows/$(*B).cpp
+       $(COMPL)
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+       $(COMPL)
+$(AR_OBJS): ../../Archive/$(*B).cpp
+       $(COMPL)
+$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
+       $(COMPL)
+
+$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
+       $(COMPL)
+
+$(COMPRESS_OBJS): ../../Compress/$(*B).cpp
+       $(COMPL)
+$(BRANCH_OPT_OBJS): ../../Compress/Branch/$(*B).cpp
+       $(COMPL_O2)
+$(SWAP_OPT_OBJS): ../../Compress/ByteSwap/$(*B).cpp
+       $(COMPL_O2)
+$(COPY_OBJS): ../../Compress/Copy/$(*B).cpp
+       $(COMPL)
+$(LZ_OBJS): ../../Compress/LZ/$(*B).cpp
+       $(COMPL)
+$(LZMA_OPT_OBJS): ../../Compress/LZMA/$(*B).cpp
+       $(COMPL_O2)
+$O\RangeCoderBit.obj: ../../Compress/RangeCoder/$(*B).cpp
+       $(COMPL)
+
+$(C_OBJS): ../../../../C/$(*B).c
+       $(COMPL_O2)
+$(C_LZ_OBJS): ../../../../C/Compress/Lz/$(*B).c
+       $(COMPL_O2)
+$(C_BRANCH_OBJS): ../../../../C/Compress/Branch/$(*B).c
+       $(COMPL_O2)
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/resource.rc b/lzma/CPP/7zip/Bundles/Format7zR/resource.rc
new file mode 100644 (file)
index 0000000..60a17fe
--- /dev/null
@@ -0,0 +1,5 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7z Standalone Plugin", "7zr")
+
+101  ICON  "../../Archive/7z/7z.ico"
diff --git a/lzma/CPP/7zip/Common/CreateCoder.cpp b/lzma/CPP/7zip/Common/CreateCoder.cpp
new file mode 100644 (file)
index 0000000..ae0f98f
--- /dev/null
@@ -0,0 +1,292 @@
+// CreateCoder.cpp
+
+#include "StdAfx.h"
+
+#include "CreateCoder.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/Defs.h"
+#include "FilterCoder.h"
+#include "RegisterCodec.h"
+
+static const unsigned int kNumCodecsMax = 64;
+unsigned int g_NumCodecs = 0;
+const CCodecInfo *g_Codecs[kNumCodecsMax]; 
+void RegisterCodec(const CCodecInfo *codecInfo) 
+{ 
+  if (g_NumCodecs < kNumCodecsMax)
+    g_Codecs[g_NumCodecs++] = codecInfo; 
+}
+
+#ifdef EXTERNAL_CODECS
+static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
+{
+  NWindows::NCOM::CPropVariant prop;
+  RINOK(codecsInfo->GetProperty(index, propID, &prop));
+  if (prop.vt == VT_EMPTY)
+    res = 1;
+  else if (prop.vt == VT_UI4)
+    res = prop.ulVal;
+  else
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
+{
+  NWindows::NCOM::CPropVariant prop;
+  RINOK(codecsInfo->GetProperty(index, propID, &prop));
+  if (prop.vt == VT_EMPTY)
+    res = true;
+  else if (prop.vt == VT_BOOL)
+    res = VARIANT_BOOLToBool(prop.boolVal);
+  else
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs)
+{
+  UInt32 num;
+  RINOK(codecsInfo->GetNumberOfMethods(&num));
+  for (UInt32 i = 0; i < num; i++)
+  {
+    CCodecInfoEx info;
+    NWindows::NCOM::CPropVariant prop;
+    RINOK(codecsInfo->GetProperty(i, NMethodPropID::kID, &prop));
+    // if (prop.vt != VT_BSTR)
+    // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);
+    // memmove(info.Id.ID, prop.bstrVal, info.Id.IDSize);
+    if (prop.vt != VT_UI8)
+    {
+      continue; // old Interface 
+      // return E_INVALIDARG;
+    }
+    info.Id = prop.uhVal.QuadPart;
+    prop.Clear();
+    
+    RINOK(codecsInfo->GetProperty(i, NMethodPropID::kName, &prop));
+    if (prop.vt == VT_BSTR)
+      info.Name = prop.bstrVal;
+    else if (prop.vt != VT_EMPTY)
+      return E_INVALIDARG;;
+    
+    RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kInStreams, info.NumInStreams));
+    RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kOutStreams, info.NumOutStreams));
+    RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
+    RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
+    
+    externalCodecs.Add(info);
+  }
+  return S_OK;
+}
+
+#endif
+
+bool FindMethod(
+  #ifdef EXTERNAL_CODECS
+  ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
+  #endif
+  const UString &name,
+  CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
+{
+  UInt32 i;
+  for (i = 0; i < g_NumCodecs; i++)
+  {
+    const CCodecInfo &codec = *g_Codecs[i]; 
+    if (name.CompareNoCase(codec.Name) == 0)
+    {
+      methodId = codec.Id;
+      numInStreams = codec.NumInStreams;
+      numOutStreams = 1;
+      return true;
+    }
+  }
+  #ifdef EXTERNAL_CODECS
+  if (externalCodecs)
+    for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+    {
+      const CCodecInfoEx &codec = (*externalCodecs)[i]; 
+      if (codec.Name.CompareNoCase(name) == 0)
+      {
+        methodId = codec.Id;
+        numInStreams = codec.NumInStreams;
+        numOutStreams = codec.NumOutStreams;
+        return true;
+      }
+    }
+  #endif
+  return false;
+}
+
+bool FindMethod(
+  #ifdef EXTERNAL_CODECS
+  ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
+  #endif
+  CMethodId methodId, UString &name)
+{
+  UInt32 i;
+  for (i = 0; i < g_NumCodecs; i++)
+  {
+    const CCodecInfo &codec = *g_Codecs[i]; 
+    if (methodId == codec.Id)
+    {
+      name = codec.Name;
+      return true;
+    }
+  }
+  #ifdef EXTERNAL_CODECS
+  if (externalCodecs)
+    for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+    {
+      const CCodecInfoEx &codec = (*externalCodecs)[i]; 
+      if (methodId == codec.Id)
+      {
+        name = codec.Name;
+        return true;
+      }
+    }
+  #endif
+  return false;
+}
+
+HRESULT CreateCoder(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressFilter> &filter,
+  CMyComPtr<ICompressCoder> &coder,
+  CMyComPtr<ICompressCoder2> &coder2,
+  bool encode, bool onlyCoder)
+{
+  bool created = false;
+  UInt32 i;
+  for (i = 0; i < g_NumCodecs; i++)
+  {
+    const CCodecInfo &codec = *g_Codecs[i]; 
+    if (codec.Id == methodId)
+    {
+      if (encode)
+      {
+        if (codec.CreateEncoder)
+        {
+          void *p = codec.CreateEncoder();
+          if (codec.IsFilter) filter = (ICompressFilter *)p;
+          else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+          else coder2 = (ICompressCoder2 *)p;
+          created = (p != 0);
+          break;
+        }
+      }
+      else
+        if (codec.CreateDecoder)
+        {
+          void *p = codec.CreateDecoder();
+          if (codec.IsFilter) filter = (ICompressFilter *)p;
+          else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+          else coder2 = (ICompressCoder2 *)p;
+          created = (p != 0);
+          break;
+        }
+    }
+  }
+
+  #ifdef EXTERNAL_CODECS
+  if (!created && externalCodecs)
+    for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+    {
+      const CCodecInfoEx &codec = (*externalCodecs)[i]; 
+      if (codec.Id == methodId)
+      {
+        if (encode)
+        {
+          if (codec.EncoderIsAssigned)
+          {
+            if (codec.IsSimpleCodec())
+            {
+              HRESULT result = codecsInfo->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);
+              if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) 
+                return result;
+              if (!coder)
+              {
+                RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));
+              }
+            }
+            else
+            {
+              RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));
+            }
+            break;
+          }
+        }
+        else
+          if (codec.DecoderIsAssigned)
+          {
+            if (codec.IsSimpleCodec())
+            {
+              HRESULT result = codecsInfo->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);
+              if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) 
+                return result;
+              if (!coder)
+              {
+                RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));
+              }
+            }
+            else
+            {
+              RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));
+            }
+            break;
+          }
+      }
+    }
+  #endif
+
+  if (onlyCoder && filter)
+  {
+    CFilterCoder *coderSpec = new CFilterCoder;
+    coder = coderSpec;
+    coderSpec->Filter = filter;
+  }
+  return S_OK;
+}
+
+HRESULT CreateCoder(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressCoder> &coder, 
+  CMyComPtr<ICompressCoder2> &coder2,
+  bool encode)
+{
+  CMyComPtr<ICompressFilter> filter;
+  return CreateCoder(
+    EXTERNAL_CODECS_LOC_VARS
+    methodId,
+    filter, coder, coder2, encode, true);
+}
+
+HRESULT CreateCoder(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressCoder> &coder, bool encode)
+{
+  CMyComPtr<ICompressFilter> filter;
+  CMyComPtr<ICompressCoder2> coder2;
+  return CreateCoder(
+    EXTERNAL_CODECS_LOC_VARS
+    methodId,
+    coder, coder2, encode);
+}
+
+HRESULT CreateFilter(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressFilter> &filter,
+  bool encode)
+{
+  CMyComPtr<ICompressCoder> coder;
+  CMyComPtr<ICompressCoder2> coder2;
+  return CreateCoder(
+    EXTERNAL_CODECS_LOC_VARS
+    methodId,
+    filter, coder, coder2, encode, false);
+}
diff --git a/lzma/CPP/7zip/Common/CreateCoder.h b/lzma/CPP/7zip/Common/CreateCoder.h
new file mode 100644 (file)
index 0000000..4d86ae7
--- /dev/null
@@ -0,0 +1,98 @@
+// CreateCoder.h
+
+#ifndef __CREATECODER_H
+#define __CREATECODER_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+#include "../ICoder.h"
+
+#include "MethodId.h"
+
+#ifdef EXTERNAL_CODECS
+
+struct CCodecInfoEx
+{
+  UString Name;
+  CMethodId Id;
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+  bool EncoderIsAssigned;
+  bool DecoderIsAssigned;
+  bool IsSimpleCodec() const { return NumOutStreams == 1 && NumInStreams == 1; }
+  CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {}
+};
+
+HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs);
+
+#define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo,
+#define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo)
+#define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo);
+#define IMPL_ISetCompressCodecsInfo2(x) \
+STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \
+  COM_TRY_BEGIN _codecsInfo = compressCodecsInfo;  return LoadExternalCodecs(_codecsInfo, _externalCodecs); COM_TRY_END }
+#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
+
+#define EXTERNAL_CODECS_VARS2 _codecsInfo, &_externalCodecs
+
+#define DECL_EXTERNAL_CODECS_VARS CMyComPtr<ICompressCodecsInfo> _codecsInfo; CObjectVector<CCodecInfoEx> _externalCodecs;
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS2 ICompressCodecsInfo *codecsInfo, const CObjectVector<CCodecInfoEx> *externalCodecs
+#define EXTERNAL_CODECS_LOC_VARS2 codecsInfo, externalCodecs
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,
+#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,
+
+#else
+
+#define PUBLIC_ISetCompressCodecsInfo
+#define QUERY_ENTRY_ISetCompressCodecsInfo
+#define DECL_ISetCompressCodecsInfo
+#define IMPL_ISetCompressCodecsInfo
+#define EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_VARS
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS2
+#define EXTERNAL_CODECS_LOC_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS
+#define EXTERNAL_CODECS_LOC_VARS
+
+#endif
+
+bool FindMethod(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams);
+
+bool FindMethod(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId, UString &name);
+
+
+HRESULT CreateCoder(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressFilter> &filter,
+  CMyComPtr<ICompressCoder> &coder,
+  CMyComPtr<ICompressCoder2> &coder2,
+  bool encode, bool onlyCoder);
+
+HRESULT CreateCoder(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressCoder> &coder,
+  CMyComPtr<ICompressCoder2> &coder2,
+  bool encode);
+
+HRESULT CreateCoder(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId, 
+  CMyComPtr<ICompressCoder> &coder, bool encode);
+
+HRESULT CreateFilter(
+  DECL_EXTERNAL_CODECS_LOC_VARS
+  CMethodId methodId,
+  CMyComPtr<ICompressFilter> &filter,
+  bool encode);
+
+#endif
diff --git a/lzma/CPP/7zip/Common/FilePathAutoRename.cpp b/lzma/CPP/7zip/Common/FilePathAutoRename.cpp
new file mode 100644 (file)
index 0000000..3c5b910
--- /dev/null
@@ -0,0 +1,57 @@
+// FilePathAutoRename.cpp
+
+#include "StdAfx.h"
+#include "FilePathAutoRename.h"
+
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileFind.h"
+
+using namespace NWindows;
+
+static bool MakeAutoName(const UString &name, 
+    const UString &extension, int value, UString &path)
+{
+  wchar_t number[32];
+  ConvertUInt64ToString(value, number);
+  path = name;
+  path += number;
+  path += extension;
+  return NFile::NFind::DoesFileExist(path);
+}
+
+bool AutoRenamePath(UString &fullProcessedPath)
+{
+  UString path;
+  int dotPos = fullProcessedPath.ReverseFind(L'.');
+
+  int slashPos = fullProcessedPath.ReverseFind(L'/');
+  #ifdef _WIN32
+  int slash1Pos = fullProcessedPath.ReverseFind(L'\\');
+  slashPos = MyMax(slashPos, slash1Pos);
+  #endif
+
+  UString name, extension;
+  if (dotPos > slashPos &&  dotPos > 0)
+  {
+    name = fullProcessedPath.Left(dotPos);
+    extension = fullProcessedPath.Mid(dotPos);
+  }
+  else
+    name = fullProcessedPath;
+  name += L'_';
+  int indexLeft = 1, indexRight = (1 << 30);
+  while (indexLeft != indexRight)
+  {
+    int indexMid = (indexLeft + indexRight) / 2;
+    if (MakeAutoName(name, extension, indexMid, path))
+      indexLeft = indexMid + 1;
+    else
+      indexRight = indexMid;
+  }
+  if (MakeAutoName(name, extension, indexRight, fullProcessedPath))
+    return false;
+  return true;
+}
diff --git a/lzma/CPP/7zip/Common/FilePathAutoRename.h b/lzma/CPP/7zip/Common/FilePathAutoRename.h
new file mode 100644 (file)
index 0000000..3ef87f4
--- /dev/null
@@ -0,0 +1,10 @@
+// Util/FilePathAutoRename.h
+
+#ifndef __FILEPATHAUTORENAME_H
+#define __FILEPATHAUTORENAME_H
+
+#include "Common/MyString.h"
+
+bool AutoRenamePath(UString &fullProcessedPath);
+
+#endif
diff --git a/lzma/CPP/7zip/Common/FileStreams.cpp b/lzma/CPP/7zip/Common/FileStreams.cpp
new file mode 100644 (file)
index 0000000..bebcf14
--- /dev/null
@@ -0,0 +1,261 @@
+// FileStreams.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include "FileStreams.h"
+
+static inline HRESULT ConvertBoolToHRESULT(bool result)
+{
+  #ifdef _WIN32
+  if (result)
+    return S_OK;
+  DWORD lastError = ::GetLastError();
+  if (lastError == 0)
+    return E_FAIL;
+  return lastError;
+  #else
+  return result ? S_OK: E_FAIL;
+  #endif
+}
+
+bool CInFileStream::Open(LPCTSTR fileName)
+{
+  return File.Open(fileName);
+}
+
+#ifdef USE_WIN_FILE
+#ifndef _UNICODE
+bool CInFileStream::Open(LPCWSTR fileName)
+{
+  return File.Open(fileName);
+}
+#endif
+#endif
+
+bool CInFileStream::OpenShared(LPCTSTR fileName, bool shareForWrite)
+{
+  return File.OpenShared(fileName, shareForWrite);
+}
+
+#ifdef USE_WIN_FILE
+#ifndef _UNICODE
+bool CInFileStream::OpenShared(LPCWSTR fileName, bool shareForWrite)
+{
+  return File.OpenShared(fileName, shareForWrite);
+}
+#endif
+#endif
+
+STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  #ifdef USE_WIN_FILE
+  
+  UInt32 realProcessedSize;
+  bool result = File.ReadPart(data, size, realProcessedSize);
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return ConvertBoolToHRESULT(result);
+  
+  #else
+  
+  if(processedSize != NULL)
+    *processedSize = 0;
+  ssize_t res = File.Read(data, (size_t)size);
+  if (res == -1)
+    return E_FAIL;
+  if(processedSize != NULL)
+    *processedSize = (UInt32)res;
+  return S_OK;
+
+  #endif
+}
+
+#ifndef _WIN32_WCE
+STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  #ifdef _WIN32
+  UInt32 realProcessedSize;
+  BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), 
+      data, size, (DWORD *)&realProcessedSize, NULL);
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
+    return S_OK;
+  return ConvertBoolToHRESULT(res != FALSE);
+  
+  #else
+
+  if(processedSize != NULL)
+    *processedSize = 0;
+  ssize_t res;
+  do 
+  {
+    res = read(0, data, (size_t)size);
+  } 
+  while (res < 0 && (errno == EINTR));
+  if (res == -1)
+    return E_FAIL;
+  if(processedSize != NULL)
+    *processedSize = (UInt32)res;
+  return S_OK;
+  
+  #endif
+}
+  
+#endif
+
+STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, 
+    UInt64 *newPosition)
+{
+  if(seekOrigin >= 3)
+    return STG_E_INVALIDFUNCTION;
+
+  #ifdef USE_WIN_FILE
+
+  UInt64 realNewPosition;
+  bool result = File.Seek(offset, seekOrigin, realNewPosition);
+  if(newPosition != NULL)
+    *newPosition = realNewPosition;
+  return ConvertBoolToHRESULT(result);
+  
+  #else
+  
+  off_t res = File.Seek(offset, seekOrigin);
+  if (res == -1)
+    return E_FAIL;
+  if(newPosition != NULL)
+    *newPosition = (UInt64)res;
+  return S_OK;
+  
+  #endif
+}
+
+STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
+{
+  return ConvertBoolToHRESULT(File.GetLength(*size));
+}
+
+
+//////////////////////////
+// COutFileStream
+
+HRESULT COutFileStream::Close()
+{
+  return ConvertBoolToHRESULT(File.Close());
+}
+
+STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  #ifdef USE_WIN_FILE
+
+  UInt32 realProcessedSize;
+  bool result = File.WritePart(data, size, realProcessedSize);
+  ProcessedSize += realProcessedSize;
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return ConvertBoolToHRESULT(result);
+  
+  #else
+  
+  if(processedSize != NULL)
+    *processedSize = 0;
+  ssize_t res = File.Write(data, (size_t)size);
+  if (res == -1)
+    return E_FAIL;
+  if(processedSize != NULL)
+    *processedSize = (UInt32)res;
+  ProcessedSize += res;
+  return S_OK;
+  
+  #endif
+}
+  
+STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+  if(seekOrigin >= 3)
+    return STG_E_INVALIDFUNCTION;
+  #ifdef USE_WIN_FILE
+
+  UInt64 realNewPosition;
+  bool result = File.Seek(offset, seekOrigin, realNewPosition);
+  if(newPosition != NULL)
+    *newPosition = realNewPosition;
+  return ConvertBoolToHRESULT(result);
+  
+  #else
+  
+  off_t res = File.Seek(offset, seekOrigin);
+  if (res == -1)
+    return E_FAIL;
+  if(newPosition != NULL)
+    *newPosition = (UInt64)res;
+  return S_OK;
+  
+  #endif
+}
+
+STDMETHODIMP COutFileStream::SetSize(Int64 newSize)
+{
+  #ifdef USE_WIN_FILE
+  UInt64 currentPos;
+  if(!File.Seek(0, FILE_CURRENT, currentPos))
+    return E_FAIL;
+  bool result = File.SetLength(newSize);
+  UInt64 currentPos2;
+  result = result && File.Seek(currentPos, currentPos2);
+  return result ? S_OK : E_FAIL;
+  #else
+  return E_FAIL;
+  #endif
+}
+
+#ifndef _WIN32_WCE
+STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if(processedSize != NULL)
+    *processedSize = 0;
+
+  #ifdef _WIN32
+  UInt32 realProcessedSize;
+  BOOL res = TRUE;
+  if (size > 0)
+  {
+    // Seems that Windows doesn't like big amounts writing to stdout.
+    // So we limit portions by 32KB.
+    UInt32 sizeTemp = (1 << 15); 
+    if (sizeTemp > size)
+      sizeTemp = size;
+    res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), 
+        data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
+    size -= realProcessedSize;
+    data = (const void *)((const Byte *)data + realProcessedSize);
+    if(processedSize != NULL)
+      *processedSize += realProcessedSize;
+  }
+  return ConvertBoolToHRESULT(res != FALSE);
+
+  #else
+  
+  ssize_t res;
+  do 
+  {
+    res = write(1, data, (size_t)size);
+  } 
+  while (res < 0 && (errno == EINTR));
+  if (res == -1)
+    return E_FAIL;
+  if(processedSize != NULL)
+    *processedSize = (UInt32)res;
+  return S_OK;
+  
+  return S_OK;
+  #endif
+}
+  
+#endif
diff --git a/lzma/CPP/7zip/Common/FileStreams.h b/lzma/CPP/7zip/Common/FileStreams.h
new file mode 100644 (file)
index 0000000..715801d
--- /dev/null
@@ -0,0 +1,143 @@
+// FileStreams.h
+
+#ifndef __FILESTREAMS_H
+#define __FILESTREAMS_H
+
+#ifdef _WIN32
+#define USE_WIN_FILE
+#endif
+
+#ifdef USE_WIN_FILE
+#include "../../Windows/FileIO.h"
+#else
+#include "../../Common/C_FileIO.h"
+#endif
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+
+class CInFileStream: 
+  public IInStream,
+  public IStreamGetSize,
+  public CMyUnknownImp
+{
+public:
+  #ifdef USE_WIN_FILE
+  NWindows::NFile::NIO::CInFile File;
+  #else
+  NC::NFile::NIO::CInFile File;
+  #endif
+  CInFileStream() {}
+  virtual ~CInFileStream() {}
+
+  bool Open(LPCTSTR fileName);
+  #ifdef USE_WIN_FILE
+  #ifndef _UNICODE
+  bool Open(LPCWSTR fileName);
+  #endif
+  #endif
+
+  bool OpenShared(LPCTSTR fileName, bool shareForWrite);
+  #ifdef USE_WIN_FILE
+  #ifndef _UNICODE
+  bool OpenShared(LPCWSTR fileName, bool shareForWrite);
+  #endif
+  #endif
+
+  MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+  STDMETHOD(GetSize)(UInt64 *size);
+};
+
+#ifndef _WIN32_WCE
+class CStdInFileStream: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+public:
+  // HANDLE File;
+  // CStdInFileStream() File(INVALID_HANDLE_VALUE): {}
+  // void Open() { File = GetStdHandle(STD_INPUT_HANDLE); };
+  MY_UNKNOWN_IMP
+
+  virtual ~CStdInFileStream() {}
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+#endif
+
+class COutFileStream: 
+  public IOutStream,
+  public CMyUnknownImp
+{
+  #ifdef USE_WIN_FILE
+  NWindows::NFile::NIO::COutFile File;
+  #else
+  NC::NFile::NIO::COutFile File;
+  #endif
+public:
+  virtual ~COutFileStream() {}
+  bool Create(LPCTSTR fileName, bool createAlways)
+  {
+    ProcessedSize = 0;
+    return File.Create(fileName, createAlways);
+  }
+  bool Open(LPCTSTR fileName, DWORD creationDisposition)
+  {
+    ProcessedSize = 0;
+    return File.Open(fileName, creationDisposition);
+  }
+  #ifdef USE_WIN_FILE
+  #ifndef _UNICODE
+  bool Create(LPCWSTR fileName, bool createAlways)
+  {
+    ProcessedSize = 0;
+    return File.Create(fileName, createAlways);
+  }
+  bool Open(LPCWSTR fileName, DWORD creationDisposition)
+  {
+    ProcessedSize = 0;
+    return File.Open(fileName, creationDisposition);
+  }
+  #endif
+  #endif
+
+  HRESULT Close();
+  
+  UInt64 ProcessedSize;
+
+  #ifdef USE_WIN_FILE
+  bool SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
+  {
+    return File.SetTime(creationTime, lastAccessTime, lastWriteTime);
+  }
+  bool SetLastWriteTime(const FILETIME *lastWriteTime)
+  {
+    return File.SetLastWriteTime(lastWriteTime);
+  }
+  #endif
+
+
+  MY_UNKNOWN_IMP1(IOutStream)
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+  STDMETHOD(SetSize)(Int64 newSize);
+};
+
+#ifndef _WIN32_WCE
+class CStdOutFileStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+
+  virtual ~CStdOutFileStream() {}
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+#endif
+
+#endif
diff --git a/lzma/CPP/7zip/Common/FilterCoder.cpp b/lzma/CPP/7zip/Common/FilterCoder.cpp
new file mode 100644 (file)
index 0000000..fd89d0e
--- /dev/null
@@ -0,0 +1,264 @@
+// FilterCoder.cpp
+
+#include "StdAfx.h"
+
+#include "FilterCoder.h"
+extern "C" 
+{ 
+#include "../../../C/Alloc.h"
+}
+#include "../../Common/Defs.h"
+#include "StreamUtils.h"
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CFilterCoder::CFilterCoder()
+{ 
+  _buffer = (Byte *)::MidAlloc(kBufferSize); 
+}
+
+CFilterCoder::~CFilterCoder() 
+{ 
+  ::MidFree(_buffer); 
+}
+
+HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size)
+{
+  if (_outSizeIsDefined)
+  {
+    UInt64 remSize = _outSize - _nowPos64;
+    if (size > remSize)
+      size = (UInt32)remSize;
+  }
+  UInt32 processedSize = 0;
+  RINOK(WriteStream(outStream, _buffer, size, &processedSize));
+  if (size != processedSize)
+    return E_FAIL;
+  _nowPos64 += processedSize;
+  return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize,
+      ICompressProgressInfo *progress)
+{
+  RINOK(Init());
+  UInt32 bufferPos = 0;
+  _outSizeIsDefined = (outSize != 0);
+  if (_outSizeIsDefined)
+    _outSize = *outSize;
+
+  while(NeedMore())
+  {
+    UInt32 processedSize;
+    
+    // Change it: It can be optimized using ReadPart
+    RINOK(ReadStream(inStream, _buffer + bufferPos, kBufferSize - bufferPos, &processedSize));
+    
+    UInt32 endPos = bufferPos + processedSize;
+
+    bufferPos = Filter->Filter(_buffer, endPos);
+    if (bufferPos > endPos)
+    {
+      for (; endPos< bufferPos; endPos++)
+        _buffer[endPos] = 0;
+      bufferPos = Filter->Filter(_buffer, endPos);
+    }
+
+    if (bufferPos == 0)
+    {
+      if (endPos > 0)
+        return WriteWithLimit(outStream, endPos);
+      return S_OK;
+    }
+    RINOK(WriteWithLimit(outStream, bufferPos));
+    if (progress != NULL)
+    {
+      RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64));
+    }
+    UInt32 i = 0;
+    while(bufferPos < endPos)
+      _buffer[i++] = _buffer[bufferPos++];
+    bufferPos = i;
+  }
+  return S_OK;
+}
+
+// #ifdef _ST_MODE
+STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
+{
+  _bufferPos = 0;
+  _outStream = outStream;
+  return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseOutStream()
+{
+  _outStream.Release();
+  return S_OK;
+};
+
+
+STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 processedSizeTotal = 0;
+  while(size > 0)
+  {
+    UInt32 sizeMax = kBufferSize - _bufferPos;
+    UInt32 sizeTemp = size;
+    if (sizeTemp > sizeMax)
+      sizeTemp = sizeMax;
+    memmove(_buffer + _bufferPos, data, sizeTemp);
+    size -= sizeTemp;
+    processedSizeTotal += sizeTemp;
+    data = (const Byte *)data + sizeTemp;
+    UInt32 endPos = _bufferPos + sizeTemp;
+    _bufferPos = Filter->Filter(_buffer, endPos);
+    if (_bufferPos == 0)
+    {
+      _bufferPos = endPos;
+      break;
+    }
+    if (_bufferPos > endPos)
+    {
+      if (size != 0)
+        return E_FAIL;
+      break;
+    }
+    RINOK(WriteWithLimit(_outStream, _bufferPos));
+    UInt32 i = 0;
+    while(_bufferPos < endPos)
+      _buffer[i++] = _buffer[_bufferPos++];
+    _bufferPos = i;
+  }
+  if (processedSize != NULL)
+    *processedSize = processedSizeTotal;
+  return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Flush()
+{
+  if (_bufferPos != 0)
+  {
+    UInt32 endPos = Filter->Filter(_buffer, _bufferPos);
+    if (endPos > _bufferPos)
+    {
+      for (; _bufferPos < endPos; _bufferPos++)
+        _buffer[_bufferPos] = 0;
+      if (Filter->Filter(_buffer, endPos) != endPos)
+        return E_FAIL;
+    }
+    UInt32 processedSize;
+    RINOK(WriteStream(_outStream, _buffer, _bufferPos, &processedSize));
+    if (_bufferPos != processedSize)
+      return E_FAIL;
+    _bufferPos = 0;
+  }
+  CMyComPtr<IOutStreamFlush> flush;
+  _outStream.QueryInterface(IID_IOutStreamFlush, &flush);
+  if (flush)
+    return  flush->Flush();
+  return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
+{
+  _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
+  _inStream = inStream;
+  return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseInStream()
+{
+  _inStream.Release();
+  return S_OK;
+};
+
+STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 processedSizeTotal = 0;
+  while(size > 0)
+  {
+    if (_convertedPosBegin != _convertedPosEnd)
+    {
+      UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
+      memmove(data, _buffer + _convertedPosBegin, sizeTemp);
+      _convertedPosBegin += sizeTemp;
+      data = (void *)((Byte *)data + sizeTemp);
+      size -= sizeTemp;
+      processedSizeTotal += sizeTemp;
+      break;
+    }
+    int i;
+    for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
+      _buffer[i] = _buffer[i + _convertedPosEnd];
+    _bufferPos = i;
+    _convertedPosBegin = _convertedPosEnd = 0;
+    UInt32 processedSizeTemp;
+    UInt32 size0 = kBufferSize - _bufferPos;
+    // Optimize it:
+    RINOK(ReadStream(_inStream, _buffer + _bufferPos, size0, &processedSizeTemp));
+    _bufferPos = _bufferPos + processedSizeTemp;
+    _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+    if (_convertedPosEnd == 0)
+    {
+      if (_bufferPos == 0)
+        break;
+      else
+      {
+        _convertedPosEnd = _bufferPos; // check it
+        continue;
+      }
+    }
+    if (_convertedPosEnd > _bufferPos)
+    {
+      for (; _bufferPos < _convertedPosEnd; _bufferPos++)
+        _buffer[_bufferPos] = 0;
+      _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+    }
+  }
+  if (processedSize != NULL)
+    *processedSize = processedSizeTotal;
+  return S_OK;
+}
+
+// #endif // _ST_MODE
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+  return _setPassword->CryptoSetPassword(data, size);
+}
+#endif
+
+#ifndef EXTRACT_ONLY
+STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs, 
+      const PROPVARIANT *properties, UInt32 numProperties)
+{
+  return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
+}
+
+STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+  return _writeCoderProperties->WriteCoderProperties(outStream);
+}
+
+/*
+STDMETHODIMP CFilterCoder::ResetSalt()
+{
+  return _CryptoResetSalt->ResetSalt();
+}
+*/
+
+STDMETHODIMP CFilterCoder::ResetInitVector()
+{
+  return _CryptoResetInitVector->ResetInitVector();
+}
+#endif
+
+STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+  return _setDecoderProperties->SetDecoderProperties2(data, size);
+}
diff --git a/lzma/CPP/7zip/Common/FilterCoder.h b/lzma/CPP/7zip/Common/FilterCoder.h
new file mode 100644 (file)
index 0000000..f654ae3
--- /dev/null
@@ -0,0 +1,143 @@
+// FilterCoder.h
+
+#ifndef __FILTERCODER_H
+#define __FILTERCODER_H
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) if (iid == IID_ ## i) \
+{ if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
+*outObject = (void *)(i *)this; AddRef(); return S_OK; } 
+
+class CFilterCoder:
+  public ICompressCoder,
+  // #ifdef _ST_MODE
+  public ICompressSetInStream,
+  public ISequentialInStream,
+  public ICompressSetOutStream,
+  public ISequentialOutStream,
+  public IOutStreamFlush,
+  // #endif
+
+  #ifndef _NO_CRYPTO
+  public ICryptoSetPassword,
+  #endif
+  #ifndef EXTRACT_ONLY
+  public ICompressSetCoderProperties,
+  public ICompressWriteCoderProperties,
+  // public ICryptoResetSalt,
+  public ICryptoResetInitVector,
+  #endif
+  public ICompressSetDecoderProperties2,
+  public CMyUnknownImp
+{
+protected:
+  Byte *_buffer;
+  // #ifdef _ST_MODE
+  CMyComPtr<ISequentialInStream> _inStream;
+  CMyComPtr<ISequentialOutStream> _outStream;
+  UInt32 _bufferPos;
+  UInt32 _convertedPosBegin;
+  UInt32 _convertedPosEnd;
+  // #endif
+  bool _outSizeIsDefined;
+  UInt64 _outSize;
+  UInt64 _nowPos64;
+
+  HRESULT Init() 
+  { 
+    _nowPos64 = 0;
+    _outSizeIsDefined = false;
+    return Filter->Init(); 
+  }
+
+  CMyComPtr<ICryptoSetPassword> _setPassword;
+  #ifndef EXTRACT_ONLY
+  CMyComPtr<ICompressSetCoderProperties> _SetCoderProperties;
+  CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
+  // CMyComPtr<ICryptoResetSalt> _CryptoResetSalt;
+  CMyComPtr<ICryptoResetInitVector> _CryptoResetInitVector;
+  #endif
+  CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties;
+public:
+  CMyComPtr<ICompressFilter> Filter;
+
+  CFilterCoder();
+  ~CFilterCoder();
+  HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size);
+  bool NeedMore() const  
+    { return (!_outSizeIsDefined || (_nowPos64 < _outSize)); }
+
+public:
+  MY_QUERYINTERFACE_BEGIN
+    MY_QUERYINTERFACE_ENTRY(ICompressCoder)
+    // #ifdef _ST_MODE
+    MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+    MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
+
+    MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)
+    MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)
+    MY_QUERYINTERFACE_ENTRY(IOutStreamFlush)
+    // #endif
+
+    #ifndef _NO_CRYPTO
+    MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword)
+    #endif
+
+    #ifndef EXTRACT_ONLY
+    MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties)
+    MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties)
+    // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt)
+    MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector)
+    #endif
+
+    MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties)
+  MY_QUERYINTERFACE_END
+  MY_ADDREF_RELEASE
+  STDMETHOD(Code)(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+  // #ifdef _ST_MODE
+  STDMETHOD(ReleaseInStream)();
+  STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \
+  STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
+  STDMETHOD(ReleaseOutStream)();
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Flush)();
+  // #endif
+
+  #ifndef _NO_CRYPTO
+  STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+  #endif
+  #ifndef EXTRACT_ONLY
+  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, 
+      const PROPVARIANT *properties, UInt32 numProperties);
+  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+  // STDMETHOD(ResetSalt)();
+  STDMETHOD(ResetInitVector)();
+  #endif
+  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+// #ifdef _ST_MODE
+class CInStreamReleaser
+{
+public:
+  CFilterCoder *FilterCoder;
+  CInStreamReleaser(): FilterCoder(0) {}
+  ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
+};
+
+class COutStreamReleaser
+{
+public:
+  CFilterCoder *FilterCoder;
+  COutStreamReleaser(): FilterCoder(0) {}
+  ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
+};
+// #endif
+
+#endif
diff --git a/lzma/CPP/7zip/Common/InBuffer.cpp b/lzma/CPP/7zip/Common/InBuffer.cpp
new file mode 100644 (file)
index 0000000..5c4361a
--- /dev/null
@@ -0,0 +1,83 @@
+// InBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "InBuffer.h"
+
+extern "C"
+{
+  #include "../../../C/Alloc.h"
+}
+
+CInBuffer::CInBuffer(): 
+  _buffer(0), 
+  _bufferLimit(0), 
+  _bufferBase(0), 
+  _stream(0),
+  _bufferSize(0)
+{}
+
+bool CInBuffer::Create(UInt32 bufferSize)
+{
+  const UInt32 kMinBlockSize = 1;
+  if (bufferSize < kMinBlockSize)
+    bufferSize = kMinBlockSize;
+  if (_bufferBase != 0 && _bufferSize == bufferSize)
+    return true;
+  Free();
+  _bufferSize = bufferSize;
+  _bufferBase = (Byte *)::MidAlloc(bufferSize);
+  return (_bufferBase != 0);
+}
+
+void CInBuffer::Free()
+{
+  ::MidFree(_bufferBase);
+  _bufferBase = 0;
+}
+
+void CInBuffer::SetStream(ISequentialInStream *stream)
+{
+  _stream = stream;
+}
+
+void CInBuffer::Init()
+{
+  _processedSize = 0;
+  _buffer = _bufferBase;
+  _bufferLimit = _buffer;
+  _wasFinished = false;
+  #ifdef _NO_EXCEPTIONS
+  ErrorCode = S_OK;
+  #endif
+}
+
+bool CInBuffer::ReadBlock()
+{
+  #ifdef _NO_EXCEPTIONS
+  if (ErrorCode != S_OK)
+    return false;
+  #endif
+  if (_wasFinished)
+    return false;
+  _processedSize += (_buffer - _bufferBase);
+  UInt32 numProcessedBytes;
+  HRESULT result = _stream->Read(_bufferBase, _bufferSize, &numProcessedBytes);
+  #ifdef _NO_EXCEPTIONS
+  ErrorCode = result;
+  #else
+  if (result != S_OK)
+    throw CInBufferException(result);
+  #endif
+  _buffer = _bufferBase;
+  _bufferLimit = _buffer + numProcessedBytes;
+  _wasFinished = (numProcessedBytes == 0);
+  return (!_wasFinished);
+}
+
+Byte CInBuffer::ReadBlock2()
+{
+  if(!ReadBlock())
+    return 0xFF;
+  return *_buffer++;
+}
diff --git a/lzma/CPP/7zip/Common/InBuffer.h b/lzma/CPP/7zip/Common/InBuffer.h
new file mode 100644 (file)
index 0000000..05fc77e
--- /dev/null
@@ -0,0 +1,75 @@
+// InBuffer.h
+
+#ifndef __INBUFFER_H
+#define __INBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef _NO_EXCEPTIONS
+struct CInBufferException: public CSystemException 
+{
+  CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} 
+};
+#endif
+
+class CInBuffer
+{
+  Byte *_buffer;
+  Byte *_bufferLimit;
+  Byte *_bufferBase;
+  CMyComPtr<ISequentialInStream> _stream;
+  UInt64 _processedSize;
+  UInt32 _bufferSize;
+  bool _wasFinished;
+
+  bool ReadBlock();
+  Byte ReadBlock2();
+
+public:
+  #ifdef _NO_EXCEPTIONS
+  HRESULT ErrorCode;
+  #endif
+
+  CInBuffer();
+  ~CInBuffer() { Free(); }
+
+  bool Create(UInt32 bufferSize);
+  void Free();
+  
+  void SetStream(ISequentialInStream *stream);
+  void Init();
+  void ReleaseStream() { _stream.Release(); }
+
+  bool ReadByte(Byte &b)
+  {
+    if(_buffer >= _bufferLimit)
+      if(!ReadBlock())
+        return false;
+    b = *_buffer++;
+    return true;
+  }
+  Byte ReadByte()
+  {
+    if(_buffer >= _bufferLimit)
+      return ReadBlock2();
+    return *_buffer++;
+  }
+  void ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+  {
+    for(processedSize = 0; processedSize < size; processedSize++)
+      if (!ReadByte(((Byte *)data)[processedSize]))
+        return;
+  }
+  bool ReadBytes(void *data, UInt32 size)
+  {
+    UInt32 processedSize;
+    ReadBytes(data, size, processedSize);
+    return (processedSize == size);
+  }
+  UInt64 GetProcessedSize() const { return _processedSize + (_buffer - _bufferBase); }
+  bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/InOutTempBuffer.cpp b/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
new file mode 100644 (file)
index 0000000..ffaed32
--- /dev/null
@@ -0,0 +1,122 @@
+// InOutTempBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "InOutTempBuffer.h"
+#include "../../Common/Defs.h"
+// #include "Windows/Defs.h"
+
+#include "StreamUtils.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDirectory;
+
+static UInt32 kTmpBufferMemorySize = (1 << 20);
+
+static LPCTSTR kTempFilePrefixString = TEXT("iot");
+
+CInOutTempBuffer::CInOutTempBuffer():
+  _buffer(NULL)
+{
+}
+
+void CInOutTempBuffer::Create()
+{
+  _buffer = new Byte[kTmpBufferMemorySize];
+}
+
+CInOutTempBuffer::~CInOutTempBuffer()
+{
+  delete []_buffer;
+}
+void CInOutTempBuffer::InitWriting()
+{
+  _bufferPosition = 0;
+  _tmpFileCreated = false;
+  _fileSize = 0;
+}
+
+bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size)
+{
+  if (size == 0)
+    return true;
+  if(!_tmpFileCreated)
+  {
+    CSysString tempDirPath;
+    if(!MyGetTempPath(tempDirPath))
+      return false;
+    if (_tempFile.Create(tempDirPath, kTempFilePrefixString, _tmpFileName) == 0)
+      return false;
+    // _outFile.SetOpenCreationDispositionCreateAlways();
+    if(!_outFile.Create(_tmpFileName, true))
+      return false;
+    _tmpFileCreated = true;
+  }
+  UInt32 processedSize;
+  if(!_outFile.Write(data, size, processedSize))
+    return false;
+  _fileSize += processedSize;
+  return (processedSize == size);
+}
+
+bool CInOutTempBuffer::FlushWrite()
+{
+  return _outFile.Close();
+}
+
+bool CInOutTempBuffer::Write(const void *data, UInt32 size)
+{
+  if(_bufferPosition < kTmpBufferMemorySize)
+  {
+    UInt32 curSize = MyMin(kTmpBufferMemorySize - _bufferPosition, size);
+    memmove(_buffer + _bufferPosition, (const Byte *)data, curSize);
+    _bufferPosition += curSize;
+    size -= curSize;
+    data = ((const Byte *)data) + curSize;
+    _fileSize += curSize;
+  }
+  return WriteToFile(data, size);
+}
+
+bool CInOutTempBuffer::InitReading()
+{
+  _currentPositionInBuffer = 0;
+  if(_tmpFileCreated)
+    return _inFile.Open(_tmpFileName);
+  return true;
+}
+
+HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
+{
+  if (_currentPositionInBuffer < _bufferPosition)
+  {
+    UInt32 sizeToWrite = _bufferPosition - _currentPositionInBuffer;
+    RINOK(WriteStream(stream, _buffer + _currentPositionInBuffer, sizeToWrite, NULL));
+    _currentPositionInBuffer += sizeToWrite;
+  }
+  if (!_tmpFileCreated)
+    return true;
+  for (;;)
+  {
+    UInt32 localProcessedSize;
+    if (!_inFile.ReadPart(_buffer, kTmpBufferMemorySize, localProcessedSize))
+      return E_FAIL;
+    if (localProcessedSize == 0)
+      return S_OK;
+    RINOK(WriteStream(stream, _buffer, localProcessedSize, NULL));
+  }
+}
+
+STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if (!_buffer->Write(data, size))
+  {
+    if (processedSize != NULL)
+      *processedSize = 0;
+    return E_FAIL;
+  }
+  if (processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Common/InOutTempBuffer.h b/lzma/CPP/7zip/Common/InOutTempBuffer.h
new file mode 100644 (file)
index 0000000..3abe76e
--- /dev/null
@@ -0,0 +1,55 @@
+// Util/InOutTempBuffer.h
+
+#ifndef __IN_OUT_TEMP_BUFFER_H
+#define __IN_OUT_TEMP_BUFFER_H
+
+#include "../../Windows/FileIO.h"
+#include "../../Windows/FileDir.h"
+#include "../../Common/MyCom.h"
+
+#include "../IStream.h"
+
+class CInOutTempBuffer
+{
+  NWindows::NFile::NDirectory::CTempFile _tempFile;
+  NWindows::NFile::NIO::COutFile _outFile;
+  NWindows::NFile::NIO::CInFile _inFile;
+  Byte *_buffer;
+  UInt32 _bufferPosition;
+  UInt32 _currentPositionInBuffer;
+  CSysString _tmpFileName;
+  bool _tmpFileCreated;
+
+  UInt64 _fileSize;
+
+  bool WriteToFile(const void *data, UInt32 size);
+public:
+  CInOutTempBuffer();
+  ~CInOutTempBuffer();
+  void Create();
+
+  void InitWriting();
+  bool Write(const void *data, UInt32 size);
+  UInt64 GetDataSize() const { return _fileSize; }
+  bool FlushWrite();
+  bool InitReading();
+  HRESULT WriteToStream(ISequentialOutStream *stream);
+};
+
+class CSequentialOutTempBufferImp: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  CInOutTempBuffer *_buffer;
+public:
+  // CSequentialOutStreamImp(): _size(0) {}
+  // UInt32 _size;
+  void Init(CInOutTempBuffer *buffer)  { _buffer = buffer; }
+  // UInt32 GetSize() const { return _size; }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/LimitedStreams.cpp b/lzma/CPP/7zip/Common/LimitedStreams.cpp
new file mode 100644 (file)
index 0000000..af72114
--- /dev/null
@@ -0,0 +1,24 @@
+// LimitedStreams.cpp
+
+#include "StdAfx.h"
+
+#include "LimitedStreams.h"
+#include "../../Common/Defs.h"
+
+STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize = 0;
+  UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size);
+  HRESULT result = S_OK;
+  if (sizeToRead > 0)
+  {
+    result = _stream->Read(data, sizeToRead, &realProcessedSize);
+    _pos += realProcessedSize;
+    if (realProcessedSize == 0)
+      _wasFinished = true;
+  }
+  if(processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return result;
+}
+
diff --git a/lzma/CPP/7zip/Common/LimitedStreams.h b/lzma/CPP/7zip/Common/LimitedStreams.h
new file mode 100644 (file)
index 0000000..ec4a3a7
--- /dev/null
@@ -0,0 +1,33 @@
+// LimitedStreams.h
+
+#ifndef __LIMITEDSTREAMS_H
+#define __LIMITEDSTREAMS_H
+
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CLimitedSequentialInStream: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialInStream> _stream;
+  UInt64 _size;
+  UInt64 _pos;
+  bool _wasFinished;
+public:
+  void SetStream(ISequentialInStream *stream) { _stream = stream; }
+  void Init(UInt64 streamSize)  
+  { 
+    _size = streamSize; 
+    _pos = 0; 
+    _wasFinished = false; 
+  }
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+  UInt64 GetSize() const { return _pos; }
+  bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/LockedStream.cpp b/lzma/CPP/7zip/Common/LockedStream.cpp
new file mode 100644 (file)
index 0000000..36be1ce
--- /dev/null
@@ -0,0 +1,23 @@
+// LockedStream.cpp
+
+#include "StdAfx.h"
+
+#include "LockedStream.h"
+
+HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size, 
+  UInt32 *processedSize)
+{
+  NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+  RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL));
+  return _stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize = 0;
+  HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize);
+  _pos += realProcessedSize;
+  if (processedSize != NULL)
+    *processedSize = realProcessedSize;
+  return result;
+}
diff --git a/lzma/CPP/7zip/Common/LockedStream.h b/lzma/CPP/7zip/Common/LockedStream.h
new file mode 100644 (file)
index 0000000..1c1e179
--- /dev/null
@@ -0,0 +1,38 @@
+// LockedStream.h
+
+#ifndef __LOCKEDSTREAM_H
+#define __LOCKEDSTREAM_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CLockedInStream
+{
+  CMyComPtr<IInStream> _stream;
+  NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+  void Init(IInStream *stream)
+    { _stream = stream; }
+  HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CLockedSequentialInStreamImp: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+  CLockedInStream *_lockedInStream;
+  UInt64 _pos;
+public:
+  void Init(CLockedInStream *lockedInStream, UInt64 startPos)
+  {
+    _lockedInStream = lockedInStream;
+    _pos = startPos;
+  }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/MethodId.cpp b/lzma/CPP/7zip/Common/MethodId.cpp
new file mode 100644 (file)
index 0000000..b797b68
--- /dev/null
@@ -0,0 +1,27 @@
+// MethodId.cpp
+
+#include "StdAfx.h"
+
+#include "MethodId.h"
+#include "../../Common/MyString.h"
+
+static inline wchar_t GetHex(Byte value)
+{
+  return (wchar_t)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+UString ConvertMethodIdToString(UInt64 id)
+{
+  wchar_t s[32];
+  int len = 32;
+  s[--len] = 0;
+  do
+  {
+    s[--len] = GetHex((Byte)id & 0xF);
+    id >>= 4;
+    s[--len] = GetHex((Byte)id & 0xF);
+    id >>= 4;
+  }
+  while (id != 0);
+  return s + len;
+}
diff --git a/lzma/CPP/7zip/Common/MethodId.h b/lzma/CPP/7zip/Common/MethodId.h
new file mode 100644 (file)
index 0000000..54ebc9f
--- /dev/null
@@ -0,0 +1,10 @@
+// MethodId.h
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Common/Types.h"
+
+typedef UInt64 CMethodId;
+
+#endif
diff --git a/lzma/CPP/7zip/Common/MethodProps.cpp b/lzma/CPP/7zip/Common/MethodProps.cpp
new file mode 100644 (file)
index 0000000..52f5511
--- /dev/null
@@ -0,0 +1,96 @@
+// MethodProps.cpp
+
+#include "StdAfx.h"
+
+#include "MethodProps.h"
+#include "../../Common/MyCom.h"
+
+static UInt64 k_LZMA = 0x030101;
+// static UInt64 k_LZMA2 = 0x030102;
+
+HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder)
+{
+  bool tryReduce = false;
+  UInt32 reducedDictionarySize = 1 << 10;
+  if (inSizeForReduce != 0 && (method.Id == k_LZMA /* || methodFull.MethodID == k_LZMA2 */))
+  {
+    for (;;)
+    {
+      const UInt32 step = (reducedDictionarySize >> 1);
+      if (reducedDictionarySize >= *inSizeForReduce)
+      {
+        tryReduce = true;
+        break;
+      }
+      reducedDictionarySize += step;
+      if (reducedDictionarySize >= *inSizeForReduce)
+      {
+        tryReduce = true;
+        break;
+      }
+      if (reducedDictionarySize >= ((UInt32)3 << 30))
+        break;
+      reducedDictionarySize += step;
+    }
+  }
+
+  {
+    int numProperties = method.Properties.Size();
+    CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+    coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+    if (setCoderProperties == NULL)
+    {
+      if (numProperties != 0)
+        return E_INVALIDARG;
+    }
+    else
+    {
+      CRecordVector<PROPID> propIDs;
+      NWindows::NCOM::CPropVariant *values = new NWindows::NCOM::CPropVariant[numProperties];
+      HRESULT res = S_OK;
+      try
+      {
+        for (int i = 0; i < numProperties; i++)
+        {
+          const CProp &prop = method.Properties[i];
+          propIDs.Add(prop.Id);
+          NWindows::NCOM::CPropVariant &value = values[i];
+          value = prop.Value;
+          // if (tryReduce && prop.Id == NCoderPropID::kDictionarySize && value.vt == VT_UI4 && reducedDictionarySize < value.ulVal)
+          if (tryReduce)
+            if (prop.Id == NCoderPropID::kDictionarySize)
+              if (value.vt == VT_UI4)
+                if (reducedDictionarySize < value.ulVal)
+            value.ulVal = reducedDictionarySize;
+        }
+        CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+        coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+        res = setCoderProperties->SetCoderProperties(&propIDs.Front(), values, numProperties);
+      }
+      catch(...)
+      {
+        delete []values;
+        throw;
+      }
+      delete []values;
+      RINOK(res);
+    }
+  }
+  /*
+  CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+  coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+  if (writeCoderProperties != NULL)
+  {
+    CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
+    CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+    outStreamSpec->Init();
+    RINOK(writeCoderProperties->WriteCoderProperties(outStream));
+    size_t size = outStreamSpec->GetSize();
+    filterProps.SetCapacity(size);
+    memmove(filterProps, outStreamSpec->GetBuffer(), size);
+  }
+  */
+  return S_OK;
+}
+
diff --git a/lzma/CPP/7zip/Common/MethodProps.h b/lzma/CPP/7zip/Common/MethodProps.h
new file mode 100644 (file)
index 0000000..7ffa8e4
--- /dev/null
@@ -0,0 +1,41 @@
+// MethodProps.h
+
+#ifndef __7Z_METHOD_PROPS_H
+#define __7Z_METHOD_PROPS_H
+
+#include "MethodId.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Common/MyVector.h"
+#include "../ICoder.h"
+
+struct CProp
+{
+  PROPID Id;
+  NWindows::NCOM::CPropVariant Value;
+};
+
+struct CMethod
+{
+  CMethodId Id;
+  CObjectVector<CProp> Properties;
+};
+
+struct CMethodsMode
+{
+  CObjectVector<CMethod> Methods;
+  #ifdef COMPRESS_MT
+  UInt32 NumThreads;
+  #endif
+
+  CMethodsMode()
+      #ifdef COMPRESS_MT
+      : NumThreads(1) 
+      #endif
+  {}
+  bool IsEmpty() const { return Methods.IsEmpty() ; }
+};
+
+HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder);
+
+#endif
diff --git a/lzma/CPP/7zip/Common/OffsetStream.cpp b/lzma/CPP/7zip/Common/OffsetStream.cpp
new file mode 100644 (file)
index 0000000..997ccae
--- /dev/null
@@ -0,0 +1,35 @@
+// OffsetStream.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Defs.h"
+#include "OffsetStream.h"
+
+HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)
+{
+  _offset = offset;
+  _stream = stream;
+  return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
+}
+
+STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  return _stream->Write(data, size, processedSize);
+}
+
+STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, 
+    UInt64 *newPosition)
+{
+  UInt64 absoluteNewPosition;
+  if (seekOrigin == STREAM_SEEK_SET)
+    offset += _offset;
+  HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);
+  if (newPosition != NULL)
+    *newPosition = absoluteNewPosition - _offset;
+  return result;
+}
+
+STDMETHODIMP COffsetOutStream::SetSize(Int64 newSize)
+{
+  return _stream->SetSize(_offset + newSize);
+}
diff --git a/lzma/CPP/7zip/Common/OffsetStream.h b/lzma/CPP/7zip/Common/OffsetStream.h
new file mode 100644 (file)
index 0000000..57a055c
--- /dev/null
@@ -0,0 +1,25 @@
+// OffsetStream.h
+
+#ifndef __OFFSETSTREAM_H
+#define __OFFSETSTREAM_H
+
+#include "Common/MyCom.h"
+#include "../IStream.h"
+
+class COffsetOutStream: 
+  public IOutStream,
+  public CMyUnknownImp
+{
+  UInt64 _offset;
+  CMyComPtr<IOutStream> _stream;
+public:
+  HRESULT Init(IOutStream *stream, UInt64 offset);
+  
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+  STDMETHOD(SetSize)(Int64 newSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/OutBuffer.cpp b/lzma/CPP/7zip/Common/OutBuffer.cpp
new file mode 100644 (file)
index 0000000..31d17c5
--- /dev/null
@@ -0,0 +1,119 @@
+// OutByte.cpp
+
+#include "StdAfx.h"
+
+#include "OutBuffer.h"
+
+extern "C"
+{
+  #include "../../../C/Alloc.h"
+}
+
+bool COutBuffer::Create(UInt32 bufferSize)
+{
+  const UInt32 kMinBlockSize = 1;
+  if (bufferSize < kMinBlockSize)
+    bufferSize = kMinBlockSize;
+  if (_buffer != 0 && _bufferSize == bufferSize)
+    return true;
+  Free();
+  _bufferSize = bufferSize;
+  _buffer = (Byte *)::MidAlloc(bufferSize);
+  return (_buffer != 0);
+}
+
+void COutBuffer::Free()
+{
+  ::MidFree(_buffer);
+  _buffer = 0;
+}
+
+void COutBuffer::SetStream(ISequentialOutStream *stream)
+{
+  _stream = stream;
+}
+
+void COutBuffer::Init()
+{
+  _streamPos = 0;
+  _limitPos = _bufferSize;
+  _pos = 0;
+  _processedSize = 0;
+  _overDict = false;
+  #ifdef _NO_EXCEPTIONS
+  ErrorCode = S_OK;
+  #endif
+}
+
+UInt64 COutBuffer::GetProcessedSize() const
+{ 
+  UInt64 res = _processedSize + _pos - _streamPos;
+  if (_streamPos > _pos) 
+    res += _bufferSize;
+  return res;
+}
+
+
+HRESULT COutBuffer::FlushPart()
+{
+  // _streamPos < _bufferSize
+  UInt32 size = (_streamPos >= _pos) ? (_bufferSize - _streamPos) : (_pos - _streamPos);
+  HRESULT result = S_OK;
+  #ifdef _NO_EXCEPTIONS
+  result = ErrorCode;
+  #endif
+  if (_buffer2 != 0)
+  {
+    memmove(_buffer2, _buffer + _streamPos, size);
+    _buffer2 += size;
+  }
+
+  if (_stream != 0
+      #ifdef _NO_EXCEPTIONS
+      && (ErrorCode == S_OK)
+      #endif
+     )
+  {
+    UInt32 processedSize = 0;
+    result = _stream->Write(_buffer + _streamPos, size, &processedSize);
+    size = processedSize;
+  }
+  _streamPos += size;
+  if (_streamPos == _bufferSize)
+    _streamPos = 0;
+  if (_pos == _bufferSize)
+  {
+    _overDict = true;
+    _pos = 0;
+  }
+  _limitPos = (_streamPos > _pos) ? _streamPos : _bufferSize;
+  _processedSize += size;
+  return result;
+}
+
+HRESULT COutBuffer::Flush()
+{
+  #ifdef _NO_EXCEPTIONS
+  if (ErrorCode != S_OK)
+    return ErrorCode;
+  #endif
+
+  while(_streamPos != _pos)
+  {
+    HRESULT result = FlushPart();
+    if (result != S_OK)
+      return result;
+  }
+  return S_OK;
+}
+
+void COutBuffer::FlushWithCheck()
+{
+  HRESULT result = Flush();
+  #ifdef _NO_EXCEPTIONS
+  ErrorCode = result;
+  #else
+  if (result != S_OK)
+    throw COutBufferException(result);
+  #endif
+}
diff --git a/lzma/CPP/7zip/Common/OutBuffer.h b/lzma/CPP/7zip/Common/OutBuffer.h
new file mode 100644 (file)
index 0000000..e99dbf2
--- /dev/null
@@ -0,0 +1,64 @@
+// OutBuffer.h
+
+#ifndef __OUTBUFFER_H
+#define __OUTBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef _NO_EXCEPTIONS
+struct COutBufferException: public CSystemException 
+{ 
+  COutBufferException(HRESULT errorCode): CSystemException(errorCode) {} 
+};
+#endif
+
+class COutBuffer
+{
+protected:
+  Byte *_buffer;
+  UInt32 _pos;
+  UInt32 _limitPos;
+  UInt32 _streamPos;
+  UInt32 _bufferSize;
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt64 _processedSize;
+  Byte  *_buffer2;
+  bool _overDict;
+
+  HRESULT FlushPart();
+public:
+  #ifdef _NO_EXCEPTIONS
+  HRESULT ErrorCode;
+  #endif
+
+  COutBuffer(): _buffer(0), _pos(0), _stream(0), _buffer2(0) {}
+  ~COutBuffer() { Free(); }
+  
+  bool Create(UInt32 bufferSize);
+  void Free();
+
+  void SetMemStream(Byte *buffer) { _buffer2 = buffer; }
+  void SetStream(ISequentialOutStream *stream);
+  void Init();
+  HRESULT Flush();
+  void FlushWithCheck();
+  void ReleaseStream() {  _stream.Release(); }
+
+  void WriteByte(Byte b)
+  {
+    _buffer[_pos++] = b;
+    if(_pos == _limitPos)
+      FlushWithCheck();
+  }
+  void WriteBytes(const void *data, size_t size)
+  {
+    for (size_t i = 0; i < size; i++)
+      WriteByte(((const Byte *)data)[i]);
+  }
+
+  UInt64 GetProcessedSize() const;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/ProgressUtils.cpp b/lzma/CPP/7zip/Common/ProgressUtils.cpp
new file mode 100644 (file)
index 0000000..f24ff6b
--- /dev/null
@@ -0,0 +1,42 @@
+// ProgressUtils.h
+
+#include "StdAfx.h"
+
+#include "ProgressUtils.h"
+
+CLocalProgress::CLocalProgress()
+{
+  ProgressOffset = InSize = OutSize = 0;
+  SendRatio = SendProgress = true;
+}
+
+void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)
+{
+  _ratioProgress.Release();
+  _progress = progress;
+  _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);
+  _inSizeIsMain = inSizeIsMain;
+}
+
+STDMETHODIMP CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+  UInt64 inSizeNew = InSize, outSizeNew = OutSize;
+  if (inSize)
+    inSizeNew += (*inSize);
+  if (outSize)
+    outSizeNew += (*outSize);
+  if (SendRatio && _ratioProgress)
+  {
+    RINOK(_ratioProgress->SetRatioInfo(&inSizeNew, &outSizeNew));
+  }
+  inSizeNew += ProgressOffset;
+  outSizeNew += ProgressOffset;
+  if (SendProgress)
+    return _progress->SetCompleted(_inSizeIsMain ? &inSizeNew : &outSizeNew);
+  return S_OK;
+}
+
+HRESULT CLocalProgress::SetCur()
+{
+  return SetRatioInfo(NULL, NULL);
+}
diff --git a/lzma/CPP/7zip/Common/ProgressUtils.h b/lzma/CPP/7zip/Common/ProgressUtils.h
new file mode 100644 (file)
index 0000000..831c736
--- /dev/null
@@ -0,0 +1,34 @@
+// ProgressUtils.h
+
+#ifndef __PROGRESSUTILS_H
+#define __PROGRESSUTILS_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+class CLocalProgress: 
+  public ICompressProgressInfo,
+  public CMyUnknownImp
+{
+  CMyComPtr<IProgress> _progress;
+  CMyComPtr<ICompressProgressInfo> _ratioProgress;
+  bool _inSizeIsMain;
+public:
+  UInt64 ProgressOffset;
+  UInt64 InSize;
+  UInt64 OutSize;
+  bool SendRatio;
+  bool SendProgress;
+
+  CLocalProgress();
+  void Init(IProgress *progress, bool inSizeIsMain);
+  HRESULT SetCur();
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/RegisterArc.h b/lzma/CPP/7zip/Common/RegisterArc.h
new file mode 100644 (file)
index 0000000..5773021
--- /dev/null
@@ -0,0 +1,36 @@
+// RegisterArc.h
+
+#ifndef __REGISTERARC_H
+#define __REGISTERARC_H
+
+#include "../Archive/IArchive.h"
+
+typedef IInArchive * (*CreateInArchiveP)();
+typedef IOutArchive * (*CreateOutArchiveP)();
+
+struct CArcInfo
+{
+  const wchar_t *Name;
+  const wchar_t *Ext;
+  const wchar_t *AddExt;
+  Byte ClassId;
+  Byte Signature[16];
+  int SignatureSize;
+  bool KeepName;
+  CreateInArchiveP CreateInArchive;
+  CreateOutArchiveP CreateOutArchive;
+};
+
+void RegisterArc(const CArcInfo *arcInfo);
+
+#define REGISTER_ARC_NAME(x) CRegister ## x 
+
+#define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) { \
+    REGISTER_ARC_NAME(x)() { g_ArcInfo.Signature[0]--; RegisterArc(&g_ArcInfo); }}; \
+    static REGISTER_ARC_NAME(x) g_RegisterArc;
+
+#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \
+    REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \
+    static REGISTER_ARC_NAME(x) g_RegisterArc;
+
+#endif
diff --git a/lzma/CPP/7zip/Common/RegisterCodec.h b/lzma/CPP/7zip/Common/RegisterCodec.h
new file mode 100644 (file)
index 0000000..1f1cd4d
--- /dev/null
@@ -0,0 +1,33 @@
+// RegisterCodec.h
+
+#ifndef __REGISTERCODEC_H
+#define __REGISTERCODEC_H
+
+#include "../Common/MethodId.h"
+
+typedef void * (*CreateCodecP)();
+struct CCodecInfo
+{
+  CreateCodecP CreateDecoder;
+  CreateCodecP CreateEncoder;
+  CMethodId Id;
+  const wchar_t *Name;
+  UInt32 NumInStreams;
+  bool IsFilter;
+};
+
+void RegisterCodec(const CCodecInfo *codecInfo);
+
+#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x 
+
+#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
+    REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \
+    static REGISTER_CODEC_NAME(x) g_RegisterCodec;
+
+#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x 
+#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
+    REGISTER_CODECS_NAME(x)() { for (int i = 0; i < sizeof(g_CodecsInfo) / sizeof(g_CodecsInfo[0]); i++) \
+    RegisterCodec(&g_CodecsInfo[i]); }}; \
+    static REGISTER_CODECS_NAME(x) g_RegisterCodecs;
+
+#endif
diff --git a/lzma/CPP/7zip/Common/StdAfx.h b/lzma/CPP/7zip/Common/StdAfx.h
new file mode 100644 (file)
index 0000000..27a77b1
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/MyWindows.h"
+#include "../../Common/NewHandler.h"
+
+#endif 
diff --git a/lzma/CPP/7zip/Common/StreamBinder.cpp b/lzma/CPP/7zip/Common/StreamBinder.cpp
new file mode 100644 (file)
index 0000000..5db9d01
--- /dev/null
@@ -0,0 +1,150 @@
+// StreamBinder.cpp
+
+#include "StdAfx.h"
+
+#include "StreamBinder.h"
+#include "../../Common/Defs.h"
+#include "../../Common/MyCom.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+class CSequentialInStreamForBinder: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+private:
+  CStreamBinder *m_StreamBinder;
+public:
+  ~CSequentialInStreamForBinder() { m_StreamBinder->CloseRead(); }
+  void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; }
+};
+
+STDMETHODIMP CSequentialInStreamForBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+  { return m_StreamBinder->Read(data, size, processedSize); }
+
+class CSequentialOutStreamForBinder: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+
+private:
+  CStreamBinder *m_StreamBinder;
+public:
+  ~CSequentialOutStreamForBinder() {  m_StreamBinder->CloseWrite(); }
+  void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; }
+};
+
+STDMETHODIMP CSequentialOutStreamForBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+  { return m_StreamBinder->Write(data, size, processedSize); }
+
+
+//////////////////////////
+// CStreamBinder
+// (_thereAreBytesToReadEvent && _bufferSize == 0) means that stream is finished.
+
+HRes CStreamBinder::CreateEvents()
+{
+  RINOK(_allBytesAreWritenEvent.Create(true));
+  RINOK(_thereAreBytesToReadEvent.Create());
+  return _readStreamIsClosedEvent.Create();
+}
+
+void CStreamBinder::ReInit()
+{
+  _thereAreBytesToReadEvent.Reset();
+  _readStreamIsClosedEvent.Reset();
+  ProcessedSize = 0;
+}
+
+
+  
+void CStreamBinder::CreateStreams(ISequentialInStream **inStream, 
+      ISequentialOutStream **outStream)
+{
+  CSequentialInStreamForBinder *inStreamSpec = new 
+      CSequentialInStreamForBinder;
+  CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+  inStreamSpec->SetBinder(this);
+  *inStream = inStreamLoc.Detach();
+
+  CSequentialOutStreamForBinder *outStreamSpec = new 
+      CSequentialOutStreamForBinder;
+  CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec);
+  outStreamSpec->SetBinder(this);
+  *outStream = outStreamLoc.Detach();
+
+  _buffer = NULL;
+  _bufferSize= 0;
+  ProcessedSize = 0;
+}
+
+HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 sizeToRead = size;
+  if (size > 0)
+  {
+    RINOK(_thereAreBytesToReadEvent.Lock());
+    sizeToRead = MyMin(_bufferSize, size);
+    if (_bufferSize > 0)
+    {
+      MoveMemory(data, _buffer, sizeToRead);
+      _buffer = ((const Byte *)_buffer) + sizeToRead;
+      _bufferSize -= sizeToRead;
+      if (_bufferSize == 0)
+      {
+        _thereAreBytesToReadEvent.Reset();
+        _allBytesAreWritenEvent.Set();
+      }
+    }
+  }
+  if (processedSize != NULL)
+    *processedSize = sizeToRead;
+  ProcessedSize += sizeToRead;
+  return S_OK;
+}
+
+void CStreamBinder::CloseRead()
+{
+  _readStreamIsClosedEvent.Set();
+}
+
+HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if (size > 0)
+  {
+    _buffer = data;
+    _bufferSize = size;
+    _allBytesAreWritenEvent.Reset();
+    _thereAreBytesToReadEvent.Set();
+
+    HANDLE events[2]; 
+    events[0] = _allBytesAreWritenEvent;
+    events[1] = _readStreamIsClosedEvent; 
+    DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
+    if (waitResult != WAIT_OBJECT_0 + 0)
+    {
+      // ReadingWasClosed = true;
+      return S_FALSE;
+    }
+    // if(!_allBytesAreWritenEvent.Lock())
+    //   return E_FAIL;
+  }
+  if (processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
+
+void CStreamBinder::CloseWrite()
+{
+  // _bufferSize must be = 0
+  _thereAreBytesToReadEvent.Set();
+}
diff --git a/lzma/CPP/7zip/Common/StreamBinder.h b/lzma/CPP/7zip/Common/StreamBinder.h
new file mode 100644 (file)
index 0000000..1de2372
--- /dev/null
@@ -0,0 +1,32 @@
+// StreamBinder.h
+
+#ifndef __STREAMBINDER_H
+#define __STREAMBINDER_H
+
+#include "../IStream.h"
+#include "../../Windows/Synchronization.h"
+
+class CStreamBinder
+{
+  NWindows::NSynchronization::CManualResetEvent _allBytesAreWritenEvent;
+  NWindows::NSynchronization::CManualResetEvent _thereAreBytesToReadEvent;
+  NWindows::NSynchronization::CManualResetEvent _readStreamIsClosedEvent;
+  UInt32 _bufferSize;
+  const void *_buffer;
+public:
+  // bool ReadingWasClosed;
+  UInt64 ProcessedSize;
+  CStreamBinder() {}
+  HRes CreateEvents();
+
+  void CreateStreams(ISequentialInStream **inStream, 
+      ISequentialOutStream **outStream);
+  HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
+  void CloseRead();
+
+  HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);
+  void CloseWrite();
+  void ReInit();
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/StreamObjects.cpp b/lzma/CPP/7zip/Common/StreamObjects.cpp
new file mode 100644 (file)
index 0000000..32f8f30
--- /dev/null
@@ -0,0 +1,68 @@
+// StreamObjects.cpp
+
+#include "StdAfx.h"
+
+#include "StreamObjects.h"
+#include "../../Common/Defs.h"
+
+
+STDMETHODIMP CSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 numBytesToRead = (UInt32)(MyMin(_pos + size, _size) - _pos);
+  memmove(data, _dataPointer + _pos, numBytesToRead);
+  _pos += numBytesToRead;
+  if(processedSize != NULL)
+    *processedSize = numBytesToRead;
+  return S_OK;
+}
+
+
+void CWriteBuffer::Write(const void *data, size_t size)
+{
+  size_t newCapacity = _size + size;
+  _buffer.EnsureCapacity(newCapacity);
+  memmove(_buffer + _size, data, size);
+  _size += size;
+}
+
+STDMETHODIMP CSequentialOutStreamImp::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  _writeBuffer.Write(data, size);
+  if(processedSize != NULL)
+    *processedSize = size;
+  return S_OK; 
+}
+
+STDMETHODIMP CSequentialOutStreamImp2::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 newSize = size;
+  if (_pos + size > _size)
+    newSize = (UInt32)(_size - _pos);
+  memmove(_buffer + _pos, data, newSize);
+  if(processedSize != NULL)
+    *processedSize = newSize;
+  _pos += newSize;
+  if (newSize != size)
+    return E_FAIL;
+  return S_OK; 
+}
+
+STDMETHODIMP CSequentialInStreamSizeCount::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result = _stream->Read(data, size, &realProcessedSize);
+  _size += realProcessedSize;
+  if (processedSize != 0)
+    *processedSize = realProcessedSize;
+  return result; 
+}
+
+STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result = _stream->Write(data, size, &realProcessedSize);
+  _size += realProcessedSize;
+  if (processedSize != 0)
+    *processedSize = realProcessedSize;
+  return result; 
+}
diff --git a/lzma/CPP/7zip/Common/StreamObjects.h b/lzma/CPP/7zip/Common/StreamObjects.h
new file mode 100644 (file)
index 0000000..6f670f5
--- /dev/null
@@ -0,0 +1,117 @@
+// StreamObjects.h
+
+#ifndef __STREAMOBJECTS_H
+#define __STREAMOBJECTS_H
+
+#include "../../Common/DynamicBuffer.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CSequentialInStreamImp: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+  const Byte *_dataPointer;
+  size_t _size;
+  size_t _pos;
+
+public:
+  void Init(const Byte *dataPointer, size_t size)
+  {
+    _dataPointer = dataPointer;
+    _size = size;
+    _pos = 0;
+  }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+
+class CWriteBuffer
+{
+  CByteDynamicBuffer _buffer;
+  size_t _size;
+public:
+  CWriteBuffer(): _size(0) {}
+  void Init() { _size = 0;  }
+  void Write(const void *data, size_t size);
+  size_t GetSize() const { return _size; }
+  const CByteDynamicBuffer& GetBuffer() const { return _buffer; }
+};
+
+class CSequentialOutStreamImp: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  CWriteBuffer _writeBuffer;
+public:
+  void Init() { _writeBuffer.Init(); }
+  size_t GetSize() const { return _writeBuffer.GetSize(); }
+  const CByteDynamicBuffer& GetBuffer() const { return _writeBuffer.GetBuffer(); }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CSequentialOutStreamImp2: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  Byte *_buffer;
+  size_t _size;
+  size_t _pos;
+public:
+
+  void Init(Byte *buffer, size_t size)  
+  { 
+    _buffer = buffer;
+    _pos = 0;
+    _size = size; 
+  }
+
+  size_t GetPos() const { return _pos; }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CSequentialInStreamSizeCount: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialInStream> _stream;
+  UInt64 _size;
+public:
+  void Init(ISequentialInStream *stream)
+  {
+    _stream = stream;
+    _size = 0;
+  }
+  UInt64 GetSize() const { return _size; }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CSequentialOutStreamSizeCount: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt64 _size;
+public:
+  void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+  void Init() { _size = 0; }
+  UInt64 GetSize() const { return _size; }
+
+  MY_UNKNOWN_IMP
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/StreamUtils.cpp b/lzma/CPP/7zip/Common/StreamUtils.cpp
new file mode 100644 (file)
index 0000000..1d95127
--- /dev/null
@@ -0,0 +1,44 @@
+// StreamUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+#include "StreamUtils.h"
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, UInt32 size, UInt32 *processedSize)
+{
+  if (processedSize != 0)
+    *processedSize = 0;
+  while(size != 0)
+  {
+    UInt32 processedSizeLoc; 
+    HRESULT res = stream->Read(data, size, &processedSizeLoc);
+    if (processedSize != 0)
+      *processedSize += processedSizeLoc;
+    data = (Byte *)((Byte *)data + processedSizeLoc);
+    size -= processedSizeLoc;
+    RINOK(res);
+    if (processedSizeLoc == 0)
+      return S_OK;
+  }
+  return S_OK;
+}
+
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if (processedSize != 0)
+    *processedSize = 0;
+  while(size != 0)
+  {
+    UInt32 processedSizeLoc; 
+    HRESULT res = stream->Write(data, size, &processedSizeLoc);
+    if (processedSize != 0)
+      *processedSize += processedSizeLoc;
+    data = (const void *)((const Byte *)data + processedSizeLoc);
+    size -= processedSizeLoc;
+    RINOK(res);
+    if (processedSizeLoc == 0)
+      return E_FAIL;
+  }
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Common/StreamUtils.h b/lzma/CPP/7zip/Common/StreamUtils.h
new file mode 100644 (file)
index 0000000..59f8873
--- /dev/null
@@ -0,0 +1,11 @@
+// StreamUtils.h
+
+#ifndef __STREAMUTILS_H
+#define __STREAMUTILS_H
+
+#include "../IStream.h"
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, UInt32 size, UInt32 *processedSize);
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, UInt32 size, UInt32 *processedSize);
+
+#endif
diff --git a/lzma/CPP/7zip/Common/VirtThread.cpp b/lzma/CPP/7zip/Common/VirtThread.cpp
new file mode 100644 (file)
index 0000000..3567f98
--- /dev/null
@@ -0,0 +1,45 @@
+// VirtThread.cpp
+
+#include "StdAfx.h"
+
+#include "VirtThread.h"
+
+static THREAD_FUNC_DECL CoderThread(void *p)
+{
+  for (;;)
+  {
+    CVirtThread *t = (CVirtThread *)p;
+    t->StartEvent.Lock();
+    if (t->ExitEvent)
+      return 0;
+    t->Execute();
+    t->FinishedEvent.Set();
+  }
+}
+
+HRes CVirtThread::Create()
+{
+  RINOK(StartEvent.CreateIfNotCreated());
+  RINOK(FinishedEvent.CreateIfNotCreated());
+  StartEvent.Reset();
+  FinishedEvent.Reset();
+  ExitEvent = false;
+  if (Thread.IsCreated())
+    return S_OK;
+  return Thread.Create(CoderThread, this);
+}
+
+void CVirtThread::Start()
+{
+  ExitEvent = false;
+  StartEvent.Set();
+}
+
+CVirtThread::~CVirtThread()
+{
+  ExitEvent = true;
+  if (StartEvent.IsCreated())
+    StartEvent.Set();
+  Thread.Wait();
+}
+
diff --git a/lzma/CPP/7zip/Common/VirtThread.h b/lzma/CPP/7zip/Common/VirtThread.h
new file mode 100644 (file)
index 0000000..62c055b
--- /dev/null
@@ -0,0 +1,23 @@
+// VirtThread.h
+
+#ifndef __VIRTTHREAD_H
+#define __VIRTTHREAD_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+
+struct CVirtThread
+{
+  NWindows::NSynchronization::CAutoResetEvent StartEvent;
+  NWindows::NSynchronization::CAutoResetEvent FinishedEvent;
+  NWindows::CThread Thread;
+  bool ExitEvent;
+
+  ~CVirtThread();
+  HRes Create();
+  void Start();
+  void WaitFinish() { FinishedEvent.Lock(); } 
+  virtual void Execute() = 0;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/ARM.cpp b/lzma/CPP/7zip/Compress/Branch/ARM.cpp
new file mode 100644 (file)
index 0000000..5870bc0
--- /dev/null
@@ -0,0 +1,19 @@
+// ARM.cpp
+
+#include "StdAfx.h"
+#include "ARM.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Compress/Branch/BranchARM.h"
+}
+
+UInt32 CBC_ARM_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::ARM_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_ARM_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::ARM_Convert(data, size, _bufferPos, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/ARM.h b/lzma/CPP/7zip/Compress/Branch/ARM.h
new file mode 100644 (file)
index 0000000..5561299
--- /dev/null
@@ -0,0 +1,10 @@
+// ARM.h
+
+#ifndef __ARM_H
+#define __ARM_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARM, 0x05, 1)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/ARMThumb.cpp b/lzma/CPP/7zip/Compress/Branch/ARMThumb.cpp
new file mode 100644 (file)
index 0000000..7df641a
--- /dev/null
@@ -0,0 +1,20 @@
+// ARMThumb.cpp
+
+#include "StdAfx.h"
+
+#include "ARMThumb.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Compress/Branch/BranchARMThumb.h"
+}
+
+UInt32 CBC_ARMThumb_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::ARMThumb_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_ARMThumb_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::ARMThumb_Convert(data, size, _bufferPos, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/ARMThumb.h b/lzma/CPP/7zip/Compress/Branch/ARMThumb.h
new file mode 100644 (file)
index 0000000..601e40b
--- /dev/null
@@ -0,0 +1,10 @@
+// ARMThumb.h
+
+#ifndef __ARMTHUMB_H
+#define __ARMTHUMB_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARMThumb, 0x07, 1)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/BCJ2Register.cpp b/lzma/CPP/7zip/Compress/Branch/BCJ2Register.cpp
new file mode 100644 (file)
index 0000000..88ebbac
--- /dev/null
@@ -0,0 +1,18 @@
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "x86_2.h"
+static void *CreateCodec() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CEncoder());  }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+  { CreateCodec, CreateCodecOut, 0x0303011B, L"BCJ2", 4, false };
+
+REGISTER_CODEC(BCJ2)
diff --git a/lzma/CPP/7zip/Compress/Branch/BCJRegister.cpp b/lzma/CPP/7zip/Compress/Branch/BCJRegister.cpp
new file mode 100644 (file)
index 0000000..a62d964
--- /dev/null
@@ -0,0 +1,18 @@
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "x86.h"
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new CBCJ_x86_Encoder());  }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+  { CreateCodec, CreateCodecOut, 0x03030103, L"BCJ", 1, true };
+
+REGISTER_CODEC(BCJ)
diff --git a/lzma/CPP/7zip/Compress/Branch/BranchCoder.cpp b/lzma/CPP/7zip/Compress/Branch/BranchCoder.cpp
new file mode 100644 (file)
index 0000000..8d25f0d
--- /dev/null
@@ -0,0 +1,18 @@
+// BranchCoder.cpp
+
+#include "StdAfx.h"
+#include "BranchCoder.h"
+
+STDMETHODIMP CBranchConverter::Init()
+{
+  _bufferPos = 0;
+  SubInit();
+  return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size)
+{
+  UInt32 processedSize = SubFilter(data, size);
+  _bufferPos += processedSize;
+  return processedSize;
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/BranchCoder.h b/lzma/CPP/7zip/Compress/Branch/BranchCoder.h
new file mode 100644 (file)
index 0000000..102f0da
--- /dev/null
@@ -0,0 +1,45 @@
+// BranchCoder.h
+
+#ifndef __BRANCH_CODER_H
+#define __BRANCH_CODER_H
+
+#include "Common/MyCom.h"
+#include "Common/Types.h"
+
+#include "../../ICoder.h"
+
+class CBranchConverter:
+  public ICompressFilter,
+  public CMyUnknownImp
+{
+protected:
+  UInt32 _bufferPos;
+  virtual void SubInit() {}
+  virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0;
+public:
+  MY_UNKNOWN_IMP;
+  STDMETHOD(Init)();
+  STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+#define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \
+  { public: UInt32 SubFilter(Byte *data, UInt32 size); }; 
+
+#define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \
+  { public: UInt32 SubFilter(Byte *data, UInt32 size); }; 
+
+#define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+  { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; 
+
+#define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+  { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; 
+
+#define MyClassA(Name, id, subId)  \
+MyClassEncoderA(Name ## _Encoder) \
+MyClassDecoderA(Name ## _Decoder)
+
+#define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT)  \
+MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \
+MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/BranchRegister.cpp b/lzma/CPP/7zip/Compress/Branch/BranchRegister.cpp
new file mode 100644 (file)
index 0000000..2ccdcc6
--- /dev/null
@@ -0,0 +1,34 @@
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "PPC.h"
+#include "IA64.h"
+#include "ARM.h"
+#include "ARMThumb.h"
+#include "SPARC.h"
+
+#define CREATE_CODEC(x) \
+  static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## _Decoder); } \
+  static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## _Encoder); }
+
+CREATE_CODEC(BC_PPC_B)
+CREATE_CODEC(BC_IA64)
+CREATE_CODEC(BC_ARM)
+CREATE_CODEC(BC_ARMThumb)
+CREATE_CODEC(BC_SPARC)
+
+#define METHOD_ITEM(x, id1, id2, name) { CreateCodec ## x, CreateCodec ## x ## Out, 0x03030000 + (id1 * 256) + id2, name, 1, true  }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+  METHOD_ITEM(BC_PPC_B,   0x02, 0x05, L"BC_PPC_B"),
+  METHOD_ITEM(BC_IA64,    0x04, 1, L"BC_IA64"),
+  METHOD_ITEM(BC_ARM,     0x05, 1, L"BC_ARM"),
+  METHOD_ITEM(BC_ARMThumb,0x07, 1, L"BC_ARMThumb"),
+  METHOD_ITEM(BC_SPARC,   0x08, 0x05, L"BC_SPARC")
+};
+
+REGISTER_CODECS(Branch)
diff --git a/lzma/CPP/7zip/Compress/Branch/IA64.cpp b/lzma/CPP/7zip/Compress/Branch/IA64.cpp
new file mode 100644 (file)
index 0000000..ae4766a
--- /dev/null
@@ -0,0 +1,19 @@
+// IA64.cpp
+
+#include "StdAfx.h"
+#include "IA64.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Compress/Branch/BranchIA64.h"
+}
+
+UInt32 CBC_IA64_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::IA64_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_IA64_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::IA64_Convert(data, size, _bufferPos, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/IA64.h b/lzma/CPP/7zip/Compress/Branch/IA64.h
new file mode 100644 (file)
index 0000000..7fe715e
--- /dev/null
@@ -0,0 +1,10 @@
+// IA64.h
+
+#ifndef __IA64_H
+#define __IA64_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_IA64, 0x04, 1)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/PPC.cpp b/lzma/CPP/7zip/Compress/Branch/PPC.cpp
new file mode 100644 (file)
index 0000000..ecd4b3d
--- /dev/null
@@ -0,0 +1,19 @@
+// PPC.cpp
+
+#include "StdAfx.h"
+#include "PPC.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Compress/Branch/BranchPPC.h"
+}
+
+UInt32 CBC_PPC_B_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::PPC_B_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_PPC_B_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::PPC_B_Convert(data, size, _bufferPos, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/PPC.h b/lzma/CPP/7zip/Compress/Branch/PPC.h
new file mode 100644 (file)
index 0000000..a0e3344
--- /dev/null
@@ -0,0 +1,10 @@
+// PPC.h
+
+#ifndef __PPC_H
+#define __PPC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_PPC_B, 0x02, 5)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/SPARC.cpp b/lzma/CPP/7zip/Compress/Branch/SPARC.cpp
new file mode 100644 (file)
index 0000000..5678eb3
--- /dev/null
@@ -0,0 +1,19 @@
+// SPARC.cpp
+
+#include "StdAfx.h"
+#include "SPARC.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Compress/Branch/BranchSPARC.h"
+}
+
+UInt32 CBC_SPARC_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::SPARC_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_SPARC_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+  return ::SPARC_Convert(data, size, _bufferPos, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/SPARC.h b/lzma/CPP/7zip/Compress/Branch/SPARC.h
new file mode 100644 (file)
index 0000000..e0a682e
--- /dev/null
@@ -0,0 +1,10 @@
+// SPARC.h
+
+#ifndef __SPARC_H
+#define __SPARC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_SPARC, 0x08, 5)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/StdAfx.cpp b/lzma/CPP/7zip/Compress/Branch/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Compress/Branch/StdAfx.h b/lzma/CPP/7zip/Compress/Branch/StdAfx.h
new file mode 100644 (file)
index 0000000..e7fb698
--- /dev/null
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/x86.cpp b/lzma/CPP/7zip/Compress/Branch/x86.cpp
new file mode 100644 (file)
index 0000000..79d4965
--- /dev/null
@@ -0,0 +1,14 @@
+// x86.cpp
+
+#include "StdAfx.h"
+#include "x86.h"
+
+UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+  return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 1);
+}
+
+UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+  return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/Branch/x86.h b/lzma/CPP/7zip/Compress/Branch/x86.h
new file mode 100644 (file)
index 0000000..5817660
--- /dev/null
@@ -0,0 +1,21 @@
+// x86.h
+
+#ifndef __X86_H
+#define __X86_H
+
+#include "BranchCoder.h"
+extern "C" 
+{ 
+#include "../../../../C/Compress/Branch/BranchX86.h"
+}
+
+struct CBranch86
+{
+  UInt32 _prevMask;
+  void x86Init() { x86_Convert_Init(_prevMask); }
+};
+
+MyClassB(BCJ_x86, 0x01, 3, CBranch86 , 
+    virtual void SubInit() { x86Init(); })
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Branch/x86_2.cpp b/lzma/CPP/7zip/Compress/Branch/x86_2.cpp
new file mode 100644 (file)
index 0000000..51176c9
--- /dev/null
@@ -0,0 +1,392 @@
+// x86_2.cpp
+
+#include "StdAfx.h"
+#include "x86_2.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Alloc.h"
+}
+
+namespace NCompress {
+namespace NBcj2 {
+
+inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); }
+inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); }
+inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); }
+
+#ifndef EXTRACT_ONLY
+
+static const int kBufferSize = 1 << 17;
+
+static bool inline Test86MSByte(Byte b)
+{
+  return (b == 0 || b == 0xFF);
+}
+
+bool CEncoder::Create()
+{
+  if (!_mainStream.Create(1 << 16))
+    return false;
+  if (!_callStream.Create(1 << 20))
+    return false;
+  if (!_jumpStream.Create(1 << 20))
+    return false;
+  if (!_rangeEncoder.Create(1 << 20))
+    return false;
+  if (_buffer == 0)
+  {
+    _buffer = (Byte *)MidAlloc(kBufferSize);
+    if (_buffer == 0)
+      return false;
+  }
+  return true;
+}
+
+CEncoder::~CEncoder()
+{
+  ::MidFree(_buffer);
+}
+
+HRESULT CEncoder::Flush()
+{
+  RINOK(_mainStream.Flush());
+  RINOK(_callStream.Flush());
+  RINOK(_jumpStream.Flush());
+  _rangeEncoder.FlushData();
+  return _rangeEncoder.FlushStream();
+}
+
+const UInt32 kDefaultLimit = (1 << 24);
+
+HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 ** /* outSizes */,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress)
+{
+  if (numInStreams != 1 || numOutStreams != 4)
+    return E_INVALIDARG;
+
+  if (!Create())
+    return E_OUTOFMEMORY;
+
+  bool sizeIsDefined = false;
+  UInt64 inSize = 0;
+  if (inSizes != NULL)
+    if (inSizes[0] != NULL)
+    {
+      inSize = *inSizes[0];
+      if (inSize <= kDefaultLimit)
+        sizeIsDefined = true;
+    }
+
+  ISequentialInStream *inStream = inStreams[0];
+
+  _mainStream.SetStream(outStreams[0]);
+  _mainStream.Init();
+  _callStream.SetStream(outStreams[1]);
+  _callStream.Init();
+  _jumpStream.SetStream(outStreams[2]);
+  _jumpStream.Init();
+  _rangeEncoder.SetStream(outStreams[3]);
+  _rangeEncoder.Init();
+  for (int i = 0; i < 256 + 2; i++)
+    _statusEncoder[i].Init();
+  CCoderReleaser releaser(this);
+
+  CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
+  {
+    inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
+  }
+
+  UInt32 nowPos = 0;
+  UInt64 nowPos64 = 0;
+  UInt32 bufferPos = 0;
+
+  Byte prevByte = 0;
+
+  UInt64 subStreamIndex = 0;
+  UInt64 subStreamStartPos  = 0;
+  UInt64 subStreamEndPos = 0;
+
+  for (;;)
+  {
+    UInt32 processedSize = 0;
+    for (;;)
+    {
+      UInt32 size = kBufferSize - (bufferPos + processedSize);
+      UInt32 processedSizeLoc;
+      if (size == 0)
+        break;
+      RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
+      if (processedSizeLoc == 0)
+        break;
+      processedSize += processedSizeLoc;
+    }
+    UInt32 endPos = bufferPos + processedSize;
+    
+    if (endPos < 5)
+    {
+      // change it 
+      for (bufferPos = 0; bufferPos < endPos; bufferPos++)
+      {
+        Byte b = _buffer[bufferPos];
+        _mainStream.WriteByte(b);
+        UInt32 index;
+        if (b == 0xE8)
+          index = prevByte;
+        else if (b == 0xE9)
+          index = 256;
+        else if (IsJcc(prevByte, b))
+          index = 257;
+        else
+        {
+          prevByte = b;
+          continue;
+        }
+        _statusEncoder[index].Encode(&_rangeEncoder, 0);
+        prevByte = b;
+      }
+      return Flush();
+    }
+
+    bufferPos = 0;
+
+    UInt32 limit = endPos - 5;
+    while(bufferPos <= limit)
+    {
+      Byte b = _buffer[bufferPos];
+      _mainStream.WriteByte(b);
+      if (!IsJ(prevByte, b))
+      {
+        bufferPos++;
+        prevByte = b;
+        continue;
+      }
+      Byte nextByte = _buffer[bufferPos + 4];
+      UInt32 src = 
+        (UInt32(nextByte) << 24) |
+        (UInt32(_buffer[bufferPos + 3]) << 16) |
+        (UInt32(_buffer[bufferPos + 2]) << 8) |
+        (_buffer[bufferPos + 1]);
+      UInt32 dest = (nowPos + bufferPos + 5) + src;
+      // if (Test86MSByte(nextByte))
+      bool convert;
+      if (getSubStreamSize != NULL)
+      {
+        UInt64 currentPos = (nowPos64 + bufferPos);
+        while (subStreamEndPos < currentPos)
+        {
+          UInt64 subStreamSize;
+          HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
+          if (result == S_OK)
+          {
+            subStreamStartPos = subStreamEndPos;
+            subStreamEndPos += subStreamSize;          
+            subStreamIndex++;
+          }
+          else if (result == S_FALSE || result == E_NOTIMPL)
+          {
+            getSubStreamSize.Release();
+            subStreamStartPos = 0;
+            subStreamEndPos = subStreamStartPos - 1;          
+          }
+          else
+            return result;
+        }
+        if (getSubStreamSize == NULL)
+        {
+          if (sizeIsDefined)
+            convert = (dest < inSize);
+          else
+            convert = Test86MSByte(nextByte);
+        }
+        else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
+          convert = Test86MSByte(nextByte);
+        else
+        {
+          UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
+          convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
+        }
+      }
+      else if (sizeIsDefined)
+        convert = (dest < inSize);
+      else
+        convert = Test86MSByte(nextByte);
+      unsigned index = GetIndex(prevByte, b);
+      if (convert)
+      {
+        _statusEncoder[index].Encode(&_rangeEncoder, 1);
+        bufferPos += 5;
+        COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+        for (int i = 24; i >= 0; i -= 8)
+          s.WriteByte((Byte)(dest >> i));
+        prevByte = nextByte;
+      }
+      else
+      {
+        _statusEncoder[index].Encode(&_rangeEncoder, 0);
+        bufferPos++;
+        prevByte = b;
+      }
+    }
+    nowPos += bufferPos;
+    nowPos64 += bufferPos;
+
+    if (progress != NULL)
+    {
+      /*
+      const UInt64 compressedSize = 
+        _mainStream.GetProcessedSize() + 
+        _callStream.GetProcessedSize() +
+        _jumpStream.GetProcessedSize() +
+        _rangeEncoder.GetProcessedSize();
+      */
+      RINOK(progress->SetRatioInfo(&nowPos64, NULL));
+    }
+    UInt32 i = 0;
+    while(bufferPos < endPos)
+      _buffer[i++] = _buffer[bufferPos++];
+    bufferPos = i;
+  }
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress)
+{
+  try
+  {
+    return CodeReal(inStreams, inSizes, numInStreams,
+      outStreams, outSizes,numOutStreams, progress);
+  }
+  catch(const COutBufferException &e) { return e.ErrorCode; }
+  catch(...) { return S_FALSE; }
+}
+
+#endif
+
+HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams,
+      const UInt64 ** /* inSizes */,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 ** /* outSizes */,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress)
+{
+  if (numInStreams != 4 || numOutStreams != 1)
+    return E_INVALIDARG;
+
+  if (!_mainInStream.Create(1 << 16))
+    return E_OUTOFMEMORY;
+  if (!_callStream.Create(1 << 20))
+    return E_OUTOFMEMORY;
+  if (!_jumpStream.Create(1 << 16))
+    return E_OUTOFMEMORY;
+  if (!_rangeDecoder.Create(1 << 20))
+    return E_OUTOFMEMORY;
+  if (!_outStream.Create(1 << 16))
+    return E_OUTOFMEMORY;
+
+  _mainInStream.SetStream(inStreams[0]);
+  _callStream.SetStream(inStreams[1]);
+  _jumpStream.SetStream(inStreams[2]);
+  _rangeDecoder.SetStream(inStreams[3]);
+  _outStream.SetStream(outStreams[0]);
+
+  _mainInStream.Init();
+  _callStream.Init();
+  _jumpStream.Init();
+  _rangeDecoder.Init();
+  _outStream.Init();
+
+  for (int i = 0; i < 256 + 2; i++)
+    _statusDecoder[i].Init();
+
+  CCoderReleaser releaser(this);
+
+  Byte prevByte = 0;
+  UInt32 processedBytes = 0;
+  for (;;)
+  {
+    if (processedBytes >= (1 << 20) && progress != NULL)
+    {
+      /*
+      const UInt64 compressedSize = 
+        _mainInStream.GetProcessedSize() + 
+        _callStream.GetProcessedSize() +
+        _jumpStream.GetProcessedSize() +
+        _rangeDecoder.GetProcessedSize();
+      */
+      const UInt64 nowPos64 = _outStream.GetProcessedSize();
+      RINOK(progress->SetRatioInfo(NULL, &nowPos64));
+      processedBytes = 0;
+    }
+    UInt32 i;
+    Byte b = 0;
+    const UInt32 kBurstSize = (1 << 18);
+    for (i = 0; i < kBurstSize; i++)
+    {
+      if (!_mainInStream.ReadByte(b))
+        return Flush();
+      _outStream.WriteByte(b);
+      if (IsJ(prevByte, b))
+        break;
+      prevByte = b;
+    }
+    processedBytes += i;
+    if (i == kBurstSize)
+      continue;
+    unsigned index = GetIndex(prevByte, b);
+    if (_statusDecoder[index].Decode(&_rangeDecoder) == 1)
+    {
+      UInt32 src = 0;
+      CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+      for (int i = 0; i < 4; i++)
+      {
+        Byte b0;
+        if(!s.ReadByte(b0))
+          return S_FALSE;
+        src <<= 8;
+        src |= ((UInt32)b0);
+      }
+      UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
+      _outStream.WriteByte((Byte)(dest));
+      _outStream.WriteByte((Byte)(dest >> 8));
+      _outStream.WriteByte((Byte)(dest >> 16));
+      _outStream.WriteByte((Byte)(dest >> 24));
+      prevByte = (Byte)(dest >> 24);
+      processedBytes += 4;
+    }
+    else
+      prevByte = b;
+  }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress)
+{
+  try
+  {
+    return CodeReal(inStreams, inSizes, numInStreams,
+        outStreams, outSizes,numOutStreams, progress);
+  }
+  catch(const CInBufferException &e) { return e.ErrorCode; }
+  catch(const COutBufferException &e) { return e.ErrorCode; }
+  catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/Branch/x86_2.h b/lzma/CPP/7zip/Compress/Branch/x86_2.h
new file mode 100644 (file)
index 0000000..2e4a526
--- /dev/null
@@ -0,0 +1,123 @@
+// x86_2.h
+
+#ifndef __BRANCH_X86_2_H
+#define __BRANCH_X86_2_H
+
+#include "../../../Common/MyCom.h"
+#include "../RangeCoder/RangeCoderBit.h"
+#include "../../ICoder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+const int kNumMoveBits = 5;
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+  public ICompressCoder2,
+  public CMyUnknownImp
+{
+  Byte *_buffer;
+public:
+  CEncoder(): _buffer(0) {};
+  ~CEncoder();
+  bool Create();
+
+  COutBuffer _mainStream;
+  COutBuffer _callStream;
+  COutBuffer _jumpStream;
+  NCompress::NRangeCoder::CEncoder _rangeEncoder;
+  NCompress::NRangeCoder::CBitEncoder<kNumMoveBits> _statusEncoder[256 + 2];
+
+  HRESULT Flush();
+  void ReleaseStreams()
+  {
+    _mainStream.ReleaseStream();
+    _callStream.ReleaseStream();
+    _jumpStream.ReleaseStream();
+    _rangeEncoder.ReleaseStream();
+  }
+
+  class CCoderReleaser
+  {
+    CEncoder *_coder;
+  public:
+    CCoderReleaser(CEncoder *coder): _coder(coder) {}
+    ~CCoderReleaser() {  _coder->ReleaseStreams(); }
+  };
+
+public: 
+
+  MY_UNKNOWN_IMP
+
+  HRESULT CodeReal(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress);
+  STDMETHOD(Code)(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress);
+}; 
+
+#endif
+
+class CDecoder:
+  public ICompressCoder2,
+  public CMyUnknownImp
+{ 
+public:
+  CInBuffer _mainInStream;
+  CInBuffer _callStream;
+  CInBuffer _jumpStream;
+  NCompress::NRangeCoder::CDecoder _rangeDecoder;
+  NCompress::NRangeCoder::CBitDecoder<kNumMoveBits> _statusDecoder[256 + 2];
+
+  COutBuffer _outStream;
+
+  void ReleaseStreams()
+  {
+    _mainInStream.ReleaseStream();
+    _callStream.ReleaseStream();
+    _jumpStream.ReleaseStream();
+    _rangeDecoder.ReleaseStream();
+    _outStream.ReleaseStream();
+  }
+
+  HRESULT Flush() { return _outStream.Flush(); }
+  class CCoderReleaser
+  {
+    CDecoder *_coder;
+  public:
+    CCoderReleaser(CDecoder *coder): _coder(coder) {}
+    ~CCoderReleaser()  { _coder->ReleaseStreams(); }
+  };
+
+public: 
+  MY_UNKNOWN_IMP
+  HRESULT CodeReal(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress);
+  STDMETHOD(Code)(ISequentialInStream **inStreams,
+      const UInt64 **inSizes,
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams,
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress);
+}; 
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/ByteSwap/ByteSwap.cpp b/lzma/CPP/7zip/Compress/ByteSwap/ByteSwap.cpp
new file mode 100644 (file)
index 0000000..3f252f2
--- /dev/null
@@ -0,0 +1,38 @@
+// ByteSwap.cpp
+
+#include "StdAfx.h"
+
+#include "ByteSwap.h"
+
+STDMETHODIMP CByteSwap2::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)
+{
+  const UInt32 kStep = 2;
+  UInt32 i;
+  for (i = 0; i + kStep <= size; i += kStep)
+  {
+    Byte b = data[i];
+    data[i] = data[i + 1];
+    data[i + 1] = b;
+  }
+  return i;
+}
+
+STDMETHODIMP CByteSwap4::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)
+{
+  const UInt32 kStep = 4;
+  UInt32 i;
+  for (i = 0; i + kStep <= size; i += kStep)
+  {
+    Byte b0 = data[i];
+    Byte b1 = data[i + 1];
+    data[i] = data[i + 3];
+    data[i + 1] = data[i + 2];
+    data[i + 2] = b1;
+    data[i + 3] = b0;
+  }
+  return i;
+}
diff --git a/lzma/CPP/7zip/Compress/ByteSwap/ByteSwap.h b/lzma/CPP/7zip/Compress/ByteSwap/ByteSwap.h
new file mode 100644 (file)
index 0000000..0030306
--- /dev/null
@@ -0,0 +1,37 @@
+// ByteSwap.h
+
+#ifndef __BYTESWAP_H
+#define __BYTESWAP_H
+
+#include "../../ICoder.h"
+#include "Common/MyCom.h"
+
+// {23170F69-40C1-278B-0203-020000000000}
+DEFINE_GUID(CLSID_CCompressConvertByteSwap2, 
+0x23170F69, 0x40C1, 0x278B, 0x02, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+// {23170F69-40C1-278B-0203-040000000000}
+DEFINE_GUID(CLSID_CCompressConvertByteSwap4, 
+0x23170F69, 0x40C1, 0x278B, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+class CByteSwap2: 
+  public ICompressFilter,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+  STDMETHOD(Init)();
+  STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+class CByteSwap4: 
+  public ICompressFilter,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+  STDMETHOD(Init)();
+  STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/ByteSwap/ByteSwapRegister.cpp b/lzma/CPP/7zip/Compress/ByteSwap/ByteSwapRegister.cpp
new file mode 100644 (file)
index 0000000..b1cf8fa
--- /dev/null
@@ -0,0 +1,17 @@
+// ByteSwapRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "ByteSwap.h"
+static void *CreateCodec2() { return (void *)(ICompressFilter *)(new CByteSwap2); }
+static void *CreateCodec4() { return (void *)(ICompressFilter *)(new CByteSwap4); }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+  { CreateCodec2, CreateCodec4, 0x020302, L"Swap2", 1, true },
+  { CreateCodec4, CreateCodec4, 0x020304, L"Swap4", 1, true }
+};
+
+REGISTER_CODECS(ByteSwap)
diff --git a/lzma/CPP/7zip/Compress/ByteSwap/StdAfx.cpp b/lzma/CPP/7zip/Compress/ByteSwap/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Compress/ByteSwap/StdAfx.h b/lzma/CPP/7zip/Compress/ByteSwap/StdAfx.h
new file mode 100644 (file)
index 0000000..e7fb698
--- /dev/null
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/CodecExports.cpp b/lzma/CPP/7zip/Compress/CodecExports.cpp
new file mode 100644 (file)
index 0000000..a4a85b6
--- /dev/null
@@ -0,0 +1,157 @@
+// CodecExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Windows/PropVariant.h"
+#include "../Common/RegisterCodec.h"
+#include "../ICoder.h"
+
+extern unsigned int g_NumCodecs;
+extern const CCodecInfo *g_Codecs[]; 
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec, 
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+  if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+    value->vt = VT_BSTR;
+  return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+  return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+static HRESULT SetClassID(CMethodId id, bool encode, PROPVARIANT *value)
+{
+  GUID clsId = CLSID_CCodec;
+  for (int i = 0; i < sizeof(id); i++, id >>= 8)
+    clsId.Data4[i] = (Byte)(id & 0xFF);
+  if (encode)
+    clsId.Data3++;
+  return SetPropGUID(clsId, value);
+}
+
+static HRESULT FindCodecClassId(const GUID *clsID, UInt32 isCoder2, bool isFilter, bool &encode, int &index)
+{
+  index = -1;
+  if (clsID->Data1 != CLSID_CCodec.Data1 || 
+      clsID->Data2 != CLSID_CCodec.Data2 ||
+      (clsID->Data3 & ~1) != kDecodeId)
+    return S_OK;
+  encode = (clsID->Data3 != kDecodeId);
+  UInt64 id = 0;
+  for (int j = 0; j < 8; j++)
+    id |= ((UInt64)clsID->Data4[j]) << (8 * j);
+  for (UInt32 i = 0; i < g_NumCodecs; i++)
+  {
+    const CCodecInfo &codec = *g_Codecs[i];
+    if (id != codec.Id || encode && !codec.CreateEncoder || !encode && !codec.CreateDecoder)
+      continue;
+    if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+        codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+      return E_NOINTERFACE;
+    index = i;
+    return S_OK;
+  }
+  return S_OK;
+}
+
+STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
+{
+  COM_TRY_BEGIN
+  *outObject = 0;
+  bool isCoder = (*iid == IID_ICompressCoder) != 0;
+  bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+  bool isFilter = (*iid == IID_ICompressFilter) != 0;
+  const CCodecInfo &codec = *g_Codecs[index];
+  if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+      codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+    return E_NOINTERFACE;
+  if (encode)
+  {
+    if (!codec.CreateEncoder)
+      return CLASS_E_CLASSNOTAVAILABLE;
+    *outObject = codec.CreateEncoder();
+  }
+  else
+  {
+    if (!codec.CreateDecoder)
+      return CLASS_E_CLASSNOTAVAILABLE;
+    *outObject = codec.CreateDecoder();
+  }
+  if (isCoder)
+    ((ICompressCoder *)*outObject)->AddRef();
+  else if (isCoder2)
+    ((ICompressCoder2 *)*outObject)->AddRef();
+  else
+    ((ICompressFilter *)*outObject)->AddRef();
+  return S_OK;
+  COM_TRY_END
+}
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
+{
+  *outObject = 0;
+  bool isCoder = (*iid == IID_ICompressCoder) != 0;
+  bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+  bool isFilter = (*iid == IID_ICompressFilter) != 0;
+  if (!isCoder && !isCoder2 && !isFilter)
+    return E_NOINTERFACE;
+  bool encode;
+  int codecIndex;
+  HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
+  if (res != S_OK)
+    return res;
+  if (codecIndex < 0)
+    return CLASS_E_CLASSNOTAVAILABLE;
+  return CreateCoder2(encode, codecIndex, iid, outObject);
+}
+
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
+{
+  ::VariantClear((VARIANTARG *)value);
+  const CCodecInfo &codec = *g_Codecs[codecIndex];
+  switch(propID)
+  {
+    case NMethodPropID::kID:
+    {
+      value->uhVal.QuadPart = (UInt64)codec.Id;
+      value->vt = VT_UI8;
+      break;
+    }
+    case NMethodPropID::kName:
+      if ((value->bstrVal = ::SysAllocString(codec.Name)) != 0)
+        value->vt = VT_BSTR;
+      break;
+    case NMethodPropID::kDecoder:
+      if (codec.CreateDecoder)
+        return SetClassID(codec.Id, false, value);
+      break;
+    case NMethodPropID::kEncoder:
+      if (codec.CreateEncoder)
+        return SetClassID(codec.Id, true, value);
+      break;
+    case NMethodPropID::kInStreams:
+    {
+      if (codec.NumInStreams != 1)
+      {
+        value->vt = VT_UI4;
+        value->ulVal = codec.NumInStreams;
+      }
+      break;
+    }
+  }
+  return S_OK;
+}
+
+STDAPI GetNumberOfMethods(UINT32 *numCodecs)
+{
+  *numCodecs = g_NumCodecs;
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Compress/Copy/CopyCoder.cpp b/lzma/CPP/7zip/Compress/Copy/CopyCoder.cpp
new file mode 100644 (file)
index 0000000..8e18db2
--- /dev/null
@@ -0,0 +1,62 @@
+// Compress/CopyCoder.cpp
+
+#include "StdAfx.h"
+
+extern "C" 
+{ 
+#include "../../../../C/Alloc.h"
+}
+
+#include "CopyCoder.h"
+#include "../../Common/StreamUtils.h"
+
+namespace NCompress {
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CCopyCoder::~CCopyCoder()
+{
+  ::MidFree(_buffer);
+}
+
+STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
+    ISequentialOutStream *outStream, 
+    const UInt64 * /* inSize */, const UInt64 *outSize,
+    ICompressProgressInfo *progress)
+{
+  if (_buffer == 0)
+  {
+    _buffer = (Byte *)::MidAlloc(kBufferSize);
+    if (_buffer == 0)
+      return E_OUTOFMEMORY;
+  }
+
+  TotalSize = 0;
+  for (;;)
+  {
+    UInt32 realProcessedSize;
+    UInt32 size = kBufferSize;
+    if (outSize != 0)
+      if (size > *outSize - TotalSize)
+        size = (UInt32)(*outSize - TotalSize);
+    RINOK(inStream->Read(_buffer, size, &realProcessedSize));
+    if (realProcessedSize == 0)
+      break;
+    RINOK(WriteStream(outStream, _buffer, realProcessedSize, NULL));
+    TotalSize += realProcessedSize;
+    if (progress != NULL)
+    {
+      RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
+    }
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
+{
+  *value = TotalSize;
+  return S_OK;
+}
+
+}
+
diff --git a/lzma/CPP/7zip/Compress/Copy/CopyCoder.h b/lzma/CPP/7zip/Compress/Copy/CopyCoder.h
new file mode 100644 (file)
index 0000000..d453069
--- /dev/null
@@ -0,0 +1,33 @@
+// Compress/CopyCoder.h
+
+#ifndef __COMPRESS_COPYCODER_H
+#define __COMPRESS_COPYCODER_H
+
+#include "../../ICoder.h"
+#include "../../../Common/MyCom.h"
+
+namespace NCompress {
+
+class CCopyCoder: 
+  public ICompressCoder,
+  public ICompressGetInStreamProcessedSize,
+  public CMyUnknownImp
+{
+  Byte *_buffer;
+public:
+  UInt64 TotalSize;
+  CCopyCoder(): TotalSize(0) , _buffer(0) {};
+  ~CCopyCoder();
+
+  MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize)
+
+  STDMETHOD(Code)(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, 
+      const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Copy/CopyRegister.cpp b/lzma/CPP/7zip/Compress/Copy/CopyRegister.cpp
new file mode 100644 (file)
index 0000000..1e688b7
--- /dev/null
@@ -0,0 +1,13 @@
+// LZMARegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "CopyCoder.h"
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); }
+
+static CCodecInfo g_CodecInfo =
+{ CreateCodec, CreateCodec, 0x00, L"Copy", 1, false };
+
+REGISTER_CODEC(Copy)
diff --git a/lzma/CPP/7zip/Compress/Copy/StdAfx.cpp b/lzma/CPP/7zip/Compress/Copy/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Compress/Copy/StdAfx.h b/lzma/CPP/7zip/Compress/Copy/StdAfx.h
new file mode 100644 (file)
index 0000000..92239ae
--- /dev/null
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif 
diff --git a/lzma/CPP/7zip/Compress/LZ/LZOutWindow.cpp b/lzma/CPP/7zip/Compress/LZ/LZOutWindow.cpp
new file mode 100644 (file)
index 0000000..9de2d06
--- /dev/null
@@ -0,0 +1,16 @@
+// LZOutWindow.cpp
+
+#include "StdAfx.h"
+
+#include "LZOutWindow.h"
+
+void CLZOutWindow::Init(bool solid)
+{
+  if(!solid)
+    COutBuffer::Init();
+  #ifdef _NO_EXCEPTIONS
+  ErrorCode = S_OK;
+  #endif
+}
+
+
diff --git a/lzma/CPP/7zip/Compress/LZ/LZOutWindow.h b/lzma/CPP/7zip/Compress/LZ/LZOutWindow.h
new file mode 100644 (file)
index 0000000..60b1b8a
--- /dev/null
@@ -0,0 +1,65 @@
+// LZOutWindow.h
+
+#ifndef __LZ_OUT_WINDOW_H
+#define __LZ_OUT_WINDOW_H
+
+#include "../../IStream.h"
+#include "../../Common/OutBuffer.h"
+
+#ifndef _NO_EXCEPTIONS
+typedef COutBufferException CLZOutWindowException;
+#endif
+
+class CLZOutWindow: public COutBuffer
+{
+public:
+  void Init(bool solid = false);
+  
+  // distance >= 0, len > 0, 
+  bool CopyBlock(UInt32 distance, UInt32 len)
+  {
+    UInt32 pos = _pos - distance - 1;
+    if (distance >= _pos)
+    {
+      if (!_overDict || distance >= _bufferSize)
+        return false;
+      pos += _bufferSize;
+    }
+    if (_limitPos - _pos > len && _bufferSize - pos > len)
+    {
+      const Byte *src = _buffer + pos;
+      Byte *dest = _buffer + _pos;
+      _pos += len;
+      do
+        *dest++ = *src++;
+      while(--len != 0);
+    }
+    else do
+    {
+      if (pos == _bufferSize)
+        pos = 0;
+      _buffer[_pos++] = _buffer[pos++];
+      if (_pos == _limitPos)
+        FlushWithCheck();  
+    }
+    while(--len != 0);
+    return true;
+  }
+  
+  void PutByte(Byte b)
+  {
+    _buffer[_pos++] = b;
+    if (_pos == _limitPos)
+      FlushWithCheck();  
+  }
+  
+  Byte GetByte(UInt32 distance) const
+  {
+    UInt32 pos = _pos - distance - 1;
+    if (pos >= _bufferSize)
+      pos += _bufferSize;
+    return _buffer[pos]; 
+  }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZ/StdAfx.h b/lzma/CPP/7zip/Compress/LZ/StdAfx.h
new file mode 100644 (file)
index 0000000..3ff6d8a
--- /dev/null
@@ -0,0 +1,6 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#endif 
diff --git a/lzma/CPP/7zip/Compress/LZMA/LZMA.h b/lzma/CPP/7zip/Compress/LZMA/LZMA.h
new file mode 100644 (file)
index 0000000..7bc4c43
--- /dev/null
@@ -0,0 +1,82 @@
+// LZMA.h
+
+#ifndef __LZMA_H
+#define __LZMA_H
+
+namespace NCompress {
+namespace NLZMA {
+
+const UInt32 kNumRepDistances = 4;
+
+const int kNumStates = 12;
+
+const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
+const Byte kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+const Byte kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+class CState
+{
+public:
+  Byte Index;
+  void Init() { Index = 0; }
+  void UpdateChar() { Index = kLiteralNextStates[Index]; }
+  void UpdateMatch() { Index = kMatchNextStates[Index]; }
+  void UpdateRep() { Index = kRepNextStates[Index]; }
+  void UpdateShortRep() { Index = kShortRepNextStates[Index]; }
+  bool IsCharState() const { return Index < 7; }
+};
+
+const int kNumPosSlotBits = 6; 
+const int kDicLogSizeMin = 0; 
+const int kDicLogSizeMax = 32; 
+const int kDistTableSizeMax = kDicLogSizeMax * 2; 
+
+const UInt32 kNumLenToPosStates = 4;
+
+inline UInt32 GetLenToPosState(UInt32 len)
+{
+  len -= 2;
+  if (len < kNumLenToPosStates)
+    return len;
+  return kNumLenToPosStates - 1;
+}
+
+namespace NLength {
+
+const int kNumPosStatesBitsMax = 4;
+const UInt32 kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
+
+const int kNumPosStatesBitsEncodingMax = 4;
+const UInt32 kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
+
+const int kNumLowBits = 3;
+const int kNumMidBits = 3;
+const int kNumHighBits = 8;
+const UInt32 kNumLowSymbols = 1 << kNumLowBits;
+const UInt32 kNumMidSymbols = 1 << kNumMidBits;
+const UInt32 kNumSymbolsTotal = kNumLowSymbols + kNumMidSymbols + (1 << kNumHighBits);
+
+}
+
+const UInt32 kMatchMinLen = 2;
+const UInt32 kMatchMaxLen = kMatchMinLen + NLength::kNumSymbolsTotal - 1;
+
+const int kNumAlignBits = 4;
+const UInt32 kAlignTableSize = 1 << kNumAlignBits;
+const UInt32 kAlignMask = (kAlignTableSize - 1);
+
+const UInt32 kStartPosModelIndex = 4;
+const UInt32 kEndPosModelIndex = 14;
+const UInt32 kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
+
+const UInt32 kNumFullDistances = 1 << (kEndPosModelIndex / 2);
+
+const int kNumLitPosStatesBitsEncodingMax = 4;
+const int kNumLitContextBitsMax = 8;
+
+const int kNumMoveBits = 5;
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA/LZMADecoder.cpp b/lzma/CPP/7zip/Compress/LZMA/LZMADecoder.cpp
new file mode 100644 (file)
index 0000000..1b73855
--- /dev/null
@@ -0,0 +1,338 @@
+// LZMADecoder.cpp
+
+#include "StdAfx.h"
+
+#include "LZMADecoder.h"
+#include "../../../Common/Defs.h"
+
+namespace NCompress {
+namespace NLZMA {
+
+const int kLenIdFinished = -1;
+const int kLenIdNeedInit = -2;
+
+void CDecoder::Init()
+{
+  { 
+    for(int i = 0; i < kNumStates; i++)
+    {
+      for (UInt32 j = 0; j <= _posStateMask; j++)
+      {
+        _isMatch[i][j].Init();
+        _isRep0Long[i][j].Init();
+      }
+      _isRep[i].Init();
+      _isRepG0[i].Init();
+      _isRepG1[i].Init();
+      _isRepG2[i].Init();
+    }
+  }
+  { 
+    for (UInt32 i = 0; i < kNumLenToPosStates; i++)
+    _posSlotDecoder[i].Init();
+  }
+  { 
+    for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+      _posDecoders[i].Init();
+  }
+  _posAlignDecoder.Init();
+  _lenDecoder.Init(_posStateMask + 1);
+  _repMatchLenDecoder.Init(_posStateMask + 1);
+  _literalDecoder.Init();
+
+  _state.Init();
+  _reps[0] = _reps[1] = _reps[2] = _reps[3] = 0;
+}
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+  if (_outSizeDefined)
+  {
+    const UInt64 rem = _outSize - _outWindowStream.GetProcessedSize();
+    if (curSize > rem)
+      curSize = (UInt32)rem;
+  }
+
+  if (_remainLen == kLenIdFinished)
+    return S_OK;
+  if (_remainLen == kLenIdNeedInit)
+  {
+    _rangeDecoder.Init();
+    Init();
+    _remainLen = 0;
+  }
+  if (curSize == 0)
+    return S_OK;
+
+  UInt32 rep0 = _reps[0];
+  UInt32 rep1 = _reps[1];
+  UInt32 rep2 = _reps[2];
+  UInt32 rep3 = _reps[3];
+  CState state = _state;
+  Byte previousByte;
+
+  while(_remainLen > 0 && curSize > 0)
+  {
+    previousByte = _outWindowStream.GetByte(rep0);
+    _outWindowStream.PutByte(previousByte);
+    _remainLen--;
+    curSize--;
+  }
+  UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
+  if (nowPos64 == 0)
+    previousByte = 0;
+  else
+    previousByte = _outWindowStream.GetByte(0);
+
+  while(curSize > 0)
+  {
+    {
+      #ifdef _NO_EXCEPTIONS
+      if (_rangeDecoder.Stream.ErrorCode != S_OK)
+        return _rangeDecoder.Stream.ErrorCode;
+      #endif
+      if (_rangeDecoder.Stream.WasFinished())
+        return S_FALSE;
+      UInt32 posState = UInt32(nowPos64) & _posStateMask;
+      if (_isMatch[state.Index][posState].Decode(&_rangeDecoder) == 0)
+      {
+        if(!state.IsCharState())
+          previousByte = _literalDecoder.DecodeWithMatchByte(&_rangeDecoder, 
+              (UInt32)nowPos64, previousByte, _outWindowStream.GetByte(rep0));
+        else
+          previousByte = _literalDecoder.DecodeNormal(&_rangeDecoder, 
+              (UInt32)nowPos64, previousByte);
+        _outWindowStream.PutByte(previousByte);
+        state.UpdateChar();
+        curSize--;
+        nowPos64++;
+      }
+      else             
+      {
+        UInt32 len;
+        if(_isRep[state.Index].Decode(&_rangeDecoder) == 1)
+        {
+          len = 0;
+          if(_isRepG0[state.Index].Decode(&_rangeDecoder) == 0)
+          {
+            if(_isRep0Long[state.Index][posState].Decode(&_rangeDecoder) == 0)
+            {
+              state.UpdateShortRep();
+              len = 1;
+            }
+          }
+          else
+          {
+            UInt32 distance;
+            if(_isRepG1[state.Index].Decode(&_rangeDecoder) == 0)
+              distance = rep1;
+            else 
+            {
+              if (_isRepG2[state.Index].Decode(&_rangeDecoder) == 0)
+                distance = rep2;
+              else
+              {
+                distance = rep3;
+                rep3 = rep2;
+              }
+              rep2 = rep1;
+            }
+            rep1 = rep0;
+            rep0 = distance;
+          }
+          if (len == 0)
+          {
+            len = _repMatchLenDecoder.Decode(&_rangeDecoder, posState) + kMatchMinLen;
+            state.UpdateRep();
+          }
+        }
+        else
+        {
+          rep3 = rep2;
+          rep2 = rep1;
+          rep1 = rep0;
+          len = kMatchMinLen + _lenDecoder.Decode(&_rangeDecoder, posState);
+          state.UpdateMatch();
+          UInt32 posSlot = _posSlotDecoder[GetLenToPosState(len)].Decode(&_rangeDecoder);
+          if (posSlot >= kStartPosModelIndex)
+          {
+            UInt32 numDirectBits = (posSlot >> 1) - 1;
+            rep0 = ((2 | (posSlot & 1)) << numDirectBits);
+
+            if (posSlot < kEndPosModelIndex)
+              rep0 += NRangeCoder::ReverseBitTreeDecode(_posDecoders + 
+                  rep0 - posSlot - 1, &_rangeDecoder, numDirectBits);
+            else
+            {
+              rep0 += (_rangeDecoder.DecodeDirectBits(
+                  numDirectBits - kNumAlignBits) << kNumAlignBits);
+              rep0 += _posAlignDecoder.ReverseDecode(&_rangeDecoder);
+              if (rep0 == 0xFFFFFFFF)
+              {
+                _remainLen = kLenIdFinished;
+                return S_OK;
+              }
+            }
+          }
+          else
+            rep0 = posSlot;
+        }
+        UInt32 locLen = len;
+        if (len > curSize)
+          locLen = (UInt32)curSize;
+        if (!_outWindowStream.CopyBlock(rep0, locLen))
+          return S_FALSE;
+        previousByte = _outWindowStream.GetByte(0);
+        curSize -= locLen;
+        nowPos64 += locLen;
+        len -= locLen;
+        if (len != 0)
+        {
+          _remainLen = (Int32)len;
+          break;
+        }
+
+        #ifdef _NO_EXCEPTIONS
+        if (_outWindowStream.ErrorCode != S_OK)
+          return _outWindowStream.ErrorCode;
+        #endif
+      }
+    }
+  }
+  if (_rangeDecoder.Stream.WasFinished())
+    return S_FALSE;
+  _reps[0] = rep0;
+  _reps[1] = rep1;
+  _reps[2] = rep2;
+  _reps[3] = rep3;
+  _state = state;
+
+  return S_OK;
+}
+
+STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream,
+    ISequentialOutStream *outStream, 
+    const UInt64 *, const UInt64 *outSize,
+    ICompressProgressInfo *progress)
+{
+  SetInStream(inStream);
+  _outWindowStream.SetStream(outStream);
+  SetOutStreamSize(outSize);
+  CDecoderFlusher flusher(this);
+
+  for (;;)
+  {
+    UInt32 curSize = 1 << 18;
+    RINOK(CodeSpec(curSize));
+    if (_remainLen == kLenIdFinished)
+      break;
+    if (progress != NULL)
+    {
+      UInt64 inSize = _rangeDecoder.GetProcessedSize();
+      UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
+      RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+    }
+    if (_outSizeDefined)
+      if (_outWindowStream.GetProcessedSize() >= _outSize)
+        break;
+  } 
+  flusher.NeedFlush = false;
+  return Flush();
+}
+
+
+#ifdef _NO_EXCEPTIONS
+
+#define LZMA_TRY_BEGIN
+#define LZMA_TRY_END
+
+#else
+
+#define LZMA_TRY_BEGIN try { 
+#define LZMA_TRY_END } \
+  catch(const CInBufferException &e)  { return e.ErrorCode; } \
+  catch(const CLZOutWindowException &e)  { return e.ErrorCode; } \
+  catch(...) { return S_FALSE; }
+
+#endif
+
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress)
+{
+  LZMA_TRY_BEGIN
+  return CodeReal(inStream, outStream, inSize, outSize, progress); 
+  LZMA_TRY_END
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
+{
+  if (size < 5)
+    return E_INVALIDARG;
+  int lc = properties[0] % 9;
+  Byte remainder = (Byte)(properties[0] / 9);
+  int lp = remainder % 5;
+  int pb = remainder / 5;
+  if (pb > NLength::kNumPosStatesBitsMax)
+    return E_INVALIDARG;
+  _posStateMask = (1 << pb) - 1;
+  UInt32 dictionarySize = 0;
+  for (int i = 0; i < 4; i++)
+    dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
+  if (!_outWindowStream.Create(dictionarySize))
+    return E_OUTOFMEMORY;
+  if (!_literalDecoder.Create(lp, lc))
+    return E_OUTOFMEMORY;
+  if (!_rangeDecoder.Create(1 << 20))
+    return E_OUTOFMEMORY;
+  return S_OK;
+}
+
+STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
+{
+  *value = _rangeDecoder.GetProcessedSize();
+  return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+  _rangeDecoder.SetStream(inStream);
+  return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+  _rangeDecoder.ReleaseStream();
+  return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+  _outSizeDefined = (outSize != NULL);
+  if (_outSizeDefined)
+    _outSize = *outSize;
+  _remainLen = kLenIdNeedInit;
+  _outWindowStream.Init();
+  return S_OK;
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  LZMA_TRY_BEGIN
+  if (processedSize)
+    *processedSize = 0;
+  const UInt64 startPos = _outWindowStream.GetProcessedSize();
+  _outWindowStream.SetMemStream((Byte *)data);
+  RINOK(CodeSpec(size));
+  if (processedSize)
+    *processedSize = (UInt32)(_outWindowStream.GetProcessedSize() - startPos);
+  return Flush();
+  LZMA_TRY_END
+}
+
+#endif
+
+}}
diff --git a/lzma/CPP/7zip/Compress/LZMA/LZMADecoder.h b/lzma/CPP/7zip/Compress/LZMA/LZMADecoder.h
new file mode 100644 (file)
index 0000000..bc44a5a
--- /dev/null
@@ -0,0 +1,255 @@
+// LZMA/Decoder.h
+
+#ifndef __LZMA_DECODER_H
+#define __LZMA_DECODER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+#include "../LZ/LZOutWindow.h"
+#include "../RangeCoder/RangeCoderBitTree.h"
+
+extern "C"
+{
+  #include "../../../../C/Alloc.h"
+}
+
+#include "LZMA.h"
+
+namespace NCompress {
+namespace NLZMA {
+
+typedef NRangeCoder::CBitDecoder<kNumMoveBits> CMyBitDecoder;
+
+class CLiteralDecoder2
+{
+  CMyBitDecoder _decoders[0x300];
+public:
+  void Init()
+  {
+    for (int i = 0; i < 0x300; i++)
+      _decoders[i].Init();
+  }
+  Byte DecodeNormal(NRangeCoder::CDecoder *rangeDecoder)
+  {
+    UInt32 symbol = 1;
+    RC_INIT_VAR
+    do
+    {
+      // symbol = (symbol << 1) | _decoders[0][symbol].Decode(rangeDecoder);
+      RC_GETBIT(kNumMoveBits, _decoders[symbol].Prob, symbol)
+    }
+    while (symbol < 0x100);
+    RC_FLUSH_VAR
+    return (Byte)symbol;
+  }
+  Byte DecodeWithMatchByte(NRangeCoder::CDecoder *rangeDecoder, Byte matchByte)
+  {
+    UInt32 symbol = 1;
+    RC_INIT_VAR
+    do
+    {
+      UInt32 matchBit = (matchByte >> 7) & 1;
+      matchByte <<= 1;
+      // UInt32 bit = _decoders[1 + matchBit][symbol].Decode(rangeDecoder);
+      // symbol = (symbol << 1) | bit;
+      UInt32 bit;
+      RC_GETBIT2(kNumMoveBits, _decoders[0x100 + (matchBit << 8) + symbol].Prob, symbol, 
+          bit = 0, bit = 1)
+      if (matchBit != bit)
+      {
+        while (symbol < 0x100)
+        {
+          // symbol = (symbol << 1) | _decoders[0][symbol].Decode(rangeDecoder);
+          RC_GETBIT(kNumMoveBits, _decoders[symbol].Prob, symbol)
+        }
+        break;
+      }
+    }
+    while (symbol < 0x100);
+    RC_FLUSH_VAR
+    return (Byte)symbol;
+  }
+};
+
+class CLiteralDecoder
+{
+  CLiteralDecoder2 *_coders;
+  int _numPrevBits;
+  int _numPosBits;
+  UInt32 _posMask;
+public:
+  CLiteralDecoder(): _coders(0) {}
+  ~CLiteralDecoder()  { Free(); }
+  void Free()
+  { 
+    MyFree(_coders);
+    _coders = 0;
+  }
+  bool Create(int numPosBits, int numPrevBits)
+  {
+    if (_coders == 0 || (numPosBits + numPrevBits) != 
+        (_numPrevBits + _numPosBits) )
+    {
+      Free();
+      UInt32 numStates = 1 << (numPosBits + numPrevBits);
+      _coders = (CLiteralDecoder2 *)MyAlloc(numStates * sizeof(CLiteralDecoder2));
+    }
+    _numPosBits = numPosBits;
+    _posMask = (1 << numPosBits) - 1;
+    _numPrevBits = numPrevBits;
+    return (_coders != 0);
+  }
+  void Init()
+  {
+    UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
+    for (UInt32 i = 0; i < numStates; i++)
+      _coders[i].Init();
+  }
+  UInt32 GetState(UInt32 pos, Byte prevByte) const
+    { return ((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits)); }
+  Byte DecodeNormal(NRangeCoder::CDecoder *rangeDecoder, UInt32 pos, Byte prevByte)
+    { return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
+  Byte DecodeWithMatchByte(NRangeCoder::CDecoder *rangeDecoder, UInt32 pos, Byte prevByte, Byte matchByte)
+    { return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
+};
+
+namespace NLength {
+
+class CDecoder
+{
+  CMyBitDecoder _choice;
+  CMyBitDecoder _choice2;
+  NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumLowBits>  _lowCoder[kNumPosStatesMax];
+  NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumMidBits>  _midCoder[kNumPosStatesMax];
+  NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumHighBits> _highCoder; 
+public:
+  void Init(UInt32 numPosStates)
+  {
+    _choice.Init();
+    _choice2.Init();
+    for (UInt32 posState = 0; posState < numPosStates; posState++)
+    {
+      _lowCoder[posState].Init();
+      _midCoder[posState].Init();
+    }
+    _highCoder.Init();
+  }
+  UInt32 Decode(NRangeCoder::CDecoder *rangeDecoder, UInt32 posState)
+  {
+    if(_choice.Decode(rangeDecoder) == 0)
+      return _lowCoder[posState].Decode(rangeDecoder);
+    if(_choice2.Decode(rangeDecoder) == 0)
+      return kNumLowSymbols + _midCoder[posState].Decode(rangeDecoder);
+    return kNumLowSymbols + kNumMidSymbols + _highCoder.Decode(rangeDecoder);
+  }
+};
+
+}
+
+class CDecoder: 
+  public ICompressCoder,
+  public ICompressSetDecoderProperties2,
+  public ICompressGetInStreamProcessedSize,
+  #ifndef NO_READ_FROM_CODER
+  public ICompressSetInStream,
+  public ICompressSetOutStreamSize,
+  public ISequentialInStream,
+  #endif
+  public CMyUnknownImp
+{
+  CLZOutWindow _outWindowStream;
+  NRangeCoder::CDecoder _rangeDecoder;
+
+  CMyBitDecoder _isMatch[kNumStates][NLength::kNumPosStatesMax];
+  CMyBitDecoder _isRep[kNumStates];
+  CMyBitDecoder _isRepG0[kNumStates];
+  CMyBitDecoder _isRepG1[kNumStates];
+  CMyBitDecoder _isRepG2[kNumStates];
+  CMyBitDecoder _isRep0Long[kNumStates][NLength::kNumPosStatesMax];
+
+  NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumPosSlotBits> _posSlotDecoder[kNumLenToPosStates];
+
+  CMyBitDecoder _posDecoders[kNumFullDistances - kEndPosModelIndex];
+  NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumAlignBits> _posAlignDecoder;
+  
+  NLength::CDecoder _lenDecoder;
+  NLength::CDecoder _repMatchLenDecoder;
+
+  CLiteralDecoder _literalDecoder;
+
+  UInt32 _posStateMask;
+
+  ///////////////////
+  // State
+  UInt32 _reps[4];
+  CState _state;
+  Int32 _remainLen; // -1 means end of stream. // -2 means need Init
+  UInt64 _outSize;
+  bool _outSizeDefined;
+
+  void Init();
+  HRESULT CodeSpec(UInt32 size);
+public:
+
+  #ifndef NO_READ_FROM_CODER
+  MY_UNKNOWN_IMP5(
+      ICompressSetDecoderProperties2, 
+      ICompressGetInStreamProcessedSize,
+      ICompressSetInStream, 
+      ICompressSetOutStreamSize, 
+      ISequentialInStream)
+  #else
+  MY_UNKNOWN_IMP2(
+      ICompressSetDecoderProperties2,
+      ICompressGetInStreamProcessedSize)
+  #endif
+
+  void ReleaseStreams()
+  {
+    _outWindowStream.ReleaseStream();
+    ReleaseInStream();
+  }
+
+  class CDecoderFlusher
+  {
+    CDecoder *_decoder;
+  public:
+    bool NeedFlush;
+    CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
+    ~CDecoderFlusher() 
+    { 
+      if (NeedFlush)
+        _decoder->Flush();
+      _decoder->ReleaseStreams(); 
+    }
+  };
+
+  HRESULT Flush() {  return _outWindowStream.Flush(); }  
+
+  STDMETHOD(CodeReal)(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+  
+  STDMETHOD(Code)(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+
+  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+
+  STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+  STDMETHOD(ReleaseInStream)();
+  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+  #ifndef NO_READ_FROM_CODER
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+  #endif
+
+  CDecoder(): _outSizeDefined(false) {}
+  virtual ~CDecoder() {}
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.cpp b/lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.cpp
new file mode 100644 (file)
index 0000000..021099d
--- /dev/null
@@ -0,0 +1,1547 @@
+// LZMA/Encoder.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../../Common/Defs.h"
+#include "../../Common/StreamUtils.h"
+
+#include "LZMAEncoder.h"
+
+// extern "C" { #include "../../../../C/7zCrc.h" }
+
+// #define SHOW_STAT
+
+
+namespace NCompress {
+namespace NLZMA {
+
+// struct CCrcInit { CCrcInit() { InitCrcTable(); } } g_CrcInit;
+
+const int kDefaultDictionaryLogSize = 22;
+const UInt32 kNumFastBytesDefault = 0x20;
+
+#ifndef LZMA_LOG_BSR
+Byte g_FastPos[1 << kNumLogBits];
+
+class CFastPosInit
+{
+public:
+  CFastPosInit() { Init(); }
+  void Init()
+  {
+    const Byte kFastSlots = kNumLogBits * 2;
+    int c = 2;
+    g_FastPos[0] = 0;
+    g_FastPos[1] = 1;
+
+    for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
+    {
+      UInt32 k = (1 << ((slotFast >> 1) - 1));
+      for (UInt32 j = 0; j < k; j++, c++)
+        g_FastPos[c] = slotFast;
+    }
+  }
+} g_FastPosInit;
+#endif
+
+void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
+{
+  UInt32 context = 1;
+  int i = 8;
+  do 
+  {
+    i--;
+    UInt32 bit = (symbol >> i) & 1;
+    _encoders[context].Encode(rangeEncoder, bit);
+    context = (context << 1) | bit;
+  }
+  while(i != 0);
+}
+
+void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, 
+    Byte matchByte, Byte symbol)
+{
+  UInt32 context = 1;
+  int i = 8;
+  do 
+  {
+    i--;
+    UInt32 bit = (symbol >> i) & 1;
+    UInt32 matchBit = (matchByte >> i) & 1;
+    _encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
+    context = (context << 1) | bit;
+    if (matchBit != bit)
+    {
+      while(i != 0)
+      {
+        i--;
+        UInt32 bit = (symbol >> i) & 1;
+        _encoders[context].Encode(rangeEncoder, bit);
+        context = (context << 1) | bit;
+      }
+      break;
+    }
+  }
+  while(i != 0);
+}
+
+UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
+{
+  UInt32 price = 0;
+  UInt32 context = 1;
+  int i = 8;
+  if (matchMode)
+  {
+    do 
+    {
+      i--;
+      UInt32 matchBit = (matchByte >> i) & 1;
+      UInt32 bit = (symbol >> i) & 1;
+      price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
+      context = (context << 1) | bit;
+      if (matchBit != bit)
+        break;
+    }
+    while (i != 0);
+  }
+  while(i != 0)
+  {
+    i--;
+    UInt32 bit = (symbol >> i) & 1;
+    price += _encoders[context].GetPrice(bit);
+    context = (context << 1) | bit;
+  }
+  return price;
+};
+
+
+namespace NLength {
+
+void CEncoder::Init(UInt32 numPosStates)
+{
+  _choice.Init();
+  _choice2.Init();
+  for (UInt32 posState = 0; posState < numPosStates; posState++)
+  {
+    _lowCoder[posState].Init();
+    _midCoder[posState].Init();
+  }
+  _highCoder.Init();
+}
+
+void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
+{
+  if(symbol < kNumLowSymbols)
+  {
+    _choice.Encode(rangeEncoder, 0);
+    _lowCoder[posState].Encode(rangeEncoder, symbol);
+  }
+  else
+  {
+    _choice.Encode(rangeEncoder, 1);
+    if(symbol < kNumLowSymbols + kNumMidSymbols)
+    {
+      _choice2.Encode(rangeEncoder, 0);
+      _midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
+    }
+    else
+    {
+      _choice2.Encode(rangeEncoder, 1);
+      _highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
+    }
+  }
+}
+
+void CEncoder::SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const
+{
+  UInt32 a0 = _choice.GetPrice0();
+  UInt32 a1 = _choice.GetPrice1();
+  UInt32 b0 = a1 + _choice2.GetPrice0();
+  UInt32 b1 = a1 + _choice2.GetPrice1();
+  UInt32 i = 0;
+  for (i = 0; i < kNumLowSymbols; i++)
+  {
+    if (i >= numSymbols)
+      return;
+    prices[i] = a0 + _lowCoder[posState].GetPrice(i);
+  }
+  for (; i < kNumLowSymbols + kNumMidSymbols; i++)
+  {
+    if (i >= numSymbols)
+      return;
+    prices[i] = b0 + _midCoder[posState].GetPrice(i - kNumLowSymbols);
+  }
+  for (; i < numSymbols; i++)
+    prices[i] = b1 + _highCoder.GetPrice(i - kNumLowSymbols - kNumMidSymbols);
+}
+
+}
+
+CEncoder::CEncoder():
+  _numFastBytes(kNumFastBytesDefault),
+  _distTableSize(kDefaultDictionaryLogSize * 2),
+  _posStateBits(2),
+  _posStateMask(4 - 1),
+  _numLiteralPosStateBits(0),
+  _numLiteralContextBits(3),
+  _dictionarySize(1 << kDefaultDictionaryLogSize),
+  _matchFinderCycles(0),
+  #ifdef COMPRESS_MF_MT
+  _multiThread(false),
+  #endif
+  _writeEndMark(false)
+{
+  MatchFinder_Construct(&_matchFinderBase);
+  // _maxMode = false;
+  _fastMode = false;
+  #ifdef COMPRESS_MF_MT
+  MatchFinderMt_Construct(&_matchFinderMt);
+  _matchFinderMt.MatchFinder = &_matchFinderBase;
+  #endif
+}
+
+
+static void *SzAlloc(size_t size) { return BigAlloc(size); }
+static void SzFree(void *address) { BigFree(address); }
+ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::~CEncoder()
+{
+  #ifdef COMPRESS_MF_MT
+  MatchFinderMt_Destruct(&_matchFinderMt, &g_Alloc);
+  #endif
+  MatchFinder_Free(&_matchFinderBase, &g_Alloc);
+}
+
+static const UInt32 kBigHashDicLimit = (UInt32)1 << 24;
+
+HRESULT CEncoder::Create()
+{
+  if (!_rangeEncoder.Create(1 << 20))
+    return E_OUTOFMEMORY;
+  bool btMode = (_matchFinderBase.btMode != 0);
+  #ifdef COMPRESS_MF_MT
+  _mtMode = (_multiThread && !_fastMode && btMode);
+  #endif
+  
+  if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
+    return E_OUTOFMEMORY;
+
+  _matchFinderBase.bigHash = (_dictionarySize > kBigHashDicLimit);
+
+  UInt32 numCycles = 16 + (_numFastBytes >> 1);
+  if (!btMode)
+    numCycles >>= 1;
+  if (_matchFinderCycles != 0)
+    numCycles = _matchFinderCycles;
+  _matchFinderBase.cutValue = numCycles;
+  #ifdef COMPRESS_MF_MT
+  if (_mtMode)
+  {
+    RINOK(MatchFinderMt_Create(&_matchFinderMt, _dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen, &g_Alloc));
+    _matchFinderObj = &_matchFinderMt;
+    MatchFinderMt_CreateVTable(&_matchFinderMt, &_matchFinder);
+  }
+  else
+  #endif
+  {
+    if (!MatchFinder_Create(&_matchFinderBase, _dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen, &g_Alloc))
+      return E_OUTOFMEMORY;
+    _matchFinderObj = &_matchFinderBase;
+    MatchFinder_CreateVTable(&_matchFinderBase, &_matchFinder);
+  }
+  return S_OK;
+}
+
+inline wchar_t GetUpperChar(wchar_t c)
+{
+  if (c >= 'a' && c <= 'z')
+    c -= 0x20;
+  return c;
+}
+
+static int ParseMatchFinder(const wchar_t *s, int *btMode, UInt32 *numHashBytes /* , int *skipModeBits */)
+{
+  wchar_t c = GetUpperChar(*s++);
+  if (c == L'H')
+  {
+    if (GetUpperChar(*s++) != L'C')
+      return 0;
+    int numHashBytesLoc = (int)(*s++ - L'0');
+    if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
+      return 0;
+    if (*s++ != 0)
+      return 0;
+    *btMode = 0;
+    *numHashBytes = numHashBytesLoc;
+    return 1;
+  }
+  if (c != L'B')
+    return 0;
+
+  if (GetUpperChar(*s++) != L'T')
+    return 0;
+  int numHashBytesLoc = (int)(*s++ - L'0');
+  if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
+    return 0;
+  c = GetUpperChar(*s++);
+  /*
+  int skipModeBitsLoc = 0;
+  if (c == L'D')
+  {
+    skipModeBitsLoc = 2;
+    c = GetUpperChar(*s++);
+  }
+  */
+  if (c != L'\0')
+    return 0;
+  *btMode = 1;
+  *numHashBytes = numHashBytesLoc;
+  // *skipModeBits = skipModeBitsLoc;
+  return 1;
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, 
+    const PROPVARIANT *properties, UInt32 numProperties)
+{
+  for (UInt32 i = 0; i < numProperties; i++)
+  {
+    const PROPVARIANT &prop = properties[i];
+    switch(propIDs[i])
+    {
+      case NCoderPropID::kNumFastBytes:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        UInt32 numFastBytes = prop.ulVal;
+        if(numFastBytes < 5 || numFastBytes > kMatchMaxLen)
+          return E_INVALIDARG;
+        _numFastBytes = numFastBytes;
+        break;
+      }
+      case NCoderPropID::kMatchFinderCycles:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        _matchFinderCycles = prop.ulVal;
+        break;
+      }
+      case NCoderPropID::kAlgorithm:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        UInt32 maximize = prop.ulVal;
+        _fastMode = (maximize == 0); 
+        // _maxMode = (maximize >= 2);
+        break;
+      }
+      case NCoderPropID::kMatchFinder:
+      {
+        if (prop.vt != VT_BSTR)
+          return E_INVALIDARG;
+        if (!ParseMatchFinder(prop.bstrVal, &_matchFinderBase.btMode, &_matchFinderBase.numHashBytes /* , &_matchFinderBase.skipModeBits */))
+          return E_INVALIDARG;
+        break;
+      }
+      case NCoderPropID::kMultiThread:
+      {
+        if (prop.vt != VT_BOOL)
+          return E_INVALIDARG;
+        #ifdef COMPRESS_MF_MT
+        Bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
+        if (newMultiThread != _multiThread)
+        {
+          ReleaseMatchFinder();
+          _multiThread = newMultiThread;
+        }
+        #endif
+        break;
+      }
+      case NCoderPropID::kNumThreads:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        #ifdef COMPRESS_MF_MT
+        Bool newMultiThread = (prop.ulVal > 1) ? True : False;
+        if (newMultiThread != _multiThread)
+        {
+          ReleaseMatchFinder();
+          _multiThread = newMultiThread;
+        }
+        #endif
+        break;
+      }
+      case NCoderPropID::kDictionarySize:
+      {
+        const int kDicLogSizeMaxCompress = 30; // must be <= ((kNumLogBits - 1) * 2) + 7 = 31;
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        UInt32 dictionarySize = prop.ulVal;
+        if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
+            dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
+          return E_INVALIDARG;
+        _dictionarySize = dictionarySize;
+        UInt32 dicLogSize;
+        for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
+          if (dictionarySize <= (UInt32(1) << dicLogSize))
+            break;
+        _distTableSize = dicLogSize * 2;
+        break;
+      }
+      case NCoderPropID::kPosStateBits:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        UInt32 value = prop.ulVal;
+        if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
+          return E_INVALIDARG;
+        _posStateBits = value;
+        _posStateMask = (1 << _posStateBits) - 1;
+        break;
+      }
+      case NCoderPropID::kLitPosBits:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        UInt32 value = prop.ulVal;
+        if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
+          return E_INVALIDARG;
+        _numLiteralPosStateBits = value;
+        break;
+      }
+      case NCoderPropID::kLitContextBits:
+      {
+        if (prop.vt != VT_UI4)
+          return E_INVALIDARG;
+        UInt32 value = prop.ulVal;
+        if (value > (UInt32)kNumLitContextBitsMax)
+          return E_INVALIDARG;
+        _numLiteralContextBits = value;
+        break;
+      }
+      case NCoderPropID::kEndMarker:
+      {
+        if (prop.vt != VT_BOOL)
+          return E_INVALIDARG;
+        SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
+        break;
+      }
+      default:
+        return E_INVALIDARG;
+    }
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{ 
+  const UInt32 kPropSize = 5;
+  Byte properties[kPropSize];
+  properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
+  for (int i = 0; i < 4; i++)
+    properties[1 + i] = Byte(_dictionarySize >> (8 * i));
+  return WriteStream(outStream, properties, kPropSize, NULL);
+}
+
+STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
+{
+  _rangeEncoder.SetStream(outStream);
+  return S_OK;
+}
+
+STDMETHODIMP CEncoder::ReleaseOutStream()
+{
+  _rangeEncoder.ReleaseStream();
+  return S_OK;
+}
+
+HRESULT CEncoder::Init()
+{
+  CBaseState::Init();
+
+  _rangeEncoder.Init();
+
+  for(int i = 0; i < kNumStates; i++)
+  {
+    for (UInt32 j = 0; j <= _posStateMask; j++)
+    {
+      _isMatch[i][j].Init();
+      _isRep0Long[i][j].Init();
+    }
+    _isRep[i].Init();
+    _isRepG0[i].Init();
+    _isRepG1[i].Init();
+    _isRepG2[i].Init();
+  }
+
+  _literalEncoder.Init();
+
+  {
+    for(UInt32 i = 0; i < kNumLenToPosStates; i++)
+      _posSlotEncoder[i].Init();
+  }
+  {
+    for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+      _posEncoders[i].Init();
+  }
+
+  _lenEncoder.Init(1 << _posStateBits);
+  _repMatchLenEncoder.Init(1 << _posStateBits);
+
+  _posAlignEncoder.Init();
+
+  _longestMatchWasFound = false;
+  _optimumEndIndex = 0;
+  _optimumCurrentIndex = 0;
+  _additionalOffset = 0;
+
+  return S_OK;
+}
+
+#ifdef SHOW_STAT
+static int ttt = 0;
+#endif
+
+void CEncoder::MovePos(UInt32 num)
+{
+  #ifdef SHOW_STAT
+  ttt += num;
+  printf("\n MovePos %d", num);
+  #endif
+  if (num != 0)
+  {
+    _additionalOffset += num;
+    _matchFinder.Skip(_matchFinderObj, num);
+  }
+}
+
+UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
+{
+  _optimumEndIndex = cur;
+  UInt32 posMem = _optimum[cur].PosPrev;
+  UInt32 backMem = _optimum[cur].BackPrev;
+  do
+  {
+    if (_optimum[cur].Prev1IsChar)
+    {
+      _optimum[posMem].MakeAsChar();
+      _optimum[posMem].PosPrev = posMem - 1;
+      if (_optimum[cur].Prev2)
+      {
+        _optimum[posMem - 1].Prev1IsChar = false;
+        _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
+        _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
+      }
+    }
+    UInt32 posPrev = posMem;
+    UInt32 backCur = backMem;
+
+    backMem = _optimum[posPrev].BackPrev;
+    posMem = _optimum[posPrev].PosPrev;
+
+    _optimum[posPrev].BackPrev = backCur;
+    _optimum[posPrev].PosPrev = cur;
+    cur = posPrev;
+  }
+  while(cur != 0);
+  backRes = _optimum[0].BackPrev;
+  _optimumCurrentIndex  = _optimum[0].PosPrev;
+  return _optimumCurrentIndex; 
+}
+
+/*
+Out:
+  (lenRes == 1) && (backRes == 0xFFFFFFFF) means Literal
+*/
+
+UInt32 CEncoder::GetOptimum(UInt32 position, UInt32 &backRes)
+{
+  if(_optimumEndIndex != _optimumCurrentIndex)
+  {
+    const COptimal &optimum = _optimum[_optimumCurrentIndex];
+    UInt32 lenRes = optimum.PosPrev - _optimumCurrentIndex;
+    backRes = optimum.BackPrev;
+    _optimumCurrentIndex = optimum.PosPrev;
+    return lenRes;
+  }
+  _optimumCurrentIndex = _optimumEndIndex = 0;
+  
+  UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
+
+  UInt32 lenMain, numDistancePairs;
+  if (!_longestMatchWasFound)
+  {
+    lenMain = ReadMatchDistances(numDistancePairs);
+  }
+  else
+  {
+    lenMain = _longestMatchLength;
+    numDistancePairs = _numDistancePairs;
+    _longestMatchWasFound = false;
+  }
+
+  const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+  if (numAvailableBytes < 2)
+  {
+    backRes = (UInt32)(-1);
+    return 1;
+  }
+  if (numAvailableBytes > kMatchMaxLen)
+    numAvailableBytes = kMatchMaxLen;
+
+  UInt32 reps[kNumRepDistances];
+  UInt32 repLens[kNumRepDistances];
+  UInt32 repMaxIndex = 0;
+  UInt32 i;
+  for(i = 0; i < kNumRepDistances; i++)
+  {
+    reps[i] = _repDistances[i];
+    const Byte *data2 = data - (reps[i] + 1);
+    if (data[0] != data2[0] || data[1] != data2[1])
+    {
+      repLens[i] = 0;
+      continue;
+    }
+    UInt32 lenTest;
+    for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
+    repLens[i] = lenTest;
+    if (lenTest > repLens[repMaxIndex])
+      repMaxIndex = i;
+  }
+  if(repLens[repMaxIndex] >= _numFastBytes)
+  {
+    backRes = repMaxIndex;
+    UInt32 lenRes = repLens[repMaxIndex];
+    MovePos(lenRes - 1);
+    return lenRes;
+  }
+
+  UInt32 *matchDistances = _matchDistances;
+  if(lenMain >= _numFastBytes)
+  {
+    backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances; 
+    MovePos(lenMain - 1);
+    return lenMain;
+  }
+  Byte currentByte = *data;
+  Byte matchByte = *(data - (reps[0] + 1));
+
+  if(lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
+  {
+    backRes = (UInt32)-1;
+    return 1;
+  }
+
+  _optimum[0].State = _state;
+
+  UInt32 posState = (position & _posStateMask);
+
+  _optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() + 
+      _literalEncoder.GetSubCoder(position, _previousByte)->GetPrice(!_state.IsCharState(), matchByte, currentByte);
+  _optimum[1].MakeAsChar();
+
+  UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
+  UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
+
+  if(matchByte == currentByte)
+  {
+    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
+    if(shortRepPrice < _optimum[1].Price)
+    {
+      _optimum[1].Price = shortRepPrice;
+      _optimum[1].MakeAsShortRep();
+    }
+  }
+  UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
+
+  if(lenEnd < 2)
+  {
+    backRes = _optimum[1].BackPrev;
+    return 1;
+  }
+
+  _optimum[1].PosPrev = 0;
+  for (i = 0; i < kNumRepDistances; i++)
+    _optimum[0].Backs[i] = reps[i];
+
+  UInt32 len = lenEnd;
+  do
+    _optimum[len--].Price = kIfinityPrice;
+  while (len >= 2);
+
+  for(i = 0; i < kNumRepDistances; i++)
+  {
+    UInt32 repLen = repLens[i];
+    if (repLen < 2)
+      continue;
+    UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
+    do
+    {
+      UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
+      COptimal &optimum = _optimum[repLen];
+      if (curAndLenPrice < optimum.Price) 
+      {
+        optimum.Price = curAndLenPrice;
+        optimum.PosPrev = 0;
+        optimum.BackPrev = i;
+        optimum.Prev1IsChar = false;
+      }
+    }
+    while(--repLen >= 2);
+  }
+
+  UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
+
+  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+  if (len <= lenMain)
+  {
+    UInt32 offs = 0;
+    while (len > matchDistances[offs])
+      offs += 2;
+    for(; ; len++)
+    {
+      UInt32 distance = matchDistances[offs + 1];
+      UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
+      COptimal &optimum = _optimum[len];
+      if (curAndLenPrice < optimum.Price) 
+      {
+        optimum.Price = curAndLenPrice;
+        optimum.PosPrev = 0;
+        optimum.BackPrev = distance + kNumRepDistances;
+        optimum.Prev1IsChar = false;
+      }
+      if (len == matchDistances[offs])
+      {
+        offs += 2;
+        if (offs == numDistancePairs)
+          break;
+      }
+    }
+  }
+
+  UInt32 cur = 0;
+
+  for (;;)
+  {
+    cur++;
+    if(cur == lenEnd)
+    {
+      return Backward(backRes, cur);
+    }
+    UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
+    UInt32 newLen, numDistancePairs;
+    newLen = ReadMatchDistances(numDistancePairs);
+    if(newLen >= _numFastBytes)
+    {
+      _numDistancePairs = numDistancePairs;
+      _longestMatchLength = newLen;
+      _longestMatchWasFound = true;
+      return Backward(backRes, cur);
+    }
+    position++;
+    COptimal &curOptimum = _optimum[cur];
+    UInt32 posPrev = curOptimum.PosPrev;
+    CState state;
+    if (curOptimum.Prev1IsChar)
+    {
+      posPrev--;
+      if (curOptimum.Prev2)
+      {
+        state = _optimum[curOptimum.PosPrev2].State;
+        if (curOptimum.BackPrev2 < kNumRepDistances)
+          state.UpdateRep();
+        else
+          state.UpdateMatch();
+      }
+      else
+        state = _optimum[posPrev].State;
+      state.UpdateChar();
+    }
+    else
+      state = _optimum[posPrev].State;
+    if (posPrev == cur - 1)
+    {
+      if (curOptimum.IsShortRep())
+        state.UpdateShortRep();
+      else
+        state.UpdateChar();
+    }
+    else
+    {
+      UInt32 pos;
+      if (curOptimum.Prev1IsChar && curOptimum.Prev2)
+      {
+        posPrev = curOptimum.PosPrev2;
+        pos = curOptimum.BackPrev2;
+        state.UpdateRep();
+      }
+      else
+      {
+        pos = curOptimum.BackPrev;
+        if (pos < kNumRepDistances)
+          state.UpdateRep();
+        else
+          state.UpdateMatch();
+      }
+      const COptimal &prevOptimum = _optimum[posPrev];
+      if (pos < kNumRepDistances)
+      {
+        reps[0] = prevOptimum.Backs[pos];
+        UInt32 i;
+        for(i = 1; i <= pos; i++)
+          reps[i] = prevOptimum.Backs[i - 1];
+        for(; i < kNumRepDistances; i++)
+          reps[i] = prevOptimum.Backs[i];
+      }
+      else
+      {
+        reps[0] = (pos - kNumRepDistances);
+        for(UInt32 i = 1; i < kNumRepDistances; i++)
+          reps[i] = prevOptimum.Backs[i - 1];
+      }
+    }
+    curOptimum.State = state;
+    for(UInt32 i = 0; i < kNumRepDistances; i++)
+      curOptimum.Backs[i] = reps[i];
+    UInt32 curPrice = curOptimum.Price; 
+    const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+    const Byte currentByte = *data;
+    const Byte matchByte = *(data - (reps[0] + 1));
+
+    UInt32 posState = (position & _posStateMask);
+
+    UInt32 curAnd1Price = curPrice +
+        _isMatch[state.Index][posState].GetPrice0() +
+        _literalEncoder.GetSubCoder(position, *(data - 1))->GetPrice(!state.IsCharState(), matchByte, currentByte);
+
+    COptimal &nextOptimum = _optimum[cur + 1];
+
+    bool nextIsChar = false;
+    if (curAnd1Price < nextOptimum.Price) 
+    {
+      nextOptimum.Price = curAnd1Price;
+      nextOptimum.PosPrev = cur;
+      nextOptimum.MakeAsChar();
+      nextIsChar = true;
+    }
+
+    UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
+    UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
+    
+    if(matchByte == currentByte &&
+        !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
+    {
+      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
+      if(shortRepPrice <= nextOptimum.Price)
+      {
+        nextOptimum.Price = shortRepPrice;
+        nextOptimum.PosPrev = cur;
+        nextOptimum.MakeAsShortRep();
+        nextIsChar = true;
+      }
+    }
+    /*
+    if(newLen == 2 && matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
+      continue;
+    */
+
+    numAvailableBytesFull = MyMin(kNumOpts - 1 - cur, numAvailableBytesFull);
+    UInt32 numAvailableBytes = numAvailableBytesFull;
+
+    if (numAvailableBytes < 2)
+      continue;
+    if (numAvailableBytes > _numFastBytes)
+      numAvailableBytes = _numFastBytes;
+    if (!nextIsChar && matchByte != currentByte) // speed optimization
+    {
+      // try Literal + rep0
+      const Byte *data2 = data - (reps[0] + 1);
+      UInt32 limit = MyMin(numAvailableBytesFull, _numFastBytes + 1);
+      UInt32 temp;
+      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
+      UInt32 lenTest2 = temp - 1;
+      if (lenTest2 >= 2)
+      {
+        CState state2 = state;
+        state2.UpdateChar();
+        UInt32 posStateNext = (position + 1) & _posStateMask;
+        UInt32 nextRepMatchPrice = curAnd1Price + 
+            _isMatch[state2.Index][posStateNext].GetPrice1() +
+            _isRep[state2.Index].GetPrice1();
+        // for (; lenTest2 >= 2; lenTest2--)
+        {
+          UInt32 offset = cur + 1 + lenTest2;
+          while(lenEnd < offset)
+            _optimum[++lenEnd].Price = kIfinityPrice;
+          UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+              0, lenTest2, state2, posStateNext);
+          COptimal &optimum = _optimum[offset];
+          if (curAndLenPrice < optimum.Price) 
+          {
+            optimum.Price = curAndLenPrice;
+            optimum.PosPrev = cur + 1;
+            optimum.BackPrev = 0;
+            optimum.Prev1IsChar = true;
+            optimum.Prev2 = false;
+          }
+        }
+      }
+    }
+    
+    UInt32 startLen = 2; // speed optimization 
+    for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
+    {
+      // UInt32 repLen = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
+      const Byte *data2 = data - (reps[repIndex] + 1);
+      if (data[0] != data2[0] || data[1] != data2[1])
+        continue;
+      UInt32 lenTest;
+      for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
+      while(lenEnd < cur + lenTest)
+        _optimum[++lenEnd].Price = kIfinityPrice;
+      UInt32 lenTestTemp = lenTest;
+      UInt32 price = repMatchPrice + GetPureRepPrice(repIndex, state, posState);
+      do
+      {
+        UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState);
+        COptimal &optimum = _optimum[cur + lenTest];
+        if (curAndLenPrice < optimum.Price) 
+        {
+          optimum.Price = curAndLenPrice;
+          optimum.PosPrev = cur;
+          optimum.BackPrev = repIndex;
+          optimum.Prev1IsChar = false;
+        }
+      }
+      while(--lenTest >= 2);
+      lenTest = lenTestTemp;
+      
+      if (repIndex == 0)
+        startLen = lenTest + 1;
+        
+      // if (_maxMode)
+        {
+          UInt32 lenTest2 = lenTest + 1;
+          UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
+          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+          lenTest2 -= lenTest + 1;
+          if (lenTest2 >= 2)
+          {
+            CState state2 = state;
+            state2.UpdateRep();
+            UInt32 posStateNext = (position + lenTest) & _posStateMask;
+            UInt32 curAndLenCharPrice = 
+                price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState) + 
+                _isMatch[state2.Index][posStateNext].GetPrice0() +
+                _literalEncoder.GetSubCoder(position + lenTest, data[lenTest - 1])->GetPrice(
+                true, data2[lenTest], data[lenTest]);
+            state2.UpdateChar();
+            posStateNext = (position + lenTest + 1) & _posStateMask;
+            UInt32 nextRepMatchPrice = curAndLenCharPrice + 
+                _isMatch[state2.Index][posStateNext].GetPrice1() +
+                _isRep[state2.Index].GetPrice1();
+            
+            // for(; lenTest2 >= 2; lenTest2--)
+            {
+              UInt32 offset = cur + lenTest + 1 + lenTest2;
+              while(lenEnd < offset)
+                _optimum[++lenEnd].Price = kIfinityPrice;
+              UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+                  0, lenTest2, state2, posStateNext);
+              COptimal &optimum = _optimum[offset];
+              if (curAndLenPrice < optimum.Price) 
+              {
+                optimum.Price = curAndLenPrice;
+                optimum.PosPrev = cur + lenTest + 1;
+                optimum.BackPrev = 0;
+                optimum.Prev1IsChar = true;
+                optimum.Prev2 = true;
+                optimum.PosPrev2 = cur;
+                optimum.BackPrev2 = repIndex;
+              }
+            }
+          }
+        }
+      }
+    
+    //    for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
+    if (newLen > numAvailableBytes)
+    {
+      newLen = numAvailableBytes;
+      for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
+      matchDistances[numDistancePairs] = newLen;
+      numDistancePairs += 2;
+    }
+    if (newLen >= startLen)
+    {
+      UInt32 normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
+      while(lenEnd < cur + newLen)
+        _optimum[++lenEnd].Price = kIfinityPrice;
+
+      UInt32 offs = 0;
+      while(startLen > matchDistances[offs])
+        offs += 2;
+      UInt32 curBack = matchDistances[offs + 1];
+      UInt32 posSlot = GetPosSlot2(curBack);
+      for(UInt32 lenTest = /*2*/ startLen; ; lenTest++)
+      {
+        UInt32 curAndLenPrice = normalMatchPrice;
+        UInt32 lenToPosState = GetLenToPosState(lenTest);
+        if (curBack < kNumFullDistances)
+          curAndLenPrice += _distancesPrices[lenToPosState][curBack];
+        else
+          curAndLenPrice += _posSlotPrices[lenToPosState][posSlot] + _alignPrices[curBack & kAlignMask];
+  
+        curAndLenPrice += _lenEncoder.GetPrice(lenTest - kMatchMinLen, posState);
+        
+        COptimal &optimum = _optimum[cur + lenTest];
+        if (curAndLenPrice < optimum.Price) 
+        {
+          optimum.Price = curAndLenPrice;
+          optimum.PosPrev = cur;
+          optimum.BackPrev = curBack + kNumRepDistances;
+          optimum.Prev1IsChar = false;
+        }
+
+        if (/*_maxMode && */lenTest == matchDistances[offs])
+        {
+          // Try Match + Literal + Rep0
+          const Byte *data2 = data - (curBack + 1);
+          UInt32 lenTest2 = lenTest + 1;
+          UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
+          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+          lenTest2 -= lenTest + 1;
+          if (lenTest2 >= 2)
+          {
+            CState state2 = state;
+            state2.UpdateMatch();
+            UInt32 posStateNext = (position + lenTest) & _posStateMask;
+            UInt32 curAndLenCharPrice = curAndLenPrice + 
+                _isMatch[state2.Index][posStateNext].GetPrice0() +
+                _literalEncoder.GetSubCoder(position + lenTest, data[lenTest - 1])->GetPrice( 
+                true, data2[lenTest], data[lenTest]);
+            state2.UpdateChar();
+            posStateNext = (posStateNext + 1) & _posStateMask;
+            UInt32 nextRepMatchPrice = curAndLenCharPrice + 
+                _isMatch[state2.Index][posStateNext].GetPrice1() +
+                _isRep[state2.Index].GetPrice1();
+            
+            // for(; lenTest2 >= 2; lenTest2--)
+            {
+              UInt32 offset = cur + lenTest + 1 + lenTest2;
+              while(lenEnd < offset)
+                _optimum[++lenEnd].Price = kIfinityPrice;
+              UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
+              COptimal &optimum = _optimum[offset];
+              if (curAndLenPrice < optimum.Price) 
+              {
+                optimum.Price = curAndLenPrice;
+                optimum.PosPrev = cur + lenTest + 1;
+                optimum.BackPrev = 0;
+                optimum.Prev1IsChar = true;
+                optimum.Prev2 = true;
+                optimum.PosPrev2 = cur;
+                optimum.BackPrev2 = curBack + kNumRepDistances;
+              }
+            }
+          }
+          offs += 2;
+          if (offs == numDistancePairs)
+            break;
+          curBack = matchDistances[offs + 1];
+          if (curBack >= kNumFullDistances)
+            posSlot = GetPosSlot2(curBack);
+        }
+      }
+    }
+  }
+}
+
+static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
+{
+  return ((bigDist >> 7) > smallDist);
+}
+
+UInt32 CEncoder::ReadMatchDistances(UInt32 &numDistancePairs)
+{
+  UInt32 lenRes = 0;
+  numDistancePairs = _matchFinder.GetMatches(_matchFinderObj, _matchDistances);
+  #ifdef SHOW_STAT
+  printf("\n i = %d numPairs = %d    ", ttt, numDistancePairs / 2);
+  if (ttt >= 61994)
+    ttt = ttt;
+
+  ttt++;
+  for (UInt32 i = 0; i < numDistancePairs; i += 2)
+    printf("%2d %6d   | ", _matchDistances[i], _matchDistances[i + 1]);
+  #endif
+  if (numDistancePairs > 0)
+  {
+    lenRes = _matchDistances[numDistancePairs - 2];
+    if (lenRes == _numFastBytes)
+    {
+      UInt32 numAvail = _matchFinder.GetNumAvailableBytes(_matchFinderObj) + 1;
+      const Byte *pby = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+      UInt32 distance = _matchDistances[numDistancePairs - 1] + 1;
+      if (numAvail > kMatchMaxLen)
+        numAvail = kMatchMaxLen;
+
+      const Byte *pby2 = pby - distance;
+      for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
+    }
+  }
+  _additionalOffset++;
+  return lenRes;
+}
+
+UInt32 CEncoder::GetOptimumFast(UInt32 &backRes)
+{
+  UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
+  UInt32 lenMain, numDistancePairs;
+  if (!_longestMatchWasFound)
+  {
+    lenMain = ReadMatchDistances(numDistancePairs);
+  }
+  else
+  {
+    lenMain = _longestMatchLength;
+    numDistancePairs = _numDistancePairs;
+    _longestMatchWasFound = false;
+  }
+
+  const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+  if (numAvailableBytes > kMatchMaxLen)
+    numAvailableBytes = kMatchMaxLen;
+  if (numAvailableBytes < 2)
+  {
+    backRes = (UInt32)(-1);
+    return 1;
+  }
+
+  UInt32 repLens[kNumRepDistances];
+  UInt32 repMaxIndex = 0;
+
+  for(UInt32 i = 0; i < kNumRepDistances; i++)
+  {
+    const Byte *data2 = data - (_repDistances[i] + 1);
+    if (data[0] != data2[0] || data[1] != data2[1])
+    {
+      repLens[i] = 0;
+      continue;
+    }
+    UInt32 len;
+    for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
+    if(len >= _numFastBytes)
+    {
+      backRes = i;
+      MovePos(len - 1);
+      return len;
+    }
+    repLens[i] = len;
+    if (len > repLens[repMaxIndex])
+      repMaxIndex = i;
+  }
+  UInt32 *matchDistances = _matchDistances;
+  if(lenMain >= _numFastBytes)
+  {
+    backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances; 
+    MovePos(lenMain - 1);
+    return lenMain;
+  }
+
+  UInt32 backMain = 0; // for GCC
+  if (lenMain >= 2)
+  {
+    backMain = matchDistances[numDistancePairs - 1];
+    while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
+    {
+      if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
+        break;
+      numDistancePairs -= 2;
+      lenMain = matchDistances[numDistancePairs - 2];
+      backMain = matchDistances[numDistancePairs - 1];
+    }
+    if (lenMain == 2 && backMain >= 0x80)
+      lenMain = 1;
+  }
+
+  if (repLens[repMaxIndex] >= 2)
+  {
+    if (repLens[repMaxIndex] + 1 >= lenMain || 
+        repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9)) ||
+        repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15)))
+    {
+      backRes = repMaxIndex;
+      UInt32 lenRes = repLens[repMaxIndex];
+      MovePos(lenRes - 1);
+      return lenRes;
+    }
+  }
+  
+  if (lenMain >= 2 && numAvailableBytes > 2)
+  {
+    numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
+    _longestMatchLength = ReadMatchDistances(_numDistancePairs);
+    if (_longestMatchLength >= 2)
+    {
+      UInt32 newDistance = matchDistances[_numDistancePairs - 1];
+      if (_longestMatchLength >= lenMain && newDistance < backMain || 
+          _longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance) ||
+          _longestMatchLength > lenMain + 1 ||
+          _longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain))
+      {
+        _longestMatchWasFound = true;
+        backRes = UInt32(-1);
+        return 1;
+      }
+    }
+    data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+    for(UInt32 i = 0; i < kNumRepDistances; i++)
+    {
+      const Byte *data2 = data - (_repDistances[i] + 1);
+      if (data[1] != data2[1] || data[2] != data2[2])
+      {
+        repLens[i] = 0;
+        continue;
+      }
+      UInt32 len;
+      for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
+      if (len + 1 >= lenMain)
+      {
+        _longestMatchWasFound = true;
+        backRes = UInt32(-1);
+        return 1;
+      }
+    }
+    backRes = backMain + kNumRepDistances; 
+    MovePos(lenMain - 2);
+    return lenMain;
+  }
+  backRes = UInt32(-1);
+  return 1;
+}
+
+HRESULT CEncoder::Flush(UInt32 nowPos)
+{
+  // ReleaseMFStream();
+  if (_matchFinderBase.result != SZ_OK)
+    return _matchFinderBase.result;
+  WriteEndMarker(nowPos & _posStateMask);
+  _rangeEncoder.FlushData();
+  return _rangeEncoder.FlushStream();
+}
+
+void CEncoder::WriteEndMarker(UInt32 posState)
+{
+  // This function for writing End Mark for stream version of LZMA. 
+  // In current version this feature is not used.
+  if (!_writeEndMark)
+    return;
+
+  _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
+  _isRep[_state.Index].Encode(&_rangeEncoder, 0);
+  _state.UpdateMatch();
+  UInt32 len = kMatchMinLen; // kMatchMaxLen;
+  _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
+  UInt32 posSlot = (1 << kNumPosSlotBits)  - 1;
+  UInt32 lenToPosState = GetLenToPosState(len);
+  _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
+  UInt32 footerBits = 30;
+  UInt32 posReduced = (UInt32(1) << footerBits) - 1;
+  _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+  _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
+}
+
+HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, 
+      const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress)
+{
+  // _needReleaseMFStream = false;
+  #ifdef COMPRESS_MF_MT
+  #ifdef USE_ALLOCA
+  alloca(0x300);
+  #endif
+  #endif
+  CCoderReleaser coderReleaser(this);
+  RINOK(SetStreams(inStream, outStream, inSize, outSize));
+  for (;;)
+  {
+    UInt64 processedInSize;
+    UInt64 processedOutSize;
+    Int32 finished;
+    RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
+    if (finished != 0)
+      break;
+    if (progress != 0)
+    {
+      RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, 
+      const UInt64 * /* inSize */, const UInt64 * /* outSize */)
+{
+  _inStream = inStream;
+  _finished = false;
+  RINOK(Create());
+  RINOK(SetOutStream(outStream));
+  RINOK(Init());
+  
+  if (!_fastMode)
+  {
+    FillDistancesPrices();
+    FillAlignPrices();
+  }
+
+  _lenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
+  _lenEncoder.UpdateTables(1 << _posStateBits);
+  _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
+  _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
+
+  nowPos64 = 0;
+  return S_OK;
+}
+
+static HRes MyRead(void *object, void *data, UInt32 size, UInt32 *processedSize)
+{
+  return (HRes)((CSeqInStream *)object)->RealStream->Read(data, size, processedSize);
+}
+
+HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
+{
+  if (_inStream != 0)
+  {
+    _seqInStream.RealStream = _inStream;
+    _seqInStream.SeqInStream.Read = MyRead;
+    _matchFinderBase.stream = &_seqInStream.SeqInStream;
+    _matchFinder.Init(_matchFinderObj);
+    _needReleaseMFStream = true;
+    _inStream = 0;
+  }
+
+
+  *finished = 1;
+  if (_finished)
+    return _matchFinderBase.result;
+  _finished = true;
+
+  if (nowPos64 == 0)
+  {
+    if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
+      return Flush((UInt32)nowPos64);
+    UInt32 len, numDistancePairs;
+    len = ReadMatchDistances(numDistancePairs);
+    UInt32 posState = UInt32(nowPos64) & _posStateMask;
+    _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
+    _state.UpdateChar();
+    Byte curByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _additionalOffset);
+    _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
+    _previousByte = curByte;
+    _additionalOffset--;
+    nowPos64++;
+  }
+
+  UInt32 nowPos32 = (UInt32)nowPos64;
+  UInt32 progressPosValuePrev = nowPos32;
+
+  if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
+    return Flush(nowPos32);
+
+  for (;;)
+  {
+    #ifdef _NO_EXCEPTIONS
+    if (_rangeEncoder.Stream.ErrorCode != S_OK)
+      return _rangeEncoder.Stream.ErrorCode;
+    #endif
+    UInt32 pos, len;
+
+    if (_fastMode)
+      len = GetOptimumFast(pos);
+    else
+      len = GetOptimum(nowPos32, pos);
+
+    UInt32 posState = nowPos32 & _posStateMask;
+    if(len == 1 && pos == 0xFFFFFFFF)
+    {
+      _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
+      Byte curByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _additionalOffset);
+      CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(nowPos32, _previousByte);
+      if(_state.IsCharState())
+        subCoder->Encode(&_rangeEncoder, curByte);
+      else
+      {
+        Byte matchByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _repDistances[0] - 1 - _additionalOffset);
+        subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
+      }
+      _state.UpdateChar();
+      _previousByte = curByte;
+    }
+    else
+    {
+      _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
+      if(pos < kNumRepDistances)
+      {
+        _isRep[_state.Index].Encode(&_rangeEncoder, 1);
+        if(pos == 0)
+        {
+          _isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
+          _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, ((len == 1) ? 0 : 1));
+        }
+        else
+        {
+          UInt32 distance = _repDistances[pos];
+          _isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
+          if (pos == 1)
+            _isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
+          else
+          {
+            _isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
+            _isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
+            if (pos == 3)
+              _repDistances[3] = _repDistances[2];
+            _repDistances[2] = _repDistances[1];
+          }
+          _repDistances[1] = _repDistances[0];
+          _repDistances[0] = distance;
+        }
+        if (len == 1)
+          _state.UpdateShortRep();
+        else
+        {
+          _repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
+          _state.UpdateRep();
+        }
+      }
+      else
+      {
+        _isRep[_state.Index].Encode(&_rangeEncoder, 0);
+        _state.UpdateMatch();
+        _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
+        pos -= kNumRepDistances;
+        UInt32 posSlot = GetPosSlot(pos);
+        _posSlotEncoder[GetLenToPosState(len)].Encode(&_rangeEncoder, posSlot);
+        
+        if (posSlot >= kStartPosModelIndex)
+        {
+          UInt32 footerBits = ((posSlot >> 1) - 1);
+          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+          UInt32 posReduced = pos - base;
+
+          if (posSlot < kEndPosModelIndex)
+            NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1, 
+                &_rangeEncoder, footerBits, posReduced);
+          else
+          {
+            _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+            _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
+            _alignPriceCount++;
+          }
+        }
+        _repDistances[3] = _repDistances[2];
+        _repDistances[2] = _repDistances[1];
+        _repDistances[1] = _repDistances[0];
+        _repDistances[0] = pos;
+        _matchPriceCount++;
+      }
+      _previousByte = _matchFinder.GetIndexByte(_matchFinderObj, len - 1 - _additionalOffset);
+    }
+    _additionalOffset -= len;
+    nowPos32 += len;
+    if (_additionalOffset == 0)
+    {
+      if (!_fastMode)
+      {
+        if (_matchPriceCount >= (1 << 7))
+          FillDistancesPrices();
+        if (_alignPriceCount >= kAlignTableSize)
+          FillAlignPrices();
+      }
+      if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
+        return Flush(nowPos32);
+      if (nowPos32 - progressPosValuePrev >= (1 << 14))
+      {
+        nowPos64 += nowPos32 - progressPosValuePrev;
+        *inSize = nowPos64;
+        *outSize = _rangeEncoder.GetProcessedSize();
+        _finished = false;
+        *finished = 0;
+        return _matchFinderBase.result;
+      }
+    }
+  }
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
+    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+    ICompressProgressInfo *progress)
+{
+  #ifndef _NO_EXCEPTIONS
+  try 
+  { 
+  #endif
+    return CodeReal(inStream, outStream, inSize, outSize, progress); 
+  #ifndef _NO_EXCEPTIONS
+  }
+  catch(const COutBufferException &e) { return e.ErrorCode; }
+  catch(...) { return E_FAIL; }
+  #endif
+}
+  
+void CEncoder::FillDistancesPrices()
+{
+  UInt32 tempPrices[kNumFullDistances];
+  for (UInt32 i = kStartPosModelIndex; i < kNumFullDistances; i++)
+  { 
+    UInt32 posSlot = GetPosSlot(i);
+    UInt32 footerBits = ((posSlot >> 1) - 1);
+    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+    tempPrices[i] = NRangeCoder::ReverseBitTreeGetPrice(_posEncoders + 
+      base - posSlot - 1, footerBits, i - base);
+  }
+
+  for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+  {
+    UInt32 posSlot;
+    NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> &encoder = _posSlotEncoder[lenToPosState];
+    UInt32 *posSlotPrices = _posSlotPrices[lenToPosState];
+    for (posSlot = 0; posSlot < _distTableSize; posSlot++)
+      posSlotPrices[posSlot] = encoder.GetPrice(posSlot);
+    for (posSlot = kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
+      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
+
+    UInt32 *distancesPrices = _distancesPrices[lenToPosState];
+    UInt32 i;
+    for (i = 0; i < kStartPosModelIndex; i++)
+      distancesPrices[i] = posSlotPrices[i];
+    for (; i < kNumFullDistances; i++)
+      distancesPrices[i] = posSlotPrices[GetPosSlot(i)] + tempPrices[i];
+  }
+  _matchPriceCount = 0;
+}
+
+void CEncoder::FillAlignPrices()
+{
+  for (UInt32 i = 0; i < kAlignTableSize; i++)
+    _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
+  _alignPriceCount = 0;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.h b/lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.h
new file mode 100644 (file)
index 0000000..da15979
--- /dev/null
@@ -0,0 +1,465 @@
+// LZMA/Encoder.h
+
+#ifndef __LZMA_ENCODER_H
+#define __LZMA_ENCODER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+extern "C"
+{
+  #include "../../../../C/Alloc.h"
+  #include "../../../../C/Compress/Lz/MatchFinder.h"
+  #ifdef COMPRESS_MF_MT
+  #include "../../../../C/Compress/Lz/MatchFinderMt.h"
+  #endif
+}
+
+#include "../RangeCoder/RangeCoderBitTree.h"
+
+#include "LZMA.h"
+
+namespace NCompress {
+namespace NLZMA {
+
+typedef NRangeCoder::CBitEncoder<kNumMoveBits> CMyBitEncoder;
+
+class CBaseState
+{
+protected:
+  CState _state;
+  Byte _previousByte;
+  UInt32 _repDistances[kNumRepDistances];
+  void Init()
+  {
+    _state.Init();
+    _previousByte = 0;
+    for(UInt32 i = 0 ; i < kNumRepDistances; i++)
+      _repDistances[i] = 0;
+  }
+};
+
+struct COptimal
+{
+  CState State;
+
+  bool Prev1IsChar;
+  bool Prev2;
+
+  UInt32 PosPrev2;
+  UInt32 BackPrev2;     
+
+  UInt32 Price;    
+  UInt32 PosPrev;         // posNext;
+  UInt32 BackPrev;     
+  UInt32 Backs[kNumRepDistances];
+  void MakeAsChar() { BackPrev = UInt32(-1); Prev1IsChar = false; }
+  void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
+  bool IsShortRep() { return (BackPrev == 0); }
+};
+
+
+// #define LZMA_LOG_BRANCH
+
+#if _MSC_VER >= 1400
+// Must give gain in core 2. but slower ~2% on k8.
+// #define LZMA_LOG_BSR
+#endif
+
+#ifndef LZMA_LOG_BSR
+static const int kNumLogBits = 13; // don't change it !
+extern Byte g_FastPos[];
+#endif
+inline UInt32 GetPosSlot(UInt32 pos)
+{
+  #ifdef LZMA_LOG_BSR
+  if (pos < 2)
+    return pos;
+  unsigned long index;
+  _BitScanReverse(&index, pos);
+  return (index + index) + ((pos >> (index - 1)) & 1);
+  #else
+  if (pos < (1 << kNumLogBits))
+    return g_FastPos[pos];
+  if (pos < (1 << (kNumLogBits * 2 - 1)))
+    return g_FastPos[pos >> (kNumLogBits - 1)] + (kNumLogBits - 1) * 2;
+  return g_FastPos[pos >> (kNumLogBits - 1) * 2] + (kNumLogBits - 1) * 4;
+  #endif
+}
+
+inline UInt32 GetPosSlot2(UInt32 pos)
+{
+  #ifdef LZMA_LOG_BSR
+  unsigned long index;
+  _BitScanReverse(&index, pos);
+  return (index + index) + ((pos >> (index - 1)) & 1);
+  #else
+  #ifdef LZMA_LOG_BRANCH
+  if (pos < (1 << (kNumLogBits + 6)))
+    return g_FastPos[pos >> 6] + 12;
+  if (pos < (1 << (kNumLogBits * 2 + 5)))
+    return g_FastPos[pos >> (kNumLogBits + 5)] + (kNumLogBits + 5) * 2;
+  return g_FastPos[pos >> (kNumLogBits * 2 + 4)] + (kNumLogBits * 2 + 4) * 2;
+  #else
+  // it's faster with VC6-32bit.
+  UInt32 s = 6 + ((kNumLogBits - 1) & (UInt32)((Int32)(((1 << (kNumLogBits + 6)) - 1) -  pos) >> 31));
+  return g_FastPos[pos >> s] + (s * 2);
+  #endif
+  #endif
+}
+
+const UInt32 kIfinityPrice = 0xFFFFFFF;
+
+const UInt32 kNumOpts = 1 << 12;
+
+
+class CLiteralEncoder2
+{
+  CMyBitEncoder _encoders[0x300];
+public:
+  void Init()
+  {
+    for (int i = 0; i < 0x300; i++)
+      _encoders[i].Init();
+  }
+  void Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol);
+  void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, Byte matchByte, Byte symbol);
+  UInt32 GetPrice(bool matchMode, Byte matchByte, Byte symbol) const;
+};
+
+class CLiteralEncoder
+{
+  CLiteralEncoder2 *_coders;
+  int _numPrevBits;
+  int _numPosBits;
+  UInt32 _posMask;
+public:
+  CLiteralEncoder(): _coders(0) {}
+  ~CLiteralEncoder()  { Free(); }
+  void Free()
+  { 
+    MyFree(_coders);
+    _coders = 0;
+  }
+  bool Create(int numPosBits, int numPrevBits)
+  {
+    if (_coders == 0 || (numPosBits + numPrevBits) != (_numPrevBits + _numPosBits))
+    {
+      Free();
+      UInt32 numStates = 1 << (numPosBits + numPrevBits);
+      _coders = (CLiteralEncoder2 *)MyAlloc(numStates * sizeof(CLiteralEncoder2));
+    }
+    _numPosBits = numPosBits;
+    _posMask = (1 << numPosBits) - 1;
+    _numPrevBits = numPrevBits;
+    return (_coders != 0);
+  }
+  void Init()
+  {
+    UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
+    for (UInt32 i = 0; i < numStates; i++)
+      _coders[i].Init();
+  }
+  CLiteralEncoder2 *GetSubCoder(UInt32 pos, Byte prevByte)
+    { return &_coders[((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits))]; }
+};
+
+namespace NLength {
+
+class CEncoder
+{
+  CMyBitEncoder _choice;
+  CMyBitEncoder _choice2;
+  NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumLowBits> _lowCoder[kNumPosStatesEncodingMax];
+  NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumMidBits> _midCoder[kNumPosStatesEncodingMax];
+  NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumHighBits> _highCoder;
+public:
+  void Init(UInt32 numPosStates);
+  void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState);
+  void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const;
+};
+
+const UInt32 kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols;
+
+class CPriceTableEncoder: public CEncoder
+{
+  UInt32 _prices[kNumPosStatesEncodingMax][kNumSymbolsTotal];
+  UInt32 _tableSize;
+  UInt32 _counters[kNumPosStatesEncodingMax];
+public:
+  void SetTableSize(UInt32 tableSize) { _tableSize = tableSize;  }
+  UInt32 GetPrice(UInt32 symbol, UInt32 posState) const { return _prices[posState][symbol]; }
+  void UpdateTable(UInt32 posState)
+  {
+    SetPrices(posState, _tableSize, _prices[posState]);
+    _counters[posState] = _tableSize;
+  }
+  void UpdateTables(UInt32 numPosStates)
+  {
+    for (UInt32 posState = 0; posState < numPosStates; posState++)
+      UpdateTable(posState);
+  }
+  void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState, bool updatePrice)
+  {
+    CEncoder::Encode(rangeEncoder, symbol, posState);
+    if (updatePrice)
+      if (--_counters[posState] == 0)
+        UpdateTable(posState);
+  }
+};
+
+}
+
+typedef struct _CSeqInStream
+{
+  ISeqInStream SeqInStream;
+  CMyComPtr<ISequentialInStream> RealStream;
+} CSeqInStream;
+
+
+class CEncoder : 
+  public ICompressCoder,
+  public ICompressSetOutStream,
+  public ICompressSetCoderProperties,
+  public ICompressWriteCoderProperties,
+  public CBaseState,
+  public CMyUnknownImp
+{
+  NRangeCoder::CEncoder _rangeEncoder;
+
+  IMatchFinder _matchFinder;
+  void *_matchFinderObj;
+  
+  #ifdef COMPRESS_MF_MT
+  Bool _multiThread;
+  Bool _mtMode;
+  CMatchFinderMt _matchFinderMt;
+  #endif
+
+  CMatchFinder _matchFinderBase;
+  #ifdef COMPRESS_MF_MT
+  Byte _pad1[kMtCacheLineDummy];
+  #endif
+
+  COptimal _optimum[kNumOpts];
+
+  CMyBitEncoder _isMatch[kNumStates][NLength::kNumPosStatesEncodingMax];
+  CMyBitEncoder _isRep[kNumStates];
+  CMyBitEncoder _isRepG0[kNumStates];
+  CMyBitEncoder _isRepG1[kNumStates];
+  CMyBitEncoder _isRepG2[kNumStates];
+  CMyBitEncoder _isRep0Long[kNumStates][NLength::kNumPosStatesEncodingMax];
+
+  NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> _posSlotEncoder[kNumLenToPosStates];
+
+  CMyBitEncoder _posEncoders[kNumFullDistances - kEndPosModelIndex];
+  NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumAlignBits> _posAlignEncoder;
+  
+  NLength::CPriceTableEncoder _lenEncoder;
+  NLength::CPriceTableEncoder _repMatchLenEncoder;
+
+  CLiteralEncoder _literalEncoder;
+
+  UInt32 _matchDistances[kMatchMaxLen * 2 + 2 + 1];
+
+  bool _fastMode;
+  // bool _maxMode;
+  UInt32 _numFastBytes;
+  UInt32 _longestMatchLength;    
+  UInt32 _numDistancePairs;
+
+  UInt32 _additionalOffset;
+
+  UInt32 _optimumEndIndex;
+  UInt32 _optimumCurrentIndex;
+
+  bool _longestMatchWasFound;
+
+  UInt32 _posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+  
+  UInt32 _distancesPrices[kNumLenToPosStates][kNumFullDistances];
+
+  UInt32 _alignPrices[kAlignTableSize];
+  UInt32 _alignPriceCount;
+
+  UInt32 _distTableSize;
+
+  UInt32 _posStateBits;
+  UInt32 _posStateMask;
+  UInt32 _numLiteralPosStateBits;
+  UInt32 _numLiteralContextBits;
+
+  UInt32 _dictionarySize;
+
+  UInt32 _matchPriceCount;
+  UInt64 nowPos64;
+  bool _finished;
+  ISequentialInStream *_inStream;
+
+  CSeqInStream _seqInStream;
+
+  UInt32 _matchFinderCycles;
+  // int _numSkip
+
+  bool _writeEndMark;
+
+  bool _needReleaseMFStream;
+
+  void ReleaseMatchFinder()
+  {
+    _matchFinder.Init = 0;
+    _seqInStream.RealStream.Release();
+  }
+
+  void ReleaseMFStream()
+  {
+    if (_matchFinderObj && _needReleaseMFStream)
+    {
+      #ifdef COMPRESS_MF_MT
+      if (_mtMode)
+        MatchFinderMt_ReleaseStream(&_matchFinderMt);
+      #endif
+      _needReleaseMFStream = false;
+    }
+    _seqInStream.RealStream.Release();
+  }
+  
+  UInt32 ReadMatchDistances(UInt32 &numDistancePairs);
+
+  void MovePos(UInt32 num);
+  UInt32 GetRepLen1Price(CState state, UInt32 posState) const
+  {
+    return _isRepG0[state.Index].GetPrice0() +
+        _isRep0Long[state.Index][posState].GetPrice0();
+  }
+  
+  UInt32 GetPureRepPrice(UInt32 repIndex, CState state, UInt32 posState) const
+  {
+    UInt32 price;
+    if(repIndex == 0)
+    {
+      price = _isRepG0[state.Index].GetPrice0();
+      price += _isRep0Long[state.Index][posState].GetPrice1();
+    }
+    else
+    {
+      price = _isRepG0[state.Index].GetPrice1();
+      if (repIndex == 1)
+        price += _isRepG1[state.Index].GetPrice0();
+      else
+      {
+        price += _isRepG1[state.Index].GetPrice1();
+        price += _isRepG2[state.Index].GetPrice(repIndex - 2);
+      }
+    }
+    return price;
+  }
+  UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, CState state, UInt32 posState) const
+  {
+    return _repMatchLenEncoder.GetPrice(len - kMatchMinLen, posState) +
+        GetPureRepPrice(repIndex, state, posState);
+  }
+  /*
+  UInt32 GetPosLen2Price(UInt32 pos, UInt32 posState) const
+  {
+    if (pos >= kNumFullDistances)
+      return kIfinityPrice;
+    return _distancesPrices[0][pos] + _lenEncoder.GetPrice(0, posState);
+  }
+  UInt32 GetPosLen3Price(UInt32 pos, UInt32 len, UInt32 posState) const
+  {
+    UInt32 price;
+    UInt32 lenToPosState = GetLenToPosState(len);
+    if (pos < kNumFullDistances)
+      price = _distancesPrices[lenToPosState][pos];
+    else
+      price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] + 
+          _alignPrices[pos & kAlignMask];
+    return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
+  }
+  */
+  UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) const
+  {
+    UInt32 price;
+    UInt32 lenToPosState = GetLenToPosState(len);
+    if (pos < kNumFullDistances)
+      price = _distancesPrices[lenToPosState][pos];
+    else
+      price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] + 
+          _alignPrices[pos & kAlignMask];
+    return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
+  }
+
+  UInt32 Backward(UInt32 &backRes, UInt32 cur);
+  UInt32 GetOptimum(UInt32 position, UInt32 &backRes);
+  UInt32 GetOptimumFast(UInt32 &backRes);
+
+  void FillDistancesPrices();
+  void FillAlignPrices();
+    
+  void ReleaseStreams()
+  {
+    ReleaseMFStream();
+    ReleaseOutStream();
+  }
+
+  HRESULT Flush(UInt32 nowPos);
+  class CCoderReleaser
+  {
+    CEncoder *_coder;
+  public:
+    CCoderReleaser(CEncoder *coder): _coder(coder) {}
+    ~CCoderReleaser() { _coder->ReleaseStreams(); }
+  };
+  friend class CCoderReleaser;
+
+  void WriteEndMarker(UInt32 posState);
+
+public:
+  CEncoder();
+  void SetWriteEndMarkerMode(bool writeEndMarker)
+    { _writeEndMark= writeEndMarker; }
+
+  HRESULT Create();
+
+  MY_UNKNOWN_IMP3(
+      ICompressSetOutStream,
+      ICompressSetCoderProperties,
+      ICompressWriteCoderProperties
+      )
+    
+  HRESULT Init();
+  
+  // ICompressCoder interface
+  HRESULT SetStreams(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream,
+      const UInt64 *inSize, const UInt64 *outSize);
+  HRESULT CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished);
+
+  HRESULT CodeReal(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, 
+      const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+
+  // ICompressCoder interface
+  STDMETHOD(Code)(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, 
+      const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+
+  // ICompressSetCoderProperties2
+  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, 
+      const PROPVARIANT *properties, UInt32 numProperties);
+  
+  // ICompressWriteCoderProperties
+  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+  STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
+  STDMETHOD(ReleaseOutStream)();
+
+  virtual ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA/LZMARegister.cpp b/lzma/CPP/7zip/Compress/LZMA/LZMARegister.cpp
new file mode 100644 (file)
index 0000000..bc8f726
--- /dev/null
@@ -0,0 +1,19 @@
+// LZMARegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "LZMADecoder.h"
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLZMA::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "LZMAEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLZMA::CEncoder);  }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+  { CreateCodec, CreateCodecOut, 0x030101, L"LZMA", 1, false };
+
+REGISTER_CODEC(LZMA)
diff --git a/lzma/CPP/7zip/Compress/LZMA/StdAfx.cpp b/lzma/CPP/7zip/Compress/LZMA/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Compress/LZMA/StdAfx.h b/lzma/CPP/7zip/Compress/LZMA/StdAfx.h
new file mode 100644 (file)
index 0000000..e7fb698
--- /dev/null
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/AloneLZMA.dsp b/lzma/CPP/7zip/Compress/LZMA_Alone/AloneLZMA.dsp
new file mode 100644 (file)
index 0000000..39fee93
--- /dev/null
@@ -0,0 +1,504 @@
+# Microsoft Developer Studio Project File - Name="AloneLZMA" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=AloneLZMA - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "AloneLZMA.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "AloneLZMA.mak" CFG="AloneLZMA - Win32 DebugU"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "AloneLZMA - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "AloneLZMA - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "AloneLZMA - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
+!MESSAGE "AloneLZMA - Win32 DebugU" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "AloneLZMA - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "BENCH_MT" /FAcs /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\lzma.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "AloneLZMA - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "BENCH_MT" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\lzma.exe" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "AloneLZMA - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "FORMAT_BZIP2" /D "FORMAT_ZIP" /D "FORMAT_TAR" /D "FORMAT_GZIP" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "COMPRESS_MF_PAT" /D "COMPRESS_MF_BT" /D "COMPRESS_PPMD" /D "COMPRESS_DEFLATE" /D "COMPRESS_IMPLODE" /D "COMPRESS_BZIP2" /D "CRYPTO_ZIP" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "BENCH_MT" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za2.exe" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\lzma.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "AloneLZMA - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "FORMAT_BZIP2" /D "FORMAT_ZIP" /D "FORMAT_TAR" /D "FORMAT_GZIP" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "COMPRESS_MF_PAT" /D "COMPRESS_MF_BT" /D "COMPRESS_PPMD" /D "COMPRESS_DEFLATE" /D "COMPRESS_IMPLODE" /D "COMPRESS_BZIP2" /D "CRYPTO_ZIP" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "COMPRESS_MF_MT" /D "BENCH_MT" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za2.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\lzma.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "AloneLZMA - Win32 Release"
+# Name "AloneLZMA - Win32 Debug"
+# Name "AloneLZMA - Win32 ReleaseU"
+# Name "AloneLZMA - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZMA\LZMA.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMADecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMADecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMAEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMAEncoder.h
+# End Source File
+# End Group
+# Begin Group "RangeCoder"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderBit.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderBit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderBitTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderOpt.h
+# End Source File
+# End Group
+# Begin Group "LZ"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZ\LZOutWindow.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\LZOutWindow.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Group "C-Lz"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinder.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinderMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\MatchFinderMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "LZMA_C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lzma\LzmaDecode.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lzma\LzmaDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lzma\LzmaTypes.h
+# End Source File
+# End Group
+# Begin Group "Branch"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchX86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Branch\BranchX86.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Types.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaAlone.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaBench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaBench.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaBenchCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaBenchCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRamDecode.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRamDecode.h
+# End Source File
+# End Target
+# End Project
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/AloneLZMA.dsw b/lzma/CPP/7zip/Compress/LZMA_Alone/AloneLZMA.dsw
new file mode 100644 (file)
index 0000000..d7482d8
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "AloneLZMA"=.\AloneLZMA.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp
new file mode 100644 (file)
index 0000000..5b97fd0
--- /dev/null
@@ -0,0 +1,554 @@
+// LzmaAlone.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#include <fcntl.h>
+#include <io.h>
+#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
+#else
+#define MY_SET_BINARY_MODE(file)
+#endif
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+
+#include "LzmaBenchCon.h"
+#include "LzmaRam.h"
+
+#ifdef COMPRESS_MF_MT
+#include "../../../Windows/System.h"
+#endif
+
+#include "../../MyVersion.h"
+
+extern "C"
+{
+#include "LzmaRamDecode.h"
+}
+
+using namespace NCommandLineParser;
+
+#ifdef _WIN32
+bool g_IsNT = false;
+static inline bool IsItWindowsNT()
+{
+  OSVERSIONINFO versionInfo;
+  versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+  if (!::GetVersionEx(&versionInfo)) 
+    return false;
+  return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+
+static const char *kCantAllocate = "Can not allocate memory";
+static const char *kReadError = "Read error";
+static const char *kWriteError = "Write error";
+
+namespace NKey {
+enum Enum
+{
+  kHelp1 = 0,
+  kHelp2,
+  kMode,
+  kDictionary,
+  kFastBytes,
+  kMatchFinderCycles,
+  kLitContext,
+  kLitPos,
+  kPosBits,
+  kMatchFinder,
+  kMultiThread,
+  kEOS,
+  kStdIn,
+  kStdOut,
+  kFilter86
+};
+}
+
+static const CSwitchForm kSwitchForms[] = 
+{
+  { L"?",  NSwitchType::kSimple, false },
+  { L"H",  NSwitchType::kSimple, false },
+  { L"A", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"D", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"FB", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"MC", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"LC", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"LP", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"PB", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"MF", NSwitchType::kUnLimitedPostString, false, 1 },
+  { L"MT", NSwitchType::kUnLimitedPostString, false, 0 },
+  { L"EOS", NSwitchType::kSimple, false },
+  { L"SI",  NSwitchType::kSimple, false },
+  { L"SO",  NSwitchType::kSimple, false },
+  { L"F86",  NSwitchType::kPostChar, false, 0, 0, L"+" }
+};
+
+static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]);
+
+static void PrintHelp()
+{
+  fprintf(stderr, "\nUsage:  LZMA <e|d> inputFile outputFile [<switches>...]\n"
+             "  e: encode file\n"
+             "  d: decode file\n"
+             "  b: Benchmark\n"
+    "<Switches>\n"
+    "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n"
+    "  -d{N}:  set dictionary - [0,30], default: 23 (8MB)\n"
+    "  -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
+    "  -mc{N}: set number of cycles for match finder\n"
+    "  -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
+    "  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
+    "  -pb{N}: set number of pos bits - [0, 4], default: 2\n"
+    "  -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], default: bt4\n"
+    "  -mt{N}: set number of CPU threads\n"
+    "  -eos:   write End Of Stream marker\n"
+    "  -si:    read data from stdin\n"
+    "  -so:    write data to stdout\n"
+    );
+}
+
+static void PrintHelpAndExit(const char *s)
+{
+  fprintf(stderr, "\nError: %s\n\n", s);
+  PrintHelp();
+  throw -1;
+}
+
+static void IncorrectCommand()
+{
+  PrintHelpAndExit("Incorrect command");
+}
+
+static void WriteArgumentsToStringList(int numArguments, const char *arguments[], 
+    UStringVector &strings)
+{
+  for(int i = 1; i < numArguments; i++)
+    strings.Add(MultiByteToUnicodeString(arguments[i]));
+}
+
+static bool GetNumber(const wchar_t *s, UInt32 &value)
+{
+  value = 0;
+  if (MyStringLen(s) == 0)
+    return false;
+  const wchar_t *end;
+  UInt64 res = ConvertStringToUInt64(s, &end);
+  if (*end != L'\0')
+    return false;
+  if (res > 0xFFFFFFFF)
+    return false;
+  value = UInt32(res);
+  return true;
+}
+
+int main2(int n, const char *args[])
+{
+  #ifdef _WIN32
+  g_IsNT = IsItWindowsNT();
+  #endif
+
+  fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
+
+  if (n == 1)
+  {
+    PrintHelp();
+    return 0;
+  }
+
+  bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
+  if (unsupportedTypes)
+  {
+    fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
+    return 1;
+  }   
+
+  UStringVector commandStrings;
+  WriteArgumentsToStringList(n, args, commandStrings);
+  CParser parser(kNumSwitches);
+  try
+  {
+    parser.ParseStrings(kSwitchForms, commandStrings);
+  }
+  catch(...) 
+  {
+    IncorrectCommand();
+  }
+
+  if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+  {
+    PrintHelp();
+    return 0;
+  }
+  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+  int paramIndex = 0;
+  if (paramIndex >= nonSwitchStrings.Size())
+    IncorrectCommand();
+  const UString &command = nonSwitchStrings[paramIndex++]; 
+
+  bool dictionaryIsDefined = false;
+  UInt32 dictionary = (UInt32)-1;
+  if(parser[NKey::kDictionary].ThereIs)
+  {
+    UInt32 dicLog;
+    if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
+      IncorrectCommand();
+    dictionary = 1 << dicLog;
+    dictionaryIsDefined = true;
+  }
+  UString mf = L"BT4";
+  if (parser[NKey::kMatchFinder].ThereIs)
+    mf = parser[NKey::kMatchFinder].PostStrings[0];
+
+  UInt32 numThreads = (UInt32)-1;
+
+  #ifdef COMPRESS_MF_MT
+  if (parser[NKey::kMultiThread].ThereIs)
+  {
+    UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+    const UString &s = parser[NKey::kMultiThread].PostStrings[0];
+    if (s.IsEmpty())
+      numThreads = numCPUs;
+    else
+      if (!GetNumber(s, numThreads))
+        IncorrectCommand();
+  }
+  #endif
+
+  if (command.CompareNoCase(L"b") == 0)
+  {
+    const UInt32 kNumDefaultItereations = 1;
+    UInt32 numIterations = kNumDefaultItereations;
+    {
+      if (paramIndex < nonSwitchStrings.Size())
+        if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
+          numIterations = kNumDefaultItereations;
+    }
+    return LzmaBenchCon(stderr, numIterations, numThreads, dictionary);
+  }
+
+  if (numThreads == (UInt32)-1)
+    numThreads = 1;
+
+  bool encodeMode = false;
+  if (command.CompareNoCase(L"e") == 0)
+    encodeMode = true;
+  else if (command.CompareNoCase(L"d") == 0)
+    encodeMode = false;
+  else
+    IncorrectCommand();
+
+  bool stdInMode = parser[NKey::kStdIn].ThereIs;
+  bool stdOutMode = parser[NKey::kStdOut].ThereIs;
+
+  CMyComPtr<ISequentialInStream> inStream;
+  CInFileStream *inStreamSpec = 0;
+  if (stdInMode)
+  {
+    inStream = new CStdInFileStream;
+    MY_SET_BINARY_MODE(stdin);
+  }
+  else
+  {
+    if (paramIndex >= nonSwitchStrings.Size())
+      IncorrectCommand();
+    const UString &inputName = nonSwitchStrings[paramIndex++]; 
+    inStreamSpec = new CInFileStream;
+    inStream = inStreamSpec;
+    if (!inStreamSpec->Open(GetSystemString(inputName)))
+    {
+      fprintf(stderr, "\nError: can not open input file %s\n", 
+          (const char *)GetOemString(inputName));
+      return 1;
+    }
+  }
+
+  CMyComPtr<ISequentialOutStream> outStream;
+  COutFileStream *outStreamSpec = NULL;
+  if (stdOutMode)
+  {
+    outStream = new CStdOutFileStream;
+    MY_SET_BINARY_MODE(stdout);
+  }
+  else
+  {
+    if (paramIndex >= nonSwitchStrings.Size())
+      IncorrectCommand();
+    const UString &outputName = nonSwitchStrings[paramIndex++]; 
+    outStreamSpec = new COutFileStream;
+    outStream = outStreamSpec;
+    if (!outStreamSpec->Create(GetSystemString(outputName), true))
+    {
+      fprintf(stderr, "\nError: can not open output file %s\n", 
+        (const char *)GetOemString(outputName));
+      return 1;
+    }
+  }
+
+  if (parser[NKey::kFilter86].ThereIs)
+  {
+    // -f86 switch is for x86 filtered mode: BCJ + LZMA.
+    if (parser[NKey::kEOS].ThereIs || stdInMode)
+      throw "Can not use stdin in this mode";
+    UInt64 fileSize;
+    inStreamSpec->File.GetLength(fileSize);
+    if (fileSize > 0xF0000000)
+      throw "File is too big";
+    UInt32 inSize = (UInt32)fileSize;
+    Byte *inBuffer = 0;
+    if (inSize != 0)
+    {
+      inBuffer = (Byte *)MyAlloc((size_t)inSize); 
+      if (inBuffer == 0)
+        throw kCantAllocate;
+    }
+    
+    UInt32 processedSize;
+    if (ReadStream(inStream, inBuffer, (UInt32)inSize, &processedSize) != S_OK)
+      throw "Can not read";
+    if ((UInt32)inSize != processedSize)
+      throw "Read size error";
+
+    Byte *outBuffer = 0;
+    size_t outSizeProcessed;
+    if (encodeMode)
+    {
+      // we allocate 105% of original size for output buffer
+      size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
+      if (outSize != 0)
+      {
+        outBuffer = (Byte *)MyAlloc((size_t)outSize); 
+        if (outBuffer == 0)
+          throw kCantAllocate;
+      }
+      if (!dictionaryIsDefined)
+        dictionary = 1 << 23;
+      int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, 
+          dictionary, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
+      if (res != 0)
+      {
+        fprintf(stderr, "\nEncoder error = %d\n", (int)res);
+        return 1;
+      }
+    }
+    else
+    {
+      size_t outSize;
+      if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
+        throw "data error";
+      if (outSize != 0)
+      {
+        outBuffer = (Byte *)MyAlloc(outSize); 
+        if (outBuffer == 0)
+          throw kCantAllocate;
+      }
+      int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
+      if (res != 0)
+        throw "LzmaDecoder error";
+    }
+    if (WriteStream(outStream, outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
+      throw kWriteError;
+    MyFree(outBuffer);
+    MyFree(inBuffer);
+    return 0;
+  }
+
+
+  UInt64 fileSize;
+  if (encodeMode)
+  {
+    NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
+    CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+    if (!dictionaryIsDefined)
+      dictionary = 1 << 23;
+
+    UInt32 posStateBits = 2;
+    UInt32 litContextBits = 3; // for normal files
+    // UInt32 litContextBits = 0; // for 32-bit data
+    UInt32 litPosBits = 0;
+    // UInt32 litPosBits = 2; // for 32-bit data
+    UInt32 algorithm = 1;
+    UInt32 numFastBytes = 128;
+    UInt32 matchFinderCycles = 16 + numFastBytes / 2;
+    bool matchFinderCyclesDefined = false;
+
+    bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
+    if(parser[NKey::kMode].ThereIs)
+      if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
+        IncorrectCommand();
+
+    if(parser[NKey::kFastBytes].ThereIs)
+      if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
+        IncorrectCommand();
+    matchFinderCyclesDefined = parser[NKey::kMatchFinderCycles].ThereIs;
+    if (matchFinderCyclesDefined)
+      if (!GetNumber(parser[NKey::kMatchFinderCycles].PostStrings[0], matchFinderCycles))
+        IncorrectCommand();
+    if(parser[NKey::kLitContext].ThereIs)
+      if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
+        IncorrectCommand();
+    if(parser[NKey::kLitPos].ThereIs)
+      if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
+        IncorrectCommand();
+    if(parser[NKey::kPosBits].ThereIs)
+      if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
+        IncorrectCommand();
+
+    PROPID propIDs[] = 
+    {
+      NCoderPropID::kDictionarySize,
+      NCoderPropID::kPosStateBits,
+      NCoderPropID::kLitContextBits,
+      NCoderPropID::kLitPosBits,
+      NCoderPropID::kAlgorithm,
+      NCoderPropID::kNumFastBytes,
+      NCoderPropID::kMatchFinder,
+      NCoderPropID::kEndMarker,
+      NCoderPropID::kNumThreads,
+      NCoderPropID::kMatchFinderCycles,
+    };
+    const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);
+
+    PROPVARIANT properties[kNumPropsMax];
+    for (int p = 0; p < 6; p++)
+      properties[p].vt = VT_UI4;
+
+    properties[0].ulVal = (UInt32)dictionary;
+    properties[1].ulVal = (UInt32)posStateBits;
+    properties[2].ulVal = (UInt32)litContextBits;
+    properties[3].ulVal = (UInt32)litPosBits;
+    properties[4].ulVal = (UInt32)algorithm;
+    properties[5].ulVal = (UInt32)numFastBytes;
+
+    properties[6].vt = VT_BSTR;
+    properties[6].bstrVal = (BSTR)(const wchar_t *)mf;
+
+    properties[7].vt = VT_BOOL;
+    properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
+
+    properties[8].vt = VT_UI4;
+    properties[8].ulVal = (UInt32)numThreads;
+
+    // it must be last in property list
+    properties[9].vt = VT_UI4;
+    properties[9].ulVal = (UInt32)matchFinderCycles;
+
+    int numProps = kNumPropsMax;
+    if (!matchFinderCyclesDefined)
+      numProps--;
+
+    if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
+      IncorrectCommand();
+    encoderSpec->WriteCoderProperties(outStream);
+
+    if (eos || stdInMode)
+      fileSize = (UInt64)(Int64)-1;
+    else
+      inStreamSpec->File.GetLength(fileSize);
+
+    for (int i = 0; i < 8; i++)
+    {
+      Byte b = Byte(fileSize >> (8 * i));
+      if (outStream->Write(&b, 1, 0) != S_OK)
+      {
+        fprintf(stderr, kWriteError);
+        return 1;
+      }
+    }
+    HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
+    if (result == E_OUTOFMEMORY)
+    {
+      fprintf(stderr, "\nError: Can not allocate memory\n");
+      return 1;
+    }   
+    else if (result != S_OK)
+    {
+      fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
+      return 1;
+    }   
+  }
+  else
+  {
+    NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;
+    CMyComPtr<ICompressCoder> decoder = decoderSpec;
+    const UInt32 kPropertiesSize = 5;
+    Byte properties[kPropertiesSize];
+    UInt32 processedSize;
+    if (ReadStream(inStream, properties, kPropertiesSize, &processedSize) != S_OK)
+    {
+      fprintf(stderr, kReadError);
+      return 1;
+    }
+    if (processedSize != kPropertiesSize)
+    {
+      fprintf(stderr, kReadError);
+      return 1;
+    }
+    if (decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK)
+    {
+      fprintf(stderr, "SetDecoderProperties error");
+      return 1;
+    }
+    fileSize = 0;
+    for (int i = 0; i < 8; i++)
+    {
+      Byte b;
+      if (inStream->Read(&b, 1, &processedSize) != S_OK)
+      {
+        fprintf(stderr, kReadError);
+        return 1;
+      }
+      if (processedSize != 1)
+      {
+        fprintf(stderr, kReadError);
+        return 1;
+      }
+      fileSize |= ((UInt64)b) << (8 * i);
+    }
+    if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
+    {
+      fprintf(stderr, "Decoder error");
+      return 1;
+    }   
+  }
+  if (outStreamSpec != NULL)
+  {
+    if (outStreamSpec->Close() != S_OK)
+    {
+      fprintf(stderr, "File closing error");
+      return 1;
+    }
+  }
+  return 0;
+}
+
+int main(int n, const char *args[])
+{
+  try { return main2(n, args); }
+  catch(const char *s) 
+  { 
+    fprintf(stderr, "\nError: %s\n", s);
+    return 1; 
+  }
+  catch(...) 
+  { 
+    fprintf(stderr, "\nError\n");
+    return 1; 
+  }
+}
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp
new file mode 100644 (file)
index 0000000..4cd2d63
--- /dev/null
@@ -0,0 +1,1024 @@
+// LzmaBench.cpp
+
+#include "StdAfx.h"
+
+#include "LzmaBench.h"
+
+#ifndef _WIN32
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+extern "C" 
+{ 
+#include "../../../../C/Alloc.h"
+#include "../../../../C/7zCrc.h"
+}
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+#ifdef BENCH_MT
+#include "../../../Windows/Thread.h"
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#ifdef EXTERNAL_LZMA
+#include "../../../Windows/PropVariant.h"
+#else
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+#endif
+
+static const UInt32 kUncompressMinBlockSize = 1 << 26;
+static const UInt32 kAdditionalSize = (1 << 16);
+static const UInt32 kCompressedAdditionalSize = (1 << 10);
+static const UInt32 kMaxLzmaPropSize = 5;
+
+class CBaseRandomGenerator
+{
+  UInt32 A1;
+  UInt32 A2;
+public:
+  CBaseRandomGenerator() { Init(); }
+  void Init() { A1 = 362436069; A2 = 521288629;}
+  UInt32 GetRnd() 
+  {
+    return 
+      ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+      ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
+  }
+};
+
+class CBenchBuffer
+{
+public:
+  size_t BufferSize;
+  Byte *Buffer;
+  CBenchBuffer(): Buffer(0) {} 
+  virtual ~CBenchBuffer() { Free(); }
+  void Free() 
+  { 
+    ::MidFree(Buffer);
+    Buffer = 0;
+  }
+  bool Alloc(size_t bufferSize) 
+  {
+    if (Buffer != 0 && BufferSize == bufferSize)
+      return true;
+    Free();
+    Buffer = (Byte *)::MidAlloc(bufferSize);
+    BufferSize = bufferSize;
+    return (Buffer != 0);
+  }
+};
+
+class CBenchRandomGenerator: public CBenchBuffer
+{
+  CBaseRandomGenerator *RG;
+public:
+  void Set(CBaseRandomGenerator *rg) { RG = rg; }
+  UInt32 GetVal(UInt32 &res, int numBits) 
+  {
+    UInt32 val = res & (((UInt32)1 << numBits) - 1);
+    res >>= numBits;
+    return val;
+  }
+  UInt32 GetLen(UInt32 &res) 
+  { 
+    UInt32 len = GetVal(res, 2);
+    return GetVal(res, 1 + len);
+  }
+  void Generate()
+  {
+    UInt32 pos = 0;
+    UInt32 rep0 = 1;
+    while (pos < BufferSize)
+    {
+      UInt32 res = RG->GetRnd();
+      res >>= 1;
+      if (GetVal(res, 1) == 0 || pos < 1024)
+        Buffer[pos++] = (Byte)(res & 0xFF);
+      else
+      {
+        UInt32 len;
+        len = 1 + GetLen(res);
+        if (GetVal(res, 3) != 0)
+        {
+          len += GetLen(res);
+          do
+          {
+            UInt32 ppp = GetVal(res, 5) + 6;
+            res = RG->GetRnd();
+            if (ppp > 30)
+              continue;
+            rep0 = /* (1 << ppp) +*/  GetVal(res, ppp);
+            res = RG->GetRnd();
+          }
+          while (rep0 >= pos);
+          rep0++;
+        }
+
+        for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++)
+          Buffer[pos] = Buffer[pos - rep0];
+      }
+    }
+  }
+};
+
+
+class CBenchmarkInStream: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+  const Byte *Data;
+  size_t Pos;
+  size_t Size;
+public:
+  MY_UNKNOWN_IMP
+  void Init(const Byte *data, size_t size)
+  {
+    Data = data;
+    Size = size;
+    Pos = 0;
+  }
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  size_t remain = Size - Pos;
+  UInt32 kMaxBlockSize = (1 << 20);
+  if (size > kMaxBlockSize)
+    size = kMaxBlockSize;
+  if (size > remain)
+    size = (UInt32)remain;
+  for (UInt32 i = 0; i < size; i++)
+    ((Byte *)data)[i] = Data[Pos + i];
+  Pos += size;
+  if(processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
+  
+class CBenchmarkOutStream: 
+  public ISequentialOutStream,
+  public CBenchBuffer,
+  public CMyUnknownImp
+{
+  // bool _overflow;
+public:
+  UInt32 Pos;
+  // CBenchmarkOutStream(): _overflow(false) {} 
+  void Init() 
+  {
+    // _overflow = false;
+    Pos = 0;
+  }
+  MY_UNKNOWN_IMP
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  size_t curSize = BufferSize - Pos;
+  if (curSize > size)
+    curSize = size;
+  memcpy(Buffer + Pos, data, curSize);
+  Pos += (UInt32)curSize;
+  if(processedSize != NULL)
+    *processedSize = (UInt32)curSize;
+  if (curSize != size)
+  {
+    // _overflow = true;
+    return E_FAIL;
+  }
+  return S_OK;
+}
+  
+class CCrcOutStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+public:
+  UInt32 Crc;
+  MY_UNKNOWN_IMP
+  void Init() { Crc = CRC_INIT_VAL; }
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  Crc = CrcUpdate(Crc, data, size);
+  if (processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
+  
+static UInt64 GetTimeCount()
+{
+  #ifdef USE_POSIX_TIME
+  #ifdef USE_POSIX_TIME2
+  timeval v;
+  if (gettimeofday(&v, 0) == 0)
+    return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
+  return (UInt64)time(NULL) * 1000000;
+  #else
+  return time(NULL);
+  #endif
+  #else
+  /*
+  LARGE_INTEGER value;
+  if (::QueryPerformanceCounter(&value))
+    return value.QuadPart;
+  */
+  return GetTickCount();
+  #endif 
+}
+
+static UInt64 GetFreq()
+{
+  #ifdef USE_POSIX_TIME
+  #ifdef USE_POSIX_TIME2
+  return 1000000;
+  #else
+  return 1;
+  #endif 
+  #else
+  /*
+  LARGE_INTEGER value;
+  if (::QueryPerformanceFrequency(&value))
+    return value.QuadPart;
+  */
+  return 1000;
+  #endif 
+}
+
+#ifndef USE_POSIX_TIME
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+#endif
+static UInt64 GetUserTime()
+{
+  #ifdef USE_POSIX_TIME
+  return clock();
+  #else
+  FILETIME creationTime, exitTime, kernelTime, userTime;
+  if (::GetProcessTimes(::GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+    return GetTime64(userTime) + GetTime64(kernelTime);
+  return (UInt64)GetTickCount() * 10000;
+  #endif 
+}
+
+static UInt64 GetUserFreq()
+{
+  #ifdef USE_POSIX_TIME
+  return CLOCKS_PER_SEC;
+  #else
+  return 10000000;
+  #endif 
+}
+
+class CBenchProgressStatus
+{
+  #ifdef BENCH_MT
+  NWindows::NSynchronization::CCriticalSection CS;  
+  #endif
+public:
+  HRESULT Res;
+  bool EncodeMode;
+  void SetResult(HRESULT res) 
+  {
+    #ifdef BENCH_MT
+    NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+    #endif
+    Res = res;
+  }
+  HRESULT GetResult()
+  {
+    #ifdef BENCH_MT
+    NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+    #endif
+    return Res;
+  }
+};
+
+class CBenchProgressInfo:
+  public ICompressProgressInfo,
+  public CMyUnknownImp
+{
+public:
+  CBenchProgressStatus *Status;
+  CBenchInfo BenchInfo;
+  HRESULT Res;
+  IBenchCallback *callback;
+  CBenchProgressInfo(): callback(0) {}
+  MY_UNKNOWN_IMP
+  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void SetStartTime(CBenchInfo &bi)
+{
+  bi.GlobalFreq = GetFreq();
+  bi.UserFreq = GetUserFreq();
+  bi.GlobalTime = ::GetTimeCount();
+  bi.UserTime = ::GetUserTime();
+}
+
+void SetFinishTime(const CBenchInfo &biStart, CBenchInfo &dest)
+{
+  dest.GlobalFreq = GetFreq();
+  dest.UserFreq = GetUserFreq();
+  dest.GlobalTime = ::GetTimeCount() - biStart.GlobalTime;
+  dest.UserTime = ::GetUserTime() - biStart.UserTime;
+}
+
+STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+  HRESULT res = Status->GetResult();
+  if (res != S_OK)
+    return res;
+  if (!callback)
+    return res;
+  CBenchInfo info = BenchInfo;
+  SetFinishTime(BenchInfo, info);
+  if (Status->EncodeMode)
+  {
+    info.UnpackSize = *inSize;
+    info.PackSize = *outSize;
+    res = callback->SetEncodeResult(info, false);
+  }
+  else
+  {
+    info.PackSize = BenchInfo.PackSize + *inSize;
+    info.UnpackSize = BenchInfo.UnpackSize + *outSize;
+    res = callback->SetDecodeResult(info, false);
+  }
+  if (res != S_OK)
+    Status->SetResult(res);
+  return res;
+}
+
+static const int kSubBits = 8;
+
+static UInt32 GetLogSize(UInt32 size)
+{
+  for (int i = kSubBits; i < 32; i++)
+    for (UInt32 j = 0; j < (1 << kSubBits); j++)
+      if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
+        return (i << kSubBits) + j;
+  return (32 << kSubBits);
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+  while (v1 > 1000000)
+  {
+    v1 >>= 1;
+    v2 >>= 1;
+  }
+}
+
+UInt64 GetUsage(const CBenchInfo &info)
+{
+  UInt64 userTime = info.UserTime;
+  UInt64 userFreq = info.UserFreq;
+  UInt64 globalTime = info.GlobalTime;
+  UInt64 globalFreq = info.GlobalFreq;
+  NormalizeVals(userTime, userFreq);
+  NormalizeVals(globalFreq, globalTime);
+  if (userFreq == 0)
+    userFreq = 1;
+  if (globalTime == 0)
+    globalTime = 1;
+  return userTime * globalFreq * 1000000 / userFreq / globalTime;
+}
+
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating)
+{
+  UInt64 userTime = info.UserTime;
+  UInt64 userFreq = info.UserFreq;
+  UInt64 globalTime = info.GlobalTime;
+  UInt64 globalFreq = info.GlobalFreq;
+  NormalizeVals(userFreq, userTime);
+  NormalizeVals(globalTime, globalFreq);
+  if (globalFreq == 0)
+    globalFreq = 1;
+  if (userTime == 0)
+    userTime = 1;
+  return userFreq * globalTime / globalFreq *  rating / userTime;
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+  UInt64 elTime = elapsedTime;
+  NormalizeVals(freq, elTime);
+  if (elTime == 0)
+    elTime = 1;
+  return value * freq / elTime;
+}
+
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
+{
+  UInt64 t = GetLogSize(dictionarySize) - (kBenchMinDicLogSize << kSubBits);
+  // UInt64 numCommandsForOne = 1000 + ((t * t * 7) >> (2 * kSubBits)); // AMD K8
+  UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits)); // Intel Core2
+
+  UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
+  return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations)
+{
+  // UInt64 numCommands = (inSize * 216 + outSize * 14) * numIterations; // AMD K8
+  UInt64 numCommands = (inSize * 220 + outSize * 8) * numIterations; // Intel Core2
+  return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+#ifdef EXTERNAL_LZMA
+typedef UInt32 (WINAPI * CreateObjectPointer)(const GUID *clsID, 
+    const GUID *interfaceID, void **outObject);
+#endif
+
+struct CEncoderInfo;
+
+struct CEncoderInfo
+{
+  #ifdef BENCH_MT
+  NWindows::CThread thread[2];
+  #endif
+  CMyComPtr<ICompressCoder> encoder;
+  CBenchProgressInfo *progressInfoSpec[2];
+  CMyComPtr<ICompressProgressInfo> progressInfo[2];
+  UInt32 NumIterations;
+  #ifdef USE_ALLOCA
+  size_t AllocaSize;
+  #endif
+
+  struct CDecoderInfo
+  {
+    CEncoderInfo *Encoder;
+    UInt32 DecoderIndex;
+    #ifdef USE_ALLOCA
+    size_t AllocaSize;
+    #endif
+    bool CallbackMode;
+  };
+  CDecoderInfo decodersInfo[2];
+
+  CMyComPtr<ICompressCoder> decoders[2];
+  HRESULT Results[2];
+  CBenchmarkOutStream *outStreamSpec;
+  CMyComPtr<ISequentialOutStream> outStream;
+  IBenchCallback *callback;
+  UInt32 crc;
+  UInt32 kBufferSize;
+  UInt32 compressedSize;
+  CBenchRandomGenerator rg;
+  CBenchmarkOutStream *propStreamSpec;
+  CMyComPtr<ISequentialOutStream> propStream;
+  HRESULT Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rg);
+  HRESULT Encode();
+  HRESULT Decode(UInt32 decoderIndex);
+
+  CEncoderInfo(): outStreamSpec(0), callback(0), propStreamSpec(0) {}
+
+  #ifdef BENCH_MT
+  static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
+  {
+    CEncoderInfo *encoder = (CEncoderInfo *)param;
+    #ifdef USE_ALLOCA
+    alloca(encoder->AllocaSize);
+    #endif
+    HRESULT res = encoder->Encode();
+    encoder->Results[0] = res;
+    if (res != S_OK)
+      encoder->progressInfoSpec[0]->Status->SetResult(res);
+
+    return 0;
+  }
+  static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
+  {
+    CDecoderInfo *decoder = (CDecoderInfo *)param;
+    #ifdef USE_ALLOCA
+    alloca(decoder->AllocaSize);
+    #endif
+    CEncoderInfo *encoder = decoder->Encoder;
+    encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
+    return 0;
+  }
+
+  HRESULT CreateEncoderThread()
+  {
+    return thread[0].Create(EncodeThreadFunction, this);
+  }
+
+  HRESULT CreateDecoderThread(int index, bool callbackMode
+      #ifdef USE_ALLOCA
+      , size_t allocaSize
+      #endif
+      )
+  {
+    CDecoderInfo &decoder = decodersInfo[index];
+    decoder.DecoderIndex = index;
+    decoder.Encoder = this;
+    #ifdef USE_ALLOCA
+    decoder.AllocaSize = allocaSize;
+    #endif
+    decoder.CallbackMode = callbackMode;
+    return thread[index].Create(DecodeThreadFunction, &decoder);
+  }
+  #endif
+};
+
+HRESULT CEncoderInfo::Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rgLoc)
+{
+  rg.Set(rgLoc);
+  kBufferSize = dictionarySize + kAdditionalSize;
+  UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+  if (!rg.Alloc(kBufferSize))
+    return E_OUTOFMEMORY;
+  rg.Generate();
+  crc = CrcCalc(rg.Buffer, rg.BufferSize);
+
+  outStreamSpec = new CBenchmarkOutStream;
+  if (!outStreamSpec->Alloc(kCompressedBufferSize))
+    return E_OUTOFMEMORY;
+
+  outStream = outStreamSpec;
+
+  propStreamSpec = 0;
+  if (!propStream)
+  {
+    propStreamSpec = new CBenchmarkOutStream;
+    propStream = propStreamSpec;
+  }
+  if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
+    return E_OUTOFMEMORY;
+  propStreamSpec->Init();
+  
+  PROPID propIDs[] = 
+  { 
+    NCoderPropID::kDictionarySize, 
+    NCoderPropID::kMultiThread
+  };
+  const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+  PROPVARIANT properties[kNumProps];
+  properties[0].vt = VT_UI4;
+  properties[0].ulVal = (UInt32)dictionarySize;
+
+  properties[1].vt = VT_BOOL;
+  properties[1].boolVal = (numThreads > 1) ? VARIANT_TRUE : VARIANT_FALSE;
+
+  {
+    CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+    RINOK(encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties));
+    if (!setCoderProperties)
+      return E_FAIL;
+    RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, kNumProps));
+
+    CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+    encoder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProperties);
+    if (writeCoderProperties)
+    {
+      RINOK(writeCoderProperties->WriteCoderProperties(propStream));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT CEncoderInfo::Encode()
+{
+  CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+  CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+  inStreamSpec->Init(rg.Buffer, rg.BufferSize);
+  outStreamSpec->Init();
+
+  RINOK(encoder->Code(inStream, outStream, 0, 0, progressInfo[0]));
+  compressedSize = outStreamSpec->Pos;
+  encoder.Release();
+  return S_OK;
+}
+
+HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
+{
+  CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+  CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+  CMyComPtr<ICompressCoder> &decoder = decoders[decoderIndex];
+
+  CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+  decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties);
+  if (!compressSetDecoderProperties)
+    return E_FAIL;
+
+  CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+  CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+    
+  CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
+  pi->BenchInfo.UnpackSize = 0;
+  pi->BenchInfo.PackSize = 0;
+
+  for (UInt32 j = 0; j < NumIterations; j++)
+  {
+    inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
+    crcOutStreamSpec->Init();
+    
+    RINOK(compressSetDecoderProperties->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos));
+    UInt64 outSize = kBufferSize;
+    RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
+    if (CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
+      return S_FALSE;
+    pi->BenchInfo.UnpackSize += kBufferSize;
+    pi->BenchInfo.PackSize += compressedSize;
+  }
+  decoder.Release();
+  return S_OK;
+}
+
+static const UInt32 kNumThreadsMax = (1 << 16);
+
+struct CBenchEncoders
+{
+  CEncoderInfo *encoders;
+  CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; }
+  ~CBenchEncoders() { delete []encoders; }
+};
+
+HRESULT LzmaBench(
+  #ifdef EXTERNAL_LZMA
+  CCodecs *codecs,
+  #endif
+  UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback)
+{
+  UInt32 numEncoderThreads = 
+    #ifdef BENCH_MT
+    (numThreads > 1 ? numThreads / 2 : 1);
+    #else
+    1;
+    #endif
+  UInt32 numSubDecoderThreads = 
+    #ifdef BENCH_MT
+    (numThreads > 1 ? 2 : 1);
+    #else
+    1;
+    #endif
+  if (dictionarySize < (1 << kBenchMinDicLogSize) || numThreads < 1 || numEncoderThreads > kNumThreadsMax)
+  {
+    return E_INVALIDARG;
+  }
+
+  CBenchEncoders encodersSpec(numEncoderThreads);
+  CEncoderInfo *encoders = encodersSpec.encoders;
+
+  #ifdef EXTERNAL_LZMA
+  UString name = L"LZMA";
+  #endif
+
+  UInt32 i;
+  for (i = 0; i < numEncoderThreads; i++)
+  {
+    CEncoderInfo &encoder = encoders[i];
+    encoder.callback = (i == 0) ? callback : 0;
+
+    #ifdef EXTERNAL_LZMA
+    RINOK(codecs->CreateCoder(name, true, encoder.encoder));
+    #else
+    encoder.encoder = new NCompress::NLZMA::CEncoder;
+    #endif
+    for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+    {
+      #ifdef EXTERNAL_LZMA
+      RINOK(codecs->CreateCoder(name, false, encoder.decoders[j]));
+      #else
+      encoder.decoders[j] = new NCompress::NLZMA::CDecoder;
+      #endif
+    }
+  }
+
+  CBaseRandomGenerator rg;
+  rg.Init();
+  for (i = 0; i < numEncoderThreads; i++)
+  {
+    RINOK(encoders[i].Init(dictionarySize, numThreads, &rg));
+  }
+
+  CBenchProgressStatus status;
+  status.Res = S_OK;
+  status.EncodeMode = true;
+
+  for (i = 0; i < numEncoderThreads; i++)
+  {
+    CEncoderInfo &encoder = encoders[i];
+    for (int j = 0; j < 2; j++)
+    {
+      encoder.progressInfo[j] = encoder.progressInfoSpec[j] = new CBenchProgressInfo;
+      encoder.progressInfoSpec[j]->Status = &status;
+    }
+    if (i == 0)
+    {
+      encoder.progressInfoSpec[0]->callback = callback;
+      encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numEncoderThreads;
+      SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+    }
+
+    #ifdef BENCH_MT
+    if (numEncoderThreads > 1)
+    {
+      #ifdef USE_ALLOCA
+      encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
+      #endif
+      RINOK(encoder.CreateEncoderThread())
+    }
+    else
+    #endif
+    {
+      RINOK(encoder.Encode());
+    }
+  }
+  #ifdef BENCH_MT
+  if (numEncoderThreads > 1)
+    for (i = 0; i < numEncoderThreads; i++)
+      encoders[i].thread[0].Wait();
+  #endif
+
+  RINOK(status.Res);
+
+  CBenchInfo info;
+
+  SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+  info.UnpackSize = 0;
+  info.PackSize = 0;
+  info.NumIterations = 1; // progressInfoSpec->NumIterations;
+  for (i = 0; i < numEncoderThreads; i++)
+  {
+    CEncoderInfo &encoder = encoders[i];
+    info.UnpackSize += encoder.kBufferSize;
+    info.PackSize += encoder.compressedSize;
+  }
+  RINOK(callback->SetEncodeResult(info, true));
+
+
+  status.Res = S_OK;
+  status.EncodeMode = false;
+
+  UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
+  for (i = 0; i < numEncoderThreads; i++)
+  {
+    CEncoderInfo &encoder = encoders[i];
+    encoder.NumIterations = 2 + kUncompressMinBlockSize / encoder.kBufferSize;
+
+    if (i == 0)
+    {
+      encoder.progressInfoSpec[0]->callback = callback;
+      encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numDecoderThreads;
+      SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+    }
+
+    #ifdef BENCH_MT
+    if (numDecoderThreads > 1)
+    {
+      for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+      {
+        size_t allocaSize = ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF;
+        HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
+            #ifdef USE_ALLOCA
+            , allocaSize
+            #endif
+            );
+        RINOK(res);
+      }
+    }
+    else
+    #endif
+    {
+      RINOK(encoder.Decode(0));
+    }
+  }
+  #ifdef BENCH_MT
+  HRESULT res = S_OK;
+  if (numDecoderThreads > 1)
+    for (i = 0; i < numEncoderThreads; i++)
+      for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+      {
+        CEncoderInfo &encoder = encoders[i];
+        encoder.thread[j].Wait();
+        if (encoder.Results[j] != S_OK)
+          res = encoder.Results[j];
+      }
+  RINOK(res);
+  #endif
+  RINOK(status.Res);
+  SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+  info.UnpackSize = 0;
+  info.PackSize = 0;
+  info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
+  for (i = 0; i < numEncoderThreads; i++)
+  {
+    CEncoderInfo &encoder = encoders[i];
+    info.UnpackSize += encoder.kBufferSize;
+    info.PackSize += encoder.compressedSize;
+  }
+  RINOK(callback->SetDecodeResult(info, false));
+  RINOK(callback->SetDecodeResult(info, true));
+  return S_OK;
+}
+
+
+inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
+{ 
+  UInt32 hs = dictionary - 1;
+  hs |= (hs >> 1);
+  hs |= (hs >> 2);
+  hs |= (hs >> 4);
+  hs |= (hs >> 8);
+  hs >>= 1;
+  hs |= 0xFFFF;
+  if (hs > (1 << 24))
+    hs >>= 1;
+  hs++;
+  return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 + 
+      (1 << 20) + (multiThread ? (6 << 20) : 0);
+}
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary)
+{
+  const UInt32 kBufferSize = dictionary;
+  const UInt32 kCompressedBufferSize = (kBufferSize / 2);
+  UInt32 numSubThreads = (numThreads > 1) ? 2 : 1;
+  UInt32 numBigThreads = numThreads / numSubThreads;
+  return (kBufferSize + kCompressedBufferSize +
+    GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads;
+}
+
+static bool CrcBig(const void *data, UInt32 size, UInt32 numCycles, UInt32 crcBase)
+{
+  for (UInt32 i = 0; i < numCycles; i++)
+    if (CrcCalc(data, size) != crcBase)
+      return false;
+  return true;
+}
+
+#ifdef BENCH_MT
+struct CCrcInfo
+{
+  NWindows::CThread Thread;
+  const Byte *Data;
+  UInt32 Size;
+  UInt32 NumCycles;
+  UInt32 Crc;
+  bool Res;
+  void Wait()
+  {
+    Thread.Wait();
+    Thread.Close();
+  }
+};
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param)
+{
+  CCrcInfo *p = (CCrcInfo *)param;
+  p->Res = CrcBig(p->Data, p->Size, p->NumCycles, p->Crc);
+  return 0;
+}
+
+struct CCrcThreads
+{
+  UInt32 NumThreads;
+  CCrcInfo *Items;
+  CCrcThreads(): Items(0), NumThreads(0) {}
+  void WaitAll()
+  {
+    for (UInt32 i = 0; i < NumThreads; i++)
+      Items[i].Wait();
+    NumThreads = 0;
+  }
+  ~CCrcThreads() 
+  { 
+    WaitAll();
+    delete []Items; 
+  }
+};
+#endif
+
+static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
+{
+  UInt32 crc = CRC_INIT_VAL;;
+  for (UInt32 i = 0; i < size; i++)
+    crc = CRC_UPDATE_BYTE(crc, buf[i]);
+  return CRC_GET_DIGEST(crc);
+}
+
+static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+  for (UInt32 i = 0; i < size; i++)
+    buf[i] = (Byte)RG.GetRnd();
+}
+
+static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+  RandGen(buf, size, RG);
+  return CrcCalc1(buf, size);
+}
+
+bool CrcInternalTest()
+{
+  CBenchBuffer buffer;
+  const UInt32 kBufferSize0 = (1 << 8);
+  const UInt32 kBufferSize1 = (1 << 10);
+  const UInt32 kCheckSize = (1 << 5);
+  if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
+    return false;
+  Byte *buf = buffer.Buffer;
+  UInt32 i;
+  for (i = 0; i < kBufferSize0; i++)
+    buf[i] = (Byte)i;
+  UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
+  if (crc1 != 0x29058C73)
+    return false;
+  CBaseRandomGenerator RG;
+  RandGen(buf + kBufferSize0, kBufferSize1, RG);
+  for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
+    for (UInt32 j = 0; j < kCheckSize; j++)
+      if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+        return false;
+  return true;
+}
+
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed)
+{
+  if (numThreads == 0)
+    numThreads = 1;
+
+  CBenchBuffer buffer;
+  size_t totalSize = (size_t)bufferSize * numThreads;
+  if (totalSize / numThreads != bufferSize)
+    return E_OUTOFMEMORY;
+  if (!buffer.Alloc(totalSize))
+    return E_OUTOFMEMORY;
+
+  Byte *buf = buffer.Buffer;
+  CBaseRandomGenerator RG;
+  UInt32 numCycles = ((UInt32)1 << 30) / ((bufferSize >> 2) + 1) + 1;
+
+  UInt64 timeVal;
+  #ifdef BENCH_MT
+  CCrcThreads threads;
+  if (numThreads > 1)
+  {
+    threads.Items = new CCrcInfo[numThreads];
+    UInt32 i;
+    for (i = 0; i < numThreads; i++)
+    {
+      CCrcInfo &info = threads.Items[i];
+      Byte *data = buf + (size_t)bufferSize * i;
+      info.Data = data;
+      info.NumCycles = numCycles;
+      info.Size = bufferSize;
+      info.Crc = RandGenCrc(data, bufferSize, RG);
+    }
+    timeVal = GetTimeCount();
+    for (i = 0; i < numThreads; i++)
+    {
+      CCrcInfo &info = threads.Items[i];
+      RINOK(info.Thread.Create(CrcThreadFunction, &info));
+      threads.NumThreads++;
+    }
+    threads.WaitAll();
+    for (i = 0; i < numThreads; i++)
+      if (!threads.Items[i].Res)
+        return S_FALSE;
+  }
+  else
+  #endif
+  {
+    UInt32 crc = RandGenCrc(buf, bufferSize, RG);
+    timeVal = GetTimeCount();
+    if (!CrcBig(buf, bufferSize, numCycles, crc))
+      return S_FALSE;
+  }
+  timeVal = GetTimeCount() - timeVal;
+  if (timeVal == 0)
+    timeVal = 1;
+
+  UInt64 size = (UInt64)numCycles * totalSize;
+  speed = MyMultDiv64(size, timeVal, GetFreq());
+  return S_OK;
+}
+
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h
new file mode 100644 (file)
index 0000000..d57e797
--- /dev/null
@@ -0,0 +1,48 @@
+// LzmaBench.h
+
+#ifndef __LZMABENCH_H
+#define __LZMABENCH_H
+
+#include <stdio.h>
+#include "../../../Common/Types.h"
+#ifdef EXTERNAL_LZMA
+#include "../../UI/Common/LoadCodecs.h"
+#endif
+
+struct CBenchInfo
+{
+  UInt64 GlobalTime;
+  UInt64 GlobalFreq; 
+  UInt64 UserTime; 
+  UInt64 UserFreq;
+  UInt64 UnpackSize;
+  UInt64 PackSize;
+  UInt32 NumIterations;
+  CBenchInfo(): NumIterations(0) {}
+};
+
+struct IBenchCallback
+{
+  virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
+  virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
+};
+
+UInt64 GetUsage(const CBenchInfo &benchOnfo);
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating);
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations);
+
+HRESULT LzmaBench(
+  #ifdef EXTERNAL_LZMA
+  CCodecs *codecs,
+  #endif
+  UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback);
+
+const int kBenchMinDicLogSize = 18;
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary);
+
+bool CrcInternalTest();
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed);
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp
new file mode 100644 (file)
index 0000000..e55b4bc
--- /dev/null
@@ -0,0 +1,311 @@
+// LzmaBenchCon.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "LzmaBench.h"
+#include "LzmaBenchCon.h"
+#include "../../../Common/IntToString.h"
+
+#if defined(BENCH_MT) || defined(_WIN32)
+#include "../../../Windows/System.h"
+#endif
+
+#ifdef BREAK_HANDLER
+#include "../../UI/Console/ConsoleClose.h"
+#endif
+#include "../../../Common/MyCom.h"
+
+struct CTotalBenchRes
+{
+  UInt64 NumIterations;
+  UInt64 Rating;
+  UInt64 Usage;
+  UInt64 RPU;
+  void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
+  void Normalize() 
+  { 
+    if (NumIterations == 0) 
+      return;
+    Rating /= NumIterations; 
+    Usage /= NumIterations; 
+    RPU /= NumIterations; 
+    NumIterations = 1;
+  }
+  void SetMid(const CTotalBenchRes &r1, const CTotalBenchRes &r2) 
+  { 
+    Rating = (r1.Rating + r2.Rating) / 2; 
+    Usage = (r1.Usage + r2.Usage) / 2;
+    RPU = (r1.RPU + r2.RPU) / 2;
+    NumIterations = (r1.NumIterations + r2.NumIterations) / 2;
+  }
+};
+
+struct CBenchCallback: public IBenchCallback
+{
+  CTotalBenchRes EncodeRes;
+  CTotalBenchRes DecodeRes;
+  FILE *f;
+  void Init() { EncodeRes.Init(); DecodeRes.Init(); }
+  void Normalize() { EncodeRes.Normalize(); DecodeRes.Normalize(); }
+  UInt32 dictionarySize;
+  HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
+  HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
+};
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+  while (v1 > 1000000)
+  {
+    v1 >>= 1;
+    v2 >>= 1;
+  }
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+  UInt64 elTime = elapsedTime;
+  NormalizeVals(freq, elTime);
+  if (elTime == 0)
+    elTime = 1;
+  return value * freq / elTime;
+}
+
+static void PrintNumber(FILE *f, UInt64 value, int size)
+{
+  char s[32];
+  ConvertUInt64ToString(value, s);
+  fprintf(f, " ");
+  for (int len = (int)strlen(s); len < size; len++)
+    fprintf(f, " ");
+  fprintf(f, "%s", s);
+}
+
+static void PrintRating(FILE *f, UInt64 rating)
+{
+  PrintNumber(f, rating / 1000000, 6);
+}
+
+static void PrintResults(FILE *f, UInt64 usage, UInt64 rpu, UInt64 rating)
+{
+  PrintNumber(f, (usage + 5000) / 10000, 5);
+  PrintRating(f, rpu);
+  PrintRating(f, rating);
+}
+
+
+static void PrintResults(FILE *f, const CBenchInfo &info, UInt64 rating, CTotalBenchRes &res)
+{
+  UInt64 speed = MyMultDiv64(info.UnpackSize, info.GlobalTime, info.GlobalFreq);
+  PrintNumber(f, speed / 1024, 7);
+  UInt64 usage = GetUsage(info);
+  UInt64 rpu = GetRatingPerUsage(info, rating);
+  PrintResults(f, usage, rpu, rating);
+  res.NumIterations++;
+  res.RPU += rpu;
+  res.Rating += rating;
+  res.Usage += usage;
+}
+
+static void PrintTotals(FILE *f, const CTotalBenchRes &res)
+{
+  fprintf(f, "       ");
+  PrintResults(f, res.Usage, res.RPU, res.Rating);
+}
+
+
+HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
+{
+  #ifdef BREAK_HANDLER
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  #endif
+
+  if (final)
+  {
+    UInt64 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, info.UnpackSize);
+    PrintResults(f, info, rating, EncodeRes);
+  }
+  return S_OK;
+}
+
+static const char *kSep = "  | ";
+
+
+HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
+{
+  #ifdef BREAK_HANDLER
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  #endif
+  if (final)
+  {
+    UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
+    fprintf(f, kSep);
+    CBenchInfo info2 = info;
+    info2.UnpackSize *= info2.NumIterations;
+    info2.PackSize *= info2.NumIterations;
+    info2.NumIterations = 1;
+    PrintResults(f, info2, rating, DecodeRes);
+  }
+  return S_OK;
+}
+
+static void PrintRequirements(FILE *f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
+{
+  fprintf(f, "\nRAM %s ", sizeString);
+  PrintNumber(f, (size >> 20), 5);
+  fprintf(f, " MB,  # %s %3d", threadsString, (unsigned int)numThreads);
+}
+
+HRESULT LzmaBenchCon(
+  #ifdef EXTERNAL_LZMA
+  CCodecs *codecs,
+  #endif
+  FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+  if (!CrcInternalTest())
+    return S_FALSE;
+  #ifdef BENCH_MT
+  UInt64 ramSize = NWindows::NSystem::GetRamSize();  // 
+  UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+  PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+  if (numThreads == (UInt32)-1)
+    numThreads = numCPUs;
+  if (numThreads > 1)
+    numThreads &= ~1;
+  if (dictionary == (UInt32)-1)
+  {
+    int dicSizeLog;
+    for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+      if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
+        break;
+    dictionary = (1 << dicSizeLog);
+  }
+  #else
+  if (dictionary == (UInt32)-1)
+    dictionary = (1 << 22);
+  numThreads = 1;
+  #endif
+
+  PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dictionary), "Benchmark threads:   ", numThreads);
+
+  CBenchCallback callback;
+  callback.Init();
+  callback.f = f;
+  
+  fprintf(f, "\n\nDict        Compressing          |        Decompressing\n   ");
+  int j;
+  for (j = 0; j < 2; j++)
+  {
+    fprintf(f, "   Speed Usage    R/U Rating");
+    if (j == 0)
+      fprintf(f, kSep);
+  }
+  fprintf(f, "\n   ");
+  for (j = 0; j < 2; j++)
+  {
+    fprintf(f, "    KB/s     %%   MIPS   MIPS");
+    if (j == 0)
+      fprintf(f, kSep);
+  }
+  fprintf(f, "\n\n");
+  for (UInt32 i = 0; i < numIterations; i++)
+  {
+    const int kStartDicLog = 22;
+    int pow = (dictionary < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
+    while (((UInt32)1 << pow) > dictionary)
+      pow--;
+    for (; ((UInt32)1 << pow) <= dictionary; pow++)
+    {
+      fprintf(f, "%2d:", pow);
+      callback.dictionarySize = (UInt32)1 << pow;
+      HRESULT res = LzmaBench(
+        #ifdef EXTERNAL_LZMA
+        codecs,
+        #endif
+        numThreads, callback.dictionarySize, &callback);
+      fprintf(f, "\n");
+      RINOK(res);
+    }
+  }
+  callback.Normalize();
+  fprintf(f, "----------------------------------------------------------------\nAvr:");
+  PrintTotals(f, callback.EncodeRes);
+  fprintf(f, "     ");
+  PrintTotals(f, callback.DecodeRes);
+  fprintf(f, "\nTot:");
+  CTotalBenchRes midRes;
+  midRes.SetMid(callback.EncodeRes, callback.DecodeRes);
+  PrintTotals(f, midRes);
+  fprintf(f, "\n");
+  return S_OK;
+}
+
+struct CTempValues
+{
+  UInt64 *Values;
+  CTempValues(UInt32 num) { Values = new UInt64[num]; }
+  ~CTempValues() { delete []Values; }
+};
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+  if (!CrcInternalTest())
+    return S_FALSE;
+
+  #ifdef BENCH_MT
+  UInt64 ramSize = NWindows::NSystem::GetRamSize();
+  UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+  PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+  if (numThreads == (UInt32)-1)
+    numThreads = numCPUs;
+  #else
+  numThreads = 1;
+  #endif
+  if (dictionary == (UInt32)-1)
+    dictionary = (1 << 24);
+
+  CTempValues speedTotals(numThreads);
+  fprintf(f, "\n\nSize");
+  for (UInt32 ti = 0; ti < numThreads; ti++)
+  {
+    fprintf(f, " %5d", ti + 1);
+    speedTotals.Values[ti] = 0;
+  }
+  fprintf(f, "\n\n");
+
+  UInt64 numSteps = 0;
+  for (UInt32 i = 0; i < numIterations; i++)
+  {
+    for (int pow = 10; pow < 32; pow++)
+    {
+      UInt32 bufSize = (UInt32)1 << pow;
+      if (bufSize > dictionary)
+        break;
+      fprintf(f, "%2d: ", pow);
+      UInt64 speed;
+      for (UInt32 ti = 0; ti < numThreads; ti++)
+      {
+        #ifdef BREAK_HANDLER
+        if (NConsoleClose::TestBreakSignal())
+          return E_ABORT;
+        #endif
+        RINOK(CrcBench(ti + 1, bufSize, speed));
+        PrintNumber(f, (speed >> 20), 5);
+        speedTotals.Values[ti] += speed;
+      }
+      fprintf(f, "\n");
+      numSteps++;
+    }
+  }
+  if (numSteps != 0)
+  {
+    fprintf(f, "\nAvg:");
+    for (UInt32 ti = 0; ti < numThreads; ti++)
+      PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), 5);
+    fprintf(f, "\n");
+  }
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h
new file mode 100644 (file)
index 0000000..ea8539d
--- /dev/null
@@ -0,0 +1,20 @@
+// LzmaBenchCon.h
+
+#ifndef __LZMABENCHCON_H
+#define __LZMABENCHCON_H
+
+#include <stdio.h>
+#include "../../../Common/Types.h"
+#ifdef EXTERNAL_LZMA
+#include "../../UI/Common/LoadCodecs.h"
+#endif
+HRESULT LzmaBenchCon(
+  #ifdef EXTERNAL_LZMA
+  CCodecs *codecs,
+  #endif
+  FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+#endif
+
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRam.cpp b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRam.cpp
new file mode 100644 (file)
index 0000000..b86d1ea
--- /dev/null
@@ -0,0 +1,226 @@
+// LzmaRam.cpp
+
+#include "StdAfx.h"
+#include "../../../Common/Types.h"
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+#include "LzmaRam.h"
+
+extern "C"
+{
+  #include "../../../../C/Compress/Branch/BranchX86.h"
+}
+
+class CInStreamRam: 
+  public ISequentialInStream,
+  public CMyUnknownImp
+{
+  const Byte *Data;
+  size_t Size;
+  size_t Pos;
+public:
+  MY_UNKNOWN_IMP
+  void Init(const Byte *data, size_t size)
+  {
+    Data = data;
+    Size = size;
+    Pos = 0;
+  }
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CInStreamRam::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  if (size > (Size - Pos))
+    size = (UInt32)(Size - Pos);
+  for (UInt32 i = 0; i < size; i++)
+    ((Byte *)data)[i] = Data[Pos + i];
+  Pos += size;
+  if(processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
+  
+class COutStreamRam: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  size_t Size;
+public:
+  Byte *Data;
+  size_t Pos;
+  bool Overflow;
+  void Init(Byte *data, size_t size)
+  {
+    Data = data;
+    Size = size;
+    Pos = 0;
+    Overflow = false;
+  }
+  void SetPos(size_t pos)
+  {
+    Overflow = false;
+    Pos = pos;
+  }
+  MY_UNKNOWN_IMP
+  HRESULT WriteByte(Byte b)
+  {
+    if (Pos >= Size)
+    {
+      Overflow = true;
+      return E_FAIL;
+    }
+    Data[Pos++] = b;
+    return S_OK;
+  }
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP COutStreamRam::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 i;
+  for (i = 0; i < size && Pos < Size; i++)
+    Data[Pos++] = ((const Byte *)data)[i];
+  if(processedSize != NULL)
+    *processedSize = i;
+  if (i != size)
+  {
+    Overflow = true;
+    return E_FAIL;
+  }
+  return S_OK;
+}
+  
+#define SZ_RAM_E_FAIL (1)
+#define SZ_RAM_E_OUTOFMEMORY (2)
+#define SZE_OUT_OVERFLOW (3)
+
+int LzmaRamEncode(
+    const Byte *inBuffer, size_t inSize, 
+    Byte *outBuffer, size_t outSize, size_t *outSizeProcessed, 
+    UInt32 dictionarySize, ESzFilterMode filterMode)
+{
+  #ifndef _NO_EXCEPTIONS
+  try { 
+  #endif
+
+  *outSizeProcessed = 0;
+  const size_t kIdSize = 1;
+  const size_t kLzmaPropsSize = 5;
+  const size_t kMinDestSize = kIdSize + kLzmaPropsSize + 8;
+  if (outSize < kMinDestSize)
+    return SZE_OUT_OVERFLOW;
+  NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
+  CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+  PROPID propIDs[] = 
+  { 
+    NCoderPropID::kAlgorithm,
+    NCoderPropID::kDictionarySize,  
+    NCoderPropID::kNumFastBytes,
+  };
+  const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+  PROPVARIANT properties[kNumProps];
+  properties[0].vt = VT_UI4;
+  properties[1].vt = VT_UI4;
+  properties[2].vt = VT_UI4;
+  properties[0].ulVal = (UInt32)2;
+  properties[1].ulVal = (UInt32)dictionarySize;
+  properties[2].ulVal = (UInt32)64;
+
+  if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
+    return 1;
+  
+  COutStreamRam *outStreamSpec = new COutStreamRam;
+  if (outStreamSpec == 0)
+    return SZ_RAM_E_OUTOFMEMORY;
+  CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+  CInStreamRam *inStreamSpec = new CInStreamRam;
+  if (inStreamSpec == 0)
+    return SZ_RAM_E_OUTOFMEMORY;
+  CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+
+  outStreamSpec->Init(outBuffer, outSize);
+  if (outStreamSpec->WriteByte(0) != S_OK)
+    return SZE_OUT_OVERFLOW;
+
+  if (encoderSpec->WriteCoderProperties(outStream) != S_OK)
+    return SZE_OUT_OVERFLOW;
+  if (outStreamSpec->Pos != kIdSize + kLzmaPropsSize)
+    return 1;
+  
+  int i;
+  for (i = 0; i < 8; i++)
+  {
+    UInt64 t = (UInt64)(inSize);
+    if (outStreamSpec->WriteByte((Byte)((t) >> (8 * i))) != S_OK)
+      return SZE_OUT_OVERFLOW;
+  }
+
+  Byte *filteredStream = 0;
+
+  bool useFilter = (filterMode != SZ_FILTER_NO);
+  if (useFilter)
+  {
+    if (inSize != 0)
+    {
+      filteredStream = (Byte *)MyAlloc(inSize);
+      if (filteredStream == 0)
+        return SZ_RAM_E_OUTOFMEMORY;
+      memmove(filteredStream, inBuffer, inSize);
+    }
+    UInt32 x86State;
+    x86_Convert_Init(x86State);
+    x86_Convert(filteredStream, (SizeT)inSize, 0, &x86State, 1);
+  }
+  
+  size_t minSize = 0;
+  int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
+  bool bestIsFiltered = false;
+  int mainResult = 0;
+  size_t startPos = outStreamSpec->Pos;
+  for (i = 0; i < numPasses; i++)
+  {
+    if (numPasses > 1 && i == numPasses - 1 && !bestIsFiltered)
+      break;
+    outStreamSpec->SetPos(startPos);
+    bool curModeIsFiltered = false;
+    if (useFilter && i == 0)
+      curModeIsFiltered = true;
+    if (numPasses > 1 && i == numPasses - 1)
+      curModeIsFiltered = true;
+
+    inStreamSpec->Init(curModeIsFiltered ? filteredStream : inBuffer, inSize);
+    
+    HRESULT lzmaResult = encoder->Code(inStream, outStream, 0, 0, 0);
+    
+    mainResult = 0;
+    if (lzmaResult == E_OUTOFMEMORY)
+    {
+      mainResult = SZ_RAM_E_OUTOFMEMORY;
+      break;
+    } 
+    if (i == 0 || outStreamSpec->Pos <= minSize)
+    {
+      minSize = outStreamSpec->Pos;
+      bestIsFiltered = curModeIsFiltered;
+    }
+    if (outStreamSpec->Overflow)
+      mainResult = SZE_OUT_OVERFLOW;
+    else if (lzmaResult != S_OK)
+    {
+      mainResult = SZ_RAM_E_FAIL;
+      break;
+    } 
+  }
+  *outSizeProcessed = outStreamSpec->Pos;
+  if (bestIsFiltered)
+    outBuffer[0] = 1;
+  if (useFilter)
+    MyFree(filteredStream);
+  return mainResult;
+  
+  #ifndef _NO_EXCEPTIONS
+  } catch(...) { return SZ_RAM_E_OUTOFMEMORY; }
+  #endif
+}
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRam.h b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRam.h
new file mode 100644 (file)
index 0000000..1244dc8
--- /dev/null
@@ -0,0 +1,46 @@
+// LzmaRam.h
+
+#ifndef __LzmaRam_h
+#define __LzmaRam_h
+
+#include <stdlib.h>
+#include "../../../Common/Types.h"
+
+/*
+LzmaRamEncode: BCJ + LZMA RAM->RAM compressing.
+It uses .lzma format, but it writes one additional byte to .lzma file:
+  0: - no filter
+  1: - x86(BCJ) filter.
+
+To provide best compression ratio dictionarySize mustbe >= inSize
+
+LzmaRamEncode allocates Data with MyAlloc/BigAlloc functions.
+RAM Requirements:
+  RamSize = dictionarySize * 9.5 + 6MB + FilterBlockSize 
+    FilterBlockSize = 0, if useFilter == false
+    FilterBlockSize = inSize, if useFilter == true
+
+  Return code:
+    0 - OK
+    1 - Unspecified Error
+    2 - Memory allocating error
+    3 - Output buffer OVERFLOW
+
+If you use SZ_FILTER_AUTO mode, then encoder will use 2 or 3 passes:
+  2 passes when FILTER_NO provides better compression.
+  3 passes when FILTER_YES provides better compression.
+*/
+
+enum ESzFilterMode 
+{
+  SZ_FILTER_NO,
+  SZ_FILTER_YES,
+  SZ_FILTER_AUTO
+};
+
+int LzmaRamEncode(
+    const Byte *inBuffer, size_t inSize, 
+    Byte *outBuffer, size_t outSize, size_t *outSizeProcessed, 
+    UInt32 dictionarySize, ESzFilterMode filterMode);
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRamDecode.c b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRamDecode.c
new file mode 100644 (file)
index 0000000..29f798b
--- /dev/null
@@ -0,0 +1,78 @@
+/* LzmaRamDecode.c */
+
+#include "LzmaRamDecode.h"
+#ifdef _SZ_ONE_DIRECTORY
+#include "LzmaDecode.h"
+#include "BranchX86.h"
+#else
+#include "../../../../C/Compress/Lzma/LzmaDecode.h"
+#include "../../../../C/Compress/Branch/BranchX86.h"
+#endif
+
+#define LZMA_PROPS_SIZE 14
+#define LZMA_SIZE_OFFSET 6
+
+int LzmaRamGetUncompressedSize(
+    const unsigned char *inBuffer, 
+    size_t inSize, 
+    size_t *outSize)
+{
+  unsigned int i;
+  if (inSize < LZMA_PROPS_SIZE)
+    return 1;
+  *outSize = 0;
+  for(i = 0; i < sizeof(size_t); i++)
+    *outSize += ((size_t)inBuffer[LZMA_SIZE_OFFSET + i]) << (8 * i);
+  for(; i < 8; i++)
+    if (inBuffer[LZMA_SIZE_OFFSET + i] != 0)
+      return 1;
+  return 0;
+}
+
+#define SZE_DATA_ERROR (1)
+#define SZE_OUTOFMEMORY (2)
+
+int LzmaRamDecompress(
+    const unsigned char *inBuffer, 
+    size_t inSize,
+    unsigned char *outBuffer,
+    size_t outSize,
+    size_t *outSizeProcessed,
+    void * (*allocFunc)(size_t size), 
+    void (*freeFunc)(void *))
+{
+  CLzmaDecoderState state;  /* it's about 24 bytes structure, if int is 32-bit */
+  int result;
+  SizeT outSizeProcessedLoc;
+  SizeT inProcessed;
+  int useFilter;
+  
+  if (inSize < LZMA_PROPS_SIZE)
+    return 1;
+  useFilter = inBuffer[0];
+
+  *outSizeProcessed = 0;
+  if (useFilter > 1)
+    return 1;
+
+  if (LzmaDecodeProperties(&state.Properties, inBuffer + 1, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+    return 1;
+  state.Probs = (CProb *)allocFunc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+  if (state.Probs == 0)
+    return SZE_OUTOFMEMORY;
+  
+  result = LzmaDecode(&state,
+    inBuffer + LZMA_PROPS_SIZE, (SizeT)inSize - LZMA_PROPS_SIZE, &inProcessed,
+    outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
+  freeFunc(state.Probs);
+  if (result != LZMA_RESULT_OK)
+    return 1;
+  *outSizeProcessed = (size_t)outSizeProcessedLoc;
+  if (useFilter == 1)
+  {
+    UInt32 x86State;
+    x86_Convert_Init(x86State);
+    x86_Convert(outBuffer, (SizeT)outSizeProcessedLoc, 0, &x86State, 0);
+  }
+  return 0;
+}
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRamDecode.h b/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaRamDecode.h
new file mode 100644 (file)
index 0000000..7e641c5
--- /dev/null
@@ -0,0 +1,55 @@
+/* LzmaRamDecode.h */
+
+#ifndef __LzmaRamDecode_h
+#define __LzmaRamDecode_h
+
+#include <stdlib.h>
+
+/*
+LzmaRamGetUncompressedSize:
+  In: 
+    inBuffer - input data
+    inSize   - input data size
+  Out: 
+    outSize  - uncompressed size
+  Return code:
+    0 - OK
+    1 - Error in headers
+*/
+
+int LzmaRamGetUncompressedSize(
+    const unsigned char *inBuffer, 
+    size_t inSize,
+    size_t *outSize);
+
+
+/*
+LzmaRamDecompress:
+  In: 
+    inBuffer  - input data
+    inSize    - input data size
+    outBuffer - output data
+    outSize   - output size
+    allocFunc - alloc function (can be malloc)
+    freeFunc  - free function (can be free)
+  Out: 
+    outSizeProcessed - processed size
+  Return code:
+    0 - OK
+    1 - Error in headers / data stream
+    2 - Memory allocating error
+
+Memory requirements depend from properties of LZMA stream.
+With default lzma settings it's about 16 KB.
+*/
+
+int LzmaRamDecompress(
+    const unsigned char *inBuffer, 
+    size_t inSize,
+    unsigned char *outBuffer,
+    size_t outSize,
+    size_t *outSizeProcessed,
+    void * (*allocFunc)(size_t size), 
+    void (*freeFunc)(void *));
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/StdAfx.cpp b/lzma/CPP/7zip/Compress/LZMA_Alone/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/StdAfx.h b/lzma/CPP/7zip/Compress/LZMA_Alone/StdAfx.h
new file mode 100644 (file)
index 0000000..e7fb698
--- /dev/null
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/makefile b/lzma/CPP/7zip/Compress/LZMA_Alone/makefile
new file mode 100644 (file)
index 0000000..16e7637
--- /dev/null
@@ -0,0 +1,136 @@
+PROG = lzma.exe
+CFLAGS = $(CFLAGS) \
+  -DCOMPRESS_MF_MT \
+  -DBENCH_MT \
+
+LIBS = $(LIBS) oleaut32.lib user32.lib
+
+!IFDEF CPU
+LIBS = $(LIBS) bufferoverflowU.lib 
+CFLAGS = $(CFLAGS) -GS- -Zc:forScope -W4 -Wp64 -DUNICODE -D_UNICODE
+!ENDIF
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+!IFDEF MY_STATIC_LINK
+!IFNDEF MY_SINGLE_THREAD
+CFLAGS = $(CFLAGS) -MT
+!ENDIF
+!ELSE
+CFLAGS = $(CFLAGS) -MD
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -EHsc -c -Fo$O/
+CFLAGS_O1 = $(CFLAGS) -O1
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1   = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2   = $(CPP) $(CFLAGS_O2) $**
+COMPL      = $(CPP) $(CFLAGS_O1) $**
+
+
+LZMA_OBJS = \
+  $O\LzmaAlone.obj \
+  $O\LzmaBench.obj \
+  $O\LzmaBenchCon.obj \
+  $O\LzmaRam.obj \
+
+LZMA_OPT_OBJS = \
+  $O\LZMADecoder.obj \
+  $O\LZMAEncoder.obj \
+
+COMMON_OBJS = \
+  $O\CommandLineParser.obj \
+  $O\CRC.obj \
+  $O\IntToString.obj \
+  $O\MyString.obj \
+  $O\StringConvert.obj \
+  $O\StringToInt.obj \
+  $O\MyVector.obj
+
+WIN_OBJS = \
+  $O\System.obj
+
+7ZIP_COMMON_OBJS = \
+  $O\InBuffer.obj \
+  $O\OutBuffer.obj \
+  $O\StreamUtils.obj \
+
+LZ_OBJS = \
+  $O\LZOutWindow.obj \
+
+C_OBJS = \
+  $O\Alloc.obj \
+  $O\7zCrc.obj \
+  $O\Threads.obj \
+
+C_LZ_OBJS = \
+  $O\MatchFinder.obj \
+  $O\MatchFinderMt.obj \
+
+OBJS = \
+  $(LZMA_OBJS) \
+  $(LZMA_OPT_OBJS) \
+  $(COMMON_OBJS) \
+  $(WIN_OBJS) \
+  $(7ZIP_COMMON_OBJS) \
+  $(LZ_OBJS) \
+  $(C_OBJS) \
+  $(C_LZ_OBJS) \
+  $O\LzmaRamDecode.obj \
+  $O\LzmaDecode.obj \
+  $O\FileStreams.obj \
+  $O\FileIO.obj \
+  $O\RangeCoderBit.obj \
+  $O\BranchX86.obj \
+
+all: $(PROGPATH) 
+
+clean:
+       -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch 
+
+$O:
+       if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS)
+       link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+
+$(LZMA_OBJS): $(*B).cpp
+       $(COMPL)
+$(LZMA_OPT_OBJS): ../LZMA/$(*B).cpp
+       $(COMPL_O2)
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+       $(COMPL)
+$(WIN_OBJS): ../../../Windows/$(*B).cpp
+       $(COMPL)
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+       $(COMPL)
+$(LZ_OBJS): ../LZ/$(*B).cpp
+       $(COMPL)
+$O\RangeCoderBit.obj: ../RangeCoder/$(*B).cpp
+       $(COMPL)
+$O\LzmaRamDecode.obj: LzmaRamDecode.c
+       $(COMPL_O1)
+$O\LzmaDecode.obj: ../../../../C/Compress/Lzma/LzmaDecode.c
+       $(COMPL_O2)
+$O\BranchX86.obj: ../../../../C/Compress/Branch/BranchX86.c
+       $(COMPL_O2)
+$O\FileStreams.obj: ../../Common/FileStreams.cpp
+       $(COMPL)
+$O\FileIO.obj: ../../../Windows/FileIO.cpp
+       $(COMPL)
+$(C_OBJS): ../../../../C/$(*B).c
+       $(COMPL_O2)
+$(C_LZ_OBJS): ../../../../C/Compress/Lz/$(*B).c
+       $(COMPL_O2)
diff --git a/lzma/CPP/7zip/Compress/LZMA_Alone/makefile.gcc b/lzma/CPP/7zip/Compress/LZMA_Alone/makefile.gcc
new file mode 100644 (file)
index 0000000..4fed05e
--- /dev/null
@@ -0,0 +1,139 @@
+PROG = lzma
+CXX = g++ -O2 -Wall
+CXX_C = gcc -O2 -Wall
+LIB = -lm
+RM = rm -f
+CFLAGS = -c
+
+ifdef SystemDrive
+IS_MINGW = 1
+endif
+
+ifdef IS_MINGW
+FILE_IO =FileIO
+FILE_IO_2 =Windows/$(FILE_IO)
+LIB2 = -luuid 
+else
+FILE_IO =C_FileIO
+FILE_IO_2 =Common/$(FILE_IO)
+endif
+
+OBJS = \
+  LzmaAlone.o \
+  LzmaBench.o \
+  LzmaBenchCon.o \
+  LzmaRam.o \
+  LZMADecoder.o \
+  LZMAEncoder.o \
+  LZOutWindow.o \
+  RangeCoderBit.o \
+  InBuffer.o \
+  OutBuffer.o \
+  FileStreams.o \
+  StreamUtils.o \
+  $(FILE_IO).o \
+  CommandLineParser.o \
+  CRC.o \
+  IntToString.o \
+  MyString.o \
+  StringConvert.o \
+  StringToInt.o \
+  MyVector.o \
+  7zCrc.o \
+  Alloc.o \
+  BranchX86.o \
+  MatchFinder.o \
+  LzmaDecode.o \
+  LzmaRamDecode.o \
+
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+       $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2)
+
+LzmaAlone.o: LzmaAlone.cpp
+       $(CXX) $(CFLAGS) LzmaAlone.cpp
+
+LzmaBench.o: LzmaBench.cpp
+       $(CXX) $(CFLAGS) LzmaBench.cpp
+
+LzmaBenchCon.o: LzmaBenchCon.cpp
+       $(CXX) $(CFLAGS) LzmaBenchCon.cpp
+
+LzmaRam.o: LzmaRam.cpp
+       $(CXX) $(CFLAGS) LzmaRam.cpp
+
+LZMADecoder.o: ../LZMA/LZMADecoder.cpp
+       $(CXX) $(CFLAGS) ../LZMA/LZMADecoder.cpp
+
+LZMAEncoder.o: ../LZMA/LZMAEncoder.cpp
+       $(CXX) $(CFLAGS) ../LZMA/LZMAEncoder.cpp
+
+LZOutWindow.o: ../LZ/LZOutWindow.cpp
+       $(CXX) $(CFLAGS) ../LZ/LZOutWindow.cpp
+
+RangeCoderBit.o: ../RangeCoder/RangeCoderBit.cpp
+       $(CXX) $(CFLAGS) ../RangeCoder/RangeCoderBit.cpp
+
+InBuffer.o: ../../Common/InBuffer.cpp
+       $(CXX) $(CFLAGS) ../../Common/InBuffer.cpp
+
+OutBuffer.o: ../../Common/OutBuffer.cpp
+       $(CXX) $(CFLAGS) ../../Common/OutBuffer.cpp
+
+FileStreams.o: ../../Common/FileStreams.cpp
+       $(CXX) $(CFLAGS) ../../Common/FileStreams.cpp
+
+StreamUtils.o: ../../Common/StreamUtils.cpp
+       $(CXX) $(CFLAGS) ../../Common/StreamUtils.cpp
+
+$(FILE_IO).o: ../../../$(FILE_IO_2).cpp
+       $(CXX) $(CFLAGS) ../../../$(FILE_IO_2).cpp
+
+
+CommandLineParser.o: ../../../Common/CommandLineParser.cpp
+       $(CXX) $(CFLAGS) ../../../Common/CommandLineParser.cpp
+
+CRC.o: ../../../Common/CRC.cpp
+       $(CXX) $(CFLAGS) ../../../Common/CRC.cpp
+
+MyWindows.o: ../../../Common/MyWindows.cpp
+       $(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp
+
+IntToString.o: ../../../Common/IntToString.cpp
+       $(CXX) $(CFLAGS) ../../../Common/IntToString.cpp
+
+MyString.o: ../../../Common/MyString.cpp
+       $(CXX) $(CFLAGS) ../../../Common/MyString.cpp
+
+StringConvert.o: ../../../Common/StringConvert.cpp
+       $(CXX) $(CFLAGS) ../../../Common/StringConvert.cpp
+
+StringToInt.o: ../../../Common/StringToInt.cpp
+       $(CXX) $(CFLAGS) ../../../Common/StringToInt.cpp
+
+MyVector.o: ../../../Common/MyVector.cpp
+       $(CXX) $(CFLAGS) ../../../Common/MyVector.cpp
+
+7zCrc.o: ../../../../C/7zCrc.c
+       $(CXX_C) $(CFLAGS) ../../../../C/7zCrc.c
+
+Alloc.o: ../../../../C/Alloc.c
+       $(CXX_C) $(CFLAGS) ../../../../C/Alloc.c
+
+BranchX86.o: ../../../../C/Compress/Branch/BranchX86.c
+       $(CXX_C) $(CFLAGS) ../../../../C/Compress/Branch/BranchX86.c
+
+MatchFinder.o: ../../../../C/Compress/Lz/MatchFinder.c
+       $(CXX_C) $(CFLAGS) ../../../../C/Compress/Lz/MatchFinder.c
+
+LzmaDecode.o: ../../../../C/Compress/Lzma/LzmaDecode.c
+       $(CXX_C) $(CFLAGS) ../../../../C/Compress/Lzma/LzmaDecode.c
+
+LzmaRamDecode.o: LzmaRamDecode.c
+       $(CXX_C) $(CFLAGS) LzmaRamDecode.c
+
+clean:
+       -$(RM) $(PROG) $(OBJS)
+
diff --git a/lzma/CPP/7zip/Compress/RangeCoder/RangeCoder.h b/lzma/CPP/7zip/Compress/RangeCoder/RangeCoder.h
new file mode 100644 (file)
index 0000000..bbb2ba8
--- /dev/null
@@ -0,0 +1,205 @@
+// Compress/RangeCoder/RangeCoder.h
+
+#ifndef __COMPRESS_RANGECODER_H
+#define __COMPRESS_RANGECODER_H
+
+#include "../../Common/InBuffer.h"
+#include "../../Common/OutBuffer.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumTopBits = 24;
+const UInt32 kTopValue = (1 << kNumTopBits);
+
+class CEncoder
+{
+  UInt32 _cacheSize;
+  Byte _cache;
+public:
+  UInt64 Low;
+  UInt32 Range;
+  COutBuffer Stream;
+  bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+  void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); }
+  void Init()
+  {
+    Stream.Init();
+    Low = 0;
+    Range = 0xFFFFFFFF;
+    _cacheSize = 1;
+    _cache = 0;
+  }
+
+  void FlushData()
+  {
+    // Low += 1; 
+    for(int i = 0; i < 5; i++)
+      ShiftLow();
+  }
+
+  HRESULT FlushStream() { return Stream.Flush();  }
+
+  void ReleaseStream() { Stream.ReleaseStream(); }
+
+  void Encode(UInt32 start, UInt32 size, UInt32 total)
+  {
+    Low += start * (Range /= total);
+    Range *= size;
+    while (Range < kTopValue)
+    {
+      Range <<= 8;
+      ShiftLow();
+    }
+  }
+
+  void ShiftLow()
+  {
+    if ((UInt32)Low < (UInt32)0xFF000000 || (int)(Low >> 32) != 0) 
+    {
+      Byte temp = _cache;
+      do
+      {
+        Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32)));
+        temp = 0xFF;
+      }
+      while(--_cacheSize != 0);
+      _cache = (Byte)((UInt32)Low >> 24);                      
+    } 
+    _cacheSize++;                               
+    Low = (UInt32)Low << 8;                           
+  }
+  
+  void EncodeDirectBits(UInt32 value, int numTotalBits)
+  {
+    for (int i = numTotalBits - 1; i >= 0; i--)
+    {
+      Range >>= 1;
+      if (((value >> i) & 1) == 1)
+        Low += Range;
+      if (Range < kTopValue)
+      {
+        Range <<= 8;
+        ShiftLow();
+      }
+    }
+  }
+
+  void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol)
+  {
+    UInt32 newBound = (Range >> numTotalBits) * size0;
+    if (symbol == 0)
+      Range = newBound;
+    else
+    {
+      Low += newBound;
+      Range -= newBound;
+    }
+    while (Range < kTopValue)
+    {
+      Range <<= 8;
+      ShiftLow();
+    }
+  }
+
+  UInt64 GetProcessedSize() {  return Stream.GetProcessedSize() + _cacheSize + 4; }
+};
+
+class CDecoder
+{
+public:
+  CInBuffer Stream;
+  UInt32 Range;
+  UInt32 Code;
+  bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+  void Normalize()
+  {
+    while (Range < kTopValue)
+    {
+      Code = (Code << 8) | Stream.ReadByte();
+      Range <<= 8;
+    }
+  }
+  
+  void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+  void Init()
+  {
+    Stream.Init();
+    Code = 0;
+    Range = 0xFFFFFFFF;
+    for(int i = 0; i < 5; i++)
+      Code = (Code << 8) | Stream.ReadByte();
+  }
+
+  void ReleaseStream() { Stream.ReleaseStream(); }
+
+  UInt32 GetThreshold(UInt32 total)
+  {
+    return (Code) / ( Range /= total);
+  }
+
+  void Decode(UInt32 start, UInt32 size)
+  {
+    Code -= start * Range;
+    Range *= size;
+    Normalize();
+  }
+
+  UInt32 DecodeDirectBits(int numTotalBits)
+  {
+    UInt32 range = Range;
+    UInt32 code = Code;        
+    UInt32 result = 0;
+    for (int i = numTotalBits; i != 0; i--)
+    {
+      range >>= 1;
+      /*
+      result <<= 1;
+      if (code >= range)
+      {
+        code -= range;
+        result |= 1;
+      }
+      */
+      UInt32 t = (code - range) >> 31;
+      code -= range & (t - 1);
+      result = (result << 1) | (1 - t);
+
+      if (range < kTopValue)
+      {
+        code = (code << 8) | Stream.ReadByte();
+        range <<= 8; 
+      }
+    }
+    Range = range;
+    Code = code;
+    return result;
+  }
+
+  UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
+  {
+    UInt32 newBound = (Range >> numTotalBits) * size0;
+    UInt32 symbol;
+    if (Code < newBound)
+    {
+      symbol = 0;
+      Range = newBound;
+    }
+    else
+    {
+      symbol = 1;
+      Code -= newBound;
+      Range -= newBound;
+    }
+    Normalize();
+    return symbol;
+  }
+
+  UInt64 GetProcessedSize() {return Stream.GetProcessedSize(); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBit.cpp b/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBit.cpp
new file mode 100644 (file)
index 0000000..8e4c4d3
--- /dev/null
@@ -0,0 +1,80 @@
+// Compress/RangeCoder/RangeCoderBit.cpp
+
+#include "StdAfx.h"
+
+#include "RangeCoderBit.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+UInt32 CPriceTables::ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+static CPriceTables g_PriceTables;
+
+CPriceTables::CPriceTables() { Init(); }
+
+void CPriceTables::Init()
+{
+  const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
+  for(int i = kNumBits - 1; i >= 0; i--)
+  {
+    UInt32 start = 1 << (kNumBits - i - 1);
+    UInt32 end = 1 << (kNumBits - i);
+    for (UInt32 j = start; j < end; j++)
+      ProbPrices[j] = (i << kNumBitPriceShiftBits) + 
+          (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
+  }
+
+  /*
+  // simplest: bad solution
+  for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++)
+    ProbPrices[i] = kBitPrice;
+  */
+  
+  /*
+  const double kDummyMultMid = (1.0 / kBitPrice) / 2;
+  const double kDummyMultMid = 0;
+  // float solution
+  double ln2 = log(double(2));
+  double lnAll = log(double(kBitModelTotal >> kNumMoveReducingBits));
+  for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++)
+    ProbPrices[i] = UInt32((fabs(lnAll - log(double(i))) / ln2 + kDummyMultMid) * kBitPrice);
+  */
+  
+  /*
+  // experimental, slow, solution:
+  for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++)
+  {
+    const int kCyclesBits = 5;
+    const UInt32 kCycles = (1 << kCyclesBits);
+
+    UInt32 range = UInt32(-1);
+    UInt32 bitCount = 0;
+    for (UInt32 j = 0; j < kCycles; j++)
+    {
+      range >>= (kNumBitModelTotalBits - kNumMoveReducingBits);
+      range *= i;
+      while(range < (1 << 31))
+      {
+        range <<= 1;
+        bitCount++;
+      }
+    }
+    bitCount <<= kNumBitPriceShiftBits;
+    range -= (1 << 31);
+    for (int k = kNumBitPriceShiftBits - 1; k >= 0; k--)
+    {
+      range <<= 1;
+      if (range > (1 << 31))
+      {
+        bitCount += (1 << k);
+        range -= (1 << 31);
+      }
+    }
+    ProbPrices[i] = (bitCount 
+      // + (1 << (kCyclesBits - 1))
+      ) >> kCyclesBits;
+  }
+  */
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBit.h b/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBit.h
new file mode 100644 (file)
index 0000000..624f887
--- /dev/null
@@ -0,0 +1,120 @@
+// Compress/RangeCoder/RangeCoderBit.h
+
+#ifndef __COMPRESS_RANGECODER_BIT_H
+#define __COMPRESS_RANGECODER_BIT_H
+
+#include "RangeCoder.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumBitModelTotalBits  = 11;
+const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
+
+const int kNumMoveReducingBits = 2;
+
+const int kNumBitPriceShiftBits = 6;
+const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
+
+class CPriceTables
+{
+public:
+  static UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+  static void Init();
+  CPriceTables();
+};
+
+template <int numMoveBits>
+class CBitModel
+{
+public:
+  UInt32 Prob;
+  void UpdateModel(UInt32 symbol)
+  {
+    /*
+    Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits;
+    Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits);
+    */
+    if (symbol == 0)
+      Prob += (kBitModelTotal - Prob) >> numMoveBits;
+    else
+      Prob -= (Prob) >> numMoveBits;
+  }
+public:
+  void Init() { Prob = kBitModelTotal / 2; }
+};
+
+template <int numMoveBits>
+class CBitEncoder: public CBitModel<numMoveBits>
+{
+public:
+  void Encode(CEncoder *encoder, UInt32 symbol)
+  {
+    /*
+    encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol);
+    this->UpdateModel(symbol);
+    */
+    UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob;
+    if (symbol == 0)
+    {
+      encoder->Range = newBound;
+      this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+    }
+    else
+    {
+      encoder->Low += newBound;
+      encoder->Range -= newBound;
+      this->Prob -= (this->Prob) >> numMoveBits;
+    }
+    if (encoder->Range < kTopValue)
+    {
+      encoder->Range <<= 8;
+      encoder->ShiftLow();
+    }
+  }
+  UInt32 GetPrice(UInt32 symbol) const
+  {
+    return CPriceTables::ProbPrices[
+      (((this->Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
+  }
+  UInt32 GetPrice0() const { return CPriceTables::ProbPrices[this->Prob >> kNumMoveReducingBits]; }
+  UInt32 GetPrice1() const { return CPriceTables::ProbPrices[(kBitModelTotal - this->Prob) >> kNumMoveReducingBits]; }
+};
+
+
+template <int numMoveBits>
+class CBitDecoder: public CBitModel<numMoveBits>
+{
+public:
+  UInt32 Decode(CDecoder *decoder)
+  {
+    UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob;
+    if (decoder->Code < newBound)
+    {
+      decoder->Range = newBound;
+      this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+      if (decoder->Range < kTopValue)
+      {
+        decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+        decoder->Range <<= 8;
+      }
+      return 0;
+    }
+    else
+    {
+      decoder->Range -= newBound;
+      decoder->Code -= newBound;
+      this->Prob -= (this->Prob) >> numMoveBits;
+      if (decoder->Range < kTopValue)
+      {
+        decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+        decoder->Range <<= 8;
+      }
+      return 1;
+    }
+  }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBitTree.h b/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderBitTree.h
new file mode 100644 (file)
index 0000000..4f0c78b
--- /dev/null
@@ -0,0 +1,161 @@
+// Compress/RangeCoder/RangeCoderBitTree.h
+
+#ifndef __COMPRESS_RANGECODER_BIT_TREE_H
+#define __COMPRESS_RANGECODER_BIT_TREE_H
+
+#include "RangeCoderBit.h"
+#include "RangeCoderOpt.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+template <int numMoveBits, int NumBitLevels>
+class CBitTreeEncoder
+{
+  CBitEncoder<numMoveBits> Models[1 << NumBitLevels];
+public:
+  void Init()
+  {
+    for(UInt32 i = 1; i < (1 << NumBitLevels); i++)
+      Models[i].Init();
+  }
+  void Encode(CEncoder *rangeEncoder, UInt32 symbol)
+  {
+    UInt32 modelIndex = 1;
+    for (int bitIndex = NumBitLevels; bitIndex != 0 ;)
+    {
+      bitIndex--;
+      UInt32 bit = (symbol >> bitIndex) & 1;
+      Models[modelIndex].Encode(rangeEncoder, bit);
+      modelIndex = (modelIndex << 1) | bit;
+    }
+  };
+  void ReverseEncode(CEncoder *rangeEncoder, UInt32 symbol)
+  {
+    UInt32 modelIndex = 1;
+    for (int i = 0; i < NumBitLevels; i++)
+    {
+      UInt32 bit = symbol & 1;
+      Models[modelIndex].Encode(rangeEncoder, bit);
+      modelIndex = (modelIndex << 1) | bit;
+      symbol >>= 1;
+    }
+  }
+  UInt32 GetPrice(UInt32 symbol) const
+  {
+    symbol |= (1 << NumBitLevels);
+    UInt32 price = 0;
+    while (symbol != 1)
+    {
+      price += Models[symbol >> 1].GetPrice(symbol & 1);
+      symbol >>= 1;
+    }
+    return price;
+  }
+  UInt32 ReverseGetPrice(UInt32 symbol) const
+  {
+    UInt32 price = 0;
+    UInt32 modelIndex = 1;
+    for (int i = NumBitLevels; i != 0; i--)
+    {
+      UInt32 bit = symbol & 1;
+      symbol >>= 1;
+      price += Models[modelIndex].GetPrice(bit);
+      modelIndex = (modelIndex << 1) | bit;
+    }
+    return price;
+  }
+};
+
+template <int numMoveBits, int NumBitLevels>
+class CBitTreeDecoder
+{
+  CBitDecoder<numMoveBits> Models[1 << NumBitLevels];
+public:
+  void Init()
+  {
+    for(UInt32 i = 1; i < (1 << NumBitLevels); i++)
+      Models[i].Init();
+  }
+  UInt32 Decode(CDecoder *rangeDecoder)
+  {
+    UInt32 modelIndex = 1;
+    RC_INIT_VAR
+    for(int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--)
+    {
+      // modelIndex = (modelIndex << 1) + Models[modelIndex].Decode(rangeDecoder);
+      RC_GETBIT(numMoveBits, Models[modelIndex].Prob, modelIndex)
+    }
+    RC_FLUSH_VAR
+    return modelIndex - (1 << NumBitLevels);
+  };
+  UInt32 ReverseDecode(CDecoder *rangeDecoder)
+  {
+    UInt32 modelIndex = 1;
+    UInt32 symbol = 0;
+    RC_INIT_VAR
+    for(int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+    {
+      // UInt32 bit = Models[modelIndex].Decode(rangeDecoder);
+      // modelIndex <<= 1;
+      // modelIndex += bit;
+      // symbol |= (bit << bitIndex);
+      RC_GETBIT2(numMoveBits, Models[modelIndex].Prob, modelIndex, ; , symbol |= (1 << bitIndex))
+    }
+    RC_FLUSH_VAR
+    return symbol;
+  }
+};
+
+template <int numMoveBits>
+void ReverseBitTreeEncode(CBitEncoder<numMoveBits> *Models, 
+    CEncoder *rangeEncoder, int NumBitLevels, UInt32 symbol)
+{
+  UInt32 modelIndex = 1;
+  for (int i = 0; i < NumBitLevels; i++)
+  {
+    UInt32 bit = symbol & 1;
+    Models[modelIndex].Encode(rangeEncoder, bit);
+    modelIndex = (modelIndex << 1) | bit;
+    symbol >>= 1;
+  }
+}
+
+template <int numMoveBits>
+UInt32 ReverseBitTreeGetPrice(CBitEncoder<numMoveBits> *Models, 
+    UInt32 NumBitLevels, UInt32 symbol)
+{
+  UInt32 price = 0;
+  UInt32 modelIndex = 1;
+  for (int i = NumBitLevels; i != 0; i--)
+  {
+    UInt32 bit = symbol & 1;
+    symbol >>= 1;
+    price += Models[modelIndex].GetPrice(bit);
+    modelIndex = (modelIndex << 1) | bit;
+  }
+  return price;
+}
+
+template <int numMoveBits>
+UInt32 ReverseBitTreeDecode(CBitDecoder<numMoveBits> *Models, 
+    CDecoder *rangeDecoder, int NumBitLevels)
+{
+  UInt32 modelIndex = 1;
+  UInt32 symbol = 0;
+  RC_INIT_VAR
+  for(int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+  {
+    // UInt32 bit = Models[modelIndex].Decode(rangeDecoder);
+    // modelIndex <<= 1;
+    // modelIndex += bit;
+    // symbol |= (bit << bitIndex);
+    RC_GETBIT2(numMoveBits, Models[modelIndex].Prob, modelIndex, ; , symbol |= (1 << bitIndex))
+  }
+  RC_FLUSH_VAR
+  return symbol;
+}
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderOpt.h b/lzma/CPP/7zip/Compress/RangeCoder/RangeCoderOpt.h
new file mode 100644 (file)
index 0000000..668b9a5
--- /dev/null
@@ -0,0 +1,31 @@
+// Compress/RangeCoder/RangeCoderOpt.h
+
+#ifndef __COMPRESS_RANGECODER_OPT_H
+#define __COMPRESS_RANGECODER_OPT_H
+
+#define RC_INIT_VAR \
+  UInt32 range = rangeDecoder->Range; \
+  UInt32 code = rangeDecoder->Code;        
+
+#define RC_FLUSH_VAR \
+  rangeDecoder->Range = range; \
+  rangeDecoder->Code = code;
+
+#define RC_NORMALIZE \
+  if (range < NCompress::NRangeCoder::kTopValue) \
+    { code = (code << 8) | rangeDecoder->Stream.ReadByte(); range <<= 8; }
+
+#define RC_GETBIT2(numMoveBits, prob, mi, A0, A1) \
+  { UInt32 bound = (range >> NCompress::NRangeCoder::kNumBitModelTotalBits) * prob; \
+  if (code < bound) \
+  { A0; range = bound; \
+    prob += (NCompress::NRangeCoder::kBitModelTotal - prob) >> numMoveBits; \
+    mi <<= 1; } \
+  else \
+  { A1; range -= bound; code -= bound; prob -= (prob) >> numMoveBits; \
+    mi = (mi + mi) + 1; }} \
+  RC_NORMALIZE
+
+#define RC_GETBIT(numMoveBits, prob, mi) RC_GETBIT2(numMoveBits, prob, mi, ; , ;)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/RangeCoder/StdAfx.h b/lzma/CPP/7zip/Compress/RangeCoder/StdAfx.h
new file mode 100644 (file)
index 0000000..b637fd4
--- /dev/null
@@ -0,0 +1,6 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#endif
diff --git a/lzma/CPP/7zip/ICoder.h b/lzma/CPP/7zip/ICoder.h
new file mode 100644 (file)
index 0000000..a497653
--- /dev/null
@@ -0,0 +1,185 @@
+// ICoder.h
+
+#ifndef __ICODER_H
+#define __ICODER_H
+
+#include "IStream.h"
+
+#define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x)
+
+CODER_INTERFACE(ICompressProgressInfo, 0x04)
+{
+  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder, 0x05)
+{
+  STDMETHOD(Code)(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, 
+      const UInt64 *inSize, 
+      const UInt64 *outSize,
+      ICompressProgressInfo *progress) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder2, 0x18)
+{
+  STDMETHOD(Code)(ISequentialInStream **inStreams,
+      const UInt64 **inSizes, 
+      UInt32 numInStreams,
+      ISequentialOutStream **outStreams, 
+      const UInt64 **outSizes,
+      UInt32 numOutStreams,
+      ICompressProgressInfo *progress) PURE;
+};
+
+namespace NCoderPropID
+{
+  enum EEnum
+  {
+    kDictionarySize = 0x400,
+    kUsedMemorySize,
+    kOrder,
+    kPosStateBits = 0x440,
+    kLitContextBits,
+    kLitPosBits,
+    kNumFastBytes = 0x450,
+    kMatchFinder,
+    kMatchFinderCycles,
+    kNumPasses = 0x460, 
+    kAlgorithm = 0x470,
+    kMultiThread = 0x480,
+    kNumThreads,
+    kEndMarker = 0x490
+  };
+}
+
+CODER_INTERFACE(ICompressSetCoderProperties, 0x20)
+{
+  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, 
+      const PROPVARIANT *properties, UInt32 numProperties) PURE;
+};
+
+/*
+CODER_INTERFACE(ICompressSetCoderProperties, 0x21)
+{
+  STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;
+};
+*/
+
+CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22)
+{
+  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressWriteCoderProperties, 0x23)
+{
+  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStreams) PURE;
+};
+
+CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24)
+{
+  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetCoderMt, 0x25)
+{
+  STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE;
+};
+
+CODER_INTERFACE(ICompressGetSubStreamSize, 0x30)
+{
+  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStream, 0x31)
+{
+  STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE;
+  STDMETHOD(ReleaseInStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStream, 0x32)
+{
+  STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE;
+  STDMETHOD(ReleaseOutStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStreamSize, 0x33)
+{
+  STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStreamSize, 0x34)
+{
+  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressFilter, 0x40)
+{
+  STDMETHOD(Init)() PURE;
+  STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE;
+  // Filter return outSize (UInt32)
+  // if (outSize <= size): Filter have converted outSize bytes
+  // if (outSize > size): Filter have not converted anything.
+  //      and it needs at least outSize bytes to convert one block 
+  //      (it's for crypto block algorithms).
+};
+
+CODER_INTERFACE(ICompressCodecsInfo, 0x60)
+{
+  STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods) PURE;
+  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;
+  STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE;
+  STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE;
+};
+CODER_INTERFACE(ISetCompressCodecsInfo, 0x61)
+{
+  STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE;
+};
+
+CODER_INTERFACE(ICryptoProperties, 0x80)
+{
+  STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE;
+  STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE;
+};
+
+/*
+CODER_INTERFACE(ICryptoResetSalt, 0x88)
+{
+  STDMETHOD(ResetSalt)() PURE;
+};
+*/
+
+CODER_INTERFACE(ICryptoResetInitVector, 0x8C)
+{
+  STDMETHOD(ResetInitVector)() PURE;
+};
+
+CODER_INTERFACE(ICryptoSetPassword, 0x90)
+{
+  STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICryptoSetCRC, 0xA0)
+{
+  STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;
+};
+
+//////////////////////
+// It's for DLL file
+namespace NMethodPropID
+{
+  enum EEnum
+  {
+    kID,
+    kName,
+    kDecoder,
+    kEncoder,
+    kInStreams,
+    kOutStreams,
+    kDescription,
+    kDecoderIsAssigned,
+    kEncoderIsAssigned
+  };
+}
+
+#endif
diff --git a/lzma/CPP/7zip/IDecl.h b/lzma/CPP/7zip/IDecl.h
new file mode 100644 (file)
index 0000000..8316eb3
--- /dev/null
@@ -0,0 +1,15 @@
+// IDecl.h
+
+#ifndef __IDECL_H
+#define __IDECL_H
+
+#include "../Common/MyUnknown.h"
+
+#define DECL_INTERFACE_SUB(i, base, groupId, subId) \
+DEFINE_GUID(IID_ ## i, \
+0x23170F69, 0x40C1, 0x278A, 0, 0, 0, (groupId), 0, (subId), 0, 0); \
+struct i: public base
+
+#define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId)
+
+#endif
diff --git a/lzma/CPP/7zip/IPassword.h b/lzma/CPP/7zip/IPassword.h
new file mode 100644 (file)
index 0000000..3ca7b09
--- /dev/null
@@ -0,0 +1,24 @@
+// IPassword.h
+
+#ifndef __IPASSWORD_H
+#define __IPASSWORD_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x)
+
+PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10)
+{
+  STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE;
+};
+
+PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11)
+{
+  STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE;
+};
+
+#endif
+
diff --git a/lzma/CPP/7zip/IProgress.h b/lzma/CPP/7zip/IProgress.h
new file mode 100644 (file)
index 0000000..f5f54b2
--- /dev/null
@@ -0,0 +1,30 @@
+// Interface/IProgress.h
+
+#ifndef __IPROGRESS_H
+#define __IPROGRESS_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+DECL_INTERFACE(IProgress, 0, 5)
+{
+  STDMETHOD(SetTotal)(UInt64 total) PURE;
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE;
+};
+
+/*
+// {23170F69-40C1-278A-0000-000000050002}
+DEFINE_GUID(IID_IProgress2, 
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002")
+IProgress2: public IUnknown
+{
+public:
+  STDMETHOD(SetTotal)(const UInt64 *total) PURE;
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE;
+};
+*/
+
+#endif
diff --git a/lzma/CPP/7zip/IStream.h b/lzma/CPP/7zip/IStream.h
new file mode 100644 (file)
index 0000000..a19d04f
--- /dev/null
@@ -0,0 +1,58 @@
+// IStream.h
+
+#ifndef __ISTREAM_H
+#define __ISTREAM_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x)
+#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x)
+
+STREAM_INTERFACE(ISequentialInStream, 0x01)
+{
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE;
+  /*
+  Out: if size != 0, return_value = S_OK and (*processedSize == 0),
+    then there are no more bytes in stream.
+  if (size > 0) && there are bytes in stream, 
+  this function must read at least 1 byte.
+  This function is allowed to read less than number of remaining bytes in stream.
+  You must call Read function in loop, if you need exact amount of data
+  */
+};
+
+STREAM_INTERFACE(ISequentialOutStream, 0x02)
+{
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE;
+  /*
+  if (size > 0) this function must write at least 1 byte.
+  This function is allowed to write less than "size".
+  You must call Write function in loop, if you need to write exact amount of data
+  */
+};
+
+STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03)
+{
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+};
+
+STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04)
+{
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+  STDMETHOD(SetSize)(Int64 newSize) PURE;
+};
+
+STREAM_INTERFACE(IStreamGetSize, 0x06)
+{
+  STDMETHOD(GetSize)(UInt64 *size) PURE;
+};
+
+STREAM_INTERFACE(IOutStreamFlush, 0x07)
+{
+  STDMETHOD(Flush)() PURE;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/MyVersion.h b/lzma/CPP/7zip/MyVersion.h
new file mode 100644 (file)
index 0000000..af5c7d3
--- /dev/null
@@ -0,0 +1,8 @@
+#define MY_VER_MAJOR 4
+#define MY_VER_MINOR 57
+#define MY_VER_BUILD 0
+#define MY_VERSION "4.57"
+#define MY_7ZIP_VERSION "7-Zip 4.57"
+#define MY_DATE "2007-12-06"
+#define MY_COPYRIGHT "Copyright (c) 1999-2007 Igor Pavlov"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION "  " MY_COPYRIGHT "  " MY_DATE
diff --git a/lzma/CPP/7zip/MyVersionInfo.rc b/lzma/CPP/7zip/MyVersionInfo.rc
new file mode 100644 (file)
index 0000000..c3712b1
--- /dev/null
@@ -0,0 +1,45 @@
+#include <WinVer.h>
+#include "MyVersion.h"
+
+#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0
+
+#ifdef DEBUG
+#define DBG_FL VS_FF_DEBUG
+#else
+#define DBG_FL 0
+#endif
+
+#define MY_VERSION_INFO(fileType, descr, intName, origName)  \
+LANGUAGE 9, 1 \
+1 VERSIONINFO \
+  FILEVERSION MY_VER \
+  PRODUCTVERSION MY_VER \
+  FILEFLAGSMASK VS_FFI_FILEFLAGSMASK \
+  FILEFLAGS DBG_FL \
+  FILEOS VOS_NT_WINDOWS32 \
+  FILETYPE fileType \
+  FILESUBTYPE 0x0L \
+BEGIN \
+    BLOCK "StringFileInfo" \
+    BEGIN  \
+        BLOCK "040904b0" \
+        BEGIN \
+            VALUE "CompanyName", "Igor Pavlov" \
+            VALUE "FileDescription", descr \
+            VALUE "FileVersion", MY_VERSION  \
+            VALUE "InternalName", intName \
+            VALUE "LegalCopyright", MY_COPYRIGHT \
+            VALUE "OriginalFilename", origName \
+            VALUE "ProductName", "7-Zip" \
+            VALUE "ProductVersion", MY_VERSION \
+        END \
+    END \
+    BLOCK "VarFileInfo" \
+    BEGIN \
+        VALUE "Translation", 0x409, 1200 \
+    END \
+END
+
+#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(VFT_APP, descr, intName, intName ".exe")
+
+#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(VFT_DLL, descr, intName, intName ".dll")
diff --git a/lzma/CPP/7zip/PropID.h b/lzma/CPP/7zip/PropID.h
new file mode 100644 (file)
index 0000000..a13fe27
--- /dev/null
@@ -0,0 +1,60 @@
+// Interface/PropID.h
+
+#ifndef __INTERFACE_PROPID_H
+#define __INTERFACE_PROPID_H
+
+enum
+{
+  kpidNoProperty = 0,
+  
+  kpidHandlerItemIndex = 2,
+  kpidPath,
+  kpidName,
+  kpidExtension,
+  kpidIsFolder,
+  kpidSize,
+  kpidPackedSize,
+  kpidAttributes,
+  kpidCreationTime,
+  kpidLastAccessTime,
+  kpidLastWriteTime,
+  kpidSolid, 
+  kpidCommented, 
+  kpidEncrypted, 
+  kpidSplitBefore, 
+  kpidSplitAfter, 
+  kpidDictionarySize, 
+  kpidCRC, 
+  kpidType,
+  kpidIsAnti,
+  kpidMethod,
+  kpidHostOS,
+  kpidFileSystem,
+  kpidUser,
+  kpidGroup,
+  kpidBlock,
+  kpidComment,
+  kpidPosition,
+  kpidPrefix,
+  kpidNumSubFolders,
+  kpidNumSubFiles,
+  kpidUnpackVer,
+  kpidVolume,
+  kpidIsVolume,
+  kpidOffset,
+  kpidLinks,
+  kpidNumBlocks,
+  kpidNumVolumes,
+
+  kpidTotalSize = 0x1100,
+  kpidFreeSpace, 
+  kpidClusterSize,
+  kpidVolumeName,
+
+  kpidLocalName = 0x1200,
+  kpidProvider,
+
+  kpidUserDefined = 0x10000
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Client7z/Client7z.cpp b/lzma/CPP/7zip/UI/Client7z/Client7z.cpp
new file mode 100644 (file)
index 0000000..fce1c4f
--- /dev/null
@@ -0,0 +1,880 @@
+// Client7z.cpp
+
+#include "StdAfx.h"
+
+#include "Common/MyInitGuid.h"
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+#include "Windows/DLL.h"
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+#include "Windows/FileFind.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Archive/IArchive.h"
+#include "../../IPassword.h"
+#include "../../MyVersion.h"
+
+
+// {23170F69-40C1-278A-1000-000110070000}
+DEFINE_GUID(CLSID_CFormat7z, 
+  0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00);
+
+using namespace NWindows;
+
+#define kDllName "7z.dll"
+
+static const char *kCopyrightString = MY_7ZIP_VERSION
+" ("  kDllName " client) "  
+MY_COPYRIGHT " " MY_DATE;
+
+static const char *kHelpString = 
+"Usage: Client7z.exe [a | l | x ] archive.7z [fileName ...]\n"
+"Examples:\n"
+"  Client7z.exe a archive.7z f1.txt f2.txt  : compress two files to archive.7z\n"
+"  Client7z.exe l archive.7z   : List contents of archive.7z\n"
+"  Client7z.exe x archive.7z   : eXtract files from archive.7z\n";
+
+
+typedef UINT32 (WINAPI * CreateObjectFunc)(
+    const GUID *clsID, 
+    const GUID *interfaceID, 
+    void **outObject);
+
+#ifdef _WIN32
+#ifndef _UNICODE
+bool g_IsNT = false;
+static inline bool IsItWindowsNT()
+{
+  OSVERSIONINFO versionInfo;
+  versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+  if (!::GetVersionEx(&versionInfo)) 
+    return false;
+  return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+#endif
+
+void PrintString(const UString &s)
+{
+  printf("%s", (LPCSTR)GetOemString(s));
+}
+
+void PrintString(const AString &s)
+{
+  printf("%s", (LPCSTR)s);
+}
+
+void PrintNewLine()
+{
+  PrintString("\n");
+}
+
+void PrintStringLn(const AString &s)
+{
+  PrintString(s);
+  PrintNewLine();
+}
+
+void PrintError(const AString &s)
+{
+  PrintNewLine();
+  PrintString(s);
+  PrintNewLine();
+}
+
+static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
+{
+  NCOM::CPropVariant prop;
+  RINOK(archive->GetProperty(index, propID, &prop));
+  if(prop.vt == VT_BOOL)
+    result = VARIANT_BOOLToBool(prop.boolVal);
+  else if (prop.vt == VT_EMPTY)
+    result = false;
+  else
+    return E_FAIL;
+  return S_OK;
+}
+
+static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
+{
+  return IsArchiveItemProp(archive, index, kpidIsFolder, result);
+}
+
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+
+//////////////////////////////////////////////////////////////
+// Archive Open callback class
+
+
+class CArchiveOpenCallback: 
+  public IArchiveOpenCallback,
+  public ICryptoGetTextPassword,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
+
+  STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
+  STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
+
+  STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+  bool PasswordIsDefined;
+  UString Password;
+
+  CArchiveOpenCallback() : PasswordIsDefined(false) {}
+};
+
+STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)
+{
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)
+{
+  return S_OK;
+}
+  
+STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)
+{
+  if (!PasswordIsDefined)
+  {
+    // You can ask real password here from user
+    // Password = GetPassword(OutStream); 
+    // PasswordIsDefined = true;
+    PrintError("Password is not defined");
+    return E_ABORT;
+  }
+  CMyComBSTR tempName(Password);
+  *password = tempName.Detach();
+  return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////
+// Archive Extracting callback class
+
+static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
+
+static const char *kTestingString    =  "Testing     ";
+static const char *kExtractingString =  "Extracting  ";
+static const char *kSkippingString   =  "Skipping    ";
+
+static const char *kUnsupportedMethod = "Unsupported Method";
+static const char *kCRCFailed = "CRC Failed";
+static const char *kDataError = "Data Error";
+static const char *kUnknownError = "Unknown Error";
+
+class CArchiveExtractCallback: 
+  public IArchiveExtractCallback,
+  public ICryptoGetTextPassword,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
+
+  // IProgress
+  STDMETHOD(SetTotal)(UInt64 size);
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+  // IArchiveExtractCallback
+  STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
+  STDMETHOD(PrepareOperation)(Int32 askExtractMode);
+  STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
+
+  // ICryptoGetTextPassword
+  STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
+
+private:
+  CMyComPtr<IInArchive> _archiveHandler;
+  UString _directoryPath;  // Output directory
+  UString _filePath;       // name inside arcvhive
+  UString _diskFilePath;   // full path to file on disk
+  bool _extractMode;
+  struct CProcessedFileInfo
+  {
+    FILETIME UTCLastWriteTime;
+    UInt32 Attributes;
+    bool IsDirectory;
+    bool AttributesAreDefined;
+    bool UTCLastWriteTimeIsDefined;
+  } _processedFileInfo;
+
+  COutFileStream *_outFileStreamSpec;
+  CMyComPtr<ISequentialOutStream> _outFileStream;
+
+public:
+  void Init(IInArchive *archiveHandler, const UString &directoryPath);
+
+  UInt64 NumErrors;
+  bool PasswordIsDefined;
+  UString Password;
+
+  CArchiveExtractCallback() : PasswordIsDefined(false) {}
+};
+
+void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const UString &directoryPath)
+{
+  NumErrors = 0;
+  _archiveHandler = archiveHandler;
+  _directoryPath = directoryPath;
+  NFile::NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */)
+{
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */)
+{
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, 
+    ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+  *outStream = 0;
+  _outFileStream.Release();
+
+  {
+    // Get Name
+    NCOM::CPropVariant propVariant;
+    RINOK(_archiveHandler->GetProperty(index, kpidPath, &propVariant));
+    
+    UString fullPath;
+    if(propVariant.vt == VT_EMPTY)
+      fullPath = kEmptyFileAlias;
+    else 
+    {
+      if(propVariant.vt != VT_BSTR)
+        return E_FAIL;
+      fullPath = propVariant.bstrVal;
+    }
+    _filePath = fullPath;
+  }
+
+  if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
+    return S_OK;
+
+  {
+    // Get Attributes
+    NCOM::CPropVariant propVariant;
+    RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &propVariant));
+    if (propVariant.vt == VT_EMPTY)
+    {
+      _processedFileInfo.Attributes = 0;
+      _processedFileInfo.AttributesAreDefined = false;
+    }
+    else
+    {
+      if (propVariant.vt != VT_UI4)
+        throw "incorrect item";
+      _processedFileInfo.Attributes = propVariant.ulVal;
+      _processedFileInfo.AttributesAreDefined = true;
+    }
+  }
+
+  RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.IsDirectory));
+
+  {
+    // Get Modified Time
+    NCOM::CPropVariant propVariant;
+    RINOK(_archiveHandler->GetProperty(index, kpidLastWriteTime, &propVariant));
+    _processedFileInfo.UTCLastWriteTimeIsDefined = false;
+    switch(propVariant.vt)
+    {
+      case VT_EMPTY:
+        // _processedFileInfo.UTCLastWriteTime = _utcLastWriteTimeDefault;
+        break;
+      case VT_FILETIME:
+        _processedFileInfo.UTCLastWriteTime = propVariant.filetime;
+        _processedFileInfo.UTCLastWriteTimeIsDefined = true;
+        break;
+      default:
+        return E_FAIL;
+    }
+
+  }
+  {
+    // Get Size
+    NCOM::CPropVariant propVariant;
+    RINOK(_archiveHandler->GetProperty(index, kpidSize, &propVariant));
+    bool newFileSizeDefined = (propVariant.vt != VT_EMPTY);
+    UInt64 newFileSize;
+    if (newFileSizeDefined)
+      newFileSize = ConvertPropVariantToUInt64(propVariant);
+  }
+
+  
+  {
+    // Create folders for file
+    int slashPos = _filePath.ReverseFind(WCHAR_PATH_SEPARATOR);
+    if (slashPos >= 0)
+      NFile::NDirectory::CreateComplexDirectory(_directoryPath + _filePath.Left(slashPos));
+  }
+
+  UString fullProcessedPath = _directoryPath + _filePath;
+  _diskFilePath = fullProcessedPath;
+
+  if (_processedFileInfo.IsDirectory)
+  {
+    NFile::NDirectory::CreateComplexDirectory(fullProcessedPath);
+  }
+  else
+  {
+    NFile::NFind::CFileInfoW fileInfo;
+    if(NFile::NFind::FindFile(fullProcessedPath, fileInfo))
+    {
+      if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
+      {
+        PrintString(UString(kCantDeleteOutputFile) + fullProcessedPath);
+        return E_ABORT;
+      }
+    }
+    
+    _outFileStreamSpec = new COutFileStream;
+    CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+    if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
+    {
+      PrintString((UString)L"can not open output file " + fullProcessedPath);
+      return E_ABORT;
+    }
+    _outFileStream = outStreamLoc;
+    *outStream = outStreamLoc.Detach();
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
+{
+  _extractMode = false;
+  switch (askExtractMode)
+  {
+    case NArchive::NExtract::NAskMode::kExtract:
+      _extractMode = true;
+  };
+  switch (askExtractMode)
+  {
+    case NArchive::NExtract::NAskMode::kExtract:
+      PrintString(kExtractingString);
+      break;
+    case NArchive::NExtract::NAskMode::kTest:
+      PrintString(kTestingString);
+      break;
+    case NArchive::NExtract::NAskMode::kSkip:
+      PrintString(kSkippingString);
+      break;
+  };
+  PrintString(_filePath);
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+  switch(operationResult)
+  {
+    case NArchive::NExtract::NOperationResult::kOK:
+      break;
+    default:
+    {
+      NumErrors++;
+      PrintString("     ");
+      switch(operationResult)
+      {
+        case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+          PrintString(kUnsupportedMethod);
+          break;
+        case NArchive::NExtract::NOperationResult::kCRCError:
+          PrintString(kCRCFailed);
+          break;
+        case NArchive::NExtract::NOperationResult::kDataError:
+          PrintString(kDataError);
+          break;
+        default:
+          PrintString(kUnknownError);
+      }
+    }
+  }
+
+  if (_outFileStream != NULL)
+  {
+    if (_processedFileInfo.UTCLastWriteTimeIsDefined)
+      _outFileStreamSpec->SetLastWriteTime(&_processedFileInfo.UTCLastWriteTime);
+    RINOK(_outFileStreamSpec->Close());
+  }
+  _outFileStream.Release();
+  if (_extractMode && _processedFileInfo.AttributesAreDefined)
+    NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes);
+  PrintNewLine();
+  return S_OK;
+}
+
+
+STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+{
+  if (!PasswordIsDefined)
+  {
+    // You can ask real password here from user
+    // Password = GetPassword(OutStream); 
+    // PasswordIsDefined = true;
+    PrintError("Password is not defined");
+    return E_ABORT;
+  }
+  CMyComBSTR tempName(Password);
+  *password = tempName.Detach();
+  return S_OK;
+}
+
+
+
+//////////////////////////////////////////////////////////////
+// Archive Creating callback class
+
+struct CDirItem
+{ 
+  UInt32 Attributes;
+  FILETIME CreationTime;
+  FILETIME LastAccessTime;
+  FILETIME LastWriteTime;
+  UInt64 Size;
+  UString Name;
+  UString FullPath;
+  bool IsDirectory() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
+};
+
+class CArchiveUpdateCallback: 
+  public IArchiveUpdateCallback2,
+  public ICryptoGetTextPassword2,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)
+
+  // IProgress
+  STDMETHOD(SetTotal)(UInt64 size);
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+  // IUpdateCallback2
+  STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator);  
+  STDMETHOD(GetUpdateItemInfo)(UInt32 index, 
+      Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
+  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
+  STDMETHOD(SetOperationResult)(Int32 operationResult);
+  STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
+  STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);
+
+  STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
+
+public:
+  CRecordVector<UInt64> VolumesSizes;
+  UString VolName;
+  UString VolExt;
+
+  UString DirPrefix;
+  const CObjectVector<CDirItem> *DirItems;
+
+  bool PasswordIsDefined;
+  UString Password;
+  bool AskPassword;
+
+  bool m_NeedBeClosed;
+
+  UStringVector FailedFiles;
+  CRecordVector<HRESULT> FailedCodes;
+
+  CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {};
+
+  ~CArchiveUpdateCallback() { Finilize(); }
+  HRESULT Finilize();
+
+  void Init(const CObjectVector<CDirItem> *dirItems)
+  {
+    DirItems = dirItems;
+    m_NeedBeClosed = false;
+    FailedFiles.Clear();
+    FailedCodes.Clear();
+  }
+};
+
+STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */)
+{
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */)
+{
+  return S_OK;
+}
+
+
+STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */)
+{
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, 
+      Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
+{
+  if(newData != NULL)
+    *newData = BoolToInt(true);
+  if(newProperties != NULL)
+    *newProperties = BoolToInt(true);
+  if(indexInArchive != NULL)
+    *indexInArchive = UInt32(-1);
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+  NWindows::NCOM::CPropVariant propVariant;
+  
+  if (propID == kpidIsAnti)
+  {
+    propVariant = false;
+    propVariant.Detach(value);
+    return S_OK;
+  }
+
+  {
+    const CDirItem &dirItem = (*DirItems)[index];
+    switch(propID)
+    {
+      case kpidPath:
+        propVariant = dirItem.Name;
+        break;
+      case kpidIsFolder:
+        propVariant = dirItem.IsDirectory();
+        break;
+      case kpidSize:
+        propVariant = dirItem.Size;
+        break;
+      case kpidAttributes:
+        propVariant = dirItem.Attributes;
+        break;
+      case kpidLastAccessTime:
+        propVariant = dirItem.LastAccessTime;
+        break;
+      case kpidCreationTime:
+        propVariant = dirItem.CreationTime;
+        break;
+      case kpidLastWriteTime:
+        propVariant = dirItem.LastWriteTime;
+        break;
+    }
+  }
+  propVariant.Detach(value);
+  return S_OK;
+}
+
+HRESULT CArchiveUpdateCallback::Finilize()
+{
+  if (m_NeedBeClosed)
+  {
+    PrintNewLine();
+    m_NeedBeClosed = false;
+  }
+  return S_OK;
+}
+
+static void GetStream2(const wchar_t *name)
+{
+  PrintString("Compressing  ");
+  if (name[0] == 0)
+    name = kEmptyFileAlias;
+  PrintString(name);
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
+{
+  RINOK(Finilize());
+
+  const CDirItem &dirItem = (*DirItems)[index];
+  GetStream2(dirItem.Name);
+  if(dirItem.IsDirectory())
+    return S_OK;
+
+  {
+    CInFileStream *inStreamSpec = new CInFileStream;
+    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+    UString path = DirPrefix + dirItem.FullPath;
+    if(!inStreamSpec->Open(path))
+    {
+      DWORD sysError = ::GetLastError();
+      FailedCodes.Add(sysError);
+      FailedFiles.Add(path);
+      // if (systemError == ERROR_SHARING_VIOLATION)
+      {
+        PrintNewLine();
+        PrintError("WARNING: can't open file");
+        // PrintString(NError::MyFormatMessageW(systemError));
+        return S_FALSE;
+      }
+      // return sysError;
+    }
+    *inStream = inStreamLoc.Detach();
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */)
+{
+  m_NeedBeClosed = true;
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
+{
+  if (VolumesSizes.Size() == 0)
+    return S_FALSE;
+  if (index >= (UInt32)VolumesSizes.Size())
+    index = VolumesSizes.Size() - 1;
+  *size = VolumesSizes[index];
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
+{
+  wchar_t temp[32];
+  ConvertUInt64ToString(index + 1, temp);
+  UString res = temp;
+  while (res.Length() < 2)
+    res = UString(L'0') + res;
+  UString fileName = VolName;
+  fileName += L'.';
+  fileName += res;
+  fileName += VolExt;
+  COutFileStream *streamSpec = new COutFileStream;
+  CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+  if(!streamSpec->Create(fileName, false))
+    return ::GetLastError();
+  *volumeStream = streamLoc.Detach();
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+  if (!PasswordIsDefined) 
+  {
+    if (AskPassword)
+    {
+      // You can ask real password here from user
+      // Password = GetPassword(OutStream); 
+      // PasswordIsDefined = true;
+      PrintError("Password is not defined");
+      return E_ABORT;
+    }
+  }
+  *passwordIsDefined = BoolToInt(PasswordIsDefined);
+  CMyComBSTR tempName(Password);
+  *password = tempName.Detach();
+  return S_OK;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// Main function
+
+int 
+#ifdef _MSC_VER
+__cdecl 
+#endif
+main(int argc, char* argv[])
+{
+  #ifdef _WIN32
+  #ifndef _UNICODE
+  g_IsNT = IsItWindowsNT();
+  #endif
+  #endif
+
+  PrintStringLn(kCopyrightString);
+
+  if (argc < 3)
+  {
+    PrintStringLn(kHelpString);
+    return 1;
+  }
+  NWindows::NDLL::CLibrary library;
+  if (!library.Load(TEXT(kDllName)))
+  {
+    PrintError("Can not load library");
+    return 1;
+  }
+  CreateObjectFunc createObjectFunc = (CreateObjectFunc)library.GetProcAddress("CreateObject");
+  if (createObjectFunc == 0)
+  {
+    PrintError("Can not get CreateObject");
+    return 1;
+  }
+
+  AString command = argv[1];
+  UString archiveName = GetUnicodeString(argv[2], CP_OEMCP);
+  if (command.CompareNoCase("a") == 0)
+  {
+    // create archive command
+    if (argc < 4)
+    {
+      PrintStringLn(kHelpString);
+      return 1;
+    }
+    CObjectVector<CDirItem> dirItems;
+    int i;
+    for (i = 3; i < argc; i++)
+    {
+      CDirItem item;
+      UString name = GetUnicodeString(argv[i], CP_OEMCP);
+      
+      NFile::NFind::CFileInfoW fileInfo;
+      if (!NFile::NFind::FindFile(name, fileInfo))
+      {
+        PrintString(UString(L"Can't find file") + name);
+        return 1;
+      }
+
+      item.Attributes = fileInfo.Attributes;
+      item.Size = fileInfo.Size;
+      item.CreationTime = fileInfo.CreationTime;
+      item.LastAccessTime = fileInfo.LastAccessTime;
+      item.LastWriteTime = fileInfo.LastWriteTime;
+      item.Name = name;
+      item.FullPath = name;
+      dirItems.Add(item);
+    }
+    COutFileStream *outFileStreamSpec = new COutFileStream;
+    CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
+    if (!outFileStreamSpec->Create(archiveName, false))
+    {
+      PrintError("can't create archive file");
+      return 1;
+    }
+
+    CMyComPtr<IOutArchive> outArchive;
+    if (createObjectFunc(&CLSID_CFormat7z, &IID_IOutArchive, (void **)&outArchive) != S_OK)
+    {
+      PrintError("Can not get class object");
+      return 1;
+    }
+
+    CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+    CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
+    updateCallbackSpec->Init(&dirItems);
+    // updateCallbackSpec->PasswordIsDefined = true;
+    // updateCallbackSpec->Password = L"1";
+
+    HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
+    updateCallbackSpec->Finilize();
+    if (result != S_OK)
+    {
+      PrintError("Update Error");
+      return 1;
+    }
+    for (i = 0; i < updateCallbackSpec->FailedFiles.Size(); i++)
+    {
+      PrintNewLine();
+      PrintString((UString)L"Error for file: " + updateCallbackSpec->FailedFiles[i]);
+    }
+    if (updateCallbackSpec->FailedFiles.Size() != 0)
+      return 1;
+  }
+  else
+  {
+    if (argc != 3)
+    {
+      PrintStringLn(kHelpString);
+      return 1;
+    }
+
+    bool listCommand;
+    if (command.CompareNoCase("l") == 0)
+      listCommand = true;
+    else if (command.CompareNoCase("x") == 0)
+      listCommand = false;
+    else
+    {
+      PrintError("incorrect command");
+      return 1;
+    }
+  
+    CMyComPtr<IInArchive> archive;
+    if (createObjectFunc(&CLSID_CFormat7z, &IID_IInArchive, (void **)&archive) != S_OK)
+    {
+      PrintError("Can not get class object");
+      return 1;
+    }
+    
+    CInFileStream *fileSpec = new CInFileStream;
+    CMyComPtr<IInStream> file = fileSpec;
+    
+    if (!fileSpec->Open(archiveName))
+    {
+      PrintError("Can not open archive file");
+      return 1;
+    }
+
+    {
+      CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
+      CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
+      openCallbackSpec->PasswordIsDefined = false;
+      // openCallbackSpec->PasswordIsDefined = true;
+      // openCallbackSpec->Password = L"1";
+      
+      if (archive->Open(file, 0, openCallback) != S_OK)
+      {
+        PrintError("Can not open archive");
+        return 1;
+      }
+    }
+    
+    if (listCommand)
+    {
+      // List command
+      UInt32 numItems = 0;
+      archive->GetNumberOfItems(&numItems);  
+      for (UInt32 i = 0; i < numItems; i++)
+      {
+        {
+          // Get uncompressed size of file
+          NWindows::NCOM::CPropVariant propVariant;
+          archive->GetProperty(i, kpidSize, &propVariant);
+          UString s = ConvertPropVariantToString(propVariant);
+          PrintString(s);
+          PrintString("  ");
+        }
+        {
+          // Get name of file
+          NWindows::NCOM::CPropVariant propVariant;
+          archive->GetProperty(i, kpidPath, &propVariant);
+          UString s = ConvertPropVariantToString(propVariant);
+          PrintString(s);
+        }
+        PrintString("\n");
+      }
+    }
+    else
+    {
+      // Extract command
+      CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+      CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
+      extractCallbackSpec->Init(archive, L""); // second parameter is output folder path
+      extractCallbackSpec->PasswordIsDefined = false;
+      // extractCallbackSpec->PasswordIsDefined = true;
+      // extractCallbackSpec->Password = L"1";
+      HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
+      if (result != S_OK)
+      {
+        PrintError("Extract Error");
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
diff --git a/lzma/CPP/7zip/UI/Client7z/Client7z.dsp b/lzma/CPP/7zip/UI/Client7z/Client7z.dsp
new file mode 100644 (file)
index 0000000..542e285
--- /dev/null
@@ -0,0 +1,226 @@
+# Microsoft Developer Studio Project File - Name="Client7z" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Client7z - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "Client7z.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Client7z.mak" CFG="Client7z - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Client7z - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Client7z - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "Client7z - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\\" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "Client7z - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "Client7z - Win32 Release"
+# Name "Client7z - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConversions.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConversions.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\Client7z.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/lzma/CPP/7zip/UI/Client7z/Client7z.dsw b/lzma/CPP/7zip/UI/Client7z/Client7z.dsw
new file mode 100644 (file)
index 0000000..598a6d3
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Client7z"=.\Client7z.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/UI/Client7z/StdAfx.cpp b/lzma/CPP/7zip/UI/Client7z/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/UI/Client7z/StdAfx.h b/lzma/CPP/7zip/UI/Client7z/StdAfx.h
new file mode 100644 (file)
index 0000000..b23436e
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include <windows.h>
+#include <stdio.h>
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Client7z/makefile b/lzma/CPP/7zip/UI/Client7z/makefile
new file mode 100644 (file)
index 0000000..226c36a
--- /dev/null
@@ -0,0 +1,45 @@
+PROG = 7z.exe
+LIBS = $(LIBS) user32.lib oleaut32.lib advapi32.lib
+CFLAGS = $(CFLAGS) -I ../../../
+
+CONSOLE_OBJS = \
+  $O\Client7z.obj \
+
+COMMON_OBJS = \
+  $O\IntToString.obj \
+  $O\NewHandler.obj \
+  $O\MyString.obj \
+  $O\StringConvert.obj \
+  $O\StringToInt.obj \
+  $O\MyVector.obj \
+  $O\Wildcard.obj \
+
+WIN_OBJS = \
+  $O\DLL.obj \
+  $O\FileDir.obj \
+  $O\FileFind.obj \
+  $O\FileIO.obj \
+  $O\FileName.obj \
+  $O\PropVariant.obj \
+  $O\PropVariantConversions.obj \
+
+7ZIP_COMMON_OBJS = \
+  $O\FileStreams.obj \
+
+OBJS = \
+  $O\StdAfx.obj \
+  $(CONSOLE_OBJS) \
+  $(COMMON_OBJS) \
+  $(WIN_OBJS) \
+  $(7ZIP_COMMON_OBJS) \
+
+!include "../../../Build.mak"
+
+$(CONSOLE_OBJS): $(*B).cpp
+       $(COMPL)
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+       $(COMPL)
+$(WIN_OBJS): ../../../Windows/$(*B).cpp
+       $(COMPL)
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+       $(COMPL)
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
new file mode 100644 (file)
index 0000000..6cf95f2
--- /dev/null
@@ -0,0 +1,1003 @@
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <io.h>
+#endif
+#include <stdio.h>
+
+#include "Common/ListFileUtils.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileDir.h"
+#ifdef _WIN32
+#include "Windows/FileMapping.h"
+#include "Windows/Synchronization.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "UpdateAction.h"
+#include "Update.h"
+#include "SortUtils.h"
+#include "EnumDirItems.h"
+
+extern bool g_CaseSensitive;
+
+#if _MSC_VER >= 1400
+#define MY_isatty_fileno(x) _isatty(_fileno(x))
+#else
+#define MY_isatty_fileno(x) isatty(fileno(x))
+#endif
+
+#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); 
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NFile;
+
+namespace NKey {
+enum Enum
+{
+  kHelp1 = 0,
+  kHelp2,
+  kHelp3,
+  kDisableHeaders,
+  kDisablePercents,
+  kArchiveType,
+  kYes,
+  kPassword,
+  kProperty,
+  kOutputDir,
+  kWorkingDir,
+  kInclude,
+  kExclude,
+  kArInclude,
+  kArExclude,
+  kNoArName,
+  kUpdate,
+  kVolume,
+  kRecursed,
+  kSfx,
+  kStdIn,
+  kStdOut,
+  kOverwrite,
+  kEmail,
+  kShowDialog,
+  kLargePages,
+  kCharSet,
+  kTechMode,
+  kShareForWrite,
+  kCaseSensitive
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'R';
+static const wchar_t *kRecursedPostCharSet = L"0-";
+
+namespace NRecursedPostCharIndex {
+  enum EEnum 
+  {
+    kWildCardRecursionOnly = 0, 
+    kNoRecursion = 1
+  };
+}
+
+static const char kImmediateNameID = '!';
+static const char kMapNameID = '#';
+static const char kFileListID = '@';
+
+static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+
+static const wchar_t *kOverwritePostCharSet = L"asut";
+
+NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
+{
+  NExtract::NOverwriteMode::kWithoutPrompt,
+  NExtract::NOverwriteMode::kSkipExisting,
+  NExtract::NOverwriteMode::kAutoRename,
+  NExtract::NOverwriteMode::kAutoRenameExisting
+};
+
+static const CSwitchForm kSwitchForms[] = 
+  {
+    { L"?",  NSwitchType::kSimple, false },
+    { L"H",  NSwitchType::kSimple, false },
+    { L"-HELP",  NSwitchType::kSimple, false },
+    { L"BA", NSwitchType::kSimple, false },
+    { L"BD", NSwitchType::kSimple, false },
+    { L"T",  NSwitchType::kUnLimitedPostString, false, 1 },
+    { L"Y",  NSwitchType::kSimple, false },
+    { L"P",  NSwitchType::kUnLimitedPostString, false, 0 },
+    { L"M",  NSwitchType::kUnLimitedPostString, true, 1 },
+    { L"O",  NSwitchType::kUnLimitedPostString, false, 1 },
+    { L"W",  NSwitchType::kUnLimitedPostString, false, 0 },
+    { L"I",  NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+    { L"X",  NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+    { L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+    { L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+    { L"AN", NSwitchType::kSimple, false },
+    { L"U",  NSwitchType::kUnLimitedPostString, true, 1},
+    { L"V",  NSwitchType::kUnLimitedPostString, true, 1},
+    { L"R",  NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet },
+    { L"SFX", NSwitchType::kUnLimitedPostString, false, 0 },
+    { L"SI", NSwitchType::kUnLimitedPostString, false, 0 },
+    { L"SO", NSwitchType::kSimple, false, 0 },
+    { L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet},
+    { L"SEML", NSwitchType::kUnLimitedPostString, false, 0},
+    { L"AD",  NSwitchType::kSimple, false },
+    { L"SLP", NSwitchType::kUnLimitedPostString, false, 0},
+    { L"SCS", NSwitchType::kUnLimitedPostString, false, 0},
+    { L"SLT", NSwitchType::kSimple, false },
+    { L"SSW", NSwitchType::kSimple, false },
+    { L"SSC", NSwitchType::kPostChar, false, 0, 0, L"-" }
+  };
+
+static const CCommandForm g_CommandForms[] = 
+{
+  { L"A", false },
+  { L"U", false },
+  { L"D", false },
+  { L"T", false },
+  { L"E", false },
+  { L"X", false },
+  { L"L", false },
+  { L"B", false },
+  { L"I", false }
+};
+
+static const int kNumCommandForms = sizeof(g_CommandForms) /  sizeof(g_CommandForms[0]);
+
+static const wchar_t *kUniversalWildcard = L"*";
+static const int kMinNonSwitchWords = 1;
+static const int kCommandIndex = 0;
+
+// ---------------------------
+// exception messages
+
+static const char *kUserErrorMessage  = "Incorrect command line";
+static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
+static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfile";
+static const char *kIncorrectWildCardInCommandLine  = "Incorrect wildcard in command line";
+static const char *kTerminalOutError = "I won't write compressed data to a terminal";
+static const char *kSameTerminalError = "I won't write data and program's messages to same terminal";
+
+static void ThrowException(const char *errorMessage)
+{
+  throw CArchiveCommandLineException(errorMessage);
+};
+
+static void ThrowUserErrorException()
+{
+  ThrowException(kUserErrorMessage);
+};
+
+// ---------------------------
+
+bool CArchiveCommand::IsFromExtractGroup() const
+{
+  switch(CommandType)
+  {
+    case NCommandType::kTest:
+    case NCommandType::kExtract:
+    case NCommandType::kFullExtract:
+      return true;
+    default:
+      return false;
+  }
+}
+
+NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const
+{
+  switch(CommandType)
+  {
+    case NCommandType::kTest:
+    case NCommandType::kFullExtract:
+      return NExtract::NPathMode::kFullPathnames;
+    default:
+      return NExtract::NPathMode::kNoPathnames;
+  }
+}
+
+bool CArchiveCommand::IsFromUpdateGroup() const
+{
+  return (CommandType == NCommandType::kAdd || 
+    CommandType == NCommandType::kUpdate ||
+    CommandType == NCommandType::kDelete);
+}
+
+static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
+{
+  switch (index)
+  {
+    case NRecursedPostCharIndex::kWildCardRecursionOnly: 
+      return NRecursedType::kWildCardOnlyRecursed;
+    case NRecursedPostCharIndex::kNoRecursion: 
+      return NRecursedType::kNonRecursed;
+    default:
+      return NRecursedType::kRecursed;
+  }
+}
+
+static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
+{
+  UString commandStringUpper = commandString;
+  commandStringUpper.MakeUpper();
+  UString postString;
+  int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStringUpper, 
+      postString) ;
+  if (commandIndex < 0)
+    return false;
+  command.CommandType = (NCommandType::EEnum)commandIndex;
+  return true;
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, 
+    const UString &name, bool include, NRecursedType::EEnum type)
+{
+  bool isWildCard = DoesNameContainWildCard(name);
+  bool recursed = false;
+
+  switch (type)
+  {
+    case NRecursedType::kWildCardOnlyRecursed:
+      recursed = isWildCard;
+      break;
+    case NRecursedType::kRecursed:
+      recursed = true;
+      break;
+    case NRecursedType::kNonRecursed:
+      recursed = false;
+      break;
+  }
+  wildcardCensor.AddItem(include, name, recursed);
+  return true;
+}
+
+static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor, 
+    LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage)
+{
+  UStringVector names;
+  if (!ReadNamesFromListFile(fileName, names, codePage))
+    throw kIncorrectListFile;
+  for (int i = 0; i < names.Size(); i++)
+    if (!AddNameToCensor(wildcardCensor, names[i], include, type))
+      throw kIncorrectWildCardInListFile;
+}
+
+static void AddCommandLineWildCardToCensr(NWildcard::CCensor &wildcardCensor, 
+    const UString &name, bool include, NRecursedType::EEnum recursedType)
+{
+  if (!AddNameToCensor(wildcardCensor, name, include, recursedType))
+    throw kIncorrectWildCardInCommandLine;
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+    int startIndex,
+    NWildcard::CCensor &wildcardCensor, 
+    const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, 
+    bool thereAreSwitchIncludes, UINT codePage)
+{
+  if(nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes)) 
+    AddCommandLineWildCardToCensr(wildcardCensor, kUniversalWildcard, true, type);
+  for(int i = startIndex; i < nonSwitchStrings.Size(); i++)
+  {
+    const UString &s = nonSwitchStrings[i];
+    if (s[0] == kFileListID)
+      AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage);
+    else
+      AddCommandLineWildCardToCensr(wildcardCensor, s, true, type);
+  }
+}
+
+#ifdef _WIN32
+static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor, 
+    const UString &switchParam, bool include, 
+    NRecursedType::EEnum commonRecursedType)
+{
+  int splitPos = switchParam.Find(L':');
+  if (splitPos < 0)
+    ThrowUserErrorException();
+  UString mappingName = switchParam.Left(splitPos);
+  
+  UString switchParam2 = switchParam.Mid(splitPos + 1);
+  splitPos = switchParam2.Find(L':');
+  if (splitPos < 0)
+    ThrowUserErrorException();
+  
+  UString mappingSize = switchParam2.Left(splitPos);
+  UString eventName = switchParam2.Mid(splitPos + 1);
+  
+  UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL);
+  UInt32 dataSize = (UInt32)dataSize64;
+  {
+    CFileMapping fileMapping;
+    if (!fileMapping.Open(FILE_MAP_READ, false, GetSystemString(mappingName)))
+      ThrowException("Can not open mapping");
+    LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_READ, 0, dataSize);
+    if (data == NULL)
+      ThrowException("MapViewOfFile error");
+    try
+    {
+      const wchar_t *curData = (const wchar_t *)data;
+      if (*curData != 0)
+        ThrowException("Incorrect mapping data");
+      UInt32 numChars = dataSize / sizeof(wchar_t);
+      UString name;
+      for (UInt32 i = 1; i < numChars; i++)
+      {
+        wchar_t c = curData[i];
+        if (c == L'\0')
+        {
+          AddCommandLineWildCardToCensr(wildcardCensor, 
+              name, include, commonRecursedType);
+          name.Empty();
+        }
+        else
+          name += c;
+      }
+      if (!name.IsEmpty())
+        ThrowException("data error");
+    }
+    catch(...)
+    {
+      UnmapViewOfFile(data);
+      throw;
+    }
+    UnmapViewOfFile(data);
+  }
+  
+  {
+    NSynchronization::CManualResetEvent event;
+    if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName)) == S_OK)
+      event.Set();
+  }
+}
+#endif
+
+static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor, 
+    const UStringVector &strings, bool include, 
+    NRecursedType::EEnum commonRecursedType, UINT codePage)
+{
+  for(int i = 0; i < strings.Size(); i++)
+  {
+    const UString &name = strings[i];
+    NRecursedType::EEnum recursedType;
+    int pos = 0;
+    if (name.Length() < kSomeCludePostStringMinSize)
+      ThrowUserErrorException();
+    if (::MyCharUpper(name[pos]) == kRecursedIDChar)
+    {
+      pos++;
+      int index = UString(kRecursedPostCharSet).Find(name[pos]);
+      recursedType = GetRecursedTypeFromIndex(index);
+      if (index >= 0)
+        pos++;
+    }
+    else
+      recursedType = commonRecursedType;
+    if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize)
+      ThrowUserErrorException();
+    UString tail = name.Mid(pos + 1);
+    if (name[pos] == kImmediateNameID)
+      AddCommandLineWildCardToCensr(wildcardCensor, tail, include, recursedType);
+    else if (name[pos] == kFileListID)
+      AddToCensorFromListFile(wildcardCensor, tail, include, recursedType, codePage);
+    #ifdef _WIN32
+    else if (name[pos] == kMapNameID)
+      ParseMapWithPaths(wildcardCensor, tail, include, recursedType);
+    #endif
+    else
+      ThrowUserErrorException();
+  }
+}
+
+#ifdef _WIN32
+
+// This code converts all short file names to long file names.
+
+static void ConvertToLongName(const UString &prefix, UString &name)
+{
+  if (name.IsEmpty() || DoesNameContainWildCard(name))
+    return;
+  NFind::CFileInfoW fileInfo;
+  if (NFind::FindFile(prefix + name, fileInfo))
+    name = fileInfo.Name;
+}
+
+static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)
+{
+  for (int i = 0; i < items.Size(); i++)
+  {
+    NWildcard::CItem &item = items[i];
+    if (item.Recursive || item.PathParts.Size() != 1)
+      continue;
+    ConvertToLongName(prefix, item.PathParts.Front());
+  }
+}
+
+static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)
+{
+  ConvertToLongNames(prefix, node.IncludeItems);
+  ConvertToLongNames(prefix, node.ExcludeItems);
+  int i;
+  for (i = 0; i < node.SubNodes.Size(); i++)
+    ConvertToLongName(prefix, node.SubNodes[i].Name);
+  // mix folders with same name
+  for (i = 0; i < node.SubNodes.Size(); i++)
+  {
+    NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];
+    for (int j = i + 1; j < node.SubNodes.Size();)
+    {
+      const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];
+      if (nextNode1.Name.CompareNoCase(nextNode2.Name) == 0)
+      {
+        nextNode1.IncludeItems += nextNode2.IncludeItems;
+        nextNode1.ExcludeItems += nextNode2.ExcludeItems;
+        node.SubNodes.Delete(j);
+      }
+      else
+        j++;
+    }
+  }
+  for (i = 0; i < node.SubNodes.Size(); i++)
+  {
+    NWildcard::CCensorNode &nextNode = node.SubNodes[i];
+    ConvertToLongNames(prefix + nextNode.Name + wchar_t(NFile::NName::kDirDelimiter), nextNode); 
+  }
+}
+
+static void ConvertToLongNames(NWildcard::CCensor &censor)
+{
+  for (int i = 0; i < censor.Pairs.Size(); i++)
+  {
+    NWildcard::CPair &pair = censor.Pairs[i];
+    ConvertToLongNames(pair.Prefix, pair.Head);
+  }
+}
+
+#endif
+
+static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
+{
+  switch(i)
+  {
+    case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
+    case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
+    case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
+    case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
+  }
+  throw 98111603;
+}
+
+const UString kUpdatePairStateIDSet = L"PQRXYZW";
+const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create Anti
+
+const wchar_t *kUpdateIgnoreItselfPostStringID = L"-"; 
+const wchar_t kUpdateNewArchivePostCharID = '!'; 
+
+
+static bool ParseUpdateCommandString2(const UString &command, 
+    NUpdateArchive::CActionSet &actionSet, UString &postString)
+{
+  for(int i = 0; i < command.Length();)
+  {
+    wchar_t c = MyCharUpper(command[i]);
+    int statePos = kUpdatePairStateIDSet.Find(c);
+    if (statePos < 0)
+    {
+      postString = command.Mid(i);
+      return true;
+    }
+    i++;
+    if (i >= command.Length())
+      return false;
+    int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i]));
+    if (actionPos < 0)
+      return false;
+    actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos);
+    if (kUpdatePairStateNotSupportedActions[statePos] == actionPos)
+      return false;
+    i++;
+  }
+  postString.Empty();
+  return true;
+}
+
+static void ParseUpdateCommandString(CUpdateOptions &options, 
+    const UStringVector &updatePostStrings, 
+    const NUpdateArchive::CActionSet &defaultActionSet)
+{
+  for(int i = 0; i < updatePostStrings.Size(); i++)
+  {
+    const UString &updateString = updatePostStrings[i];
+    if(updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0)
+    {
+      if(options.UpdateArchiveItself)
+      {
+        options.UpdateArchiveItself = false;
+        options.Commands.Delete(0);
+      }
+    }
+    else
+    {
+      NUpdateArchive::CActionSet actionSet = defaultActionSet;
+
+      UString postString;
+      if (!ParseUpdateCommandString2(updateString, actionSet, postString))
+        ThrowUserErrorException();
+      if(postString.IsEmpty())
+      {
+        if(options.UpdateArchiveItself)
+          options.Commands[0].ActionSet = actionSet;
+      }
+      else
+      {
+        if(MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID)
+          ThrowUserErrorException();
+        CUpdateArchiveCommand uc;
+        UString archivePath = postString.Mid(1);
+        if (archivePath.IsEmpty())
+          ThrowUserErrorException();
+        uc.UserArchivePath = archivePath;
+        uc.ActionSet = actionSet;
+        options.Commands.Add(uc);
+      }
+    }
+  }
+}
+
+static const char kByteSymbol = 'B';
+static const char kKiloSymbol = 'K';
+static const char kMegaSymbol = 'M';
+static const char kGigaSymbol = 'G';
+
+static bool ParseComplexSize(const UString &src, UInt64 &result)
+{
+  UString s = src;
+  s.MakeUpper();
+
+  const wchar_t *start = s;
+  const wchar_t *end;
+  UInt64 number = ConvertStringToUInt64(start, &end);
+  int numDigits = (int)(end - start);
+  if (numDigits == 0 || s.Length() > numDigits + 1)
+    return false;
+  if (s.Length() == numDigits)
+  {
+    result = number;
+    return true;
+  }
+  int numBits;
+  switch (s[numDigits])
+  {
+    case kByteSymbol:
+      result = number;
+      return true;
+    case kKiloSymbol:
+      numBits = 10;
+      break;
+    case kMegaSymbol:
+      numBits = 20;
+      break;
+    case kGigaSymbol:
+      numBits = 30;
+      break;
+    default:
+      return false;
+  }
+  if (number >= ((UInt64)1 << (64 - numBits)))
+    return false;
+  result = number << numBits;
+  return true;
+}
+
+static void SetAddCommandOptions(
+    NCommandType::EEnum commandType, 
+    const CParser &parser, 
+    CUpdateOptions &options)
+{
+  NUpdateArchive::CActionSet defaultActionSet;
+  switch(commandType)
+  {
+    case NCommandType::kAdd: 
+      defaultActionSet = NUpdateArchive::kAddActionSet;
+      break;
+    case NCommandType::kDelete: 
+      defaultActionSet = NUpdateArchive::kDeleteActionSet;
+      break;
+    default: 
+      defaultActionSet = NUpdateArchive::kUpdateActionSet;
+  }
+  
+  options.UpdateArchiveItself = true;
+  
+  options.Commands.Clear();
+  CUpdateArchiveCommand updateMainCommand;
+  updateMainCommand.ActionSet = defaultActionSet;
+  options.Commands.Add(updateMainCommand);
+  if(parser[NKey::kUpdate].ThereIs)
+    ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, 
+        defaultActionSet);
+  if(parser[NKey::kWorkingDir].ThereIs)
+  {
+    const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
+    if (postString.IsEmpty())
+      NDirectory::MyGetTempPath(options.WorkingDir);
+    else
+      options.WorkingDir = postString;
+  }
+  options.SfxMode = parser[NKey::kSfx].ThereIs;
+  if (options.SfxMode)
+    options.SfxModule = parser[NKey::kSfx].PostStrings[0];
+
+  if (parser[NKey::kVolume].ThereIs)
+  {
+    const UStringVector &sv = parser[NKey::kVolume].PostStrings;
+    for (int i = 0; i < sv.Size(); i++)
+    {
+      UInt64 size;
+      if (!ParseComplexSize(sv[i], size))
+        ThrowException("Incorrect volume size");
+      options.VolumesSizes.Add(size);
+    }
+  }
+}
+
+static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
+{
+  if (parser[NKey::kProperty].ThereIs)
+  {
+    // options.MethodMode.Properties.Clear();
+    for(int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+    {
+      CProperty property;
+      const UString &postString = parser[NKey::kProperty].PostStrings[i];
+      int index = postString.Find(L'=');
+      if (index < 0)
+        property.Name = postString;
+      else
+      {
+        property.Name = postString.Left(index);
+        property.Value = postString.Mid(index + 1);
+      }
+      properties.Add(property);
+    }
+  }
+}
+
+CArchiveCommandLineParser::CArchiveCommandLineParser(): 
+  parser(sizeof(kSwitchForms) / sizeof(kSwitchForms[0])) {}
+
+void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings,
+    CArchiveCommandLineOptions &options)
+{
+  try
+  {
+    parser.ParseStrings(kSwitchForms, commandStrings);
+  }
+  catch(...) 
+  {
+    ThrowUserErrorException();
+  }
+
+  options.IsInTerminal = MY_IS_TERMINAL(stdin);
+  options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
+  options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
+  options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+  options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+  options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs  || parser[NKey::kHelp3].ThereIs;
+
+  #ifdef _WIN32
+  options.LargePages = false;
+  if (parser[NKey::kLargePages].ThereIs)
+  {
+    const UString &postString = parser[NKey::kLargePages].PostStrings.Front();
+    if (postString.IsEmpty())
+      options.LargePages = true;
+  }
+  #endif
+}
+
+struct CCodePagePair
+{
+  const wchar_t *Name;
+  UINT CodePage;
+};
+
+static CCodePagePair g_CodePagePairs[] = 
+{
+  { L"UTF-8", CP_UTF8 },
+  { L"WIN",   CP_ACP },
+  { L"DOS",   CP_OEMCP }
+};
+
+static const int kNumCodePages = sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0]);
+
+static bool ConvertStringToUInt32(const wchar_t *s, UInt32 &v)
+{
+  const wchar_t *end;
+  UInt64 number = ConvertStringToUInt64(s, &end);
+  if (*end != 0)
+    return false;
+  if (number > (UInt32)0xFFFFFFFF)
+    return false;
+  v = (UInt32)number;
+  return true;
+}
+
+void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options)
+{
+  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+  int numNonSwitchStrings = nonSwitchStrings.Size();
+  if(numNonSwitchStrings < kMinNonSwitchWords)  
+    ThrowUserErrorException();
+
+  if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+    ThrowUserErrorException();
+
+  options.TechMode = parser[NKey::kTechMode].ThereIs;
+
+  if (parser[NKey::kCaseSensitive].ThereIs)
+    g_CaseSensitive = (parser[NKey::kCaseSensitive].PostCharIndex < 0);
+
+  NRecursedType::EEnum recursedType;
+  if (parser[NKey::kRecursed].ThereIs)
+    recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
+  else
+    recursedType = NRecursedType::kNonRecursed;
+
+  UINT codePage = CP_UTF8;
+  if (parser[NKey::kCharSet].ThereIs)
+  {
+    UString name = parser[NKey::kCharSet].PostStrings.Front();
+    name.MakeUpper();
+    int i;
+    for (i = 0; i < kNumCodePages; i++)
+    {
+      const CCodePagePair &pair = g_CodePagePairs[i];
+      if (name.Compare(pair.Name) == 0)
+      {
+        codePage = pair.CodePage;
+        break;
+      }
+    }
+    if (i >= kNumCodePages)
+      ThrowUserErrorException();
+  }
+
+  bool thereAreSwitchIncludes = false;
+  if (parser[NKey::kInclude].ThereIs)
+  {
+    thereAreSwitchIncludes = true;
+    AddSwitchWildCardsToCensor(options.WildcardCensor, 
+        parser[NKey::kInclude].PostStrings, true, recursedType, codePage);
+  }
+  if (parser[NKey::kExclude].ThereIs)
+    AddSwitchWildCardsToCensor(options.WildcardCensor, 
+        parser[NKey::kExclude].PostStrings, false, recursedType, codePage);
+  int curCommandIndex = kCommandIndex + 1;
+  bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && 
+      options.Command.CommandType != NCommandType::kBenchmark && 
+      options.Command.CommandType != NCommandType::kInfo;
+  if (thereIsArchiveName)
+  {
+    if(curCommandIndex >= numNonSwitchStrings)  
+      ThrowUserErrorException();
+    options.ArchiveName = nonSwitchStrings[curCommandIndex++];
+  }
+
+  AddToCensorFromNonSwitchesStrings(
+      curCommandIndex, options.WildcardCensor, 
+      nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage);
+
+  options.YesToAll = parser[NKey::kYes].ThereIs;
+
+  bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+
+  options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
+
+  if(options.PasswordEnabled)
+    options.Password = parser[NKey::kPassword].PostStrings[0];
+
+  options.StdInMode = parser[NKey::kStdIn].ThereIs;
+  options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
+
+  if(isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+  {
+    if (options.StdInMode)
+      ThrowException("Reading archives from stdin is not implemented");
+    if (!options.WildcardCensor.AllAreRelative())
+      ThrowException("Cannot use absolute pathnames for this command");
+
+    NWildcard::CCensor archiveWildcardCensor;
+
+    if (parser[NKey::kArInclude].ThereIs)
+    {
+      AddSwitchWildCardsToCensor(archiveWildcardCensor, 
+        parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, codePage);
+    }
+    if (parser[NKey::kArExclude].ThereIs)
+      AddSwitchWildCardsToCensor(archiveWildcardCensor, 
+      parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, codePage);
+
+    if (thereIsArchiveName)
+      AddCommandLineWildCardToCensr(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed);
+
+    #ifdef _WIN32
+    ConvertToLongNames(archiveWildcardCensor);
+    #endif
+
+    archiveWildcardCensor.ExtendExclude();
+
+    CObjectVector<CDirItem> dirItems;
+    {
+      UStringVector errorPaths;
+      CRecordVector<DWORD> errorCodes;
+      HRESULT res = EnumerateItems(archiveWildcardCensor, dirItems, NULL, errorPaths, errorCodes);
+      if (res != S_OK || errorPaths.Size() > 0)
+        throw "cannot find archive";
+    }
+    UStringVector archivePaths;
+    int i;
+    for (i = 0; i < dirItems.Size(); i++)
+    {
+      const CDirItem &dirItem = dirItems[i];
+      if (!dirItem.IsDirectory())
+        archivePaths.Add(dirItem.FullPath);
+    }
+
+    if (archivePaths.Size() == 0)
+      throw "there is no such archive";
+
+    UStringVector archivePathsFull;
+
+    for (i = 0; i < archivePaths.Size(); i++)
+    {
+      UString fullPath;
+      NFile::NDirectory::MyGetFullPathName(archivePaths[i], fullPath);
+      archivePathsFull.Add(fullPath);
+    }
+    CIntVector indices;
+    SortFileNames(archivePathsFull, indices);
+    options.ArchivePathsSorted.Reserve(indices.Size());
+    options.ArchivePathsFullSorted.Reserve(indices.Size());
+    for (i = 0; i < indices.Size(); i++)
+    {
+      options.ArchivePathsSorted.Add(archivePaths[indices[i]]);
+      options.ArchivePathsFullSorted.Add(archivePathsFull[indices[i]]);
+    }
+
+    if (isExtractGroupCommand)
+    {
+      SetMethodOptions(parser, options.ExtractProperties); 
+      if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal)
+        throw kSameTerminalError;
+      if(parser[NKey::kOutputDir].ThereIs)
+      {
+        options.OutputDir = parser[NKey::kOutputDir].PostStrings[0];
+        NFile::NName::NormalizeDirPathPrefix(options.OutputDir);
+      }
+
+      options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
+      if(parser[NKey::kOverwrite].ThereIs)
+        options.OverwriteMode = 
+            k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex];
+      else if (options.YesToAll)
+        options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+    }
+  }
+  else if(options.Command.IsFromUpdateGroup())
+  {
+    CUpdateOptions &updateOptions = options.UpdateOptions;
+
+    if(parser[NKey::kArchiveType].ThereIs)
+      options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
+
+    SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); 
+    
+    SetMethodOptions(parser, updateOptions.MethodMode.Properties); 
+
+    if (parser[NKey::kShareForWrite].ThereIs)
+      updateOptions.OpenShareForWrite = true;
+
+    options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs;
+
+    if (options.EnablePercents)
+    {
+      if ((options.StdOutMode && !options.IsStdErrTerminal) || 
+         (!options.StdOutMode && !options.IsStdOutTerminal))  
+        options.EnablePercents = false;
+    }
+
+    updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
+    if (updateOptions.EMailMode)
+    {
+      updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
+      if (updateOptions.EMailAddress.Length() > 0)
+        if (updateOptions.EMailAddress[0] == L'.')
+        {
+          updateOptions.EMailRemoveAfter = true;
+          updateOptions.EMailAddress.Delete(0);
+        }
+    }
+
+    updateOptions.StdOutMode = options.StdOutMode;
+    updateOptions.StdInMode = options.StdInMode;
+
+    if (updateOptions.StdOutMode && updateOptions.EMailMode)
+      throw "stdout mode and email mode cannot be combined";
+    if (updateOptions.StdOutMode && options.IsStdOutTerminal)
+      throw kTerminalOutError;
+    if(updateOptions.StdInMode)
+      updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
+
+    #ifdef _WIN32
+    ConvertToLongNames(options.WildcardCensor);
+    #endif
+  }
+  else if(options.Command.CommandType == NCommandType::kBenchmark)
+  {
+    options.NumThreads = (UInt32)-1;
+    options.DictionarySize = (UInt32)-1;
+    options.NumIterations = 1;
+    if (curCommandIndex < numNonSwitchStrings)  
+    {
+      if (!ConvertStringToUInt32(nonSwitchStrings[curCommandIndex++], options.NumIterations))
+        ThrowUserErrorException();
+    }
+    for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+    {
+      UString postString = parser[NKey::kProperty].PostStrings[i];
+      postString.MakeUpper();
+      if (postString.Length() < 2)
+        ThrowUserErrorException();
+      if (postString[0] == 'D')
+      {
+        int pos = 1;
+        if (postString[pos] == '=')
+          pos++;
+        UInt32 logSize;
+        if (!ConvertStringToUInt32((const wchar_t *)postString + pos, logSize))
+          ThrowUserErrorException();
+        if (logSize > 31)
+          ThrowUserErrorException();
+        options.DictionarySize = 1 << logSize;
+      }
+      else if (postString[0] == 'M' && postString[1] == 'T' )
+      {
+        int pos = 2;
+        if (postString[pos] == '=')
+          pos++;
+        if (postString[pos] != 0)
+          if (!ConvertStringToUInt32((const wchar_t *)postString + pos, options.NumThreads))
+            ThrowUserErrorException();
+      }
+      else if (postString[0] == 'M' && postString[1] == '=' )
+      {
+        int pos = 2;
+        if (postString[pos] != 0)
+          options.Method = postString.Mid(2);
+      }
+      else
+        ThrowUserErrorException();
+    }
+  }
+  else if(options.Command.CommandType == NCommandType::kInfo)
+  {
+  }
+  else 
+    ThrowUserErrorException();
+  options.WildcardCensor.ExtendExclude();
+}
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.h b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.h
new file mode 100644 (file)
index 0000000..5f54b06
--- /dev/null
@@ -0,0 +1,104 @@
+// ArchiveCommandLine.h
+
+#ifndef __ARCHIVECOMMANDLINE_H
+#define __ARCHIVECOMMANDLINE_H
+
+#include "Common/Wildcard.h"
+#include "Common/CommandLineParser.h"
+
+#include "Extract.h"
+#include "Update.h"
+
+struct CArchiveCommandLineException: public AString
+{
+  CArchiveCommandLineException(const char *errorMessage): AString(errorMessage) {}
+};
+
+namespace NCommandType { enum EEnum
+{
+  kAdd = 0,
+  kUpdate,
+  kDelete,
+  kTest,
+  kExtract,
+  kFullExtract,
+  kList,
+  kBenchmark,
+  kInfo
+};}
+
+namespace NRecursedType { enum EEnum
+{
+  kRecursed,
+  kWildCardOnlyRecursed,
+  kNonRecursed
+};}
+
+struct CArchiveCommand
+{
+  NCommandType::EEnum CommandType;
+  bool IsFromExtractGroup() const;
+  bool IsFromUpdateGroup() const;
+  bool IsTestMode() const { return CommandType == NCommandType::kTest; }
+  NExtract::NPathMode::EEnum GetPathMode() const;
+};
+
+struct CArchiveCommandLineOptions
+{
+  bool HelpMode;
+
+  #ifdef _WIN32
+  bool LargePages;
+  #endif
+
+  bool IsInTerminal;
+  bool IsStdOutTerminal;
+  bool IsStdErrTerminal;
+  bool StdInMode;
+  bool StdOutMode;
+  bool EnableHeaders;
+
+  bool YesToAll;
+  bool ShowDialog;
+  // NWildcard::CCensor ArchiveWildcardCensor;
+  NWildcard::CCensor WildcardCensor;
+
+  CArchiveCommand Command; 
+  UString ArchiveName;
+
+  bool PasswordEnabled;
+  UString Password;
+
+  bool TechMode;
+  // Extract
+  bool AppendName;
+  UString OutputDir;
+  NExtract::NOverwriteMode::EEnum OverwriteMode;
+  UStringVector ArchivePathsSorted;
+  UStringVector ArchivePathsFullSorted;
+  CObjectVector<CProperty> ExtractProperties;
+
+  CUpdateOptions UpdateOptions;
+  UString ArcType;
+  bool EnablePercents;
+
+  // Benchmark 
+  UInt32 NumIterations;
+  UInt32 NumThreads;
+  UInt32 DictionarySize;
+  UString Method;
+
+
+  CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {};
+};
+
+class CArchiveCommandLineParser
+{
+  NCommandLineParser::CParser parser;
+public:
+  CArchiveCommandLineParser();
+  void Parse1(const UStringVector &commandStrings, CArchiveCommandLineOptions &options);
+  void Parse2(CArchiveCommandLineOptions &options);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
new file mode 100644 (file)
index 0000000..c3913e1
--- /dev/null
@@ -0,0 +1,479 @@
+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#include "ArchiveExtractCallback.h"
+
+#include "Common/Wildcard.h"
+#include "Common/StringConvert.h"
+#include "Common/ComTry.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/Time.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+#include "OpenArchive.h"
+
+using namespace NWindows;
+
+static const wchar_t *kCantAutoRename = L"ERROR: Can not create file with auto name";
+static const wchar_t *kCantRenameFile = L"ERROR: Can not rename existing file ";
+static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
+
+
+void CArchiveExtractCallback::Init(
+    IInArchive *archiveHandler,
+    IFolderArchiveExtractCallback *extractCallback2,
+    bool stdOutMode,
+    const UString &directoryPath, 
+    const UStringVector &removePathParts,
+    const UString &itemDefaultName,
+    const FILETIME &utcLastWriteTimeDefault,
+    UInt32 attributesDefault,
+    UInt64 packSize)
+{
+  _stdOutMode = stdOutMode;
+  _numErrors = 0;
+  _unpTotal = 1;
+  _packTotal = packSize;
+
+  _extractCallback2 = extractCallback2;
+  _compressProgress.Release();
+  _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
+
+  LocalProgressSpec->Init(extractCallback2, true);
+  LocalProgressSpec->SendProgress = false;
+
+  _itemDefaultName = itemDefaultName;
+  _utcLastWriteTimeDefault = utcLastWriteTimeDefault;
+  _attributesDefault = attributesDefault;
+  _removePathParts = removePathParts;
+  _archiveHandler = archiveHandler;
+  _directoryPath = directoryPath;
+  NFile::NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
+{
+  COM_TRY_BEGIN
+  _unpTotal = size;
+  if (!_multiArchives && _extractCallback2)
+    return _extractCallback2->SetTotal(size);
+  return S_OK;
+  COM_TRY_END
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+  const UInt64 kMax = (UInt64)1 << 31;
+  while (v1 > kMax)
+  {
+    v1 >>= 1;
+    v2 >>= 1;
+  }
+}
+
+static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
+{
+  NormalizeVals(packTotal, unpTotal);
+  NormalizeVals(unpCur, unpTotal);
+  if (unpTotal == 0)
+    unpTotal = 1;
+  return unpCur * packTotal / unpTotal;
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
+{
+  COM_TRY_BEGIN
+  if (!_extractCallback2)
+    return S_OK;
+
+  if (_multiArchives)
+  {
+    if (completeValue != NULL)
+    {
+      UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal);
+      return _extractCallback2->SetCompleted(&packCur);
+    }
+  }
+  return _extractCallback2->SetCompleted(completeValue);
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+  COM_TRY_BEGIN
+  return _localProgress->SetRatioInfo(inSize, outSize);
+  COM_TRY_END
+}
+
+void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath)
+{
+  fullPath = _directoryPath;
+  for(int i = 0; i < dirPathParts.Size(); i++)
+  {
+    if (i > 0)
+      fullPath += wchar_t(NFile::NName::kDirDelimiter);
+    fullPath += dirPathParts[i];
+    NFile::NDirectory::MyCreateDirectory(fullPath);
+  }
+}
+
+static UString MakePathNameFromParts(const UStringVector &parts)
+{
+  UString result;
+  for(int i = 0; i < parts.Size(); i++)
+  {
+    if(i != 0)
+      result += wchar_t(NFile::NName::kDirDelimiter);
+    result += parts[i];
+  }
+  return result;
+}
+
+
+HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+{
+  filetimeIsDefined = false;
+  NCOM::CPropVariant prop;
+  RINOK(_archiveHandler->GetProperty(index, propID, &prop));
+  if (prop.vt == VT_FILETIME)
+  {
+    filetime = prop.filetime;
+    filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
+  }
+  else if (prop.vt != VT_EMPTY)
+    return E_FAIL;
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+  COM_TRY_BEGIN
+  *outStream = 0;
+  _outFileStream.Release();
+
+  _encrypted = false;
+  _isSplit = false;
+  _curSize = 0;
+
+  UString fullPath;
+
+  RINOK(GetArchiveItemPath(_archiveHandler, index, _itemDefaultName, fullPath));
+  RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.IsDirectory));
+
+  _filePath = fullPath;
+
+  {
+    NCOM::CPropVariant prop;
+    RINOK(_archiveHandler->GetProperty(index, kpidPosition, &prop));
+    if (prop.vt != VT_EMPTY)
+    {
+      if (prop.vt != VT_UI8)
+        return E_FAIL;
+      _position = prop.uhVal.QuadPart;
+      _isSplit = true;
+    }
+  }
+    
+  RINOK(IsArchiveItemProp(_archiveHandler, index, kpidEncrypted, _encrypted));
+
+  bool newFileSizeDefined;
+  UInt64 newFileSize;
+  {
+    NCOM::CPropVariant prop;
+    RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop));
+    newFileSizeDefined = (prop.vt != VT_EMPTY);
+    if (newFileSizeDefined)
+    {
+      newFileSize = ConvertPropVariantToUInt64(prop);
+      _curSize = newFileSize;
+    }
+  }
+
+  if(askExtractMode == NArchive::NExtract::NAskMode::kExtract)
+  {
+    if (_stdOutMode)
+    {
+      CMyComPtr<ISequentialOutStream> outStreamLoc = new CStdOutFileStream;
+      *outStream = outStreamLoc.Detach();
+      return S_OK;
+    }
+
+    {
+      NCOM::CPropVariant prop;
+      RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &prop));
+      if (prop.vt == VT_EMPTY)
+      {
+        _processedFileInfo.Attributes = _attributesDefault;
+        _processedFileInfo.AttributesAreDefined = false;
+      }
+      else
+      {
+        if (prop.vt != VT_UI4)
+          return E_FAIL;
+        _processedFileInfo.Attributes = prop.ulVal;
+        _processedFileInfo.AttributesAreDefined = true;
+      }
+    }
+
+    RINOK(GetTime(index, kpidCreationTime, _processedFileInfo.CreationTime,
+        _processedFileInfo.IsCreationTimeDefined));
+    RINOK(GetTime(index, kpidLastWriteTime, _processedFileInfo.LastWriteTime, 
+        _processedFileInfo.IsLastWriteTimeDefined));
+    RINOK(GetTime(index, kpidLastAccessTime, _processedFileInfo.LastAccessTime,
+        _processedFileInfo.IsLastAccessTimeDefined));
+
+    bool isAnti = false;
+    RINOK(IsArchiveItemProp(_archiveHandler, index, kpidIsAnti, isAnti));
+
+    UStringVector pathParts; 
+    SplitPathToParts(fullPath, pathParts);
+    
+    if(pathParts.IsEmpty())
+      return E_FAIL;
+    int numRemovePathParts = 0;
+    switch(_pathMode)
+    {
+      case NExtract::NPathMode::kFullPathnames:
+        break;
+      case NExtract::NPathMode::kCurrentPathnames:
+      {
+        numRemovePathParts = _removePathParts.Size();
+        if (pathParts.Size() <= numRemovePathParts)
+          return E_FAIL;
+        for (int i = 0; i < numRemovePathParts; i++)
+          if (_removePathParts[i].CompareNoCase(pathParts[i]) != 0)
+            return E_FAIL;
+        break;
+      }
+      case NExtract::NPathMode::kNoPathnames:
+      {
+        numRemovePathParts = pathParts.Size() - 1;
+        break;
+      }
+    }
+    pathParts.Delete(0, numRemovePathParts);
+    MakeCorrectPath(pathParts);
+    UString processedPath = MakePathNameFromParts(pathParts);
+    if (!isAnti)
+    {
+      if (!_processedFileInfo.IsDirectory)
+      {
+        if (!pathParts.IsEmpty())
+          pathParts.DeleteBack();
+      }
+    
+      if (!pathParts.IsEmpty())
+      {
+        UString fullPathNew;
+        CreateComplexDirectory(pathParts, fullPathNew);
+        if (_processedFileInfo.IsDirectory)
+          NFile::NDirectory::SetDirTime(fullPathNew, 
+            (WriteCreated && _processedFileInfo.IsCreationTimeDefined) ? &_processedFileInfo.CreationTime : NULL, 
+            (WriteAccessed && _processedFileInfo.IsLastAccessTimeDefined) ? &_processedFileInfo.LastAccessTime : NULL, 
+            (WriteModified && _processedFileInfo.IsLastWriteTimeDefined) ? &_processedFileInfo.LastWriteTime : &_utcLastWriteTimeDefault);
+      }
+    }
+
+
+    UString fullProcessedPath = _directoryPath + processedPath;
+
+    if(_processedFileInfo.IsDirectory)
+    {
+      _diskFilePath = fullProcessedPath;
+      if (isAnti)
+        NFile::NDirectory::MyRemoveDirectory(_diskFilePath);
+      return S_OK;
+    }
+
+    if (!_isSplit)
+    {
+    NFile::NFind::CFileInfoW fileInfo;
+    if(NFile::NFind::FindFile(fullProcessedPath, fileInfo))
+    {
+      switch(_overwriteMode)
+      {
+        case NExtract::NOverwriteMode::kSkipExisting:
+          return S_OK;
+        case NExtract::NOverwriteMode::kAskBefore:
+        {
+          Int32 overwiteResult;
+          RINOK(_extractCallback2->AskOverwrite(
+              fullProcessedPath, &fileInfo.LastWriteTime, &fileInfo.Size, fullPath, 
+              _processedFileInfo.IsLastWriteTimeDefined ? &_processedFileInfo.LastWriteTime : NULL, 
+              newFileSizeDefined ? &newFileSize : NULL, 
+              &overwiteResult))
+
+          switch(overwiteResult)
+          {
+            case NOverwriteAnswer::kCancel:
+              return E_ABORT;
+            case NOverwriteAnswer::kNo:
+              return S_OK;
+            case NOverwriteAnswer::kNoToAll:
+              _overwriteMode = NExtract::NOverwriteMode::kSkipExisting;
+              return S_OK;
+            case NOverwriteAnswer::kYesToAll:
+              _overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+              break;
+            case NOverwriteAnswer::kYes:
+              break;
+            case NOverwriteAnswer::kAutoRename:
+              _overwriteMode = NExtract::NOverwriteMode::kAutoRename;
+              break;
+            default:
+              return E_FAIL;
+          }
+        }
+      }
+      if (_overwriteMode == NExtract::NOverwriteMode::kAutoRename)
+      {
+        if (!AutoRenamePath(fullProcessedPath))
+        {
+          UString message = UString(kCantAutoRename) + fullProcessedPath;
+          RINOK(_extractCallback2->MessageError(message));
+          return E_FAIL;
+        }
+      }
+      else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting)
+      {
+        UString existPath = fullProcessedPath;
+        if (!AutoRenamePath(existPath))
+        {
+          UString message = kCantAutoRename + fullProcessedPath;
+          RINOK(_extractCallback2->MessageError(message));
+          return E_FAIL;
+        }
+        if(!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath))
+        {
+          UString message = UString(kCantRenameFile) + fullProcessedPath;
+          RINOK(_extractCallback2->MessageError(message));
+          return E_FAIL;
+        }
+      }
+      else
+        if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
+        {
+          UString message = UString(kCantDeleteOutputFile) +  fullProcessedPath;
+          RINOK(_extractCallback2->MessageError(message));
+          return S_OK;
+          // return E_FAIL;
+        }
+    }
+    }
+    if (!isAnti)
+    {
+      _outFileStreamSpec = new COutFileStream;
+      CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+      if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+      {
+        // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+        {
+          UString message = L"can not open output file " + fullProcessedPath;
+          RINOK(_extractCallback2->MessageError(message));
+          return S_OK;
+        }
+      }
+      if (_isSplit)
+      {
+        RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
+      }
+      _outFileStream = outStreamLoc;
+      *outStream = outStreamLoc.Detach();
+    }
+    _diskFilePath = fullProcessedPath;
+  }
+  else
+  {
+    *outStream = NULL;
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
+{
+  COM_TRY_BEGIN
+  _extractMode = false;
+  switch (askExtractMode)
+  {
+    case NArchive::NExtract::NAskMode::kExtract:
+      _extractMode = true;
+  };
+  return _extractCallback2->PrepareOperation(_filePath, _processedFileInfo.IsDirectory, 
+      askExtractMode, _isSplit ? &_position: 0);
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+  COM_TRY_BEGIN
+  switch(operationResult)
+  {
+    case NArchive::NExtract::NOperationResult::kOK:
+    case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+    case NArchive::NExtract::NOperationResult::kCRCError:
+    case NArchive::NExtract::NOperationResult::kDataError:
+      break;
+    default:
+      _outFileStream.Release();
+      return E_FAIL;
+  }
+  if (_outFileStream != NULL)
+  {
+    _outFileStreamSpec->SetTime(
+        (WriteCreated && _processedFileInfo.IsCreationTimeDefined) ? &_processedFileInfo.CreationTime : NULL, 
+        (WriteAccessed && _processedFileInfo.IsLastAccessTimeDefined) ? &_processedFileInfo.LastAccessTime : NULL, 
+        (WriteModified && _processedFileInfo.IsLastWriteTimeDefined) ? &_processedFileInfo.LastWriteTime : &_utcLastWriteTimeDefault);
+    _curSize = _outFileStreamSpec->ProcessedSize;
+    RINOK(_outFileStreamSpec->Close());
+    _outFileStream.Release();
+  }
+  UnpackSize += _curSize;
+  if (_processedFileInfo.IsDirectory)
+    NumFolders++;
+  else
+    NumFiles++;
+
+  if (_extractMode && _processedFileInfo.AttributesAreDefined)
+    NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes);
+  RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+  return S_OK;
+  COM_TRY_END
+}
+
+/*
+STDMETHODIMP CArchiveExtractCallback::GetInStream(
+    const wchar_t *name, ISequentialInStream **inStream)
+{
+  COM_TRY_BEGIN
+  CInFileStream *inFile = new CInFileStream;
+  CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
+  if (!inFile->Open(_srcDirectoryPrefix + name))
+    return ::GetLastError();
+  *inStream = inStreamTemp.Detach();
+  return S_OK;
+  COM_TRY_END
+}
+*/
+
+STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+{
+  COM_TRY_BEGIN
+  if (!_cryptoGetTextPassword)
+  {
+    RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, 
+        &_cryptoGetTextPassword));
+  }
+  return _cryptoGetTextPassword->CryptoGetTextPassword(password);
+  COM_TRY_END
+}
+
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.h
new file mode 100644 (file)
index 0000000..fd30d64
--- /dev/null
@@ -0,0 +1,139 @@
+// ArchiveExtractCallback.h
+
+#ifndef __ARCHIVEEXTRACTCALLBACK_H
+#define __ARCHIVEEXTRACTCALLBACK_H
+
+#include "../../Archive/IArchive.h"
+#include "IFileExtractCallback.h"
+
+#include "Common/MyString.h"
+#include "Common/MyCom.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../IPassword.h"
+
+#include "ExtractMode.h"
+
+class CArchiveExtractCallback: 
+  public IArchiveExtractCallback,
+  // public IArchiveVolumeExtractCallback,
+  public ICryptoGetTextPassword,
+  public ICompressProgressInfo,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo)
+  // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
+
+  // IProgress
+  STDMETHOD(SetTotal)(UInt64 size);
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+  // IExtractCallBack
+  STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
+  STDMETHOD(PrepareOperation)(Int32 askExtractMode);
+  STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
+
+  // IArchiveVolumeExtractCallback
+  // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
+
+  // ICryptoGetTextPassword
+  STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
+
+private:
+  CMyComPtr<IInArchive> _archiveHandler;
+  CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
+  CMyComPtr<ICompressProgressInfo> _compressProgress;
+  CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+  UString _directoryPath;
+  NExtract::NPathMode::EEnum _pathMode;
+  NExtract::NOverwriteMode::EEnum _overwriteMode;
+
+  UString _filePath;
+  UInt64 _position;
+  bool _isSplit;
+
+  UString _diskFilePath;
+
+  bool _extractMode;
+
+  bool WriteModified;
+  bool WriteCreated;
+  bool WriteAccessed;
+
+  bool _encrypted;
+
+  struct CProcessedFileInfo
+  {
+    FILETIME CreationTime;
+    FILETIME LastWriteTime;
+    FILETIME LastAccessTime;
+    UInt32 Attributes;
+  
+    bool IsCreationTimeDefined;
+    bool IsLastWriteTimeDefined;
+    bool IsLastAccessTimeDefined;
+
+    bool IsDirectory;
+    bool AttributesAreDefined;
+  } _processedFileInfo;
+
+  UInt64 _curSize;
+  COutFileStream *_outFileStreamSpec;
+  CMyComPtr<ISequentialOutStream> _outFileStream;
+  UStringVector _removePathParts;
+
+  UString _itemDefaultName;
+  FILETIME _utcLastWriteTimeDefault;
+  UInt32 _attributesDefault;
+  bool _stdOutMode;
+
+  void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath);
+  HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+public:
+  CArchiveExtractCallback():
+      WriteModified(true),
+      WriteCreated(false),
+      WriteAccessed(false),
+      _multiArchives(false)
+  {
+    LocalProgressSpec = new CLocalProgress();
+    _localProgress = LocalProgressSpec;
+  }
+
+  CLocalProgress *LocalProgressSpec;
+  CMyComPtr<ICompressProgressInfo> _localProgress;
+  UInt64 _packTotal;
+  UInt64 _unpTotal;
+
+  bool _multiArchives;
+  UInt64 NumFolders;
+  UInt64 NumFiles;
+  UInt64 UnpackSize;
+  
+  void InitForMulti(bool multiArchives, 
+      NExtract::NPathMode::EEnum pathMode,
+      NExtract::NOverwriteMode::EEnum overwriteMode) 
+  { 
+    _multiArchives = multiArchives; NumFolders = NumFiles = UnpackSize = 0; 
+    _pathMode = pathMode;
+    _overwriteMode = overwriteMode;
+  }
+
+  void Init(
+      IInArchive *archiveHandler, 
+      IFolderArchiveExtractCallback *extractCallback2,
+      bool stdOutMode,
+      const UString &directoryPath,
+      const UStringVector &removePathParts,
+      const UString &itemDefaultName,
+      const FILETIME &utcLastWriteTimeDefault, 
+      UInt32 attributesDefault,
+      UInt64 packSize);
+
+  UInt64 _numErrors;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveName.cpp b/lzma/CPP/7zip/UI/Common/ArchiveName.cpp
new file mode 100644 (file)
index 0000000..2d50ede
--- /dev/null
@@ -0,0 +1,46 @@
+// ArchiveName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileFind.h"
+#include "Windows/FileDir.h"
+
+using namespace NWindows;
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
+{
+  UString resultName = L"Archive";
+  if (fromPrev)
+  {
+    UString dirPrefix;
+    if (NFile::NDirectory::GetOnlyDirPrefix(srcName, dirPrefix))
+    {
+      if (dirPrefix.Length() > 0)
+        if (dirPrefix[dirPrefix.Length() - 1] == '\\')
+        {
+          dirPrefix.Delete(dirPrefix.Length() - 1);
+          NFile::NFind::CFileInfoW fileInfo;
+          if (NFile::NFind::FindFile(dirPrefix, fileInfo))
+            resultName = fileInfo.Name;
+        }
+    }
+  }
+  else
+  {
+    NFile::NFind::CFileInfoW fileInfo;
+    if (!NFile::NFind::FindFile(srcName, fileInfo))
+      return resultName;
+    resultName = fileInfo.Name;
+    if (!fileInfo.IsDirectory() && !keepName)
+    {
+      int dotPos = resultName.ReverseFind('.');
+      if (dotPos > 0)
+      {
+        UString archiveName2 = resultName.Left(dotPos);
+        if (archiveName2.ReverseFind('.') < 0)
+          resultName = archiveName2;
+      }
+    }
+  }
+  return resultName;
+}
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveName.h b/lzma/CPP/7zip/UI/Common/ArchiveName.h
new file mode 100644 (file)
index 0000000..9513fb2
--- /dev/null
@@ -0,0 +1,10 @@
+// ArchiveName.h
+
+#ifndef __ARCHIVENAME_H
+#define __ARCHIVENAME_H
+
+#include "Common/MyString.h"
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
new file mode 100644 (file)
index 0000000..2f0c41a
--- /dev/null
@@ -0,0 +1,137 @@
+// ArchiveOpenCallback.cpp
+
+#include "StdAfx.h"
+
+#include "ArchiveOpenCallback.h"
+
+#include "Common/StringConvert.h"
+#include "Common/ComTry.h"
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+using namespace NWindows;
+
+STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
+{
+  COM_TRY_BEGIN
+  if (!Callback)
+    return S_OK;
+  return Callback->SetTotal(files, bytes);
+  COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
+{
+  COM_TRY_BEGIN
+  if (!Callback)
+    return S_OK;
+  return Callback->SetTotal(files, bytes);
+  COM_TRY_END
+}
+  
+STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
+{
+  COM_TRY_BEGIN
+  NCOM::CPropVariant propVariant;
+  if (_subArchiveMode)
+  {
+    switch(propID)
+    {
+      case kpidName:
+        propVariant = _subArchiveName;
+        break;
+    }
+    propVariant.Detach(value);
+    return S_OK;
+  }
+  switch(propID)
+  {
+    case kpidName:
+      propVariant = _fileInfo.Name;
+      break;
+    case kpidIsFolder:
+      propVariant = _fileInfo.IsDirectory();
+      break;
+    case kpidSize:
+      propVariant = _fileInfo.Size;
+      break;
+    case kpidAttributes:
+      propVariant = (UInt32)_fileInfo.Attributes;
+      break;
+    case kpidLastAccessTime:
+      propVariant = _fileInfo.LastAccessTime;
+      break;
+    case kpidCreationTime:
+      propVariant = _fileInfo.CreationTime;
+      break;
+    case kpidLastWriteTime:
+      propVariant = _fileInfo.LastWriteTime;
+      break;
+    }
+  propVariant.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+int COpenCallbackImp::FindName(const UString &name)
+{
+  for (int i = 0; i < FileNames.Size(); i++)
+    if (name.CompareNoCase(FileNames[i]) == 0)
+      return i;
+  return -1;
+}
+
+struct CInFileStreamVol: public CInFileStream
+{
+  UString Name;
+  COpenCallbackImp *OpenCallbackImp;
+  CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
+  ~CInFileStreamVol()
+  {
+    int index = OpenCallbackImp->FindName(Name);
+    if (index >= 0)
+      OpenCallbackImp->FileNames.Delete(index);
+  }
+};
+
+STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
+{
+  COM_TRY_BEGIN
+  if (_subArchiveMode)
+    return S_FALSE;
+  if (Callback)
+  {
+    RINOK(Callback->CheckBreak());
+  }
+  *inStream = NULL;
+  UString fullPath = _folderPrefix + name;
+  if (!NFile::NFind::FindFile(fullPath, _fileInfo))
+    return S_FALSE;
+  if (_fileInfo.IsDirectory())
+    return S_FALSE;
+  CInFileStreamVol *inFile = new CInFileStreamVol;
+  CMyComPtr<IInStream> inStreamTemp = inFile;
+  if (!inFile->Open(fullPath))
+    return ::GetLastError();
+  *inStream = inStreamTemp.Detach();
+  inFile->Name = name;
+  inFile->OpenCallbackImp = this;
+  inFile->OpenCallbackRef = this;
+  FileNames.Add(name);
+  TotalSize += _fileInfo.Size;
+  return S_OK;
+  COM_TRY_END
+}
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
+{
+  COM_TRY_BEGIN
+  if (!Callback)
+    return E_NOTIMPL;
+  return Callback->CryptoGetTextPassword(password);
+  COM_TRY_END
+}
+#endif
+  
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.h
new file mode 100644 (file)
index 0000000..12b2b32
--- /dev/null
@@ -0,0 +1,93 @@
+// ArchiveOpenCallback.h
+
+#ifndef __ARCHIVE_OPEN_CALLBACK_H
+#define __ARCHIVE_OPEN_CALLBACK_H
+
+#include "Common/MyString.h"
+#include "Common/MyCom.h"
+#include "Windows/FileFind.h"
+
+#ifndef _NO_CRYPTO
+#include "../../IPassword.h"
+#endif  
+#include "../../Archive/IArchive.h"
+
+struct IOpenCallbackUI
+{
+  virtual HRESULT CheckBreak() = 0;
+  virtual HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes) = 0;
+  virtual HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes) = 0;
+  #ifndef _NO_CRYPTO
+  virtual HRESULT CryptoGetTextPassword(BSTR *password) = 0;
+  virtual HRESULT GetPasswordIfAny(UString &password) = 0;
+  virtual bool WasPasswordAsked() = 0;
+  virtual void ClearPasswordWasAskedFlag() = 0;
+  #endif  
+};
+
+class COpenCallbackImp: 
+  public IArchiveOpenCallback,
+  public IArchiveOpenVolumeCallback,
+  public IArchiveOpenSetSubArchiveName,
+  #ifndef _NO_CRYPTO
+  public ICryptoGetTextPassword,
+  #endif  
+  public CMyUnknownImp
+{
+public:
+  #ifndef _NO_CRYPTO
+  MY_UNKNOWN_IMP3(
+      IArchiveOpenVolumeCallback, 
+      ICryptoGetTextPassword,
+      IArchiveOpenSetSubArchiveName
+      )
+  #else
+  MY_UNKNOWN_IMP2(
+      IArchiveOpenVolumeCallback, 
+      IArchiveOpenSetSubArchiveName
+      )
+  #endif
+
+  STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
+  STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
+
+  // IArchiveOpenVolumeCallback
+  STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
+  STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream);
+
+  #ifndef _NO_CRYPTO
+  // ICryptoGetTextPassword
+  STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+  #endif
+
+  STDMETHOD(SetSubArchiveName(const wchar_t *name))
+  {
+    _subArchiveMode = true;
+    _subArchiveName = name;
+    return  S_OK;
+  }
+
+private:
+  UString _folderPrefix;
+  NWindows::NFile::NFind::CFileInfoW _fileInfo;
+  bool _subArchiveMode;
+  UString _subArchiveName;
+public:
+  UStringVector FileNames;
+  IOpenCallbackUI *Callback;
+  UInt64 TotalSize;
+
+  COpenCallbackImp(): Callback(NULL) {}
+  void Init(const UString &folderPrefix,  const UString &fileName)
+  {
+    _folderPrefix = folderPrefix;
+    if (!NWindows::NFile::NFind::FindFile(_folderPrefix + fileName, _fileInfo))
+      throw 1;
+    FileNames.Clear();
+    _subArchiveMode = false;
+    TotalSize = 0;
+  }
+  int FindName(const UString &name);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/DefaultName.cpp b/lzma/CPP/7zip/UI/Common/DefaultName.cpp
new file mode 100644 (file)
index 0000000..8ee7c04
--- /dev/null
@@ -0,0 +1,26 @@
+// DefaultName.cpp
+
+#include "StdAfx.h"
+
+#include "DefaultName.h"
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+UString GetDefaultName2(const UString &fileName, 
+    const UString &extension, const UString &addSubExtension)
+{
+  int extLength = extension.Length();
+  int fileNameLength = fileName.Length();
+  if (fileNameLength > extLength + 1)
+  {
+    int dotPos = fileNameLength - (extLength + 1);
+    if (fileName[dotPos] == '.')
+      if (extension.CompareNoCase(fileName.Mid(dotPos + 1)) == 0)
+        return fileName.Left(dotPos) + addSubExtension;
+  }
+  int dotPos = fileName.ReverseFind(L'.');
+  if (dotPos > 0)
+    return fileName.Left(dotPos) + addSubExtension;
+  return kEmptyFileAlias;
+}
+
diff --git a/lzma/CPP/7zip/UI/Common/DefaultName.h b/lzma/CPP/7zip/UI/Common/DefaultName.h
new file mode 100644 (file)
index 0000000..a702cb0
--- /dev/null
@@ -0,0 +1,11 @@
+// DefaultName.h
+
+#ifndef __DEFAULTNAME_H
+#define __DEFAULTNAME_H
+
+#include "Common/MyString.h"
+
+UString GetDefaultName2(const UString &fileName, 
+    const UString &extension, const UString &addSubExtension);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/DirItem.h b/lzma/CPP/7zip/UI/Common/DirItem.h
new file mode 100644 (file)
index 0000000..89bd4cd
--- /dev/null
@@ -0,0 +1,34 @@
+// DirItem.h
+
+#ifndef __DIR_ITEM_H
+#define __DIR_ITEM_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+struct CDirItem
+{ 
+  UInt32 Attributes;
+  FILETIME CreationTime;
+  FILETIME LastAccessTime;
+  FILETIME LastWriteTime;
+  UInt64 Size;
+  UString Name;
+  UString FullPath;
+  bool IsDirectory() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
+};
+
+struct CArchiveItem
+{ 
+  bool IsDirectory;
+  // DWORD Attributes;
+  // NWindows::NCOM::CPropVariant LastWriteTime;
+  FILETIME LastWriteTime;
+  bool SizeIsDefined;
+  UInt64 Size;
+  UString Name;
+  bool Censored;
+  int IndexInServer;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp b/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
new file mode 100644 (file)
index 0000000..454092e
--- /dev/null
@@ -0,0 +1,281 @@
+// EnumDirItems.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+#include "Common/MyCom.h"
+
+#include "EnumDirItems.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+void AddDirFileInfo(
+    const UString &prefix,        // prefix for logical path
+    const UString &fullPathName,  // path on disk: can be relative to some basePrefix
+    const NFind::CFileInfoW &fileInfo, 
+    CObjectVector<CDirItem> &dirItems)
+{
+  CDirItem item;
+  item.Attributes = fileInfo.Attributes;
+  item.Size = fileInfo.Size;
+  item.CreationTime = fileInfo.CreationTime;
+  item.LastAccessTime = fileInfo.LastAccessTime;
+  item.LastWriteTime = fileInfo.LastWriteTime;
+  item.Name = prefix + fileInfo.Name;
+  item.FullPath = fullPathName;
+  dirItems.Add(item);
+}
+
+static void EnumerateDirectory(
+    const UString &baseFolderPrefix,  // base (disk) prefix for scanning  
+    const UString &directory,         // additional disk prefix starting from baseFolderPrefix
+    const UString &prefix,            // logical prefix
+    CObjectVector<CDirItem> &dirItems,
+    UStringVector &errorPaths,
+    CRecordVector<DWORD> &errorCodes)
+{
+  NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
+  for (;;)
+  { 
+    NFind::CFileInfoW fileInfo;
+    bool found;
+    if (!enumerator.Next(fileInfo, found))
+    {
+      errorCodes.Add(::GetLastError());
+      errorPaths.Add(baseFolderPrefix + directory);
+      return;
+    }
+    if (!found)
+      break;
+    AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
+    if (fileInfo.IsDirectory())
+    {
+      EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter), 
+          prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes);
+    }
+  }
+}
+
+void EnumerateDirItems(
+    const UString &baseFolderPrefix,   // base (disk) prefix for scanning  
+    const UStringVector &fileNames,    // names relative to baseFolderPrefix
+    const UString &archiveNamePrefix, 
+    CObjectVector<CDirItem> &dirItems,
+    UStringVector &errorPaths,
+    CRecordVector<DWORD> &errorCodes)
+{
+  for(int i = 0; i < fileNames.Size(); i++)
+  {
+    const UString &fileName = fileNames[i];
+    NFind::CFileInfoW fileInfo;
+    if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo))
+    {
+      errorCodes.Add(::GetLastError());
+      errorPaths.Add(baseFolderPrefix + fileName);
+      continue;
+    }
+    AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
+    if (fileInfo.IsDirectory())
+    {
+      EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter), 
+          archiveNamePrefix + fileInfo.Name +  wchar_t(kDirDelimiter), 
+          dirItems, errorPaths, errorCodes);
+    }
+  }
+}
+
+static HRESULT EnumerateDirItems(
+    const NWildcard::CCensorNode &curNode, 
+    const UString &diskPrefix,        // full disk path prefix 
+    const UString &archivePrefix,     // prefix from root
+    const UStringVector &addArchivePrefix,  // prefix from curNode
+    CObjectVector<CDirItem> &dirItems, 
+    bool enterToSubFolders,
+    IEnumDirItemCallback *callback,
+    UStringVector &errorPaths,
+    CRecordVector<DWORD> &errorCodes)
+{
+  if (!enterToSubFolders)
+    if (curNode.NeedCheckSubDirs())
+      enterToSubFolders = true;
+  if (callback)
+    RINOK(callback->CheckBreak());
+
+  // try direct_names case at first
+  if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
+  {
+    // check that all names are direct
+    int i;
+    for (i = 0; i < curNode.IncludeItems.Size(); i++)
+    {
+      const NWildcard::CItem &item = curNode.IncludeItems[i];
+      if (item.Recursive || item.PathParts.Size() != 1)
+        break;
+      const UString &name = item.PathParts.Front();
+      if (name.IsEmpty() || DoesNameContainWildCard(name))
+        break;
+    }
+    if (i == curNode.IncludeItems.Size())
+    {
+      // all names are direct (no wildcards)
+      // so we don't need file_system's dir enumerator
+      CRecordVector<bool> needEnterVector;
+      for (i = 0; i < curNode.IncludeItems.Size(); i++)
+      {
+        const NWildcard::CItem &item = curNode.IncludeItems[i];
+        const UString &name = item.PathParts.Front();
+        const UString fullPath = diskPrefix + name;
+        NFind::CFileInfoW fileInfo;
+        if (!NFind::FindFile(fullPath, fileInfo))
+        {
+          errorCodes.Add(::GetLastError());
+          errorPaths.Add(fullPath);
+          continue;
+        }
+        bool isDir = fileInfo.IsDirectory();
+        if (isDir && !item.ForDir || !isDir && !item.ForFile)
+        {
+          errorCodes.Add((DWORD)E_FAIL);
+          errorPaths.Add(fullPath);
+          continue;
+        }
+        const UString realName = fileInfo.Name;
+        const UString realDiskPath = diskPrefix + realName;
+        {
+          UStringVector pathParts;
+          pathParts.Add(fileInfo.Name);
+          if (curNode.CheckPathToRoot(false, pathParts, !isDir))
+            continue;
+        }
+        AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems);
+        if (!isDir)
+          continue;
+        
+        UStringVector addArchivePrefixNew;
+        const NWildcard::CCensorNode *nextNode = 0;
+        int index = curNode.FindSubNode(name);
+        if (index >= 0)
+        {
+          for (int t = needEnterVector.Size(); t <= index; t++)
+            needEnterVector.Add(true);
+          needEnterVector[index] = false;
+          nextNode = &curNode.SubNodes[index];
+        }
+        else
+        {
+          nextNode = &curNode;
+          addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support
+        }
+        RINOK(EnumerateDirItems(*nextNode,   
+            realDiskPath + wchar_t(kDirDelimiter), 
+            archivePrefix + realName + wchar_t(kDirDelimiter), 
+            addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
+      }
+      for (i = 0; i < curNode.SubNodes.Size(); i++)
+      {
+        if (i < needEnterVector.Size())
+          if (!needEnterVector[i])
+            continue;
+        const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+        const UString fullPath = diskPrefix + nextNode.Name;
+        NFind::CFileInfoW fileInfo;
+        if (!NFind::FindFile(fullPath, fileInfo))
+        {
+          if (!nextNode.AreThereIncludeItems())
+            continue;
+          errorCodes.Add(::GetLastError());
+          errorPaths.Add(fullPath);
+          continue;
+        }
+        if (!fileInfo.IsDirectory())
+        {
+          errorCodes.Add((DWORD)E_FAIL);
+          errorPaths.Add(fullPath);
+          continue;
+        }
+        RINOK(EnumerateDirItems(nextNode, 
+            diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter), 
+            archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter), 
+            UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
+      }
+      return S_OK;
+    }
+  }
+
+
+  NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
+  for (;;)
+  {
+    NFind::CFileInfoW fileInfo;
+    bool found;
+    if (!enumerator.Next(fileInfo, found))
+    {
+      errorCodes.Add(::GetLastError());
+      errorPaths.Add(diskPrefix);
+      break;
+    }
+    if (!found)
+      break;
+
+    if (callback)
+      RINOK(callback->CheckBreak());
+    const UString &name = fileInfo.Name;
+    bool enterToSubFolders2 = enterToSubFolders;
+    UStringVector addArchivePrefixNew = addArchivePrefix;
+    addArchivePrefixNew.Add(name);
+    {
+      UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
+      if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory()))
+        continue;
+    }
+    if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory()))
+    {
+      AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems);
+      if (fileInfo.IsDirectory())
+        enterToSubFolders2 = true;
+    }
+    if (!fileInfo.IsDirectory())
+      continue;
+
+    const NWildcard::CCensorNode *nextNode = 0;
+    if (addArchivePrefix.IsEmpty())
+    {
+      int index = curNode.FindSubNode(name);
+      if (index >= 0)
+        nextNode = &curNode.SubNodes[index];
+    }
+    if (!enterToSubFolders2 && nextNode == 0)
+      continue;
+
+    addArchivePrefixNew = addArchivePrefix;
+    if (nextNode == 0)
+    {
+      nextNode = &curNode;
+      addArchivePrefixNew.Add(name);
+    }
+    RINOK(EnumerateDirItems(*nextNode,   
+        diskPrefix + name + wchar_t(kDirDelimiter), 
+        archivePrefix + name + wchar_t(kDirDelimiter), 
+        addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
+  }
+  return S_OK;
+}
+
+HRESULT EnumerateItems(
+    const NWildcard::CCensor &censor, 
+    CObjectVector<CDirItem> &dirItems, 
+    IEnumDirItemCallback *callback,
+    UStringVector &errorPaths,
+    CRecordVector<DWORD> &errorCodes)
+{
+  for (int i = 0; i < censor.Pairs.Size(); i++)
+  {
+    const NWildcard::CPair &pair = censor.Pairs[i];
+    RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false, 
+        callback, errorPaths, errorCodes));
+  }
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Common/EnumDirItems.h b/lzma/CPP/7zip/UI/Common/EnumDirItems.h
new file mode 100644 (file)
index 0000000..8d5495a
--- /dev/null
@@ -0,0 +1,39 @@
+// EnumDirItems.h
+
+#ifndef __ENUM_DIR_ITEMS_H
+#define __ENUM_DIR_ITEMS_H
+
+#include "Common/Wildcard.h"
+#include "DirItem.h"
+
+#include "Windows/FileFind.h"
+
+void AddDirFileInfo(
+    const UString &prefix, 
+    const UString &fullPathName,
+    const NWindows::NFile::NFind::CFileInfoW &fileInfo, 
+    CObjectVector<CDirItem> &dirItems);
+
+
+void EnumerateDirItems(
+    const UString &baseFolderPrefix,
+    const UStringVector &fileNames,
+    const UString &archiveNamePrefix, 
+    CObjectVector<CDirItem> &dirItems, 
+    UStringVector &errorPaths,
+    CRecordVector<DWORD> &errorCodes);
+
+struct IEnumDirItemCallback
+{
+  virtual HRESULT CheckBreak() { return  S_OK; }
+};
+
+
+HRESULT EnumerateItems(
+    const NWildcard::CCensor &censor, 
+    CObjectVector<CDirItem> &dirItems, 
+    IEnumDirItemCallback *callback, 
+    UStringVector &errorPaths,
+    CRecordVector<DWORD> &errorCodes);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ExitCode.h b/lzma/CPP/7zip/UI/Common/ExitCode.h
new file mode 100644 (file)
index 0000000..0aac369
--- /dev/null
@@ -0,0 +1,27 @@
+// ExitCode.h
+
+#ifndef __EXIT_CODE_H
+#define __EXIT_CODE_H
+
+namespace NExitCode {
+
+enum EEnum {
+
+  kSuccess       = 0,     // Successful operation
+  kWarning       = 1,     // Non fatal error(s) occurred
+  kFatalError    = 2,     // A fatal error occurred
+  // kCRCError      = 3,     // A CRC error occurred when unpacking     
+  // kLockedArchive = 4,     // Attempt to modify an archive previously locked
+  // kWriteError    = 5,     // Write to disk error
+  // kOpenError     = 6,     // Open file error
+  kUserError     = 7,     // Command line option error
+  kMemoryError   = 8,     // Not enough memory for operation
+  // kCreateFileError = 9,     // Create file error
+  
+  kUserBreak     = 255   // User stopped the process
+
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/Extract.cpp b/lzma/CPP/7zip/UI/Common/Extract.cpp
new file mode 100644 (file)
index 0000000..0e56a08
--- /dev/null
@@ -0,0 +1,187 @@
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include "Extract.h"
+
+#include "Windows/Defs.h"
+#include "Windows/FileDir.h"
+
+#include "OpenArchive.h"
+#include "SetProperties.h"
+
+using namespace NWindows;
+
+HRESULT DecompressArchive(
+    IInArchive *archive,
+    UInt64 packSize,
+    const UString &defaultName,
+    const NWildcard::CCensorNode &wildcardCensor,
+    const CExtractOptions &options,
+    IExtractCallbackUI *callback,
+    CArchiveExtractCallback *extractCallbackSpec,
+    UString &errorMessage)
+{
+  CRecordVector<UInt32> realIndices;
+  UInt32 numItems;
+  RINOK(archive->GetNumberOfItems(&numItems));
+
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    UString filePath;
+    RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath));
+    bool isFolder;
+    RINOK(IsArchiveItemFolder(archive, i, isFolder));
+    if (!wildcardCensor.CheckPath(filePath, !isFolder))
+      continue;
+    realIndices.Add(i);
+  }
+  if (realIndices.Size() == 0)
+  {
+    callback->ThereAreNoFiles();
+    return S_OK;
+  }
+
+  UStringVector removePathParts;
+
+  UString outDir = options.OutputDir;
+  outDir.Replace(L"*", defaultName);
+  if(!outDir.IsEmpty())
+    if(!NFile::NDirectory::CreateComplexDirectory(outDir))
+    {
+      HRESULT res = ::GetLastError();
+      if (res == S_OK)
+        res = E_FAIL;
+      errorMessage = ((UString)L"Can not create output directory ") + outDir;
+      return res;
+    }
+
+  extractCallbackSpec->Init(
+      archive, 
+      callback,
+      options.StdOutMode,
+      outDir, 
+      removePathParts, 
+      options.DefaultItemName, 
+      options.ArchiveFileInfo.LastWriteTime,
+      options.ArchiveFileInfo.Attributes,
+      packSize);
+
+  #ifdef COMPRESS_MT
+  RINOK(SetProperties(archive, options.Properties));
+  #endif
+
+  HRESULT result = archive->Extract(&realIndices.Front(), 
+    realIndices.Size(), options.TestMode? 1: 0, extractCallbackSpec);
+
+  return callback->ExtractResult(result);
+}
+
+HRESULT DecompressArchives(
+    CCodecs *codecs,
+    UStringVector &archivePaths, UStringVector &archivePathsFull,    
+    const NWildcard::CCensorNode &wildcardCensor,
+    const CExtractOptions &optionsSpec,
+    IOpenCallbackUI *openCallback,
+    IExtractCallbackUI *extractCallback, 
+    UString &errorMessage, 
+    CDecompressStat &stat)
+{
+  stat.Clear();
+  CExtractOptions options = optionsSpec;
+  int i;
+  UInt64 totalPackSize = 0;
+  CRecordVector<UInt64> archiveSizes;
+  for (i = 0; i < archivePaths.Size(); i++)
+  {
+    const UString &archivePath = archivePaths[i];
+    NFile::NFind::CFileInfoW archiveFileInfo;
+    if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
+      throw "there is no such archive";
+    if (archiveFileInfo.IsDirectory())
+      throw "can't decompress folder";
+    archiveSizes.Add(archiveFileInfo.Size);
+    totalPackSize += archiveFileInfo.Size;
+  }
+  CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+  CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
+  bool multi = (archivePaths.Size() > 1);
+  extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
+  if (multi)
+  {
+    RINOK(extractCallback->SetTotal(totalPackSize));  
+  }
+  for (i = 0; i < archivePaths.Size(); i++)
+  {
+    const UString &archivePath = archivePaths[i];
+    NFile::NFind::CFileInfoW archiveFileInfo;
+    if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
+      throw "there is no such archive";
+
+    if (archiveFileInfo.IsDirectory())
+      throw "there is no such archive";
+
+    options.ArchiveFileInfo = archiveFileInfo;
+
+    #ifndef _NO_CRYPTO
+    openCallback->ClearPasswordWasAskedFlag();
+    #endif
+
+    RINOK(extractCallback->BeforeOpen(archivePath));
+    CArchiveLink archiveLink;
+    HRESULT result = MyOpenArchive(codecs, archivePath, archiveLink, openCallback);
+
+    bool crypted = false;
+    #ifndef _NO_CRYPTO
+    crypted = openCallback->WasPasswordAsked();
+    #endif
+
+    RINOK(extractCallback->OpenResult(archivePath, result, crypted));
+    if (result != S_OK)
+      continue;
+
+    for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+    {
+      int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+      if (index >= 0 && index > i)
+      {
+        archivePaths.Delete(index);
+        archivePathsFull.Delete(index);
+        totalPackSize -= archiveSizes[index];
+        archiveSizes.Delete(index);
+      }
+    }
+    if (archiveLink.VolumePaths.Size() != 0)
+    {
+      totalPackSize += archiveLink.VolumesSize;
+      RINOK(extractCallback->SetTotal(totalPackSize));  
+    }
+
+    #ifndef _NO_CRYPTO
+    UString password;
+    RINOK(openCallback->GetPasswordIfAny(password));
+    if (!password.IsEmpty())
+    {
+      RINOK(extractCallback->SetPassword(password));
+    }
+    #endif
+
+    options.DefaultItemName = archiveLink.GetDefaultItemName();
+    RINOK(DecompressArchive(
+        archiveLink.GetArchive(), 
+        archiveFileInfo.Size + archiveLink.VolumesSize,
+        archiveLink.GetDefaultItemName(),
+        wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage));
+    extractCallbackSpec->LocalProgressSpec->InSize += archiveFileInfo.Size + 
+        archiveLink.VolumesSize;
+    extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
+    if (!errorMessage.IsEmpty())
+      return E_FAIL;
+  }
+  stat.NumFolders = extractCallbackSpec->NumFolders;
+  stat.NumFiles = extractCallbackSpec->NumFiles;
+  stat.UnpackSize = extractCallbackSpec->UnpackSize;
+  stat.NumArchives = archivePaths.Size();
+  stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Common/Extract.h b/lzma/CPP/7zip/UI/Common/Extract.h
new file mode 100644 (file)
index 0000000..e7add12
--- /dev/null
@@ -0,0 +1,77 @@
+// Extract.h
+
+#ifndef __EXTRACT_H
+#define __EXTRACT_H
+
+#include "Common/Wildcard.h"
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveExtractCallback.h"
+#include "ArchiveOpenCallback.h"
+#include "ExtractMode.h"
+#include "Property.h"
+
+#include "../Common/LoadCodecs.h"
+
+class CExtractOptions
+{
+public:
+  bool StdOutMode;
+  bool TestMode;
+  NExtract::NPathMode::EEnum PathMode;
+
+  UString OutputDir;
+  bool YesToAll;
+  UString DefaultItemName;
+  NWindows::NFile::NFind::CFileInfoW ArchiveFileInfo;
+  
+  // bool ShowDialog;
+  // bool PasswordEnabled;
+  // UString Password;
+  #ifdef COMPRESS_MT
+  CObjectVector<CProperty> Properties;
+  #endif
+
+  NExtract::NOverwriteMode::EEnum OverwriteMode;
+
+  #ifdef EXTERNAL_CODECS
+  CCodecs *Codecs;
+  #endif
+
+  CExtractOptions(): 
+      StdOutMode(false), 
+      YesToAll(false), 
+      TestMode(false),
+      PathMode(NExtract::NPathMode::kFullPathnames),
+      OverwriteMode(NExtract::NOverwriteMode::kAskBefore)
+      {}
+
+  /*
+    bool FullPathMode() const { return (ExtractMode == NExtractMode::kTest) || 
+    (ExtractMode == NExtractMode::kFullPath); }
+  */
+};
+
+struct CDecompressStat
+{
+  UInt64 NumArchives;
+  UInt64 UnpackSize;
+  UInt64 PackSize;
+  UInt64 NumFolders;
+  UInt64 NumFiles;
+  void Clear() { NumArchives = PackSize = UnpackSize = NumFolders = NumFiles = 0; }
+};
+
+HRESULT DecompressArchives(
+    CCodecs *codecs,
+    UStringVector &archivePaths, UStringVector &archivePathsFull,
+    const NWildcard::CCensorNode &wildcardCensor,
+    const CExtractOptions &options,
+    IOpenCallbackUI *openCallback,
+    IExtractCallbackUI *extractCallback,
+    UString &errorMessage, 
+    CDecompressStat &stat);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ExtractMode.h b/lzma/CPP/7zip/UI/Common/ExtractMode.h
new file mode 100644 (file)
index 0000000..96b5a8c
--- /dev/null
@@ -0,0 +1,31 @@
+// ExtractMode.h
+
+#ifndef __EXTRACT_MODE_H
+#define __EXTRACT_MODE_H
+
+namespace NExtract {
+  
+  namespace NPathMode
+  {
+    enum EEnum
+    {
+      kFullPathnames,
+      kCurrentPathnames,
+      kNoPathnames
+    };
+  }
+  
+  namespace NOverwriteMode
+  {
+    enum EEnum
+    {
+      kAskBefore,
+      kWithoutPrompt,
+      kSkipExisting,
+      kAutoRename,
+      kAutoRenameExisting
+    };
+  }
+}  
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp
new file mode 100644 (file)
index 0000000..fa796ca
--- /dev/null
@@ -0,0 +1,96 @@
+// ExtractingFilePath.cpp
+
+#include "StdAfx.h"
+#include "ExtractingFilePath.h"
+
+static UString ReplaceIncorrectChars(const UString &s)
+{
+  #ifdef _WIN32
+  UString res;
+  for (int i = 0; i < s.Length(); i++)
+  {
+    wchar_t c = s[i];
+    if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>'  || c == '|' || c == ':' || c == '"')
+      c = '_';
+    res += c;
+  }
+  return res;
+  #else
+  return s;
+  #endif
+}
+
+#ifdef _WIN32
+static const wchar_t *g_ReservedNames[] =
+{
+  L"CON", L"PRN", L"AUX", L"NUL"
+};
+
+static bool CheckTail(const UString &name, int len)
+{
+  int dotPos = name.Find(L'.');
+  if (dotPos < 0)
+    dotPos = name.Length();
+  UString s = name.Left(dotPos);
+  s.TrimRight();
+  return (s.Length() != len);
+}
+
+static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
+{
+  int len = MyStringLen(reservedName);
+  if (name.Length() <= len)
+    return true;
+  if (name.Left(len).CompareNoCase(reservedName) != 0)
+    return true;
+  wchar_t c = name[len];
+  if (c < L'0' || c > L'9')
+    return true;
+  return CheckTail(name, len + 1);
+}
+
+static bool IsSupportedName(const UString &name)
+{
+  for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++)
+  {
+    const wchar_t *reservedName = g_ReservedNames[i];
+    int len = MyStringLen(reservedName);
+    if (name.Length() < len)
+      continue;
+    if (name.Left(len).CompareNoCase(reservedName) != 0)
+      continue;
+    if (!CheckTail(name, len))
+      return false;
+  }
+  if (!CheckNameNum(name, L"COM"))
+    return false;
+  return CheckNameNum(name, L"LPT");
+}
+#endif
+
+static UString GetCorrectFileName(const UString &path)
+{
+  if (path == L".." || path == L".")
+    return UString();
+  return ReplaceIncorrectChars(path);
+}
+
+void MakeCorrectPath(UStringVector &pathParts)
+{
+  for (int i = 0; i < pathParts.Size();)
+  {
+    UString &s = pathParts[i];
+    s = GetCorrectFileName(s);
+    if (s.IsEmpty())
+      pathParts.Delete(i);
+    else
+    {
+      #ifdef _WIN32
+      if (!IsSupportedName(s))
+        s = (UString)L"_" + s;
+      #endif
+      i++;
+    }
+  }
+}
+
diff --git a/lzma/CPP/7zip/UI/Common/ExtractingFilePath.h b/lzma/CPP/7zip/UI/Common/ExtractingFilePath.h
new file mode 100644 (file)
index 0000000..a86a6a9
--- /dev/null
@@ -0,0 +1,10 @@
+// ExtractingFilePath.h
+
+#ifndef __EXTRACTINGFILEPATH_H
+#define __EXTRACTINGFILEPATH_H
+
+#include "Common/MyString.h"
+
+void MakeCorrectPath(UStringVector &pathParts);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/IFileExtractCallback.h b/lzma/CPP/7zip/UI/Common/IFileExtractCallback.h
new file mode 100644 (file)
index 0000000..284e9cb
--- /dev/null
@@ -0,0 +1,43 @@
+// IFileExtractCallback.h
+
+#ifndef __IFILEEXTRACTCALLBACK_H
+#define __IFILEEXTRACTCALLBACK_H
+
+#include "Common/MyString.h"
+#include "../../IDecl.h"
+
+namespace NOverwriteAnswer
+{
+  enum EEnum
+  {
+    kYes,
+    kYesToAll,
+    kNo,
+    kNoToAll,
+    kAutoRename,
+    kCancel
+  };
+}
+
+DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
+{
+public:
+  STDMETHOD(AskOverwrite)(
+      const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+      const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+      Int32 *answer) PURE;
+  STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE;
+  STDMETHOD(MessageError)(const wchar_t *message) PURE;
+  STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE;
+};
+
+struct IExtractCallbackUI: IFolderArchiveExtractCallback
+{
+  virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
+  virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0;
+  virtual HRESULT ThereAreNoFiles() = 0;
+  virtual HRESULT ExtractResult(HRESULT result) = 0;
+  virtual HRESULT SetPassword(const UString &password) = 0;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/LoadCodecs.cpp b/lzma/CPP/7zip/UI/Common/LoadCodecs.cpp
new file mode 100644 (file)
index 0000000..087340a
--- /dev/null
@@ -0,0 +1,644 @@
+// LoadCodecs.cpp
+
+#include "StdAfx.h"
+
+#include "LoadCodecs.h"
+
+#include "../../../Common/MyCom.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Common/StringToInt.h"
+#endif
+#include "../../../Windows/PropVariant.h"
+
+#include "../../ICoder.h"
+#include "../../Common/RegisterArc.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/DLL.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Windows/ResourceString.h"
+static const UINT kIconTypesResId = 100;
+#endif
+
+#ifdef _WIN32
+#include "Windows/Registry.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+
+#ifdef _WIN32
+extern HINSTANCE g_hInstance;
+#endif
+
+static CSysString GetLibraryFolderPrefix()
+{
+  #ifdef _WIN32
+  TCHAR fullPath[MAX_PATH + 1];
+  ::GetModuleFileName(g_hInstance, fullPath, MAX_PATH);
+  CSysString path = fullPath;
+  int pos = path.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+  return path.Left(pos + 1);
+  #else
+  return CSysString(); // FIX IT
+  #endif
+}
+
+#define kCodecsFolderName TEXT("Codecs")
+#define kFormatsFolderName TEXT("Formats")
+static TCHAR *kMainDll = TEXT("7z.dll");
+
+#ifdef _WIN32
+static LPCTSTR kRegistryPath = TEXT("Software\\7-zip");
+static LPCTSTR kProgramPathValue = TEXT("Path");
+static bool ReadPathFromRegistry(HKEY baseKey, CSysString &path)
+{
+  NRegistry::CKey key;
+  if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
+    if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS)
+    {
+      NName::NormalizeDirPathPrefix(path);
+      return true;
+    }
+  return false;
+}
+
+#endif
+
+CSysString GetBaseFolderPrefixFromRegistry()
+{
+  CSysString moduleFolderPrefix = GetLibraryFolderPrefix();
+  NFind::CFileInfo fileInfo;
+  if (NFind::FindFile(moduleFolderPrefix + kMainDll, fileInfo))
+    if (!fileInfo.IsDirectory())
+      return moduleFolderPrefix;
+  if (NFind::FindFile(moduleFolderPrefix + kCodecsFolderName, fileInfo))
+    if (fileInfo.IsDirectory())
+      return moduleFolderPrefix;
+  if (NFind::FindFile(moduleFolderPrefix + kFormatsFolderName, fileInfo))
+    if (fileInfo.IsDirectory())
+      return moduleFolderPrefix;
+  #ifdef _WIN32
+  CSysString path;
+  if (ReadPathFromRegistry(HKEY_CURRENT_USER, path))
+    return path;
+  if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path))
+    return path;
+  #endif
+  return moduleFolderPrefix;
+}
+
+typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods);
+typedef UInt32 (WINAPI *GetNumberOfFormatsFunc)(UInt32 *numFormats);
+typedef UInt32 (WINAPI *GetHandlerPropertyFunc)(PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *GetHandlerPropertyFunc2)(UInt32 index, PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *iid, void **outObject);
+typedef UInt32 (WINAPI *SetLargePageModeFunc)();
+
+
+static HRESULT GetCoderClass(GetMethodPropertyFunc getMethodProperty, UInt32 index, 
+    PROPID propId, CLSID &clsId, bool &isAssigned)
+{
+  NWindows::NCOM::CPropVariant prop;
+  isAssigned = false;
+  RINOK(getMethodProperty(index, propId, &prop));
+  if (prop.vt == VT_BSTR)
+  {
+    isAssigned = true;
+    clsId = *(const GUID *)prop.bstrVal;
+  }
+  else if (prop.vt != VT_EMPTY)
+    return E_FAIL;
+  return S_OK;
+}
+
+HRESULT CCodecs::LoadCodecs()
+{
+  CCodecLib &lib = Libs.Back();
+  lib.GetMethodProperty = (GetMethodPropertyFunc)lib.Lib.GetProcAddress("GetMethodProperty");
+  if (lib.GetMethodProperty == NULL)
+    return S_OK;
+
+  UInt32 numMethods = 1;
+  GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)lib.Lib.GetProcAddress("GetNumberOfMethods");
+  if (getNumberOfMethodsFunc != NULL)
+  {
+    RINOK(getNumberOfMethodsFunc(&numMethods));
+  }
+
+  for(UInt32 i = 0; i < numMethods; i++)
+  {
+    CDllCodecInfo info;
+    info.LibIndex = Libs.Size() - 1;
+    info.CodecIndex = i;
+
+    RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
+    RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
+
+    Codecs.Add(info);
+  }
+  return S_OK;
+}
+
+static HRESULT ReadProp(
+    GetHandlerPropertyFunc getProp, 
+    GetHandlerPropertyFunc2 getProp2, 
+    UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
+{
+  if (getProp2)
+    return getProp2(index, propID, &prop);;
+  return getProp(propID, &prop);
+}
+
+static HRESULT ReadBoolProp(
+    GetHandlerPropertyFunc getProp, 
+    GetHandlerPropertyFunc2 getProp2, 
+    UInt32 index, PROPID propID, bool &res)
+{
+  NCOM::CPropVariant prop;
+  RINOK(ReadProp(getProp, getProp2, index, propID, prop));
+  if (prop.vt == VT_BOOL)
+    res = VARIANT_BOOLToBool(prop.boolVal);
+  else if (prop.vt != VT_EMPTY)
+    return E_FAIL;
+  return S_OK;
+}
+
+static HRESULT ReadStringProp(
+    GetHandlerPropertyFunc getProp, 
+    GetHandlerPropertyFunc2 getProp2, 
+    UInt32 index, PROPID propID, UString &res)
+{
+  NCOM::CPropVariant prop;
+  RINOK(ReadProp(getProp, getProp2, index, propID, prop));
+  if (prop.vt == VT_BSTR)
+    res = prop.bstrVal;
+  else if (prop.vt != VT_EMPTY)
+    return E_FAIL;
+  return S_OK;
+}
+
+#endif
+
+static const unsigned int kNumArcsMax = 32;
+static unsigned int g_NumArcs = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax]; 
+void RegisterArc(const CArcInfo *arcInfo) 
+{ 
+  if (g_NumArcs < kNumArcsMax)
+    g_Arcs[g_NumArcs++] = arcInfo; 
+}
+
+static void SplitString(const UString &srcString, UStringVector &destStrings)
+{
+  destStrings.Clear();
+  UString s;
+  int len = srcString.Length();
+  if (len == 0)
+    return;
+  for (int i = 0; i < len; i++)
+  {
+    wchar_t c = srcString[i];
+    if (c == L' ')
+    {
+      if (!s.IsEmpty())
+      {
+        destStrings.Add(s);
+        s.Empty();
+      }
+    }
+    else
+      s += c;
+  }
+  if (!s.IsEmpty())
+    destStrings.Add(s);
+}
+
+void CArcInfoEx::AddExts(const wchar_t* ext, const wchar_t* addExt)
+{
+  UStringVector exts, addExts;
+  SplitString(ext, exts);
+  if (addExt != 0)
+    SplitString(addExt, addExts);
+  for (int i = 0; i < exts.Size(); i++)
+  {
+    CArcExtInfo extInfo;
+    extInfo.Ext = exts[i];
+    if (i < addExts.Size())
+    {
+      extInfo.AddExt = addExts[i];
+      if (extInfo.AddExt == L"*")
+        extInfo.AddExt.Empty();
+    }
+    Exts.Add(extInfo);
+  }
+}
+
+#ifdef EXTERNAL_CODECS
+
+HRESULT CCodecs::LoadFormats()
+{
+  const NDLL::CLibrary &lib = Libs.Back().Lib;
+  GetHandlerPropertyFunc getProp = 0;
+  GetHandlerPropertyFunc2 getProp2 = (GetHandlerPropertyFunc2)
+      lib.GetProcAddress("GetHandlerProperty2");
+  if (getProp2 == NULL)
+  {
+    getProp = (GetHandlerPropertyFunc)
+        lib.GetProcAddress("GetHandlerProperty");
+    if (getProp == NULL)
+      return S_OK;
+  }
+
+  UInt32 numFormats = 1;
+  GetNumberOfFormatsFunc getNumberOfFormats = (GetNumberOfFormatsFunc)
+    lib.GetProcAddress("GetNumberOfFormats");
+  if (getNumberOfFormats != NULL)
+  {
+    RINOK(getNumberOfFormats(&numFormats));
+  }
+  if (getProp2 == NULL)
+    numFormats = 1;
+
+  for(UInt32 i = 0; i < numFormats; i++)
+  {
+    CArcInfoEx item;
+    item.LibIndex = Libs.Size() - 1;
+    item.FormatIndex = i;
+
+    RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kName, item.Name));
+
+    NCOM::CPropVariant prop;
+    if (ReadProp(getProp, getProp2, i, NArchive::kClassID, prop) != S_OK)
+      continue;
+    if (prop.vt != VT_BSTR)
+      continue;
+    item.ClassID = *(const GUID *)prop.bstrVal;
+    prop.Clear();
+
+    UString ext, addExt;
+    RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kExtension, ext));
+    RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kAddExtension, addExt));
+    item.AddExts(ext, addExt);
+
+    ReadBoolProp(getProp, getProp2, i, NArchive::kUpdate, item.UpdateEnabled);
+    if (item.UpdateEnabled)
+      ReadBoolProp(getProp, getProp2, i, NArchive::kKeepName, item.KeepName);
+    
+    if (ReadProp(getProp, getProp2, i, NArchive::kStartSignature, prop) == S_OK)
+      if (prop.vt == VT_BSTR)
+      {
+        UINT len = ::SysStringByteLen(prop.bstrVal);
+        item.StartSignature.SetCapacity(len);
+        memmove(item.StartSignature, prop.bstrVal, len);
+      }
+    Formats.Add(item);
+  }
+  return S_OK;
+}
+
+#ifdef NEW_FOLDER_INTERFACE
+void CCodecLib::LoadIcons()
+{
+  UString iconTypes = MyLoadStringW((HMODULE)Lib, kIconTypesResId);
+  UStringVector pairs;
+  SplitString(iconTypes, pairs);
+  for (int i = 0; i < pairs.Size(); i++)
+  {
+    const UString &s = pairs[i];
+    int pos = s.Find(L':');
+    if (pos < 0)
+      continue;
+    CIconPair iconPair;
+    const wchar_t *end;
+    UString num = s.Mid(pos + 1);
+    iconPair.IconIndex = (UInt32)ConvertStringToUInt64(num, &end);
+    if (*end != L'\0')
+      continue;
+    iconPair.Ext = s.Left(pos);
+    IconPairs.Add(iconPair);
+  }
+}
+
+int CCodecLib::FindIconIndex(const UString &ext) const
+{
+  for (int i = 0; i < IconPairs.Size(); i++)
+  {
+    const CIconPair &pair = IconPairs[i];
+    if (ext.CompareNoCase(pair.Ext) == 0)
+      return pair.IconIndex;
+  }
+  return -1;
+}
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+extern "C" 
+{
+  extern SIZE_T g_LargePageSize;
+}
+#endif
+
+HRESULT CCodecs::LoadDll(const CSysString &dllPath)
+{
+  {
+    NDLL::CLibrary library;
+    if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
+      return S_OK;
+  }
+  Libs.Add(CCodecLib());
+  CCodecLib &lib = Libs.Back();
+  #ifdef NEW_FOLDER_INTERFACE
+  lib.Path = dllPath;
+  #endif
+  bool used = false;
+  HRESULT res = S_OK;
+  if (lib.Lib.Load(dllPath))
+  {
+    #ifdef NEW_FOLDER_INTERFACE
+    lib.LoadIcons();
+    #endif
+
+    #ifdef _7ZIP_LARGE_PAGES
+    if (g_LargePageSize != 0)
+    {
+      SetLargePageModeFunc setLargePageMode = (SetLargePageModeFunc)lib.Lib.GetProcAddress("SetLargePageMode");
+      if (setLargePageMode != 0)
+        setLargePageMode();
+    }
+    #endif
+
+    lib.CreateObject = (CreateObjectFunc)lib.Lib.GetProcAddress("CreateObject");
+    if (lib.CreateObject != 0)
+    {
+      int startSize = Codecs.Size();
+      res = LoadCodecs();
+      used = (Codecs.Size() != startSize);
+      if (res == S_OK)
+      {
+        startSize = Formats.Size();
+        res = LoadFormats();
+        used = used || (Formats.Size() != startSize);
+      }
+    }
+  }
+  if (!used)
+    Libs.DeleteBack();
+  return res;
+}
+
+HRESULT CCodecs::LoadDllsFromFolder(const CSysString &folderPrefix)
+{
+  NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*")));
+  NFile::NFind::CFileInfo fileInfo;
+  while (enumerator.Next(fileInfo))
+  {
+    if (fileInfo.IsDirectory())
+      continue;
+    RINOK(LoadDll(folderPrefix + fileInfo.Name));
+  }
+  return S_OK;
+}
+
+#endif
+
+#ifndef _SFX
+static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
+{
+  bb.SetCapacity(size);
+  memmove((Byte *)bb, data, size);
+}
+#endif
+
+HRESULT CCodecs::Load()
+{
+  Formats.Clear();
+  #ifdef EXTERNAL_CODECS
+  Codecs.Clear();
+  #endif
+  for (UInt32 i = 0; i < g_NumArcs; i++)
+  {
+    const CArcInfo &arc = *g_Arcs[i];
+    CArcInfoEx item;
+    item.Name = arc.Name;
+    item.CreateInArchive = arc.CreateInArchive;
+    item.CreateOutArchive = arc.CreateOutArchive;
+    item.AddExts(arc.Ext, arc.AddExt);
+    item.UpdateEnabled = (arc.CreateOutArchive != 0);
+    item.KeepName = arc.KeepName;
+
+    #ifndef _SFX
+    SetBuffer(item.StartSignature, arc.Signature, arc.SignatureSize);
+    #endif
+    Formats.Add(item);
+  }
+  #ifdef EXTERNAL_CODECS
+  const CSysString baseFolder = GetBaseFolderPrefixFromRegistry();
+  RINOK(LoadDll(baseFolder + kMainDll));
+  RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName TEXT(STRING_PATH_SEPARATOR)));
+  RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName TEXT(STRING_PATH_SEPARATOR)));
+  #endif
+  return S_OK;
+}
+
+int CCodecs::FindFormatForArchiveName(const UString &archivePath) const
+{
+  int slashPos1 = archivePath.ReverseFind(L'\\');
+  int slashPos2 = archivePath.ReverseFind(L'.');
+  int dotPos = archivePath.ReverseFind(L'.');
+  if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2)
+    return -1;
+  UString ext = archivePath.Mid(dotPos + 1);
+  for (int i = 0; i < Formats.Size(); i++)
+  {
+    const CArcInfoEx &arc = Formats[i];
+    if (!arc.UpdateEnabled)
+      continue;
+    // if (arc.FindExtension(ext) >= 0)
+    UString mainExt = arc.GetMainExt();
+    if (!mainExt.IsEmpty() && ext.CompareNoCase(mainExt) == 0)
+      return i;
+  }
+  return -1;
+}
+
+int CCodecs::FindFormatForArchiveType(const UString &arcType) const
+{
+  for (int i = 0; i < Formats.Size(); i++)
+  {
+    const CArcInfoEx &arc = Formats[i];
+    if (!arc.UpdateEnabled)
+      continue;
+    if (arc.Name.CompareNoCase(arcType) == 0)
+      return i;
+  }
+  return -1;
+}
+
+#ifdef EXTERNAL_CODECS
+
+#ifdef EXPORT_CODECS
+extern unsigned int g_NumCodecs;
+STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject);
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+// STDAPI GetNumberOfMethods(UINT32 *numCodecs);
+#endif
+
+STDMETHODIMP CCodecs::GetNumberOfMethods(UINT32 *numMethods)
+{
+  *numMethods = 
+      #ifdef EXPORT_CODECS
+      g_NumCodecs + 
+      #endif
+      Codecs.Size();
+  return S_OK;
+}
+
+STDMETHODIMP CCodecs::GetProperty(UINT32 index, PROPID propID, PROPVARIANT *value)
+{
+  #ifdef EXPORT_CODECS
+  if (index < g_NumCodecs)
+    return GetMethodProperty(index, propID, value);
+  #endif
+
+  const CDllCodecInfo &ci = Codecs[index 
+      #ifdef EXPORT_CODECS
+      - g_NumCodecs
+      #endif
+      ];
+
+  if (propID == NMethodPropID::kDecoderIsAssigned)
+  {
+    NWindows::NCOM::CPropVariant propVariant;
+    propVariant = ci.DecoderIsAssigned;
+    propVariant.Detach(value);
+    return S_OK;
+  }
+  if (propID == NMethodPropID::kEncoderIsAssigned)
+  {
+    NWindows::NCOM::CPropVariant propVariant;
+    propVariant = ci.EncoderIsAssigned;
+    propVariant.Detach(value);
+    return S_OK;
+  }
+  return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value);
+}
+
+STDMETHODIMP CCodecs::CreateDecoder(UINT32 index, const GUID *iid, void **coder)
+{
+  #ifdef EXPORT_CODECS
+  if (index < g_NumCodecs)
+    return CreateCoder2(false, index, iid, coder);
+  #endif
+  const CDllCodecInfo &ci = Codecs[index 
+      #ifdef EXPORT_CODECS
+      - g_NumCodecs
+      #endif
+      ];
+  if (ci.DecoderIsAssigned)
+    return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder);
+  return S_OK;
+}
+
+STDMETHODIMP CCodecs::CreateEncoder(UINT32 index, const GUID *iid, void **coder)
+{
+  #ifdef EXPORT_CODECS
+  if (index < g_NumCodecs)
+    return CreateCoder2(true, index, iid, coder);
+  #endif
+  const CDllCodecInfo &ci = Codecs[index 
+      #ifdef EXPORT_CODECS
+      - g_NumCodecs
+      #endif
+      ];
+  if (ci.EncoderIsAssigned)
+    return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder);
+  return S_OK;
+}
+
+HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const
+{ 
+  for (int i = 0; i < Codecs.Size(); i++)
+  {
+    const CDllCodecInfo &codec = Codecs[i];
+    if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned)
+      continue;
+    const CCodecLib &lib = Libs[codec.LibIndex];
+    UString res;
+    NWindows::NCOM::CPropVariant prop;
+    RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop));
+    if (prop.vt == VT_BSTR)
+      res = prop.bstrVal;
+    else if (prop.vt != VT_EMPTY)
+      continue;
+    if (name.CompareNoCase(res) == 0)
+      return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder);
+  }
+  return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+int CCodecs::GetCodecLibIndex(UInt32 index)
+{
+  #ifdef EXPORT_CODECS
+  if (index < g_NumCodecs)
+    return -1;
+  #endif
+  #ifdef EXTERNAL_CODECS
+  const CDllCodecInfo &ci = Codecs[index 
+      #ifdef EXPORT_CODECS
+      - g_NumCodecs
+      #endif
+      ];
+  return ci.LibIndex;
+  #else
+  return -1;
+  #endif
+}
+
+bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index)
+{
+  #ifdef EXPORT_CODECS
+  if (index < g_NumCodecs)
+  {
+    NWindows::NCOM::CPropVariant prop;
+    if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
+      if (prop.vt != VT_EMPTY)
+        return true;
+    return false;
+  }
+  #endif
+  #ifdef EXTERNAL_CODECS
+  const CDllCodecInfo &ci = Codecs[index 
+      #ifdef EXPORT_CODECS
+      - g_NumCodecs
+      #endif
+      ];
+  return ci.EncoderIsAssigned;
+  #else
+  return false;
+  #endif
+}
+
+HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id)
+{
+  UString s;
+  NWindows::NCOM::CPropVariant prop;
+  RINOK(GetProperty(index, NMethodPropID::kID, &prop));
+  if (prop.vt != VT_UI8)
+    return E_INVALIDARG;
+  id = prop.uhVal.QuadPart;
+  return S_OK;
+}
+
+UString CCodecs::GetCodecName(UInt32 index)
+{
+  UString s;
+  NWindows::NCOM::CPropVariant prop;
+  if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
+    if (prop.vt == VT_BSTR)
+      s = prop.bstrVal;
+  return s;
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/LoadCodecs.h b/lzma/CPP/7zip/UI/Common/LoadCodecs.h
new file mode 100644 (file)
index 0000000..231680b
--- /dev/null
@@ -0,0 +1,215 @@
+// LoadCodecs.h
+
+#ifndef __LOADCODECS_H
+#define __LOADCODECS_H
+
+#include "../../../Common/Types.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/Buffer.h"
+#include "../../ICoder.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/DLL.h"
+#endif
+
+struct CDllCodecInfo
+{
+  CLSID Encoder;
+  CLSID Decoder;
+  bool EncoderIsAssigned;
+  bool DecoderIsAssigned;
+  int LibIndex;
+  UInt32 CodecIndex;
+};
+
+#include "../../Archive/IArchive.h"
+
+typedef IInArchive * (*CreateInArchiveP)();
+typedef IOutArchive * (*CreateOutArchiveP)();
+
+struct CArcExtInfo
+{
+  UString Ext;
+  UString AddExt;
+  CArcExtInfo() {}
+  CArcExtInfo(const UString &ext): Ext(ext) {}
+  CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
+};
+
+
+struct CArcInfoEx
+{
+  #ifdef EXTERNAL_CODECS
+  int LibIndex;
+  UInt32 FormatIndex;
+  CLSID ClassID;
+  #endif
+  bool UpdateEnabled;
+  CreateInArchiveP CreateInArchive;
+  CreateOutArchiveP CreateOutArchive;
+  UString Name;
+  CObjectVector<CArcExtInfo> Exts;
+  #ifndef _SFX
+  CByteBuffer StartSignature;
+  // CByteBuffer FinishSignature;
+  #ifdef NEW_FOLDER_INTERFACE
+  UStringVector AssociateExts;
+  #endif
+  #endif
+  bool KeepName;
+  UString GetMainExt() const
+  {
+    if (Exts.IsEmpty())
+      return UString();
+    return Exts[0].Ext;
+  }
+  int FindExtension(const UString &ext) const
+  {
+    for (int i = 0; i < Exts.Size(); i++)
+      if (ext.CompareNoCase(Exts[i].Ext) == 0)
+        return i;
+    return -1;
+  }
+  UString GetAllExtensions() const
+  {
+    UString s;
+    for (int i = 0; i < Exts.Size(); i++)
+    {
+      if (i > 0)
+        s += ' ';
+      s += Exts[i].Ext;
+    }
+    return s;
+  }
+
+  void AddExts(const wchar_t* ext, const wchar_t* addExt);
+
+  CArcInfoEx(): 
+    #ifdef EXTERNAL_CODECS
+    LibIndex(-1),
+    #endif
+    UpdateEnabled(false),
+    CreateInArchive(0), CreateOutArchive(0),
+    KeepName(false)
+    #ifndef _SFX
+    #endif
+  {}
+};
+
+#ifdef EXTERNAL_CODECS
+typedef UInt32 (WINAPI *GetMethodPropertyFunc)(UInt32 index, PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *interfaceID, void **outObject);
+
+
+struct CCodecLib
+{
+  NWindows::NDLL::CLibrary Lib;
+  GetMethodPropertyFunc GetMethodProperty;
+  CreateObjectFunc CreateObject;
+  #ifdef NEW_FOLDER_INTERFACE
+  struct CIconPair
+  {
+    UString Ext;
+    UInt32 IconIndex;
+  };
+  CSysString Path;
+  CObjectVector<CIconPair> IconPairs;
+  void LoadIcons();
+  int FindIconIndex(const UString &ext) const;
+  #endif
+  CCodecLib(): GetMethodProperty(0) {}
+};
+#endif
+
+class CCodecs:
+  #ifdef EXTERNAL_CODECS
+  public ICompressCodecsInfo,
+  #else
+  public IUnknown,
+  #endif
+  public CMyUnknownImp
+{
+public:  
+  #ifdef EXTERNAL_CODECS
+  CObjectVector<CCodecLib> Libs;
+  CObjectVector<CDllCodecInfo> Codecs;
+  HRESULT LoadCodecs();
+  HRESULT LoadFormats();
+  HRESULT LoadDll(const CSysString &path);
+  HRESULT LoadDllsFromFolder(const CSysString &folderPrefix);
+
+  HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const
+  {
+    return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+  }
+  #endif
+
+public:
+  CObjectVector<CArcInfoEx> Formats;
+  HRESULT Load();
+  int FindFormatForArchiveName(const UString &archivePath) const;
+  int FindFormatForArchiveType(const UString &arcType) const;
+
+  MY_UNKNOWN_IMP
+
+  #ifdef EXTERNAL_CODECS
+  STDMETHOD(GetNumberOfMethods)(UINT32 *numMethods);
+  STDMETHOD(GetProperty)(UINT32 index, PROPID propID, PROPVARIANT *value);
+  STDMETHOD(CreateDecoder)(UINT32 index, const GUID *interfaceID, void **coder);
+  STDMETHOD(CreateEncoder)(UINT32 index, const GUID *interfaceID, void **coder);
+  #endif
+
+  int GetCodecLibIndex(UInt32 index);
+  bool GetCodecEncoderIsAssigned(UInt32 index);
+  HRESULT GetCodecId(UInt32 index, UInt64 &id);
+  UString GetCodecName(UInt32 index);
+
+  HRESULT CreateInArchive(int formatIndex, CMyComPtr<IInArchive> &archive) const
+  { 
+    const CArcInfoEx &ai = Formats[formatIndex]; 
+    #ifdef EXTERNAL_CODECS
+    if (ai.LibIndex < 0)
+    #endif
+    {
+      archive = ai.CreateInArchive();
+      return S_OK;
+    }
+    #ifdef EXTERNAL_CODECS
+    return CreateArchiveHandler(ai, (void **)&archive, false); 
+    #endif
+  }
+  HRESULT CreateOutArchive(int formatIndex, CMyComPtr<IOutArchive> &archive) const
+  { 
+    const CArcInfoEx &ai = Formats[formatIndex]; 
+    #ifdef EXTERNAL_CODECS
+    if (ai.LibIndex < 0)
+    #endif
+    {
+      archive = ai.CreateOutArchive();
+      return S_OK;
+    }
+    #ifdef EXTERNAL_CODECS
+    return CreateArchiveHandler(ai, (void **)&archive, true); 
+    #endif
+  }
+  int FindOutFormatFromName(const UString &name) const
+  {
+    for (int i = 0; i < Formats.Size(); i++)
+    {
+      const CArcInfoEx &arc = Formats[i];
+      if (!arc.UpdateEnabled)
+        continue;
+      if (arc.Name.CompareNoCase(name) == 0)
+        return i;
+    }
+    return -1;
+  }
+
+  #ifdef EXTERNAL_CODECS
+  HRESULT CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const;
+  #endif
+
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/OpenArchive.cpp b/lzma/CPP/7zip/UI/Common/OpenArchive.cpp
new file mode 100644 (file)
index 0000000..2874f6a
--- /dev/null
@@ -0,0 +1,461 @@
+// OpenArchive.cpp
+
+#include "StdAfx.h"
+
+#include "OpenArchive.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileDir.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "Common/StringConvert.h"
+
+#include "DefaultName.h"
+
+using namespace NWindows;
+
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
+{
+  NCOM::CPropVariant prop;
+  RINOK(archive->GetProperty(index, kpidPath, &prop));
+  if(prop.vt == VT_BSTR)
+    result = prop.bstrVal;
+  else if (prop.vt == VT_EMPTY)
+    result.Empty();
+  else
+    return E_FAIL;
+  return S_OK;
+}
+
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
+{
+  RINOK(GetArchiveItemPath(archive, index, result));
+  if (result.IsEmpty())
+    result = defaultName;
+  return S_OK;
+}
+
+HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, 
+    const FILETIME &defaultFileTime, FILETIME &fileTime)
+{
+  NCOM::CPropVariant prop;
+  RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
+  if (prop.vt == VT_FILETIME)
+    fileTime = prop.filetime;
+  else if (prop.vt == VT_EMPTY)
+    fileTime = defaultFileTime;
+  else
+    return E_FAIL;
+  return S_OK;
+}
+
+HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
+{
+  NCOM::CPropVariant prop;
+  RINOK(archive->GetProperty(index, propID, &prop));
+  if(prop.vt == VT_BOOL)
+    result = VARIANT_BOOLToBool(prop.boolVal);
+  else if (prop.vt == VT_EMPTY)
+    result = false;
+  else
+    return E_FAIL;
+  return S_OK;
+}
+
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
+{
+  return IsArchiveItemProp(archive, index, kpidIsFolder, result);
+}
+
+HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
+{
+  return IsArchiveItemProp(archive, index, kpidIsAnti, result);
+}
+
+// Static-SFX (for Linux) can be big.
+const UInt64 kMaxCheckStartPosition = 1 << 22;
+
+HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName, IArchiveOpenCallback *openArchiveCallback)
+{
+  CInFileStream *inStreamSpec = new CInFileStream;
+  CMyComPtr<IInStream> inStream(inStreamSpec);
+  inStreamSpec->Open(fileName);
+  return archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
+}
+
+#ifndef _SFX
+static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
+{
+  for (size_t i = 0; i < size; i++)
+    if (p1[i] != p2[i])
+      return false;
+  return true;
+}
+#endif
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    IInStream *inStream,
+    const UString &fileName, 
+    IInArchive **archiveResult, 
+    int &formatIndex,
+    UString &defaultItemName,
+    IArchiveOpenCallback *openArchiveCallback)
+{
+  *archiveResult = NULL;
+  UString extension;
+  {
+    int dotPos = fileName.ReverseFind(L'.');
+    if (dotPos >= 0)
+      extension = fileName.Mid(dotPos + 1);
+  }
+  CIntVector orderIndices;
+  int i;
+  int numFinded = 0;
+  for (i = 0; i < codecs->Formats.Size(); i++)
+    if (codecs->Formats[i].FindExtension(extension) >= 0)
+      orderIndices.Insert(numFinded++, i);
+    else
+      orderIndices.Add(i);
+  
+  #ifndef _SFX
+  if (numFinded != 1)
+  {
+    CIntVector orderIndices2;
+    CByteBuffer byteBuffer;
+    const UInt32 kBufferSize = (200 << 10);
+    byteBuffer.SetCapacity(kBufferSize);
+    Byte *buffer = byteBuffer;
+    RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+    UInt32 processedSize;
+    RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
+    for (UInt32 pos = 0; pos < processedSize; pos++)
+    {
+      for (int i = 0; i < orderIndices.Size(); i++)
+      {
+        int index = orderIndices[i];
+        const CArcInfoEx &ai = codecs->Formats[index];
+        const CByteBuffer &sig = ai.StartSignature;
+        if (sig.GetCapacity() == 0)
+          continue;
+        if (pos + sig.GetCapacity() > processedSize)
+          continue;
+        if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
+        {
+          orderIndices2.Add(index);
+          orderIndices.Delete(i--);
+        }
+      }
+    }
+    orderIndices2 += orderIndices;
+    orderIndices = orderIndices2;
+  }
+  else if (extension == L"000" || extension == L"001")
+  {
+    CByteBuffer byteBuffer;
+    const UInt32 kBufferSize = (1 << 10);
+    byteBuffer.SetCapacity(kBufferSize);
+    Byte *buffer = byteBuffer;
+    RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+    UInt32 processedSize;
+    RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
+    if (processedSize >= 16)
+    {
+      Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
+      if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] && 1) != 0)
+      {
+        for (int i = 0; i < orderIndices.Size(); i++)
+        {
+          int index = orderIndices[i];
+          const CArcInfoEx &ai = codecs->Formats[index];
+          if (ai.Name.CompareNoCase(L"rar") != 0)
+            continue;
+          orderIndices.Delete(i--);
+          orderIndices.Insert(0, index);
+          break;
+        }
+      }
+    }
+  }
+  #endif
+
+  HRESULT badResult = S_OK;
+  for(i = 0; i < orderIndices.Size(); i++)
+  {
+    inStream->Seek(0, STREAM_SEEK_SET, NULL);
+
+    CMyComPtr<IInArchive> archive;
+
+    formatIndex = orderIndices[i];
+    RINOK(codecs->CreateInArchive(formatIndex, archive));
+    if (!archive)
+      continue;
+
+    #ifdef EXTERNAL_CODECS
+    {
+      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+      archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+      if (setCompressCodecsInfo)
+      {
+        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
+      }
+    }
+    #endif
+
+    HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
+    if (result == S_FALSE)
+      continue;
+    if(result != S_OK)
+    {
+      badResult = result;
+      if(result == E_ABORT)
+        break;
+      continue;
+    }
+    *archiveResult = archive.Detach();
+    const CArcInfoEx &format = codecs->Formats[formatIndex];
+    if (format.Exts.Size() == 0)
+    {
+      defaultItemName = GetDefaultName2(fileName, L"", L"");
+    }
+    else
+    {
+      int subExtIndex = format.FindExtension(extension);
+      if (subExtIndex < 0)
+        subExtIndex = 0;
+      defaultItemName = GetDefaultName2(fileName, 
+          format.Exts[subExtIndex].Ext, 
+          format.Exts[subExtIndex].AddExt);
+    }
+    return S_OK;
+  }
+  if (badResult != S_OK)
+    return badResult;
+  return S_FALSE;
+}
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    const UString &filePath, 
+    IInArchive **archiveResult, 
+    int &formatIndex,
+    UString &defaultItemName,
+    IArchiveOpenCallback *openArchiveCallback)
+{
+  CInFileStream *inStreamSpec = new CInFileStream;
+  CMyComPtr<IInStream> inStream(inStreamSpec);
+  if (!inStreamSpec->Open(filePath))
+    return GetLastError();
+  return OpenArchive(codecs, inStream, ExtractFileNameFromPath(filePath),
+    archiveResult, formatIndex,
+    defaultItemName, openArchiveCallback);
+}
+
+static void MakeDefaultName(UString &name)
+{
+  int dotPos = name.ReverseFind(L'.');
+  if (dotPos < 0)
+    return;
+  UString ext = name.Mid(dotPos + 1);
+  if (ext.IsEmpty())
+    return;
+  for (int pos = 0; pos < ext.Length(); pos++)
+    if (ext[pos] < L'0' || ext[pos] > L'9')
+      return;
+  name = name.Left(dotPos);
+}
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    const UString &fileName, 
+    IInArchive **archive0, 
+    IInArchive **archive1, 
+    int &formatIndex0,
+    int &formatIndex1,
+    UString &defaultItemName0,
+    UString &defaultItemName1,
+    IArchiveOpenCallback *openArchiveCallback)
+{
+  HRESULT result = OpenArchive(codecs, fileName, 
+      archive0, formatIndex0, defaultItemName0, openArchiveCallback);
+  RINOK(result);
+  CMyComPtr<IInArchiveGetStream> getStream;
+  result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
+  if (result != S_OK || getStream == 0)
+    return S_OK;
+
+  CMyComPtr<ISequentialInStream> subSeqStream;
+  result = getStream->GetStream(0, &subSeqStream);
+  if (result != S_OK)
+    return S_OK;
+
+  CMyComPtr<IInStream> subStream;
+  if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
+    return S_OK;
+  if (!subStream)
+    return S_OK;
+
+  UInt32 numItems;
+  RINOK((*archive0)->GetNumberOfItems(&numItems));
+  if (numItems < 1)
+    return S_OK;
+
+  UString subPath;
+  RINOK(GetArchiveItemPath(*archive0, 0, subPath))
+  if (subPath.IsEmpty())
+  {
+    MakeDefaultName(defaultItemName0);
+    subPath = defaultItemName0;
+    const CArcInfoEx &format = codecs->Formats[formatIndex0];
+    if (format.Name.CompareNoCase(L"7z") == 0)
+    {
+      if (subPath.Right(3).CompareNoCase(L".7z") != 0)
+        subPath += L".7z";
+    }
+  }
+  else
+    subPath = ExtractFileNameFromPath(subPath);
+
+  CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
+  openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
+  if (setSubArchiveName)
+    setSubArchiveName->SetSubArchiveName(subPath);
+
+  result = OpenArchive(codecs, subStream, subPath,
+      archive1, formatIndex1, defaultItemName1, openArchiveCallback);
+  return S_OK;
+}
+
+static void SetCallback(const UString &archiveName,
+    IOpenCallbackUI *openCallbackUI, CMyComPtr<IArchiveOpenCallback> &openCallback)
+{
+  COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+  openCallback = openCallbackSpec;
+  openCallbackSpec->Callback = openCallbackUI;
+
+  UString fullName;
+  int fileNamePartStartIndex;
+  NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
+  openCallbackSpec->Init(
+      fullName.Left(fileNamePartStartIndex), 
+      fullName.Mid(fileNamePartStartIndex));
+}
+
+HRESULT MyOpenArchive(
+    CCodecs *codecs, 
+    const UString &archiveName,
+    IInArchive **archive, UString &defaultItemName, IOpenCallbackUI *openCallbackUI)
+{
+  CMyComPtr<IArchiveOpenCallback> openCallback;
+  SetCallback(archiveName, openCallbackUI, openCallback);
+  int formatInfo;
+  return OpenArchive(codecs, archiveName, archive, formatInfo, defaultItemName, openCallback);
+}
+
+HRESULT MyOpenArchive(
+    CCodecs *codecs,
+    const UString &archiveName,
+    IInArchive **archive0,
+    IInArchive **archive1,
+    UString &defaultItemName0,
+    UString &defaultItemName1,
+    UStringVector &volumePaths,
+    UInt64 &volumesSize,
+    IOpenCallbackUI *openCallbackUI)
+{
+  volumesSize = 0;
+  COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+  CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
+  openCallbackSpec->Callback = openCallbackUI;
+
+  UString fullName;
+  int fileNamePartStartIndex;
+  NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
+  UString prefix = fullName.Left(fileNamePartStartIndex);
+  UString name = fullName.Mid(fileNamePartStartIndex);
+  openCallbackSpec->Init(prefix, name);
+
+  int formatIndex0, formatIndex1;
+  RINOK(OpenArchive(codecs, archiveName,
+      archive0, 
+      archive1, 
+      formatIndex0, 
+      formatIndex1, 
+      defaultItemName0,
+      defaultItemName1,
+      openCallback));
+  volumePaths.Add(prefix + name);
+  for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
+    volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
+  volumesSize = openCallbackSpec->TotalSize;
+  return S_OK;
+}
+
+HRESULT CArchiveLink::Close()
+{
+  if (Archive1 != 0)
+    RINOK(Archive1->Close());
+  if (Archive0 != 0)
+    RINOK(Archive0->Close());
+  IsOpen = false;
+  return S_OK;
+}
+
+void CArchiveLink::Release()
+{
+  IsOpen = false;
+  Archive1.Release();
+  Archive0.Release();
+}
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    const UString &archiveName,
+    CArchiveLink &archiveLink,
+    IArchiveOpenCallback *openCallback)
+{
+  HRESULT res = OpenArchive(codecs, archiveName, 
+    &archiveLink.Archive0, &archiveLink.Archive1, 
+    archiveLink.FormatIndex0, archiveLink.FormatIndex1, 
+    archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, 
+    openCallback);
+  archiveLink.IsOpen = (res == S_OK);
+  return res;
+}
+
+HRESULT MyOpenArchive(CCodecs *codecs,
+    const UString &archiveName, 
+    CArchiveLink &archiveLink,
+    IOpenCallbackUI *openCallbackUI)
+{
+  HRESULT res = MyOpenArchive(codecs, archiveName,
+    &archiveLink.Archive0, &archiveLink.Archive1, 
+    archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, 
+    archiveLink.VolumePaths,
+    archiveLink.VolumesSize,
+    openCallbackUI);
+  archiveLink.IsOpen = (res == S_OK);
+  return res;
+}
+
+HRESULT ReOpenArchive(CCodecs *codecs, CArchiveLink &archiveLink, const UString &fileName)
+{
+  if (archiveLink.GetNumLevels() > 1)
+    return E_NOTIMPL;
+
+  if (archiveLink.GetNumLevels() == 0)
+    return MyOpenArchive(codecs, fileName, archiveLink, 0);
+
+  CMyComPtr<IArchiveOpenCallback> openCallback;
+  SetCallback(fileName, NULL, openCallback);
+
+  HRESULT res = ReOpenArchive(archiveLink.GetArchive(), fileName, openCallback);
+  archiveLink.IsOpen = (res == S_OK);
+  return res;
+}
diff --git a/lzma/CPP/7zip/UI/Common/OpenArchive.h b/lzma/CPP/7zip/UI/Common/OpenArchive.h
new file mode 100644 (file)
index 0000000..7b42446
--- /dev/null
@@ -0,0 +1,130 @@
+// OpenArchive.h
+
+#ifndef __OPENARCHIVE_H
+#define __OPENARCHIVE_H
+
+#include "Common/MyString.h"
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+#include "LoadCodecs.h"
+#include "ArchiveOpenCallback.h"
+
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result);
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result);
+HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, 
+    const FILETIME &defaultFileTime, FILETIME &fileTime);
+HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result);
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result);
+HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result);
+
+struct ISetSubArchiveName
+{
+  virtual void SetSubArchiveName(const wchar_t *name) = 0;
+};
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    IInStream *inStream,
+    const UString &fileName, 
+    IInArchive **archiveResult, 
+    int &formatIndex,
+    UString &defaultItemName,
+    IArchiveOpenCallback *openArchiveCallback);
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    const UString &filePath, 
+    IInArchive **archive, 
+    int &formatIndex,
+    UString &defaultItemName,
+    IArchiveOpenCallback *openArchiveCallback);
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    const UString &filePath, 
+    IInArchive **archive0, 
+    IInArchive **archive1, 
+    int &formatIndex0,
+    int &formatIndex1,
+    UString &defaultItemName0,
+    UString &defaultItemName1,
+    IArchiveOpenCallback *openArchiveCallback);
+
+
+HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName, IArchiveOpenCallback *openArchiveCallback);
+
+HRESULT MyOpenArchive(
+    CCodecs *codecs,
+    const UString &archiveName, 
+    IInArchive **archive,
+    UString &defaultItemName,
+    IOpenCallbackUI *openCallbackUI);
+
+HRESULT MyOpenArchive(
+    CCodecs *codecs,
+    const UString &archiveName, 
+    IInArchive **archive0,
+    IInArchive **archive1,
+    UString &defaultItemName0,
+    UString &defaultItemName1,
+    UStringVector &volumePaths,
+    UInt64 &volumesSize,
+    IOpenCallbackUI *openCallbackUI);
+
+struct CArchiveLink
+{
+  CMyComPtr<IInArchive> Archive0;
+  CMyComPtr<IInArchive> Archive1;
+  UString DefaultItemName0;
+  UString DefaultItemName1;
+
+  int FormatIndex0;
+  int FormatIndex1;
+  
+  UStringVector VolumePaths;
+
+  UInt64 VolumesSize;
+
+  int GetNumLevels() const
+  { 
+    int result = 0;
+    if (Archive0)
+    {
+      result++;
+      if (Archive1)
+        result++;
+    }
+    return result;
+  }
+
+  bool IsOpen;
+
+  CArchiveLink(): IsOpen(false), VolumesSize(0) {};
+
+  IInArchive *GetArchive() { return Archive1 != 0 ? Archive1: Archive0; }
+  UString GetDefaultItemName()  { return Archive1 != 0 ? DefaultItemName1: DefaultItemName0; }
+  int GetArchiverIndex() const { return Archive1 != 0 ? FormatIndex1: FormatIndex0; }
+  HRESULT Close();
+  void Release();
+};
+
+HRESULT OpenArchive(
+    CCodecs *codecs,
+    const UString &archiveName, 
+    CArchiveLink &archiveLink,
+    IArchiveOpenCallback *openCallback);
+
+HRESULT MyOpenArchive(
+    CCodecs *codecs,
+    const UString &archiveName, 
+    CArchiveLink &archiveLink,
+    IOpenCallbackUI *openCallbackUI);
+
+HRESULT ReOpenArchive(
+    CCodecs *codecs,
+    CArchiveLink &archiveLink, 
+    const UString &fileName);
+
+#endif
+
diff --git a/lzma/CPP/7zip/UI/Common/PropIDUtils.cpp b/lzma/CPP/7zip/UI/Common/PropIDUtils.cpp
new file mode 100644 (file)
index 0000000..7659688
--- /dev/null
@@ -0,0 +1,89 @@
+// PropIDUtils.cpp
+
+#include "StdAfx.h"
+
+#include "PropIDUtils.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/FileFind.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../PropID.h"
+
+using namespace NWindows;
+
+static UString ConvertUInt32ToString(UInt32 value)
+{
+  wchar_t buffer[32];
+  ConvertUInt64ToString(value, buffer);
+  return buffer;
+}
+
+static void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
+{
+  for (int i = 0; i < 8; i++)
+  {
+    int t = value & 0xF;
+    value >>= 4;
+    s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
+  }
+  s[8] = L'\0';
+}
+
+UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full)
+{
+  switch(propID)
+  {
+    case kpidCreationTime:
+    case kpidLastWriteTime:
+    case kpidLastAccessTime:
+    {
+      if (propVariant.vt != VT_FILETIME)
+        return UString(); // It is error;
+      FILETIME localFileTime;
+      if (propVariant.filetime.dwHighDateTime == 0 && 
+          propVariant.filetime.dwLowDateTime == 0)
+        return UString();
+      if (!::FileTimeToLocalFileTime(&propVariant.filetime, &localFileTime))
+        return UString(); // It is error;
+      return ConvertFileTimeToString(localFileTime, true, full);
+    }
+    case kpidCRC:
+    {
+      if(propVariant.vt != VT_UI4)
+        break;
+      wchar_t temp[12];
+      ConvertUInt32ToHex(propVariant.ulVal, temp);
+      return temp;
+    }
+    case kpidAttributes:
+    {
+      if(propVariant.vt != VT_UI4)
+        break;
+      UString result;
+      UInt32 attributes = propVariant.ulVal;
+      if (NFile::NFind::NAttributes::IsReadOnly(attributes)) result += L'R';
+      if (NFile::NFind::NAttributes::IsHidden(attributes)) result += L'H';
+      if (NFile::NFind::NAttributes::IsSystem(attributes)) result += L'S';
+      if (NFile::NFind::NAttributes::IsDirectory(attributes)) result += L'D';
+      if (NFile::NFind::NAttributes::IsArchived(attributes)) result += L'A';
+      if (NFile::NFind::NAttributes::IsCompressed(attributes)) result += L'C';
+      if (NFile::NFind::NAttributes::IsEncrypted(attributes)) result += L'E';
+      return result;
+    }
+    case kpidDictionarySize:
+    {
+      if(propVariant.vt != VT_UI4)
+        break;
+      UInt32 size = propVariant.ulVal;
+      if (size % (1 << 20) == 0)
+        return ConvertUInt32ToString(size >> 20) + L"MB";
+      if (size % (1 << 10) == 0)
+        return ConvertUInt32ToString(size >> 10) + L"KB";
+      return ConvertUInt32ToString(size);
+    }
+  }
+  return ConvertPropVariantToString(propVariant);
+}
diff --git a/lzma/CPP/7zip/UI/Common/PropIDUtils.h b/lzma/CPP/7zip/UI/Common/PropIDUtils.h
new file mode 100644 (file)
index 0000000..1d82097
--- /dev/null
@@ -0,0 +1,10 @@
+// PropIDUtils.h
+
+#ifndef __PROPIDUTILS_H
+#define __PROPIDUTILS_H
+
+#include "Common/MyString.h"
+
+UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full = true);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/Property.h b/lzma/CPP/7zip/UI/Common/Property.h
new file mode 100644 (file)
index 0000000..9fd340c
--- /dev/null
@@ -0,0 +1,14 @@
+// Property.h
+
+#ifndef __PROPERTY_H
+#define __PROPERTY_H
+
+#include "Common/MyString.h"
+
+struct CProperty
+{
+  UString Name;
+  UString Value;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/SetProperties.cpp b/lzma/CPP/7zip/UI/Common/SetProperties.cpp
new file mode 100644 (file)
index 0000000..b1434ac
--- /dev/null
@@ -0,0 +1,65 @@
+// SetProperties.cpp
+
+#include "StdAfx.h"
+
+#include "SetProperties.h"
+
+#include "Windows/PropVariant.h"
+#include "Common/MyString.h"
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+#include "../../Archive/IArchive.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+  const wchar_t *endPtr;
+  UInt64 result = ConvertStringToUInt64(s, &endPtr);
+  if (endPtr - (const wchar_t *)s != s.Length())
+    prop = s;
+  else if (result <= 0xFFFFFFFF)
+    prop = (UInt32)result;
+  else 
+    prop = result;
+}
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
+{
+  if (properties.IsEmpty())
+    return S_OK;
+  CMyComPtr<ISetProperties> setProperties;
+  unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
+  if (!setProperties)
+    return S_OK;
+
+  UStringVector realNames;
+  CPropVariant *values = new CPropVariant[properties.Size()];
+  try
+  {
+    int i;
+    for(i = 0; i < properties.Size(); i++)
+    {
+      const CProperty &property = properties[i];
+      NCOM::CPropVariant propVariant;
+      if (!property.Value.IsEmpty())
+        ParseNumberString(property.Value, propVariant);
+      realNames.Add(property.Name);
+      values[i] = propVariant;
+    }
+    CRecordVector<const wchar_t *> names;
+    for(i = 0; i < realNames.Size(); i++)
+      names.Add((const wchar_t *)realNames[i]);
+    
+    RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
+  }
+  catch(...)
+  {
+    delete []values;
+    throw;
+  }
+  delete []values;
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Common/SetProperties.h b/lzma/CPP/7zip/UI/Common/SetProperties.h
new file mode 100644 (file)
index 0000000..892f1a2
--- /dev/null
@@ -0,0 +1,10 @@
+// SetProperties.h
+
+#ifndef __SETPROPERTIES_H
+#define __SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/SortUtils.cpp b/lzma/CPP/7zip/UI/Common/SortUtils.cpp
new file mode 100644 (file)
index 0000000..061e777
--- /dev/null
@@ -0,0 +1,22 @@
+// SortUtils.cpp
+
+#include "StdAfx.h"
+
+#include "SortUtils.h"
+#include "Common/Wildcard.h"
+
+static int CompareStrings(const int *p1, const int *p2, void *param)
+{
+  const UStringVector &strings = *(const UStringVector *)param;
+  return CompareFileNames(strings[*p1], strings[*p2]);
+}
+
+void SortFileNames(const UStringVector &strings, CIntVector &indices)
+{
+  indices.Clear();
+  int numItems = strings.Size();
+  indices.Reserve(numItems);
+  for(int i = 0; i < numItems; i++)
+    indices.Add(i);
+  indices.Sort(CompareStrings, (void *)&strings);
+}
diff --git a/lzma/CPP/7zip/UI/Common/SortUtils.h b/lzma/CPP/7zip/UI/Common/SortUtils.h
new file mode 100644 (file)
index 0000000..e152246
--- /dev/null
@@ -0,0 +1,10 @@
+// SortUtils.h
+
+#ifndef __SORTUTLS_H
+#define __SORTUTLS_H
+
+#include "Common/MyString.h"
+
+void SortFileNames(const UStringVector &strings, CIntVector &indices);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/TempFiles.cpp b/lzma/CPP/7zip/UI/Common/TempFiles.cpp
new file mode 100644 (file)
index 0000000..eeaec18
--- /dev/null
@@ -0,0 +1,22 @@
+// TempFiles.cpp
+
+#include "StdAfx.h"
+
+#include "TempFiles.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileIO.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+void CTempFiles::Clear()
+{
+  while(!Paths.IsEmpty())
+  {
+    NDirectory::DeleteFileAlways((LPCWSTR)Paths.Back());
+    Paths.DeleteBack();
+  }
+}
+
+
diff --git a/lzma/CPP/7zip/UI/Common/TempFiles.h b/lzma/CPP/7zip/UI/Common/TempFiles.h
new file mode 100644 (file)
index 0000000..eb474a7
--- /dev/null
@@ -0,0 +1,16 @@
+// TempFiles.h
+
+#ifndef __TEMPFILES_H
+#define __TEMPFILES_H
+
+#include "Common/MyString.h"
+
+class CTempFiles
+{
+  void Clear();
+public:
+  UStringVector Paths;
+  ~CTempFiles() { Clear(); }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/Update.cpp b/lzma/CPP/7zip/UI/Common/Update.cpp
new file mode 100644 (file)
index 0000000..ec5ebc8
--- /dev/null
@@ -0,0 +1,852 @@
+// Update.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <mapi.h>
+#endif
+
+#include "Update.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+#include "Common/CommandLineParser.h"
+
+#ifdef _WIN32
+#include "Windows/DLL.h"
+#endif
+
+#include "Windows/Defs.h"
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/FileName.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+// #include "Windows/Synchronization.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Compress/Copy/CopyCoder.h"
+
+#include "../Common/DirItem.h"
+#include "../Common/EnumDirItems.h"
+#include "../Common/UpdateProduce.h"
+#include "../Common/OpenArchive.h"
+
+#include "TempFiles.h"
+#include "UpdateCallback.h"
+#include "EnumDirItems.h"
+#include "SetProperties.h"
+
+static const char *kUpdateIsNotSupoorted = 
+  "update operations are not supported for this archive";
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NCOM;
+using namespace NFile;
+using namespace NName;
+
+static const wchar_t *kTempFolderPrefix = L"7zE";
+
+using namespace NUpdateArchive;
+
+static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
+{
+  CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+  return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
+}
+
+class COutMultiVolStream: 
+  public IOutStream,
+  public CMyUnknownImp
+{
+  int _streamIndex; // required stream
+  UInt64 _offsetPos; // offset from start of _streamIndex index
+  UInt64 _absPos;
+  UInt64 _length;
+
+  struct CSubStreamInfo
+  {
+    COutFileStream *StreamSpec;
+    CMyComPtr<IOutStream> Stream;
+    UString Name;
+    UInt64 Pos;
+    UInt64 RealSize;
+  };
+  CObjectVector<CSubStreamInfo> Streams;
+public:
+  // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+  CRecordVector<UInt64> Sizes;
+  UString Prefix;
+  CTempFiles *TempFiles;
+
+  void Init()
+  {
+    _streamIndex = 0;
+    _offsetPos = 0;
+    _absPos = 0;
+    _length = 0;
+  }
+
+  HRESULT Close(); 
+
+  MY_UNKNOWN_IMP1(IOutStream)
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+  STDMETHOD(SetSize)(Int64 newSize);
+};
+
+// static NSynchronization::CCriticalSection g_TempPathsCS;
+
+HRESULT COutMultiVolStream::Close()
+{
+  HRESULT res = S_OK;
+  for (int i = 0; i < Streams.Size(); i++)
+  {
+    CSubStreamInfo &s = Streams[i];
+    if (s.StreamSpec)
+    {
+      HRESULT res2 = s.StreamSpec->Close();
+      if (res2 != S_OK)
+        res = res2;
+    }
+  }
+  return res;
+}
+
+STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if(processedSize != NULL)
+    *processedSize = 0;
+  while(size > 0)
+  {
+    if (_streamIndex >= Streams.Size())
+    {
+      CSubStreamInfo subStream;
+
+      wchar_t temp[32];
+      ConvertUInt64ToString(_streamIndex + 1, temp);
+      UString res = temp;
+      while (res.Length() < 3)
+        res = UString(L'0') + res;
+      UString name = Prefix + res;
+      subStream.StreamSpec = new COutFileStream;
+      subStream.Stream = subStream.StreamSpec;
+      if(!subStream.StreamSpec->Create(name, false))
+        return ::GetLastError();
+      {
+        // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
+        TempFiles->Paths.Add(name);
+      }
+
+      subStream.Pos = 0;
+      subStream.RealSize = 0;
+      subStream.Name = name;
+      Streams.Add(subStream);
+      continue;
+    }
+    CSubStreamInfo &subStream = Streams[_streamIndex];
+
+    int index = _streamIndex;
+    if (index >= Sizes.Size())
+      index = Sizes.Size() - 1;
+    UInt64 volSize = Sizes[index];
+
+    if (_offsetPos >= volSize)
+    {
+      _offsetPos -= volSize;
+      _streamIndex++;
+      continue;
+    }
+    if (_offsetPos != subStream.Pos)
+    {
+      // CMyComPtr<IOutStream> outStream;
+      // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+      RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+      subStream.Pos = _offsetPos;
+    }
+
+    UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
+    UInt32 realProcessed;
+    RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+    data = (void *)((Byte *)data + realProcessed);
+    size -= realProcessed;
+    subStream.Pos += realProcessed;
+    _offsetPos += realProcessed;
+    _absPos += realProcessed;
+    if (_absPos > _length)
+      _length = _absPos;
+    if (_offsetPos > subStream.RealSize)
+      subStream.RealSize = _offsetPos;
+    if(processedSize != NULL)
+      *processedSize += realProcessed;
+    if (subStream.Pos == volSize)
+    {
+      _streamIndex++;
+      _offsetPos = 0;
+    }
+    if (realProcessed == 0 && curSize != 0)
+      return E_FAIL;
+    break;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+  if(seekOrigin >= 3)
+    return STG_E_INVALIDFUNCTION;
+  switch(seekOrigin)
+  {
+    case STREAM_SEEK_SET:
+      _absPos = offset;
+      break;
+    case STREAM_SEEK_CUR:
+      _absPos += offset;
+      break;
+    case STREAM_SEEK_END:
+      _absPos = _length + offset;
+      break;
+  }
+  _offsetPos = _absPos;
+  if (newPosition != NULL)
+    *newPosition = _absPos;
+  _streamIndex = 0;
+  return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::SetSize(Int64 newSize)
+{
+  if (newSize < 0)
+    return E_INVALIDARG;
+  int i = 0;
+  while (i < Streams.Size())
+  {
+    CSubStreamInfo &subStream = Streams[i++];
+    if ((UInt64)newSize < subStream.RealSize)
+    {
+      RINOK(subStream.Stream->SetSize(newSize));
+      subStream.RealSize = newSize;
+      break;
+    }
+    newSize -= subStream.RealSize;
+  }
+  while (i < Streams.Size())
+  {
+    {
+      CSubStreamInfo &subStream = Streams.Back();
+      subStream.Stream.Release();
+      NDirectory::DeleteFileAlways(subStream.Name);
+    }
+    Streams.DeleteBack();
+  }
+  _offsetPos = _absPos;
+  _streamIndex = 0;
+  _length = newSize;
+  return S_OK;
+}
+
+static const wchar_t *kDefaultArchiveType = L"7z";
+static const wchar_t *kSFXExtension =
+  #ifdef _WIN32
+    L"exe";
+  #else
+    L"";
+  #endif
+
+bool CUpdateOptions::Init(const CCodecs *codecs, const UString &arcPath, const UString &arcType)
+{
+  if (!arcType.IsEmpty())
+    MethodMode.FormatIndex = codecs->FindFormatForArchiveType(arcType);
+  else
+  {
+    MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
+    if (MethodMode.FormatIndex < 0)
+      MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType);
+  }
+  if (MethodMode.FormatIndex < 0)
+    return false;
+  const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex];
+  UString typeExt = arcInfo.GetMainExt();
+  UString ext = typeExt;
+  if (SfxMode)
+    ext = kSFXExtension;
+  ArchivePath.BaseExtension = ext;
+  ArchivePath.VolExtension = typeExt;
+  ArchivePath.ParseFromPath(arcPath);
+  for (int i = 0; i < Commands.Size(); i++)
+  {
+    CUpdateArchiveCommand &uc = Commands[i];
+    uc.ArchivePath.BaseExtension = ext;
+    uc.ArchivePath.VolExtension = typeExt;
+    uc.ArchivePath.ParseFromPath(uc.UserArchivePath);
+  }
+  return true;
+}
+
+
+static HRESULT Compress(
+    CCodecs *codecs,
+    const CActionSet &actionSet, 
+    IInArchive *archive,
+    const CCompressionMethodMode &compressionMethod,
+    CArchivePath &archivePath, 
+    const CObjectVector<CArchiveItem> &archiveItems,
+    bool shareForWrite,
+    bool stdInMode,
+    /* const UString & stdInFileName, */
+    bool stdOutMode,
+    const CObjectVector<CDirItem> &dirItems,
+    bool sfxMode,
+    const UString &sfxModule,
+    const CRecordVector<UInt64> &volumesSizes,
+    CTempFiles &tempFiles,
+    CUpdateErrorInfo &errorInfo,
+    IUpdateCallbackUI *callback)
+{
+  CMyComPtr<IOutArchive> outArchive;
+  if(archive != NULL)
+  {
+    CMyComPtr<IInArchive> archive2 = archive;
+    HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
+    if(result != S_OK)
+      throw kUpdateIsNotSupoorted;
+  }
+  else
+  {
+    RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive));
+
+    #ifdef EXTERNAL_CODECS
+    {
+      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+      outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+      if (setCompressCodecsInfo)
+      {
+        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
+      }
+    }
+    #endif
+  }
+  if (outArchive == 0)
+    throw kUpdateIsNotSupoorted;
+  
+  NFileTimeType::EEnum fileTimeType;
+  UInt32 value;
+  RINOK(outArchive->GetFileTimeType(&value));
+
+  switch(value)
+  {
+    case NFileTimeType::kWindows:
+    case NFileTimeType::kDOS:
+    case NFileTimeType::kUnix:
+      fileTimeType = NFileTimeType::EEnum(value);
+      break;
+    default:
+      return E_FAIL;
+  }
+
+  CObjectVector<CUpdatePair> updatePairs;
+  GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); // must be done only once!!!
+  
+  CObjectVector<CUpdatePair2> updatePairs2;
+  UpdateProduce(updatePairs, actionSet, updatePairs2);
+
+  UInt32 numFiles = 0;
+  for (int i = 0; i < updatePairs2.Size(); i++)
+    if (updatePairs2[i].NewData)
+      numFiles++;
+  
+  RINOK(callback->SetNumFiles(numFiles));
+
+  
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+  
+  updateCallbackSpec->ShareForWrite = shareForWrite;
+  updateCallbackSpec->StdInMode = stdInMode;
+  updateCallbackSpec->Callback = callback;
+  updateCallbackSpec->DirItems = &dirItems;
+  updateCallbackSpec->ArchiveItems = &archiveItems;
+  updateCallbackSpec->UpdatePairs = &updatePairs2;
+
+  CMyComPtr<ISequentialOutStream> outStream;
+
+  const UString &archiveName = archivePath.GetFinalPath();
+  if (!stdOutMode)
+  {
+    UString resultPath;
+    int pos;
+    if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
+      throw 1417161;
+    NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
+  }
+
+  COutFileStream *outStreamSpec = NULL;
+  COutMultiVolStream *volStreamSpec = NULL;
+
+  if (volumesSizes.Size() == 0)
+  {
+    if (stdOutMode)
+      outStream = new CStdOutFileStream;
+    else
+    {
+      outStreamSpec = new COutFileStream;
+      outStream = outStreamSpec;
+      bool isOK = false;
+      UString realPath;
+      for (int i = 0; i < (1 << 16); i++)
+      {
+        if (archivePath.Temp)
+        {
+          if (i > 0)
+          {
+            wchar_t s[32];
+            ConvertUInt64ToString(i, s);
+            archivePath.TempPostfix = s;
+          }
+          realPath = archivePath.GetTempPath();
+        }
+        else
+          realPath = archivePath.GetFinalPath();
+        if (outStreamSpec->Create(realPath, false))
+        {
+          tempFiles.Paths.Add(realPath);
+          isOK = true;
+          break;
+        }
+        if (::GetLastError() != ERROR_FILE_EXISTS)
+          break;
+        if (!archivePath.Temp)
+          break;
+      }
+      if (!isOK)
+      {
+        errorInfo.SystemError = ::GetLastError();
+        errorInfo.FileName = realPath;
+        errorInfo.Message = L"Can not open file";
+        return E_FAIL;
+      }
+    }
+  }
+  else
+  {
+    if (stdOutMode)
+      return E_FAIL;
+    volStreamSpec = new COutMultiVolStream;
+    outStream = volStreamSpec;
+    volStreamSpec->Sizes = volumesSizes;
+    volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
+    volStreamSpec->TempFiles = &tempFiles;
+    volStreamSpec->Init();
+
+    /*
+    updateCallbackSpec->VolumesSizes = volumesSizes;
+    updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
+    if (!archivePath.VolExtension.IsEmpty())
+      updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
+    */
+  }
+
+  RINOK(SetProperties(outArchive, compressionMethod.Properties));
+
+  if (sfxMode)
+  {
+    CInFileStream *sfxStreamSpec = new CInFileStream;
+    CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+    if (!sfxStreamSpec->Open(sfxModule))
+    {
+      errorInfo.SystemError = ::GetLastError();
+      errorInfo.Message = L"Can't open sfx module";
+      errorInfo.FileName = sfxModule;
+      return E_FAIL;
+    }
+
+    CMyComPtr<ISequentialOutStream> sfxOutStream;
+    COutFileStream *outStreamSpec = NULL;
+    if (volumesSizes.Size() == 0)
+      sfxOutStream = outStream;
+    else
+    {
+      outStreamSpec = new COutFileStream;
+      sfxOutStream = outStreamSpec;
+      UString realPath = archivePath.GetFinalPath();
+      if (!outStreamSpec->Create(realPath, false))
+      {
+        errorInfo.SystemError = ::GetLastError();
+        errorInfo.FileName = realPath;
+        errorInfo.Message = L"Can not open file";
+        return E_FAIL;
+      }
+    }
+    RINOK(CopyBlock(sfxStream, sfxOutStream));
+    if (outStreamSpec)
+    {
+      RINOK(outStreamSpec->Close());
+    }
+  }
+
+  HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback);
+  callback->Finilize();
+  RINOK(result);
+  if (outStreamSpec)
+    result = outStreamSpec->Close();
+  else if (volStreamSpec)
+    result = volStreamSpec->Close();
+  return result;
+}
+
+HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
+    IInArchive *archive,
+    const UString &defaultItemName,
+    const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
+    CObjectVector<CArchiveItem> &archiveItems)
+{
+  archiveItems.Clear();
+  UInt32 numItems;
+  RINOK(archive->GetNumberOfItems(&numItems));
+  archiveItems.Reserve(numItems);
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    CArchiveItem ai;
+
+    RINOK(GetArchiveItemPath(archive, i, ai.Name));
+    RINOK(IsArchiveItemFolder(archive, i, ai.IsDirectory));
+    ai.Censored = censor.CheckPath(ai.Name.IsEmpty() ? defaultItemName : ai.Name, !ai.IsDirectory);
+    RINOK(GetArchiveItemFileTime(archive, i, 
+        archiveFileInfo.LastWriteTime, ai.LastWriteTime));
+
+    CPropVariant propertySize;
+    RINOK(archive->GetProperty(i, kpidSize, &propertySize));
+    ai.SizeIsDefined = (propertySize.vt != VT_EMPTY);
+    if (ai.SizeIsDefined)
+      ai.Size = ConvertPropVariantToUInt64(propertySize);
+
+    ai.IndexInServer = i;
+    archiveItems.Add(ai);
+  }
+  return S_OK;
+}
+
+
+static HRESULT UpdateWithItemLists(
+    CCodecs *codecs,
+    CUpdateOptions &options,
+    IInArchive *archive, 
+    const CObjectVector<CArchiveItem> &archiveItems,
+    const CObjectVector<CDirItem> &dirItems,
+    CTempFiles &tempFiles,
+    CUpdateErrorInfo &errorInfo,
+    IUpdateCallbackUI2 *callback)
+{
+  for(int i = 0; i < options.Commands.Size(); i++)
+  {
+    CUpdateArchiveCommand &command = options.Commands[i];
+    if (options.StdOutMode)
+    {
+      RINOK(callback->StartArchive(0, archive != 0));
+    }
+    else
+    {
+      RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(), 
+          i == 0 && options.UpdateArchiveItself && archive != 0));
+    }
+
+    RINOK(Compress(
+        codecs,
+        command.ActionSet, archive,
+        options.MethodMode, 
+        command.ArchivePath, 
+        archiveItems, 
+        options.OpenShareForWrite,
+        options.StdInMode, 
+        /* options.StdInFileName, */
+        options.StdOutMode,
+        dirItems, 
+        options.SfxMode, options.SfxModule, 
+        options.VolumesSizes,
+        tempFiles,
+        errorInfo, callback));
+
+    RINOK(callback->FinishArchive());
+  }
+  return S_OK;
+}
+
+#ifdef _WIN32
+class CCurrentDirRestorer
+{
+  UString m_CurrentDirectory;
+public:
+  CCurrentDirRestorer()
+    { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }
+  ~CCurrentDirRestorer()
+    { RestoreDirectory();}
+  bool RestoreDirectory()
+    { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(m_CurrentDirectory)); }
+};
+#endif
+
+struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
+{
+  IUpdateCallbackUI2 *Callback;
+  HRESULT CheckBreak() { return Callback->CheckBreak(); }
+};
+
+HRESULT UpdateArchive(
+    CCodecs *codecs,
+    const NWildcard::CCensor &censor, 
+    CUpdateOptions &options,
+    CUpdateErrorInfo &errorInfo,
+    IOpenCallbackUI *openCallback,
+    IUpdateCallbackUI2 *callback)
+{
+  if (options.StdOutMode && options.EMailMode)
+    return E_FAIL;
+
+  if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
+    return E_NOTIMPL;
+
+  if (options.SfxMode)
+  {
+    CProperty property;
+    property.Name = L"rsfx";
+    property.Value = L"on";
+    options.MethodMode.Properties.Add(property);
+    if (options.SfxModule.IsEmpty())
+    {
+      errorInfo.Message = L"sfx file is not specified";
+      return E_FAIL;
+    }
+    UString name = options.SfxModule;
+    if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
+    {
+      errorInfo.Message = L"can't find specified sfx module";
+      return E_FAIL;
+    }
+  }
+
+  const UString archiveName = options.ArchivePath.GetFinalPath();
+
+  UString defaultItemName;
+  NFind::CFileInfoW archiveFileInfo;
+
+  CArchiveLink archiveLink;
+  IInArchive *archive = 0;
+  if (NFind::FindFile(archiveName, archiveFileInfo))
+  {
+    if (archiveFileInfo.IsDirectory())
+      throw "there is no such archive";
+    if (options.VolumesSizes.Size() > 0)
+      return E_NOTIMPL;
+    HRESULT result = MyOpenArchive(codecs, archiveName, archiveLink, openCallback);
+    RINOK(callback->OpenResult(archiveName, result));
+    RINOK(result);
+    if (archiveLink.VolumePaths.Size() > 1)
+    {
+      errorInfo.SystemError = (DWORD)E_NOTIMPL;
+      errorInfo.Message = L"Updating for multivolume archives is not implemented";
+      return E_NOTIMPL;
+    }
+    archive = archiveLink.GetArchive();
+    defaultItemName = archiveLink.GetDefaultItemName();
+  }
+  else
+  {
+    /*
+    if (archiveType.IsEmpty())
+      throw "type of archive is not specified";
+    */
+  }
+
+  CObjectVector<CDirItem> dirItems;
+  if (options.StdInMode)
+  {
+    CDirItem item;
+    item.FullPath = item.Name = options.StdInFileName;
+    item.Size = (UInt64)(Int64)-1;
+    item.Attributes = 0;
+    SYSTEMTIME st;
+    FILETIME ft;
+    GetSystemTime(&st);
+    SystemTimeToFileTime(&st, &ft);
+    item.CreationTime = item.LastAccessTime = item.LastWriteTime = ft;
+    dirItems.Add(item);
+  }
+  else
+  {
+    bool needScanning = false;
+    for(int i = 0; i < options.Commands.Size(); i++)
+      if (options.Commands[i].ActionSet.NeedScanning())
+        needScanning = true;
+    if (needScanning)
+    {
+      CEnumDirItemUpdateCallback enumCallback;
+      enumCallback.Callback = callback;
+      RINOK(callback->StartScanning());
+      UStringVector errorPaths;
+      CRecordVector<DWORD> errorCodes;
+      HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
+      for (int i = 0; i < errorPaths.Size(); i++)
+      {
+        RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
+      }
+      if(res != S_OK) 
+      {
+        errorInfo.Message = L"Scanning error";
+        // errorInfo.FileName = errorPath;
+        return res;
+      }
+      RINOK(callback->FinishScanning());
+    }
+  }
+
+  UString tempDirPrefix;
+  bool usesTempDir = false;
+  
+  #ifdef _WIN32
+  NDirectory::CTempDirectoryW tempDirectory;
+  if (options.EMailMode && options.EMailRemoveAfter)
+  {
+    tempDirectory.Create(kTempFolderPrefix);
+    tempDirPrefix = tempDirectory.GetPath();
+    NormalizeDirPathPrefix(tempDirPrefix);
+    usesTempDir = true;
+  }
+  #endif
+
+  CTempFiles tempFiles;
+
+  bool createTempFile = false;
+  if(!options.StdOutMode && options.UpdateArchiveItself)
+  {
+    CArchivePath &ap = options.Commands[0].ArchivePath;
+    ap = options.ArchivePath;
+    // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
+    if ((archive != 0 || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
+    {
+      createTempFile = true;
+      ap.Temp = true;
+      if (!options.WorkingDir.IsEmpty())
+      {
+        ap.TempPrefix = options.WorkingDir;
+        NormalizeDirPathPrefix(ap.TempPrefix);
+      }
+    }
+  }
+
+  for(int i = 0; i < options.Commands.Size(); i++)
+  {
+    CArchivePath &ap = options.Commands[i].ArchivePath;
+    if (usesTempDir)
+    {
+      // Check it
+      ap.Prefix = tempDirPrefix;
+      // ap.Temp = true;
+      // ap.TempPrefix = tempDirPrefix;
+    }
+    if (i > 0 || !createTempFile)
+    {
+      const UString &path = ap.GetFinalPath();
+      if (NFind::DoesFileExist(path))
+      {
+        errorInfo.SystemError = 0;
+        errorInfo.Message = L"File already exists";
+        errorInfo.FileName = path;
+        return E_FAIL;
+      }
+    }
+  }
+
+  CObjectVector<CArchiveItem> archiveItems;
+  if (archive != NULL)
+  {
+    RINOK(EnumerateInArchiveItems(censor, 
+        archive, defaultItemName, archiveFileInfo, archiveItems));
+  }
+
+  RINOK(UpdateWithItemLists(codecs, options, archive, archiveItems, dirItems, 
+      tempFiles, errorInfo, callback));
+
+  if (archive != NULL)
+  {
+    RINOK(archiveLink.Close());
+    archiveLink.Release();
+  }
+
+  tempFiles.Paths.Clear();
+  if(createTempFile)
+  {
+    try
+    {
+      CArchivePath &ap = options.Commands[0].ArchivePath;
+      const UString &tempPath = ap.GetTempPath();
+      if (archive != NULL)
+        if (!NDirectory::DeleteFileAlways(archiveName))
+        {
+          errorInfo.SystemError = ::GetLastError();
+          errorInfo.Message = L"delete file error";
+          errorInfo.FileName = archiveName;
+          return E_FAIL;
+        }
+      if (!NDirectory::MyMoveFile(tempPath, archiveName))
+      {
+        errorInfo.SystemError = ::GetLastError();
+        errorInfo.Message = L"move file error";
+        errorInfo.FileName = tempPath;
+        errorInfo.FileName2 = archiveName;
+        return E_FAIL;
+      }
+    }
+    catch(...)
+    {
+      throw;
+    }
+  }
+
+  #ifdef _WIN32
+  if (options.EMailMode)
+  {
+    NDLL::CLibrary mapiLib;
+    if (!mapiLib.Load(TEXT("Mapi32.dll")))
+    {
+      errorInfo.SystemError = ::GetLastError();
+      errorInfo.Message = L"can not load Mapi32.dll";
+      return E_FAIL;
+    }
+    LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)
+        mapiLib.GetProcAddress("MAPISendDocuments");
+    if (fnSend == 0)
+    {
+      errorInfo.SystemError = ::GetLastError();
+      errorInfo.Message = L"can not find MAPISendDocuments function";
+      return E_FAIL;
+    }
+    UStringVector fullPaths;
+    int i;
+    for(i = 0; i < options.Commands.Size(); i++)
+    {
+      CArchivePath &ap = options.Commands[i].ArchivePath;
+      UString arcPath;
+      if(!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
+      {
+        errorInfo.SystemError = ::GetLastError();
+        return E_FAIL;
+      }
+      fullPaths.Add(arcPath);
+    }
+    CCurrentDirRestorer curDirRestorer;
+    for(i = 0; i < fullPaths.Size(); i++)
+    {
+      UString arcPath = fullPaths[i];
+      UString fileName = ExtractFileNameFromPath(arcPath);
+      AString path = GetAnsiString(arcPath);
+      AString name = GetAnsiString(fileName);
+      // Warning!!! MAPISendDocuments function changes Current directory
+      fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); 
+    }
+  }
+  #endif
+  return S_OK;
+}
+
diff --git a/lzma/CPP/7zip/UI/Common/Update.h b/lzma/CPP/7zip/UI/Common/Update.h
new file mode 100644 (file)
index 0000000..49e4be8
--- /dev/null
@@ -0,0 +1,165 @@
+// Update.h
+
+#ifndef __UPDATE_H
+#define __UPDATE_H
+
+#include "Common/Wildcard.h"
+#include "Windows/FileFind.h"
+#include "../../Archive/IArchive.h"
+
+#include "UpdateAction.h"
+#include "ArchiveOpenCallback.h"
+#include "UpdateCallback.h"
+#include "Property.h"
+#include "LoadCodecs.h"
+
+struct CArchivePath
+{
+  UString Prefix;   // path(folder) prefix including slash
+  UString Name; // base name
+  UString BaseExtension; // archive type extension or "exe" extension 
+  UString VolExtension;  // archive type extension for volumes
+
+  bool Temp;
+  UString TempPrefix;  // path(folder) for temp location
+  UString TempPostfix;
+
+  CArchivePath(): Temp(false) {};
+  
+  void ParseFromPath(const UString &path)
+  {
+    SplitPathToParts(path, Prefix, Name);
+    if (Name.IsEmpty())
+      return;
+    int dotPos = Name.ReverseFind(L'.');
+    if (dotPos <= 0)
+      return;
+    if (dotPos == Name.Length() - 1)
+    {
+      Name = Name.Left(dotPos);
+      BaseExtension.Empty();
+      return;
+    }
+    if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
+    {
+      BaseExtension = Name.Mid(dotPos + 1);
+      Name = Name.Left(dotPos);
+    }
+    else
+      BaseExtension.Empty();
+  }
+
+  UString GetPathWithoutExt() const
+  {
+    return Prefix + Name;
+  }
+
+  UString GetFinalPath() const
+  {
+    UString path = GetPathWithoutExt();
+    if (!BaseExtension.IsEmpty())
+      path += UString(L'.') + BaseExtension;
+    return path;
+  }
+
+  
+  UString GetTempPath() const
+  {
+    UString path = TempPrefix + Name;
+    if (!BaseExtension.IsEmpty())
+      path += UString(L'.') + BaseExtension;
+    path += L".tmp";
+    path += TempPostfix;
+    return path; 
+  }
+};
+
+struct CUpdateArchiveCommand
+{
+  UString UserArchivePath;
+  CArchivePath ArchivePath;
+  NUpdateArchive::CActionSet ActionSet;
+};
+
+struct CCompressionMethodMode
+{
+  int FormatIndex;
+  CObjectVector<CProperty> Properties;
+  CCompressionMethodMode(): FormatIndex(-1) {}
+};
+
+struct CUpdateOptions
+{
+  CCompressionMethodMode MethodMode;
+
+  CObjectVector<CUpdateArchiveCommand> Commands;
+  bool UpdateArchiveItself;
+  CArchivePath ArchivePath;
+  
+  bool SfxMode;
+  UString SfxModule;
+  
+  bool OpenShareForWrite;
+
+  bool StdInMode;
+  UString StdInFileName;
+  bool StdOutMode;
+  
+  bool EMailMode;
+  bool EMailRemoveAfter;
+  UString EMailAddress;
+
+  UString WorkingDir;
+
+  bool Init(const CCodecs *codecs, const UString &arcPath, const UString &arcType);
+
+  CUpdateOptions():
+    UpdateArchiveItself(true),
+    SfxMode(false),
+    StdInMode(false),
+    StdOutMode(false),
+    EMailMode(false),
+    EMailRemoveAfter(false),
+    OpenShareForWrite(false)
+      {};
+  CRecordVector<UInt64> VolumesSizes;
+};
+
+struct CErrorInfo
+{
+  DWORD SystemError;
+  UString FileName;
+  UString FileName2;
+  UString Message;
+  // UStringVector ErrorPaths;
+  // CRecordVector<DWORD> ErrorCodes;
+  CErrorInfo(): SystemError(0) {};
+};
+
+struct CUpdateErrorInfo: public CErrorInfo
+{
+};
+
+#define INTERFACE_IUpdateCallbackUI2(x) \
+  INTERFACE_IUpdateCallbackUI(x) \
+  virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) x; \
+  virtual HRESULT StartScanning() x; \
+  virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \
+  virtual HRESULT FinishScanning() x; \
+  virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
+  virtual HRESULT FinishArchive() x; \
+
+struct IUpdateCallbackUI2: public IUpdateCallbackUI
+{
+  INTERFACE_IUpdateCallbackUI2(=0)
+};
+
+HRESULT UpdateArchive(
+    CCodecs *codecs,
+    const NWildcard::CCensor &censor, 
+    CUpdateOptions &options,
+    CUpdateErrorInfo &errorInfo,
+    IOpenCallbackUI *openCallback,
+    IUpdateCallbackUI2 *callback);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/UpdateAction.cpp b/lzma/CPP/7zip/UI/Common/UpdateAction.cpp
new file mode 100644 (file)
index 0000000..5e3b5a1
--- /dev/null
@@ -0,0 +1,64 @@
+// UpdateAction.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateAction.h"
+
+namespace NUpdateArchive {
+
+const CActionSet kAddActionSet = 
+{
+  NPairAction::kCopy,
+  NPairAction::kCopy,
+  NPairAction::kCompress,
+  NPairAction::kCompress,
+  NPairAction::kCompress,
+  NPairAction::kCompress,
+  NPairAction::kCompress
+};
+
+const CActionSet kUpdateActionSet = 
+{
+  NPairAction::kCopy,
+  NPairAction::kCopy,
+  NPairAction::kCompress,
+  NPairAction::kCopy,
+  NPairAction::kCompress,
+  NPairAction::kCopy,
+  NPairAction::kCompress
+};
+
+const CActionSet kFreshActionSet = 
+{
+  NPairAction::kCopy,
+  NPairAction::kCopy,
+  NPairAction::kIgnore,
+  NPairAction::kCopy,
+  NPairAction::kCompress,
+  NPairAction::kCopy,
+  NPairAction::kCompress
+};
+
+const CActionSet kSynchronizeActionSet = 
+{
+  NPairAction::kCopy,
+  NPairAction::kIgnore,
+  NPairAction::kCompress,
+  NPairAction::kCopy,
+  NPairAction::kCompress,
+  NPairAction::kCopy,
+  NPairAction::kCompress,
+};
+
+const CActionSet kDeleteActionSet = 
+{
+  NPairAction::kCopy,
+  NPairAction::kIgnore,
+  NPairAction::kIgnore,
+  NPairAction::kIgnore,
+  NPairAction::kIgnore,
+  NPairAction::kIgnore,
+  NPairAction::kIgnore
+};
+
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdateAction.h b/lzma/CPP/7zip/UI/Common/UpdateAction.h
new file mode 100644 (file)
index 0000000..aa05097
--- /dev/null
@@ -0,0 +1,57 @@
+// UpdateAction.h
+
+#ifndef __UPDATE_ACTION_H
+#define __UPDATE_ACTION_H
+
+namespace NUpdateArchive {
+
+  namespace NPairState 
+  {
+    const int kNumValues = 7;
+    enum EEnum
+    {
+      kNotMasked = 0,
+      kOnlyInArchive,
+      kOnlyOnDisk,
+      kNewInArchive,
+      kOldInArchive,
+      kSameFiles,
+      kUnknowNewerFiles
+    };
+  }
+  namespace NPairAction
+  {
+    enum EEnum
+    {
+      kIgnore = 0,
+      kCopy,
+      kCompress,
+      kCompressAsAnti
+    };
+  }
+  struct CActionSet
+  {
+    NPairAction::EEnum StateActions[NPairState::kNumValues];
+    bool NeedScanning() const
+    {
+      int i;
+      for (i = 0; i < NPairState::kNumValues; i++)
+        if (StateActions[i] == NPairAction::kCompress)
+          return true;
+      for (i = 1; i < NPairState::kNumValues; i++)
+        if (StateActions[i] != NPairAction::kIgnore)
+          return true;
+      return false;
+    }
+  };
+  extern const CActionSet kAddActionSet;
+  extern const CActionSet kUpdateActionSet;
+  extern const CActionSet kFreshActionSet;
+  extern const CActionSet kSynchronizeActionSet;
+  extern const CActionSet kDeleteActionSet;
+};
+
+
+#endif
+
+
diff --git a/lzma/CPP/7zip/UI/Common/UpdateCallback.cpp b/lzma/CPP/7zip/UI/Common/UpdateCallback.cpp
new file mode 100644 (file)
index 0000000..a5f0a54
--- /dev/null
@@ -0,0 +1,267 @@
+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateCallback.h"
+
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+#include "Common/Defs.h"
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+using namespace NWindows;
+
+CArchiveUpdateCallback::CArchiveUpdateCallback():
+  Callback(0),
+  ShareForWrite(false),
+  StdInMode(false),
+  DirItems(0),
+  ArchiveItems(0),
+  UpdatePairs(0)
+  {}
+
+
+STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
+{
+  COM_TRY_BEGIN
+  return Callback->SetTotal(size);
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
+{
+  COM_TRY_BEGIN
+  return Callback->SetCompleted(completeValue);
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+  COM_TRY_BEGIN
+  return Callback->SetRatioInfo(inSize, outSize);
+  COM_TRY_END
+}
+
+
+/*
+STATPROPSTG kProperties[] = 
+{
+  { NULL, kpidPath, VT_BSTR},
+  { NULL, kpidIsFolder, VT_BOOL},
+  { NULL, kpidSize, VT_UI8},
+  { NULL, kpidLastAccessTime, VT_FILETIME},
+  { NULL, kpidCreationTime, VT_FILETIME},
+  { NULL, kpidLastWriteTime, VT_FILETIME},
+  { NULL, kpidAttributes, VT_UI4},
+  { NULL, kpidIsAnti, VT_BOOL}
+};
+*/
+
+STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
+{
+  return E_NOTIMPL;
+  /*
+  return CStatPropEnumerator::CreateEnumerator(kProperties, 
+      sizeof(kProperties) / sizeof(kProperties[0]), enumerator);
+  */
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, 
+      Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
+{
+  COM_TRY_BEGIN
+  RINOK(Callback->CheckBreak());
+  const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
+  if(newData != NULL)
+    *newData = BoolToInt(updatePair.NewData);
+  if(newProperties != NULL)
+    *newProperties = BoolToInt(updatePair.NewProperties);
+  if(indexInArchive != NULL)
+  {
+    if (updatePair.ExistInArchive)
+    {
+      if (ArchiveItems == 0)
+        *indexInArchive = updatePair.ArchiveItemIndex;
+      else
+        *indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
+    }
+    else
+      *indexInArchive = UInt32(-1);
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+  COM_TRY_BEGIN
+  const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
+  NWindows::NCOM::CPropVariant propVariant;
+  
+  if (propID == kpidIsAnti)
+  {
+    propVariant = updatePair.IsAnti;
+    propVariant.Detach(value);
+    return S_OK;
+  }
+
+  if (updatePair.IsAnti)
+  {
+    switch(propID)
+    {
+      case kpidIsFolder:
+      case kpidPath:
+        break;
+      case kpidSize:
+        propVariant = (UInt64)0;
+        propVariant.Detach(value);
+        return S_OK;
+      default:
+        propVariant.Detach(value);
+        return S_OK;
+    }
+  }
+  
+  if(updatePair.ExistOnDisk)
+  {
+    const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
+    switch(propID)
+    {
+      case kpidPath:
+        propVariant = dirItem.Name;
+        break;
+      case kpidIsFolder:
+        propVariant = dirItem.IsDirectory();
+        break;
+      case kpidSize:
+        propVariant = dirItem.Size;
+        break;
+      case kpidAttributes:
+        propVariant = dirItem.Attributes;
+        break;
+      case kpidLastAccessTime:
+        propVariant = dirItem.LastAccessTime;
+        break;
+      case kpidCreationTime:
+        propVariant = dirItem.CreationTime;
+        break;
+      case kpidLastWriteTime:
+        propVariant = dirItem.LastWriteTime;
+        break;
+    }
+  }
+  else
+  {
+    if (propID == kpidPath)
+    {
+      if (updatePair.NewNameIsDefined)
+      {
+        propVariant = updatePair.NewName;
+        propVariant.Detach(value);
+        return S_OK;
+      }
+    }
+    if (updatePair.ExistInArchive && Archive)
+    {
+      UInt32 indexInArchive;
+      if (ArchiveItems == 0)
+        indexInArchive = updatePair.ArchiveItemIndex;
+      else
+        indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
+      return Archive->GetProperty(indexInArchive, propID, value);
+    }
+  }
+  propVariant.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
+{
+  COM_TRY_BEGIN
+  const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
+  if(!updatePair.NewData)
+    return E_FAIL;
+  
+  RINOK(Callback->CheckBreak());
+  RINOK(Callback->Finilize());
+
+  if(updatePair.IsAnti)
+  {
+    return Callback->GetStream((*ArchiveItems)[updatePair.ArchiveItemIndex].Name, true);
+  }
+  const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
+  RINOK(Callback->GetStream(dirItem.Name, false));
+  if(dirItem.IsDirectory())
+    return S_OK;
+
+  if (StdInMode)
+  {
+    CStdInFileStream *inStreamSpec = new CStdInFileStream;
+    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+    *inStream = inStreamLoc.Detach();
+  }
+  else
+  {
+    CInFileStream *inStreamSpec = new CInFileStream;
+    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+    UString path = DirPrefix + dirItem.FullPath;
+    if(!inStreamSpec->OpenShared(path, ShareForWrite))
+    {
+      return Callback->OpenFileError(path, ::GetLastError());
+    }
+    *inStream = inStreamLoc.Detach();
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
+{
+  COM_TRY_BEGIN
+  return Callback->SetOperationResult(operationResult);
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
+{
+  if (VolumesSizes.Size() == 0)
+    return S_FALSE;
+  if (index >= (UInt32)VolumesSizes.Size())
+    index = VolumesSizes.Size() - 1;
+  *size = VolumesSizes[index];
+  return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
+{
+  COM_TRY_BEGIN
+  wchar_t temp[32];
+  ConvertUInt64ToString(index + 1, temp);
+  UString res = temp;
+  while (res.Length() < 2)
+    res = UString(L'0') + res;
+  UString fileName = VolName;
+  fileName += L'.';
+  fileName += res;
+  fileName += VolExt;
+  COutFileStream *streamSpec = new COutFileStream;
+  CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+  if(!streamSpec->Create(fileName, false))
+    return ::GetLastError();
+  *volumeStream = streamLoc.Detach();
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+  COM_TRY_BEGIN
+  return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
+  COM_TRY_END
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdateCallback.h b/lzma/CPP/7zip/UI/Common/UpdateCallback.h
new file mode 100644 (file)
index 0000000..bf90ff9
--- /dev/null
@@ -0,0 +1,82 @@
+// UpdateCallback.h
+
+#ifndef __UPDATECALLBACK_H
+#define __UPDATECALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/UpdateProduce.h"
+
+#define INTERFACE_IUpdateCallbackUI(x) \
+  virtual HRESULT SetTotal(UInt64 size) x; \
+  virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
+  virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \
+  virtual HRESULT CheckBreak() x; \
+  virtual HRESULT Finilize() x; \
+  virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
+  virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \
+  virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \
+  virtual HRESULT SetOperationResult(Int32 operationResult) x; \
+  virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
+
+  // virtual HRESULT CloseProgress() { return S_OK; };
+
+struct IUpdateCallbackUI
+{
+  INTERFACE_IUpdateCallbackUI(=0)
+};
+
+class CArchiveUpdateCallback: 
+  public IArchiveUpdateCallback2,
+  public ICryptoGetTextPassword2,
+  public ICompressProgressInfo,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP3(
+      IArchiveUpdateCallback2, 
+      ICryptoGetTextPassword2,
+      ICompressProgressInfo)
+
+  // IProgress
+  STDMETHOD(SetTotal)(UInt64 size);
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+  // IUpdateCallback
+  STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator);  
+  STDMETHOD(GetUpdateItemInfo)(UInt32 index, 
+      Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
+  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
+  STDMETHOD(SetOperationResult)(Int32 operationResult);
+
+  STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
+  STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);
+
+  STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
+
+public:
+  CRecordVector<UInt64> VolumesSizes;
+  UString VolName;
+  UString VolExt;
+
+  IUpdateCallbackUI *Callback;
+
+  UString DirPrefix;
+  bool ShareForWrite;
+  bool StdInMode;
+  const CObjectVector<CDirItem> *DirItems;
+  const CObjectVector<CArchiveItem> *ArchiveItems;
+  const CObjectVector<CUpdatePair2> *UpdatePairs;
+  CMyComPtr<IInArchive> Archive;
+
+  CArchiveUpdateCallback();
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/UpdatePair.cpp b/lzma/CPP/7zip/UI/Common/UpdatePair.cpp
new file mode 100644 (file)
index 0000000..b4fb2a1
--- /dev/null
@@ -0,0 +1,166 @@
+// UpdatePair.cpp
+
+#include "StdAfx.h"
+
+#include <time.h>
+
+#include "Common/Defs.h"
+#include "Common/Wildcard.h"
+#include "Windows/Time.h"
+
+#include "UpdatePair.h"
+#include "SortUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+static int MyCompareTime(NFileTimeType::EEnum fileTimeType, 
+    const FILETIME &time1, const FILETIME &time2)
+{
+  switch(fileTimeType)
+  {
+    case NFileTimeType::kWindows:
+      return ::CompareFileTime(&time1, &time2);
+    case NFileTimeType::kUnix:
+      {
+        UInt32 unixTime1, unixTime2;
+        if (!FileTimeToUnixTime(time1, unixTime1))
+        {
+          unixTime1 = 0;
+          // throw 4191614;
+        }
+        if (!FileTimeToUnixTime(time2, unixTime2))
+        {
+          unixTime2 = 0;
+          // throw 4191615;
+        }
+        return MyCompare(unixTime1, unixTime2);
+      }
+    case NFileTimeType::kDOS:
+      {
+        UInt32 dosTime1, dosTime2;
+        FileTimeToDosTime(time1, dosTime1);
+        FileTimeToDosTime(time2, dosTime2);
+        /*
+        if (!FileTimeToDosTime(time1, dosTime1))
+          throw 4191616;
+        if (!FileTimeToDosTime(time2, dosTime2))
+          throw 4191617;
+        */
+        return MyCompare(dosTime1, dosTime2);
+      }
+  }
+  throw 4191618;
+}
+
+static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:";
+
+/*
+static const char *kNotCensoredCollisionMessaged = "Internal file name collision:\n";
+static const char *kSameTimeChangedSizeCollisionMessaged = 
+    "Collision between files with same date/time and different sizes:\n";
+*/
+
+static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
+{
+  for(int i = 0; i + 1 < indices.Size(); i++)
+    if (CompareFileNames(strings[indices[i]], strings[indices[i + 1]]) == 0)
+    {
+      UString message = kDuplicateFileNameMessage;
+      message += L"\n";
+      message += strings[indices[i]];
+      message += L"\n";
+      message += strings[indices[i + 1]];
+      throw message;
+    }
+}
+
+void GetUpdatePairInfoList(
+    const CObjectVector<CDirItem> &dirItems, 
+    const CObjectVector<CArchiveItem> &archiveItems,
+    NFileTimeType::EEnum fileTimeType,
+    CObjectVector<CUpdatePair> &updatePairs)
+{
+  CIntVector dirIndices, archiveIndices;
+  UStringVector dirNames, archiveNames;
+  
+  int numDirItems = dirItems.Size(); 
+  int i;
+  for(i = 0; i < numDirItems; i++)
+    dirNames.Add(dirItems[i].Name);
+  SortFileNames(dirNames, dirIndices);
+  TestDuplicateString(dirNames, dirIndices);
+
+  int numArchiveItems = archiveItems.Size(); 
+  for(i = 0; i < numArchiveItems; i++)
+    archiveNames.Add(archiveItems[i].Name);
+  SortFileNames(archiveNames, archiveIndices);
+  TestDuplicateString(archiveNames, archiveIndices);
+  
+  int dirItemIndex = 0, archiveItemIndex = 0; 
+  CUpdatePair pair;
+  while(dirItemIndex < numDirItems && archiveItemIndex < numArchiveItems)
+  {
+    int dirItemIndex2 = dirIndices[dirItemIndex],
+        archiveItemIndex2 = archiveIndices[archiveItemIndex]; 
+    const CDirItem &dirItem = dirItems[dirItemIndex2];
+    const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
+    int compareResult = CompareFileNames(dirItem.Name, archiveItem.Name);
+    if (compareResult < 0)
+    {
+        pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+        pair.DirItemIndex = dirItemIndex2;
+        dirItemIndex++;
+    }
+    else if (compareResult > 0)
+    {
+      pair.State = archiveItem.Censored ? 
+        NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked;
+      pair.ArchiveItemIndex = archiveItemIndex2;
+      archiveItemIndex++;
+    }
+    else
+    {
+      if (!archiveItem.Censored)
+        throw 1082022;; // TTString(kNotCensoredCollisionMessaged + dirItem.Name);
+      pair.DirItemIndex = dirItemIndex2;
+      pair.ArchiveItemIndex = archiveItemIndex2;
+      switch (MyCompareTime(fileTimeType, dirItem.LastWriteTime, archiveItem.LastWriteTime))
+      {
+        case -1:
+          pair.State = NUpdateArchive::NPairState::kNewInArchive;
+          break;
+        case 1:
+          pair.State = NUpdateArchive::NPairState::kOldInArchive;
+          break;
+        default:
+          if (archiveItem.SizeIsDefined)
+            if (dirItem.Size != archiveItem.Size)
+              // throw 1082034; // kSameTimeChangedSizeCollisionMessaged;
+              pair.State = NUpdateArchive::NPairState::kUnknowNewerFiles;
+            else
+              pair.State = NUpdateArchive::NPairState::kSameFiles;
+          else
+              pair.State = NUpdateArchive::NPairState::kUnknowNewerFiles;
+      }
+      dirItemIndex++;
+      archiveItemIndex++;
+    }
+    updatePairs.Add(pair);
+  }
+  for(;dirItemIndex < numDirItems; dirItemIndex++)
+  {
+    pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+    pair.DirItemIndex = dirIndices[dirItemIndex];
+    updatePairs.Add(pair);
+  }
+  for(;archiveItemIndex < numArchiveItems; archiveItemIndex++)
+  {
+    int archiveItemIndex2 = archiveIndices[archiveItemIndex]; 
+    const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
+    pair.State = archiveItem.Censored ?  
+        NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked;
+    pair.ArchiveItemIndex = archiveItemIndex2;
+    updatePairs.Add(pair);
+  }
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdatePair.h b/lzma/CPP/7zip/UI/Common/UpdatePair.h
new file mode 100644 (file)
index 0000000..f50a23f
--- /dev/null
@@ -0,0 +1,24 @@
+// UpdatePair.h
+
+#ifndef __UPDATE_PAIR_H
+#define __UPDATE_PAIR_H
+
+#include "DirItem.h"
+#include "UpdateAction.h"
+
+#include "../../Archive/IArchive.h"
+
+struct CUpdatePair
+{
+  NUpdateArchive::NPairState::EEnum State;
+  int ArchiveItemIndex;
+  int DirItemIndex;
+};
+
+void GetUpdatePairInfoList(
+    const CObjectVector<CDirItem> &dirItems,
+    const CObjectVector<CArchiveItem> &archiveItems,
+    NFileTimeType::EEnum fileTimeType,
+    CObjectVector<CUpdatePair> &updatePairs);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/UpdateProduce.cpp b/lzma/CPP/7zip/UI/Common/UpdateProduce.cpp
new file mode 100644 (file)
index 0000000..5552161
--- /dev/null
@@ -0,0 +1,63 @@
+// UpdateProduce.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateProduce.h"
+
+using namespace NUpdateArchive;
+
+static const char *kUpdateActionSetCollision =
+    "Internal collision in update action set";
+
+void UpdateProduce(
+    const CObjectVector<CUpdatePair> &updatePairs,
+    const NUpdateArchive::CActionSet &actionSet,
+    CObjectVector<CUpdatePair2> &operationChain)
+{
+  for(int i = 0; i < updatePairs.Size(); i++)
+  {
+    // CUpdateArchiveRange aRange;
+    const CUpdatePair &pair = updatePairs[i];
+
+    CUpdatePair2 pair2;
+    pair2.IsAnti = false;
+    pair2.ArchiveItemIndex = pair.ArchiveItemIndex;
+    pair2.DirItemIndex = pair.DirItemIndex;
+    pair2.ExistInArchive = (pair.State != NPairState::kOnlyOnDisk);
+    pair2.ExistOnDisk = (pair.State != NPairState::kOnlyInArchive && pair.State != NPairState::kNotMasked);
+    switch(actionSet.StateActions[pair.State])
+    {
+      case NPairAction::kIgnore:
+        /*
+        if (pair.State != NPairState::kOnlyOnDisk)
+          IgnoreArchiveItem(m_ArchiveItems[pair.ArchiveItemIndex]);
+        // cout << "deleting";
+        */
+        break;
+      case NPairAction::kCopy:
+        {
+          if (pair.State == NPairState::kOnlyOnDisk)
+            throw kUpdateActionSetCollision;
+          pair2.NewData = pair2.NewProperties = false;
+          operationChain.Add(pair2);
+          break;
+        }
+      case NPairAction::kCompress:
+        {
+          if (pair.State == NPairState::kOnlyInArchive || 
+            pair.State == NPairState::kNotMasked)
+            throw kUpdateActionSetCollision;
+          pair2.NewData = pair2.NewProperties = true;
+          operationChain.Add(pair2);
+          break;
+        }
+      case NPairAction::kCompressAsAnti:
+        {
+          pair2.IsAnti = true;
+          pair2.NewData = pair2.NewProperties = true;
+          operationChain.Add(pair2);
+          break;
+        }
+    }
+  }
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdateProduce.h b/lzma/CPP/7zip/UI/Common/UpdateProduce.h
new file mode 100644 (file)
index 0000000..8f58dab
--- /dev/null
@@ -0,0 +1,31 @@
+// UpdateProduce.h
+
+#ifndef __UPDATE_PRODUCE_H
+#define __UPDATE_PRODUCE_H
+
+#include "UpdatePair.h"
+
+struct CUpdatePair2
+{
+  // bool OperationIsCompress;
+  bool NewData;
+  bool NewProperties;
+
+  bool ExistInArchive;
+  bool ExistOnDisk;
+  bool IsAnti;
+  int ArchiveItemIndex;
+  int DirItemIndex;
+
+  bool NewNameIsDefined;
+  UString NewName;
+
+  CUpdatePair2(): NewNameIsDefined(false) {}
+};
+
+void UpdateProduce(
+    const CObjectVector<CUpdatePair> &updatePairs,
+    const NUpdateArchive::CActionSet &actionSet,
+    CObjectVector<CUpdatePair2> &operationChain);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/WorkDir.cpp b/lzma/CPP/7zip/UI/Common/WorkDir.cpp
new file mode 100644 (file)
index 0000000..8db6f4f
--- /dev/null
@@ -0,0 +1,64 @@
+// WorkDir.cpp
+
+#include "StdAfx.h"
+
+#include "WorkDir.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileDir.h"
+
+static inline UINT GetCurrentCodePage() 
+  { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } 
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path)
+{
+  NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
+  if (workDirInfo.ForRemovableOnly)
+  {
+    mode = NWorkDir::NMode::kCurrent;
+    UString prefix = path.Left(3);
+    if (prefix[1] == L':' && prefix[2] == L'\\')
+    {
+      UINT driveType = GetDriveType(GetSystemString(prefix, GetCurrentCodePage()));
+      if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
+        mode = workDirInfo.Mode;
+    }
+    /*
+    CParsedPath parsedPath;
+    parsedPath.ParsePath(archiveName);
+    UINT driveType = GetDriveType(parsedPath.Prefix);
+    if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
+      mode = NZipSettings::NWorkDir::NMode::kCurrent;
+    */
+  }
+  switch(mode)
+  {
+    case NWorkDir::NMode::kCurrent:
+    {
+      return ExtractDirPrefixFromPath(path);
+    }
+    case NWorkDir::NMode::kSpecified:
+    {
+      UString tempDir = workDirInfo.Path;
+      NormalizeDirPathPrefix(tempDir);
+      return tempDir;
+    }
+    default:
+    {
+      UString tempDir;
+      if(!NFile::NDirectory::MyGetTempPath(tempDir))
+        throw 141717;
+      return tempDir;
+    }
+  }
+}
+
+
+
diff --git a/lzma/CPP/7zip/UI/Common/WorkDir.h b/lzma/CPP/7zip/UI/Common/WorkDir.h
new file mode 100644 (file)
index 0000000..0643d67
--- /dev/null
@@ -0,0 +1,10 @@
+// WorkDir.h
+
+#ifndef __WORKDIR_H
+#define __WORKDIR_H
+
+#include "ZipRegistry.h"
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ZipRegistry.h b/lzma/CPP/7zip/UI/Common/ZipRegistry.h
new file mode 100644 (file)
index 0000000..753287d
--- /dev/null
@@ -0,0 +1,98 @@
+// ZipRegistry.h
+
+#ifndef __ZIPREGISTRY_H
+#define __ZIPREGISTRY_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+#include "ExtractMode.h"
+
+namespace NExtract
+{
+  struct CInfo
+  {
+    NPathMode::EEnum PathMode;
+    NOverwriteMode::EEnum OverwriteMode;
+    UStringVector Paths;
+    bool ShowPassword;
+  };
+}
+
+namespace NCompression {
+  
+  struct CFormatOptions
+  {
+    CSysString FormatID;
+    UString Options;
+    UString Method;
+    UString EncryptionMethod;
+    UInt32 Level;
+    UInt32 Dictionary;
+    UInt32 Order;
+    UInt32 BlockLogSize;
+    UInt32 NumThreads;
+    void ResetForLevelChange() 
+    { 
+      BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-1); 
+      Method.Empty();
+      // EncryptionMethod.Empty();
+      // Options.Empty();
+    }
+    CFormatOptions() { ResetForLevelChange(); }
+  };
+
+  struct CInfo
+  {
+    UStringVector HistoryArchives;
+    UInt32 Level;
+    UString ArchiveType;
+
+    CObjectVector<CFormatOptions> FormatOptionsVector;
+
+    bool ShowPassword;
+    bool EncryptHeaders;
+  };
+}
+
+namespace NWorkDir{
+  
+  namespace NMode
+  {
+    enum EEnum
+    {
+      kSystem,
+      kCurrent,
+      kSpecified
+    };
+  }
+  struct CInfo
+  {
+    NMode::EEnum Mode;
+    UString Path;
+    bool ForRemovableOnly;
+    void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
+    void SetDefault()
+    {
+      Mode = NMode::kSystem;
+      Path.Empty();
+      SetForRemovableOnlyDefault();
+    }
+  };
+}
+
+void SaveExtractionInfo(const NExtract::CInfo &info);
+void ReadExtractionInfo(NExtract::CInfo &info);
+
+void SaveCompressionInfo(const NCompression::CInfo &info);
+void ReadCompressionInfo(NCompression::CInfo &info);
+
+void SaveWorkDirInfo(const NWorkDir::CInfo &info);
+void ReadWorkDirInfo(NWorkDir::CInfo &info);
+
+void SaveCascadedMenu(bool enabled);
+bool ReadCascadedMenu();
+
+void SaveContextMenuStatus(UInt32 value);
+bool ReadContextMenuStatus(UInt32 &value);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/ConsoleClose.cpp b/lzma/CPP/7zip/UI/Console/ConsoleClose.cpp
new file mode 100644 (file)
index 0000000..d18b39e
--- /dev/null
@@ -0,0 +1,63 @@
+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "ConsoleClose.h"
+
+static int g_BreakCounter = 0;
+static const int kBreakAbortThreshold = 2;
+
+namespace NConsoleClose {
+
+static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
+{
+  if (ctrlType == CTRL_LOGOFF_EVENT)
+  {
+    // printf("\nCTRL_LOGOFF_EVENT\n");
+    return TRUE;
+  }
+
+  g_BreakCounter++;
+  if (g_BreakCounter < kBreakAbortThreshold)
+    return TRUE;
+  return FALSE;
+  /*
+  switch(ctrlType)
+  {
+    case CTRL_C_EVENT:
+    case CTRL_BREAK_EVENT:
+      if (g_BreakCounter < kBreakAbortThreshold)
+      return TRUE;
+  }
+  return FALSE;
+  */
+}
+
+bool TestBreakSignal()
+{
+  /*
+  if (g_BreakCounter > 0)
+    return true;
+  */
+  return (g_BreakCounter > 0);
+}
+
+void CheckCtrlBreak()
+{
+  if (TestBreakSignal())
+    throw CCtrlBreakException();
+}
+
+CCtrlHandlerSetter::CCtrlHandlerSetter()
+{
+  if(!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
+    throw "SetConsoleCtrlHandler fails";
+}
+
+CCtrlHandlerSetter::~CCtrlHandlerSetter()
+{
+  if(!SetConsoleCtrlHandler(HandlerRoutine, FALSE))
+    throw "SetConsoleCtrlHandler fails";
+}
+
+}
diff --git a/lzma/CPP/7zip/UI/Console/ConsoleClose.h b/lzma/CPP/7zip/UI/Console/ConsoleClose.h
new file mode 100644 (file)
index 0000000..3c5fd55
--- /dev/null
@@ -0,0 +1,24 @@
+// ConsoleCloseUtils.h
+
+#ifndef __CONSOLECLOSEUTILS_H
+#define __CONSOLECLOSEUTILS_H
+
+namespace NConsoleClose {
+
+bool TestBreakSignal();
+
+class CCtrlHandlerSetter
+{
+public:
+  CCtrlHandlerSetter();
+  virtual ~CCtrlHandlerSetter();
+};
+
+class CCtrlBreakException 
+{};
+
+void CheckCtrlBreak();
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
new file mode 100644 (file)
index 0000000..d693cb4
--- /dev/null
@@ -0,0 +1,235 @@
+// ExtractCallbackConsole.h
+
+#include "StdAfx.h"
+
+#include "ExtractCallbackConsole.h"
+#include "UserInputUtils.h"
+#include "ConsoleClose.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/Time.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+#include "Windows/Error.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDirectory;
+
+static const char *kTestingString    =  "Testing     ";
+static const char *kExtractingString =  "Extracting  ";
+static const char *kSkippingString   =  "Skipping    ";
+
+// static const char *kCantAutoRename = "can not create file with auto name\n";
+// static const char *kCantRenameFile = "can not rename existing file\n";
+// static const char *kCantDeleteOutputFile = "can not delete output file ";
+static const char *kError = "ERROR: ";
+static const char *kMemoryExceptionMessage = "Can't allocate required memory!";
+
+static const char *kProcessing = "Processing archive: ";
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kNoFiles = "No files to process";
+
+static const char *kUnsupportedMethod = "Unsupported Method";
+static const char *kCrcFailed = "CRC Failed";
+static const char *kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
+static const char *kDataError = "Data Error";
+static const char *kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
+static const char *kUnknownError = "Unknown Error";
+
+STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64)
+{
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *)
+{
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
+    const wchar_t *existName, const FILETIME *, const UInt64 *,
+    const wchar_t *newName, const FILETIME *, const UInt64 *,
+    Int32 *answer)
+{
+  (*OutStream) << "file " << existName << 
+    "\nalready exists. Overwrite with " << endl;
+  (*OutStream) << newName;
+  
+  NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(OutStream);
+  
+  switch(overwriteAnswer)
+  {
+    case NUserAnswerMode::kQuit:
+      return E_ABORT;
+    case NUserAnswerMode::kNo:
+      *answer = NOverwriteAnswer::kNo;
+      break;
+    case NUserAnswerMode::kNoAll:
+      *answer = NOverwriteAnswer::kNoToAll;
+      break;
+    case NUserAnswerMode::kYesAll:
+      *answer = NOverwriteAnswer::kYesToAll;
+      break;
+    case NUserAnswerMode::kYes:
+      *answer = NOverwriteAnswer::kYes;
+      break;
+    case NUserAnswerMode::kAutoRename:
+      *answer = NOverwriteAnswer::kAutoRename;
+      break;
+    default:
+      return E_FAIL;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, bool /* isFolder */, Int32 askExtractMode, const UInt64 *position)
+{
+  switch (askExtractMode)
+  {
+    case NArchive::NExtract::NAskMode::kExtract:
+      (*OutStream) << kExtractingString;
+      break;
+    case NArchive::NExtract::NAskMode::kTest:
+      (*OutStream) << kTestingString;
+      break;
+    case NArchive::NExtract::NAskMode::kSkip:
+      (*OutStream) << kSkippingString;
+      break;
+  };
+  (*OutStream) << name;
+  if (position != 0)
+    (*OutStream) << " <" << *position << ">";
+  return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
+{
+  (*OutStream) << message << endl;
+  NumFileErrorsInCurrentArchive++;
+  NumFileErrors++;
+  return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 operationResult, bool encrypted)
+{
+  switch(operationResult)
+  {
+    case NArchive::NExtract::NOperationResult::kOK:
+      break;
+    default:
+    {
+      NumFileErrorsInCurrentArchive++;
+      NumFileErrors++;
+      (*OutStream) << "     ";
+      switch(operationResult)
+      {
+        case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+          (*OutStream) << kUnsupportedMethod;
+          break;
+        case NArchive::NExtract::NOperationResult::kCRCError:
+          (*OutStream) << (encrypted ? kCrcFailedEncrypted: kCrcFailed);
+          break;
+        case NArchive::NExtract::NOperationResult::kDataError:
+          (*OutStream) << (encrypted ? kDataErrorEncrypted : kDataError);
+          break;
+        default:
+          (*OutStream) << kUnknownError;
+      }
+    }
+  }
+  (*OutStream) << endl;
+  return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+  if (!PasswordIsDefined)
+  {
+    Password = GetPassword(OutStream); 
+    PasswordIsDefined = true;
+  }
+  CMyComBSTR tempName(Password);
+  *password = tempName.Detach();
+  return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name)
+{
+  NumArchives++;
+  NumFileErrorsInCurrentArchive = 0;
+  (*OutStream) << endl << kProcessing << name << endl;
+  return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::OpenResult(const wchar_t * /* name */, HRESULT result, bool encrypted)
+{
+  (*OutStream) << endl;
+  if (result != S_OK)
+  {
+    (*OutStream) << "Error: ";
+    if (encrypted)
+      (*OutStream) << "Can not open encrypted archive. Wrong password?";
+    else
+      (*OutStream) << "Can not open file as archive";
+    (*OutStream) << endl;
+    NumArchiveErrors++;
+  }
+  return S_OK;
+}
+  
+HRESULT CExtractCallbackConsole::ThereAreNoFiles()
+{
+  (*OutStream) << endl << kNoFiles << endl;
+  return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
+{
+  if (result == S_OK)
+  {
+    (*OutStream) << endl;
+    if (NumFileErrorsInCurrentArchive == 0)
+      (*OutStream) << kEverythingIsOk << endl;
+    else 
+    {
+      NumArchiveErrors++;
+      (*OutStream) << "Sub items Errors: " << NumFileErrorsInCurrentArchive << endl;
+    }
+  }
+  if (result == S_OK)
+    return result;
+  NumArchiveErrors++;
+  if (result == E_ABORT || result == ERROR_DISK_FULL)
+    return result;
+  (*OutStream) << endl << kError;
+  if (result == E_OUTOFMEMORY)
+    (*OutStream) << kMemoryExceptionMessage;
+  else
+  {
+    UString message;
+    NError::MyFormatMessage(result, message);
+    (*OutStream) << message;
+  }
+  (*OutStream) << endl;
+  return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
+{
+  PasswordIsDefined = true;
+  Password = password;
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.h
new file mode 100644 (file)
index 0000000..7e5d9c5
--- /dev/null
@@ -0,0 +1,65 @@
+// ExtractCallbackConsole.h
+
+#ifndef __EXTRACTCALLBACKCONSOLE_H
+#define __EXTRACTCALLBACKCONSOLE_H
+
+#include "Common/MyString.h"
+#include "Common/StdOutStream.h"
+#include "../../Common/FileStreams.h"
+#include "../../IPassword.h"
+#include "../../Archive/IArchive.h"
+#include "../Common/ArchiveExtractCallback.h"
+
+class CExtractCallbackConsole: 
+  public IExtractCallbackUI,
+  public ICryptoGetTextPassword,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP2(IFolderArchiveExtractCallback, ICryptoGetTextPassword)
+
+  STDMETHOD(SetTotal)(UInt64 total);
+  STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+  // IFolderArchiveExtractCallback
+  STDMETHOD(AskOverwrite)(
+      const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+      const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+      Int32 *answer);
+  STDMETHOD (PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position);
+
+  STDMETHOD(MessageError)(const wchar_t *message);
+  STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted);
+
+  // ICryptoGetTextPassword
+  STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+  HRESULT BeforeOpen(const wchar_t *name);
+  HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted);
+  HRESULT ThereAreNoFiles();
+  HRESULT ExtractResult(HRESULT result);
+
+  HRESULT SetPassword(const UString &password);
+
+public:
+  bool PasswordIsDefined;
+  UString Password;
+  
+  UInt64 NumArchives;
+  UInt64 NumArchiveErrors;
+  UInt64 NumFileErrors;
+  UInt64 NumFileErrorsInCurrentArchive;
+
+  CStdOutStream *OutStream;
+
+  void Init()
+  {
+    NumArchives = 0;
+    NumArchiveErrors = 0;
+    NumFileErrors = 0;
+    NumFileErrorsInCurrentArchive = 0;
+  }
+
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/List.cpp b/lzma/CPP/7zip/UI/Console/List.cpp
new file mode 100644 (file)
index 0000000..7a2b962
--- /dev/null
@@ -0,0 +1,579 @@
+// List.cpp
+
+#include "StdAfx.h"
+
+#include "List.h"
+#include "ConsoleClose.h"
+
+#include "Common/StringConvert.h"
+#include "Common/StdOutStream.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariantConversions.h"
+#include "Windows/FileDir.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../Common/PropIDUtils.h"
+#include "../Common/OpenArchive.h"
+
+#include "OpenCallbackConsole.h"
+
+using namespace NWindows;
+
+struct CPropIdToName
+{
+  PROPID PropID;
+  const wchar_t *Name;
+};
+
+static CPropIdToName kPropIdToName[] =  
+{
+  { kpidPath, L"Path" },
+  { kpidName, L"Name" },
+  { kpidIsFolder, L"Folder" }, 
+  { kpidSize, L"Size" },
+  { kpidPackedSize, L"Packed Size" },
+  { kpidAttributes, L"Attributes" },
+  { kpidCreationTime, L"Created" },
+  { kpidLastAccessTime, L"Accessed" },
+  { kpidLastWriteTime, L"Modified" },
+  { kpidSolid, L"Solid" },
+  { kpidCommented, L"Commented" },
+  { kpidEncrypted, L"Encrypted" },
+  { kpidSplitBefore, L"Split Before" },
+  { kpidSplitAfter, L"Split After" },
+  { kpidDictionarySize, L"Dictionary Size" },
+  { kpidCRC, L"CRC" },
+  { kpidType, L"Type" },
+  { kpidIsAnti, L"Anti" },
+  { kpidMethod, L"Method" },
+  { kpidHostOS, L"Host OS" },
+  { kpidFileSystem, L"File System" },
+  { kpidUser, L"User" },
+  { kpidGroup, L"Group" },
+  { kpidBlock, L"Block" },
+  { kpidComment, L"Comment" },
+  { kpidPosition, L"Position" },
+  { kpidPrefix, L"Prefix" },
+  { kpidNumSubFolders, L"Folders" },
+  { kpidNumSubFiles, L"Files" },
+  { kpidUnpackVer, L"Version" },
+  { kpidVolume, L"Volume" },
+  { kpidIsVolume, L"Multivolume" },
+  { kpidOffset, L"Offset" },
+  { kpidLinks, L"Links" },
+  { kpidNumBlocks, L"Blocks" },
+  { kpidNumVolumes, L"Volumes" }
+};
+
+static const char kEmptyAttributeChar = '.';
+static const char kDirectoryAttributeChar = 'D';
+static const char kReadonlyAttributeChar  = 'R';
+static const char kHiddenAttributeChar    = 'H';
+static const char kSystemAttributeChar    = 'S';
+static const char kArchiveAttributeChar   = 'A';
+
+static const char *kListing = "Listing archive: ";
+static const wchar_t *kFilesMessage = L"files";
+static const wchar_t *kDirsMessage = L"folders";
+
+static void GetAttributesString(DWORD wa, bool directory, char *s)
+{
+  s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || directory) ? 
+      kDirectoryAttributeChar: kEmptyAttributeChar;
+  s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0)? 
+      kReadonlyAttributeChar: kEmptyAttributeChar;
+  s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 
+      kHiddenAttributeChar: kEmptyAttributeChar;
+  s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 
+      kSystemAttributeChar: kEmptyAttributeChar;
+  s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 
+      kArchiveAttributeChar: kEmptyAttributeChar;
+  s[5] = '\0';
+}
+
+enum EAdjustment
+{
+  kLeft,
+  kCenter,
+  kRight
+};
+
+struct CFieldInfo
+{
+  PROPID PropID;
+  UString Name;
+  EAdjustment TitleAdjustment;
+  EAdjustment TextAdjustment;
+  int PrefixSpacesWidth;
+  int Width;
+};
+
+struct CFieldInfoInit
+{
+  PROPID PropID;
+  const wchar_t *Name;
+  EAdjustment TitleAdjustment;
+  EAdjustment TextAdjustment;
+  int PrefixSpacesWidth;
+  int Width;
+};
+
+CFieldInfoInit kStandardFieldTable[] = 
+{
+  { kpidLastWriteTime, L"   Date      Time", kLeft, kLeft, 0, 19 },
+  { kpidAttributes, L"Attr", kRight, kCenter, 1, 5 },
+  { kpidSize, L"Size", kRight, kRight, 1, 12 },
+  { kpidPackedSize, L"Compressed", kRight, kRight, 1, 12 },
+  { kpidPath, L"Name", kLeft, kLeft, 2, 24 }
+};
+
+void PrintSpaces(int numSpaces)
+{
+  for (int i = 0; i < numSpaces; i++)
+    g_StdOut << ' ';
+}
+
+void PrintString(EAdjustment adjustment, int width, const UString &textString)
+{
+  const int numSpaces = width - textString.Length();
+  int numLeftSpaces = 0;
+  switch (adjustment)
+  {
+    case kLeft:
+      numLeftSpaces = 0;
+      break;
+    case kCenter:
+      numLeftSpaces = numSpaces / 2;
+      break;
+    case kRight:
+      numLeftSpaces = numSpaces;
+      break;
+  }
+  PrintSpaces(numLeftSpaces);
+  g_StdOut << textString;
+  PrintSpaces(numSpaces - numLeftSpaces);
+}
+
+class CFieldPrinter
+{
+  CObjectVector<CFieldInfo> _fields;
+public:
+  void Clear() { _fields.Clear(); }
+  void Init(const CFieldInfoInit *standardFieldTable, int numItems);
+  HRESULT Init(IInArchive *archive);
+  void PrintTitle();
+  void PrintTitleLines();
+  HRESULT PrintItemInfo(IInArchive *archive, 
+      const UString &defaultItemName,
+      const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
+      UInt32 index,
+      bool techMode);
+  HRESULT PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs, 
+      const UInt64 *size, const UInt64 *compressedSize);
+};
+
+void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems)
+{
+  Clear();
+  for (int i = 0; i < numItems; i++)
+  {
+    CFieldInfo fieldInfo;
+    const CFieldInfoInit &fieldInfoInit = standardFieldTable[i];
+    fieldInfo.PropID = fieldInfoInit.PropID;
+    fieldInfo.Name = fieldInfoInit.Name;
+    fieldInfo.TitleAdjustment = fieldInfoInit.TitleAdjustment;
+    fieldInfo.TextAdjustment = fieldInfoInit.TextAdjustment;
+    fieldInfo.PrefixSpacesWidth = fieldInfoInit.PrefixSpacesWidth;
+    fieldInfo.Width = fieldInfoInit.Width;
+    _fields.Add(fieldInfo);
+  }
+}
+
+static UString GetPropName(PROPID propID, BSTR name)
+{
+  for (int i = 0; i < sizeof(kPropIdToName) / sizeof(kPropIdToName[0]); i++)
+  {
+    const CPropIdToName &propIdToName = kPropIdToName[i];
+    if (propIdToName.PropID == propID)
+      return propIdToName.Name;
+  }
+  if (name)
+    return name;
+  return L"?";
+}
+
+HRESULT CFieldPrinter::Init(IInArchive *archive)
+{
+  Clear();
+  UInt32 numProps;
+  RINOK(archive->GetNumberOfProperties(&numProps));
+  for (UInt32 i = 0; i < numProps; i++)
+  {
+    CMyComBSTR name;
+    PROPID propID;
+    VARTYPE vt;
+    RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
+    CFieldInfo fieldInfo;
+    fieldInfo.PropID = propID;
+    fieldInfo.Name = GetPropName(propID, name);
+    _fields.Add(fieldInfo);
+  }
+  return S_OK;
+}
+
+void CFieldPrinter::PrintTitle()
+{
+  for (int i = 0; i < _fields.Size(); i++)
+  {
+    const CFieldInfo &fieldInfo = _fields[i];
+    PrintSpaces(fieldInfo.PrefixSpacesWidth);
+    PrintString(fieldInfo.TitleAdjustment, 
+      ((fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width), fieldInfo.Name);
+  }
+}
+
+void CFieldPrinter::PrintTitleLines()
+{
+  for (int i = 0; i < _fields.Size(); i++)
+  {
+    const CFieldInfo &fieldInfo = _fields[i];
+    PrintSpaces(fieldInfo.PrefixSpacesWidth);
+    for (int i = 0; i < fieldInfo.Width; i++)
+      g_StdOut << '-';
+  }
+}
+
+
+BOOL IsFileTimeZero(CONST FILETIME *lpFileTime)
+{
+  return (lpFileTime->dwLowDateTime == 0) && (lpFileTime->dwHighDateTime == 0);
+}
+
+static const char *kEmptyTimeString = "                   ";
+void PrintTime(const NCOM::CPropVariant &propVariant)
+{
+  if (propVariant.vt != VT_FILETIME)
+    throw "incorrect item";
+  if (IsFileTimeZero(&propVariant.filetime))
+    g_StdOut << kEmptyTimeString;
+  else
+  {
+    FILETIME localFileTime;
+    if (!FileTimeToLocalFileTime(&propVariant.filetime, &localFileTime))
+      throw "FileTimeToLocalFileTime error";
+    char s[32];
+    if (ConvertFileTimeToString(localFileTime, s, true, true))
+      g_StdOut << s;
+    else
+      g_StdOut << kEmptyTimeString;
+  }
+}
+
+HRESULT CFieldPrinter::PrintItemInfo(IInArchive *archive, 
+    const UString &defaultItemName, 
+    const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
+    UInt32 index,
+    bool techMode)
+{
+  /*
+  if (techMode)
+  {
+    g_StdOut << "Index = ";
+    g_StdOut << (UInt64)index;
+    g_StdOut << endl;
+  }
+  */
+  for (int i = 0; i < _fields.Size(); i++)
+  {
+    const CFieldInfo &fieldInfo = _fields[i];
+    if (!techMode)
+      PrintSpaces(fieldInfo.PrefixSpacesWidth);
+
+    NCOM::CPropVariant propVariant;
+    RINOK(archive->GetProperty(index, fieldInfo.PropID, &propVariant));
+    if (techMode)
+    {
+      g_StdOut << fieldInfo.Name << " = ";
+    }
+    int width = (fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width;
+    if (propVariant.vt == VT_EMPTY)
+    {
+      switch(fieldInfo.PropID)
+      {
+        case kpidPath:
+          propVariant = defaultItemName;
+          break;
+        case kpidLastWriteTime:
+          propVariant = archiveFileInfo.LastWriteTime;
+          break;
+        default:
+          if (techMode)
+            g_StdOut << endl;
+          else
+            PrintSpaces(width);
+          continue;
+      }
+    }
+    if (fieldInfo.PropID == kpidLastWriteTime)
+    {
+      PrintTime(propVariant);
+    }
+    else if (fieldInfo.PropID == kpidAttributes)
+    {
+      if (propVariant.vt != VT_UI4)
+        throw "incorrect item";
+      UInt32 attributes = propVariant.ulVal;
+      bool isFolder;
+      RINOK(IsArchiveItemFolder(archive, index, isFolder));
+      char s[8];
+      GetAttributesString(attributes, isFolder, s);
+      g_StdOut << s;
+    }
+    else if (propVariant.vt == VT_BSTR)
+    {
+      if (techMode)
+        g_StdOut << propVariant.bstrVal;
+      else
+        PrintString(fieldInfo.TextAdjustment, width, propVariant.bstrVal);
+    }
+    else
+    {
+      UString s = ConvertPropertyToString(propVariant, fieldInfo.PropID);
+      s.Replace(wchar_t(0xA), L' '); 
+      s.Replace(wchar_t(0xD), L' '); 
+
+      if (techMode)
+        g_StdOut << s;
+      else
+        PrintString(fieldInfo.TextAdjustment, width, s);
+    }
+    if (techMode)
+      g_StdOut << endl;
+  }
+  return S_OK;
+}
+
+void PrintNumberString(EAdjustment adjustment, int width, const UInt64 *value)
+{
+  wchar_t textString[32] = { 0 };
+  if (value != NULL)
+    ConvertUInt64ToString(*value, textString);
+  PrintString(adjustment, width, textString);
+}
+
+
+HRESULT CFieldPrinter::PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs, 
+    const UInt64 *size, const UInt64 *compressedSize)
+{
+  for (int i = 0; i < _fields.Size(); i++)
+  {
+    const CFieldInfo &fieldInfo = _fields[i];
+    PrintSpaces(fieldInfo.PrefixSpacesWidth);
+    NCOM::CPropVariant propVariant;
+    if (fieldInfo.PropID == kpidSize)
+      PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, size);
+    else if (fieldInfo.PropID == kpidPackedSize)
+      PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, compressedSize);
+    else if (fieldInfo.PropID == kpidPath)
+    {
+      wchar_t textString[32];
+      ConvertUInt64ToString(numFiles, textString);
+      UString temp = textString;
+      temp += L" ";
+      temp += kFilesMessage;
+      temp += L", ";
+      ConvertUInt64ToString(numDirs, textString);
+      temp += textString;
+      temp += L" ";
+      temp += kDirsMessage;
+      PrintString(fieldInfo.TextAdjustment, 0, temp);
+    }
+    else 
+      PrintString(fieldInfo.TextAdjustment, fieldInfo.Width, L"");
+  }
+  return S_OK;
+}
+
+bool GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &value)
+{
+  NCOM::CPropVariant propVariant;
+  if (archive->GetProperty(index, propID, &propVariant) != S_OK)
+    throw "GetPropertyValue error";
+  if (propVariant.vt == VT_EMPTY)
+    return false;
+  value = ConvertPropVariantToUInt64(propVariant);
+  return true;
+}
+
+HRESULT ListArchives(
+    CCodecs *codecs,
+    UStringVector &archivePaths, UStringVector &archivePathsFull,
+    const NWildcard::CCensorNode &wildcardCensor,
+    bool enableHeaders, bool techMode, bool &passwordEnabled, UString &password, UInt64 &numErrors)
+{
+  numErrors = 0;
+  CFieldPrinter fieldPrinter;
+  if (!techMode)
+    fieldPrinter.Init(kStandardFieldTable, sizeof(kStandardFieldTable) / sizeof(kStandardFieldTable[0]));
+
+  UInt64 numFiles2 = 0, numDirs2 = 0, totalPackSize2 = 0, totalUnPackSize2 = 0;
+  UInt64 *totalPackSizePointer2 = 0, *totalUnPackSizePointer2 = 0;
+  for (int i = 0; i < archivePaths.Size(); i++)
+  {
+    const UString &archiveName = archivePaths[i];
+    NFile::NFind::CFileInfoW archiveFileInfo;
+    if (!NFile::NFind::FindFile(archiveName, archiveFileInfo) || archiveFileInfo.IsDirectory())
+    {
+      g_StdOut << endl << "Error: " << archiveName << " is not archive" << endl;
+      numErrors++;
+      continue;
+    }
+    if (archiveFileInfo.IsDirectory())
+    {
+      g_StdOut << endl << "Error: " << archiveName << " is not file" << endl;
+      numErrors++;
+      continue;
+    }
+
+    CArchiveLink archiveLink;
+
+    COpenCallbackConsole openCallback;
+    openCallback.OutStream = &g_StdOut;
+    openCallback.PasswordIsDefined = passwordEnabled;
+    openCallback.Password = password;
+
+    HRESULT result = MyOpenArchive(codecs, archiveName, archiveLink, &openCallback);
+    if (result != S_OK)
+    {
+      g_StdOut << endl << "Error: " << archiveName << " is not supported archive" << endl;
+      numErrors++;
+      continue;
+    }
+
+    for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+    {
+      int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+      if (index >= 0 && index > i)
+      {
+        archivePaths.Delete(index);
+        archivePathsFull.Delete(index);
+      }
+    }
+
+    IInArchive *archive = archiveLink.GetArchive();
+    const UString defaultItemName = archiveLink.GetDefaultItemName();
+
+    if (enableHeaders)
+    {
+      g_StdOut << endl << kListing << archiveName << endl << endl;
+
+      UInt32 numProps;
+      if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK)
+      {
+        for (UInt32 i = 0; i < numProps; i++)
+        {
+          CMyComBSTR name;
+          PROPID propID;
+          VARTYPE vt;
+          if (archive->GetArchivePropertyInfo(i, &name, &propID, &vt) != S_OK)
+            continue;
+          NCOM::CPropVariant prop;
+          if (archive->GetArchiveProperty(propID, &prop) != S_OK)
+            continue;
+          UString s = ConvertPropertyToString(prop, propID);
+          if (!s.IsEmpty())
+            g_StdOut << GetPropName(propID, name) << " = " << s << endl;
+        }
+      }
+      if (techMode)
+        g_StdOut << "----------\n";
+      if (numProps > 0)
+        g_StdOut << endl;
+    }
+
+    if (enableHeaders && !techMode)
+    {
+      fieldPrinter.PrintTitle();
+      g_StdOut << endl;
+      fieldPrinter.PrintTitleLines();
+      g_StdOut << endl;
+    }
+
+    if (techMode)
+    {
+      RINOK(fieldPrinter.Init(archive));
+    }
+    UInt64 numFiles = 0, numDirs = 0, totalPackSize = 0, totalUnPackSize = 0;
+    UInt64 *totalPackSizePointer = 0, *totalUnPackSizePointer = 0;
+    UInt32 numItems;
+    RINOK(archive->GetNumberOfItems(&numItems));
+    for(UInt32 i = 0; i < numItems; i++)
+    {
+      if (NConsoleClose::TestBreakSignal())
+        return E_ABORT;
+
+      UString filePath;
+      RINOK(GetArchiveItemPath(archive, i, defaultItemName, filePath));
+
+      bool isFolder;
+      RINOK(IsArchiveItemFolder(archive, i, isFolder));
+      if (!wildcardCensor.CheckPath(filePath, !isFolder))
+        continue;
+      
+      fieldPrinter.PrintItemInfo(archive, defaultItemName, archiveFileInfo, i, techMode);
+      
+      UInt64 packSize, unpackSize;
+      if (!GetUInt64Value(archive, i, kpidSize, unpackSize))
+        unpackSize = 0;
+      else
+        totalUnPackSizePointer = &totalUnPackSize;
+      if (!GetUInt64Value(archive, i, kpidPackedSize, packSize))
+        packSize = 0;
+      else
+        totalPackSizePointer = &totalPackSize;
+      
+      g_StdOut << endl;
+
+      if (isFolder)
+        numDirs++;
+      else
+        numFiles++;
+      totalPackSize += packSize;
+      totalUnPackSize += unpackSize;
+    }
+    if (enableHeaders && !techMode)
+    {
+      fieldPrinter.PrintTitleLines();
+      g_StdOut << endl;
+      fieldPrinter.PrintSummaryInfo(numFiles, numDirs, totalUnPackSizePointer, totalPackSizePointer);
+      g_StdOut << endl;
+    }
+    if (totalPackSizePointer != 0)
+    {
+      totalPackSizePointer2 = &totalPackSize2;
+      totalPackSize2 += totalPackSize;
+    }
+    if (totalUnPackSizePointer != 0)
+    {
+      totalUnPackSizePointer2 = &totalUnPackSize2;
+      totalUnPackSize2 += totalUnPackSize;
+    }
+    numFiles2 += numFiles;
+    numDirs2 += numDirs;
+  }
+  if (enableHeaders && !techMode && archivePaths.Size() > 1)
+  {
+    g_StdOut << endl;
+    fieldPrinter.PrintTitleLines();
+    g_StdOut << endl;
+    fieldPrinter.PrintSummaryInfo(numFiles2, numDirs2, totalUnPackSizePointer2, totalPackSizePointer2);
+    g_StdOut << endl;
+    g_StdOut << "Archives: " << archivePaths.Size() << endl;
+  }
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Console/List.h b/lzma/CPP/7zip/UI/Console/List.h
new file mode 100644 (file)
index 0000000..6e9fa24
--- /dev/null
@@ -0,0 +1,16 @@
+// List.h
+
+#ifndef __LIST_H
+#define __LIST_H
+
+#include "Common/Wildcard.h"
+#include "../Common/LoadCodecs.h"
+
+HRESULT ListArchives(
+    CCodecs *codecs,
+    UStringVector &archivePaths, UStringVector &archivePathsFull,
+    const NWildcard::CCensorNode &wildcardCensor,
+    bool enableHeaders, bool techMode, bool &passwordEnabled, UString &password, UInt64 &errors);
+
+#endif
+
diff --git a/lzma/CPP/7zip/UI/Console/Main.cpp b/lzma/CPP/7zip/UI/Console/Main.cpp
new file mode 100644 (file)
index 0000000..980f60d
--- /dev/null
@@ -0,0 +1,563 @@
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "Common/MyInitGuid.h"
+
+#include "Common/CommandLineParser.h"
+#include "Common/MyException.h"
+#include "Common/IntToString.h"
+#include "Common/StdOutStream.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+#include "Windows/Defs.h"
+#include "Windows/Error.h"
+#ifdef _WIN32
+#include "Windows/MemoryLock.h"
+#endif
+
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+#include "../Common/UpdateAction.h"
+#include "../Common/Update.h"
+#include "../Common/Extract.h"
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+#ifdef EXTERNAL_CODECS
+#include "../Common/LoadCodecs.h"
+#endif
+
+#include "../../Compress/LZMA_Alone/LzmaBenchCon.h"
+
+#include "List.h"
+#include "OpenCallbackConsole.h"
+#include "ExtractCallbackConsole.h"
+#include "UpdateCallbackConsole.h"
+
+#include "../../MyVersion.h"
+
+#if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
+extern "C" 
+{ 
+#include "../../../../C/Alloc.h"
+}
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NCommandLineParser;
+
+HINSTANCE g_hInstance = 0;
+extern CStdOutStream *g_StdStream;
+
+static const char *kCopyrightString = "\n7-Zip"
+#ifndef EXTERNAL_CODECS
+" (A)"
+#endif
+
+#ifdef _WIN64
+" [64]"
+#endif
+
+" " MY_VERSION_COPYRIGHT_DATE "\n";
+
+static const char *kHelpString = 
+    "\nUsage: 7z"
+#ifdef _NO_CRYPTO
+    "r"
+#else
+#ifndef EXTERNAL_CODECS
+    "a"
+#endif
+#endif
+    " <command> [<switches>...] <archive_name> [<file_names>...]\n"
+    "       [<@listfiles...>]\n"
+    "\n"
+    "<Commands>\n"
+    "  a: Add files to archive\n"
+    "  b: Benchmark\n"
+    "  d: Delete files from archive\n"
+    "  e: Extract files from archive (without using directory names)\n"
+    "  l: List contents of archive\n"
+//    "  l[a|t][f]: List contents of archive\n"
+//    "    a - with Additional fields\n"
+//    "    t - with all fields\n"
+//    "    f - with Full pathnames\n"
+    "  t: Test integrity of archive\n"
+    "  u: Update files to archive\n"
+    "  x: eXtract files with full paths\n"
+    "<Switches>\n"
+    "  -ai[r[-|0]]{@listfile|!wildcard}: Include archives\n"
+    "  -ax[r[-|0]]{@listfile|!wildcard}: eXclude archives\n"
+    "  -bd: Disable percentage indicator\n"
+    "  -i[r[-|0]]{@listfile|!wildcard}: Include filenames\n"
+    "  -m{Parameters}: set compression Method\n"
+    "  -o{Directory}: set Output directory\n"
+    "  -p{Password}: set Password\n"
+    "  -r[-|0]: Recurse subdirectories\n"
+    "  -scs{UTF-8 | WIN | DOS}: set charset for list files\n"
+    "  -sfx[{name}]: Create SFX archive\n"
+    "  -si[{name}]: read data from stdin\n"
+    "  -slt: show technical information for l (List) command\n"
+    "  -so: write data to stdout\n"
+    "  -ssc[-]: set sensitive case mode\n"
+    "  -ssw: compress shared files\n"
+    "  -t{Type}: Set type of archive\n"
+    "  -v{Size}[b|k|m|g]: Create volumes\n"
+    "  -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options\n"
+    "  -w[{path}]: assign Work directory. Empty path means a temporary directory\n"
+    "  -x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames\n"
+    "  -y: assume Yes on all queries\n";
+
+// ---------------------------
+// exception messages
+
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kUserErrorMessage  = "Incorrect command line"; // NExitCode::kUserError
+
+static const wchar_t *kDefaultSfxModule = L"7zCon.sfx";
+
+static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
+{
+  s << message << endl;
+  throw code;
+}
+
+static void PrintHelpAndExit(CStdOutStream &s) // yyy
+{
+  s << kHelpString;
+  ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
+}
+
+#ifndef _WIN32
+static void GetArguments(int numArguments, const char *arguments[], UStringVector &parts)
+{
+  parts.Clear();
+  for(int i = 0; i < numArguments; i++)
+  {
+    UString s = MultiByteToUnicodeString(arguments[i]);
+    parts.Add(s);
+  }
+}
+#endif
+
+static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
+{
+  s << kCopyrightString;
+  // s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
+  if (needHelp) 
+    s << kHelpString;
+}
+
+#ifdef EXTERNAL_CODECS
+static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
+{
+  int len = s.Length();
+  stdStream << s;
+  for (int i = len; i < size; i++)
+    stdStream << ' ';
+}
+#endif
+
+static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
+{
+  int len = s.Length();
+  stdStream << s;
+  for (int i = len; i < size; i++)
+    stdStream << ' ';
+}
+
+static inline char GetHex(Byte value)
+{
+  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+int Main2(
+  #ifndef _WIN32  
+  int numArguments, const char *arguments[]
+  #endif
+)
+{
+  #ifdef _WIN32  
+  SetFileApisToOEM();
+  #endif
+  
+  UStringVector commandStrings;
+  #ifdef _WIN32  
+  NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+  #else
+  GetArguments(numArguments, arguments, commandStrings);
+  #endif
+
+  if(commandStrings.Size() == 1)
+  {
+    ShowCopyrightAndHelp(g_StdOut, true);
+    return 0;
+  }
+  commandStrings.Delete(0);
+
+  CArchiveCommandLineOptions options;
+
+  CArchiveCommandLineParser parser;
+
+  parser.Parse1(commandStrings, options);
+
+  if(options.HelpMode)
+  {
+    ShowCopyrightAndHelp(g_StdOut, true);
+    return 0;
+  }
+
+  #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+  if (options.LargePages)
+  {
+    SetLargePageSize();
+    NSecurity::EnableLockMemoryPrivilege();
+  }
+  #endif
+
+  CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
+  g_StdStream = &stdStream;
+
+  if (options.EnableHeaders)
+    ShowCopyrightAndHelp(stdStream, false);
+
+  parser.Parse2(options);
+
+  CCodecs *codecs = new CCodecs;
+  CMyComPtr<
+    #ifdef EXTERNAL_CODECS
+    ICompressCodecsInfo
+    #else
+    IUnknown
+    #endif
+    > compressCodecsInfo = codecs;
+  HRESULT result = codecs->Load();
+  if (result != S_OK)
+    throw CSystemException(result);
+
+  bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+  if (options.Command.CommandType == NCommandType::kInfo)
+  {
+    stdStream << endl << "Formats:" << endl;
+    int i;
+    for (i = 0; i < codecs->Formats.Size(); i++)
+    {
+      const CArcInfoEx &arc = codecs->Formats[i];
+      #ifdef EXTERNAL_CODECS
+      if (arc.LibIndex >= 0)
+      {
+        char s[32];
+        ConvertUInt64ToString(arc.LibIndex, s);
+        PrintString(stdStream, s, 2);
+      }
+      else
+      #endif
+        stdStream << "  ";
+      stdStream << ' ';
+      stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
+      stdStream << (char)(arc.KeepName ? 'K' : ' ');
+      stdStream << "  ";
+      PrintString(stdStream, arc.Name, 6);
+      stdStream << "  ";
+      UString s;
+      for (int t = 0; t < arc.Exts.Size(); t++)
+      {
+        const CArcExtInfo &ext = arc.Exts[t];
+        s += ext.Ext;
+        if (!ext.AddExt.IsEmpty())
+        {
+          s += L" (";
+          s += ext.AddExt;
+          s += L')';
+        }
+        s += L' ';
+      }
+      PrintString(stdStream, s, 14);
+      stdStream << "  ";
+      const CByteBuffer &sig = arc.StartSignature;
+      for (size_t j = 0; j < sig.GetCapacity(); j++)
+      {
+        Byte b = sig[j];
+        if (b > 0x20 && b < 0x80)
+        {
+          stdStream << (char)b;
+        }
+        else
+        {
+          stdStream << GetHex((Byte)((b >> 4) & 0xF));
+          stdStream << GetHex((Byte)(b & 0xF));
+        }
+        stdStream << ' ';
+      }
+      stdStream << endl;
+    }
+    stdStream << endl << "Codecs:" << endl;
+
+    #ifdef EXTERNAL_CODECS
+    UINT32 numMethods;
+    if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
+    for (UInt32 j = 0; j < numMethods; j++)
+    {
+      int libIndex = codecs->GetCodecLibIndex(j);
+      if (libIndex >= 0)
+      {
+        char s[32];
+        ConvertUInt64ToString(libIndex, s);
+        PrintString(stdStream, s, 2);
+      }
+      else
+        stdStream << "  ";
+      stdStream << ' ';
+      stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
+      UInt64 id;
+      stdStream << "  ";
+      HRESULT res = codecs->GetCodecId(j, id);
+      if (res != S_OK)
+        id = (UInt64)(Int64)-1;
+      char s[32];
+      ConvertUInt64ToString(id, s, 16);
+      PrintString(stdStream, s, 8);
+      stdStream << "  ";
+      PrintString(stdStream, codecs->GetCodecName(j), 11);
+      stdStream << endl;
+      /*
+      if (res != S_OK)
+        throw "incorrect Codec ID";
+      */
+    }
+    #endif
+    return S_OK;
+  }
+  else if (options.Command.CommandType == NCommandType::kBenchmark)
+  {
+    if (options.Method.CompareNoCase(L"CRC") == 0)
+    {
+      HRESULT res = CrcBenchCon((FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
+      if (res != S_OK)
+      {
+        if (res == S_FALSE)
+        {
+          stdStream << "\nCRC Error\n";
+          return NExitCode::kFatalError;
+        }
+        throw CSystemException(res);
+      }
+    }
+    else
+    {
+      HRESULT res = LzmaBenchCon(
+        #ifdef EXTERNAL_LZMA
+        codecs,
+        #endif
+        (FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
+      if (res != S_OK)
+      {
+        if (res == S_FALSE)
+        {
+          stdStream << "\nDecoding Error\n";
+          return NExitCode::kFatalError;
+        }
+        throw CSystemException(res);
+      }
+    }
+  }
+  else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+  {
+    if(isExtractGroupCommand)
+    {
+      CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
+      CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+      ecs->OutStream = &stdStream;
+      ecs->PasswordIsDefined = options.PasswordEnabled;
+      ecs->Password = options.Password;
+      ecs->Init();
+
+      COpenCallbackConsole openCallback;
+      openCallback.OutStream = &stdStream;
+      openCallback.PasswordIsDefined = options.PasswordEnabled;
+      openCallback.Password = options.Password;
+
+      CExtractOptions eo;
+      eo.StdOutMode = options.StdOutMode;
+      eo.PathMode = options.Command.GetPathMode();
+      eo.TestMode = options.Command.IsTestMode();
+      eo.OverwriteMode = options.OverwriteMode;
+      eo.OutputDir = options.OutputDir;
+      eo.YesToAll = options.YesToAll;
+      #ifdef COMPRESS_MT
+      eo.Properties = options.ExtractProperties;
+      #endif
+      UString errorMessage;
+      CDecompressStat stat;
+      HRESULT result = DecompressArchives(
+          codecs,
+          options.ArchivePathsSorted, 
+          options.ArchivePathsFullSorted,
+          options.WildcardCensor.Pairs.Front().Head, 
+          eo, &openCallback, ecs, errorMessage, stat);
+      if (!errorMessage.IsEmpty())
+      {
+        stdStream << endl << "Error: " << errorMessage;
+        if (result == S_OK)
+          result = E_FAIL;
+      }
+
+      stdStream << endl;
+      if (ecs->NumArchives > 1)
+        stdStream << "Archives: " << ecs->NumArchives << endl;
+      if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
+      {
+        if (ecs->NumArchives > 1)
+        {
+          stdStream << endl;
+          if (ecs->NumArchiveErrors != 0)
+            stdStream << "Archive Errors: " << ecs->NumArchiveErrors << endl;
+          if (ecs->NumFileErrors != 0)
+            stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
+        }
+        if (result != S_OK)
+          throw CSystemException(result);
+        return NExitCode::kFatalError;
+      }
+      if (result != S_OK)
+        throw CSystemException(result);
+      if (stat.NumFolders != 0)
+        stdStream << "Folders: " << stat.NumFolders << endl;
+      if (stat.NumFiles != 1 || stat.NumFolders != 0)
+          stdStream << "Files: " << stat.NumFiles << endl;
+      stdStream 
+           << "Size:       " << stat.UnpackSize << endl
+           << "Compressed: " << stat.PackSize << endl;
+    }
+    else
+    {
+      UInt64 numErrors = 0;
+      HRESULT result = ListArchives(
+          codecs,
+          options.ArchivePathsSorted, 
+          options.ArchivePathsFullSorted,
+          options.WildcardCensor.Pairs.Front().Head, 
+          options.EnableHeaders, 
+          options.TechMode,
+          options.PasswordEnabled, 
+          options.Password, numErrors);
+      if (numErrors > 0)
+      {
+        g_StdOut << endl << "Errors: " << numErrors;
+        return NExitCode::kFatalError;
+      }
+      if (result != S_OK)
+        throw CSystemException(result);
+    }
+  }
+  else if(options.Command.IsFromUpdateGroup())
+  {
+    UString workingDir;
+
+    CUpdateOptions &uo = options.UpdateOptions;
+    if (uo.SfxMode && uo.SfxModule.IsEmpty())
+      uo.SfxModule = kDefaultSfxModule;
+
+    bool passwordIsDefined = 
+        options.PasswordEnabled && !options.Password.IsEmpty();
+
+    COpenCallbackConsole openCallback;
+    openCallback.OutStream = &stdStream;
+    openCallback.PasswordIsDefined = passwordIsDefined;
+    openCallback.Password = options.Password;
+
+    CUpdateCallbackConsole callback;
+    callback.EnablePercents = options.EnablePercents;
+    callback.PasswordIsDefined = passwordIsDefined;
+    callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
+    callback.Password = options.Password;
+    callback.StdOutMode = uo.StdOutMode;
+    callback.Init(&stdStream);
+
+    CUpdateErrorInfo errorInfo;
+
+    if (!uo.Init(codecs, options.ArchiveName, options.ArcType))
+      throw "Unsupported archive type";
+    HRESULT result = UpdateArchive(codecs, 
+        options.WildcardCensor, uo, 
+        errorInfo, &openCallback, &callback);
+
+    int exitCode = NExitCode::kSuccess;
+    if (callback.CantFindFiles.Size() > 0)
+    {
+      stdStream << endl;
+      stdStream << "WARNINGS for files:" << endl << endl;
+      int numErrors = callback.CantFindFiles.Size();
+      for (int i = 0; i < numErrors; i++)
+      {
+        stdStream << callback.CantFindFiles[i] << " : ";
+        stdStream << NError::MyFormatMessageW(callback.CantFindCodes[i]) << endl;
+      }
+      stdStream << "----------------" << endl;
+      stdStream << "WARNING: Cannot find " << numErrors << " file";
+      if (numErrors > 1)
+        stdStream << "s";
+      stdStream << endl;
+      exitCode = NExitCode::kWarning;
+    }
+
+    if (result != S_OK)
+    {
+      UString message;
+      if (!errorInfo.Message.IsEmpty())
+      {
+        message += errorInfo.Message;
+        message += L"\n";
+      }
+      if (!errorInfo.FileName.IsEmpty())
+      {
+        message += errorInfo.FileName;
+        message += L"\n";
+      }
+      if (!errorInfo.FileName2.IsEmpty())
+      {
+        message += errorInfo.FileName2;
+        message += L"\n";
+      }
+      if (errorInfo.SystemError != 0)
+      {
+        message += NError::MyFormatMessageW(errorInfo.SystemError);
+        message += L"\n";
+      }
+      if (!message.IsEmpty())
+        stdStream << L"\nError:\n" << message;
+      throw CSystemException(result);
+    }
+    int numErrors = callback.FailedFiles.Size();
+    if (numErrors == 0)
+    {
+      if (callback.CantFindFiles.Size() == 0)
+        stdStream << kEverythingIsOk << endl;
+    }
+    else
+    {
+      stdStream << endl;
+      stdStream << "WARNINGS for files:" << endl << endl;
+      for (int i = 0; i < numErrors; i++)
+      {
+        stdStream << callback.FailedFiles[i] << " : ";
+        stdStream << NError::MyFormatMessageW(callback.FailedCodes[i]) << endl;
+      }
+      stdStream << "----------------" << endl;
+      stdStream << "WARNING: Cannot open " << numErrors << " file";
+      if (numErrors > 1)
+        stdStream << "s";
+      stdStream << endl;
+      exitCode = NExitCode::kWarning;
+    }
+    return exitCode;
+  }
+  else 
+    PrintHelpAndExit(stdStream);
+  return 0;
+}
diff --git a/lzma/CPP/7zip/UI/Console/MainAr.cpp b/lzma/CPP/7zip/UI/Console/MainAr.cpp
new file mode 100644 (file)
index 0000000..fd42e4f
--- /dev/null
@@ -0,0 +1,161 @@
+// MainAr.cpp
+
+#include "StdAfx.h"
+
+// #include <locale.h>
+
+#include "Windows/Error.h"
+
+#include "Common/StdOutStream.h"
+#include "Common/NewHandler.h"
+#include "Common/MyException.h"
+#include "Common/StringConvert.h"
+
+#include "../Common/ExitCode.h"
+#include "../Common/ArchiveCommandLine.h"
+#include "ConsoleClose.h"
+
+using namespace NWindows;
+
+CStdOutStream *g_StdStream = 0;
+
+#ifdef _WIN32
+#ifndef _UNICODE
+bool g_IsNT = false;
+#endif
+#if !defined(_UNICODE) || !defined(_WIN64)
+static inline bool IsItWindowsNT()
+{
+  OSVERSIONINFO versionInfo;
+  versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+  if (!::GetVersionEx(&versionInfo)) 
+    return false;
+  return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+#endif
+
+extern int Main2(
+  #ifndef _WIN32  
+  int numArguments, const char *arguments[]
+  #endif
+);
+
+static const char *kExceptionErrorMessage = "\n\nError:\n";
+static const char *kUserBreak  = "\nBreak signaled\n";
+
+static const char *kMemoryExceptionMessage = "\n\nERROR: Can't allocate required memory!\n";
+static const char *kUnknownExceptionMessage = "\n\nUnknown Error\n";
+static const char *kInternalExceptionMessage = "\n\nInternal Error #";
+
+int 
+#ifdef _MSC_VER
+__cdecl 
+#endif
+main
+(
+#ifndef _WIN32  
+int numArguments, const char *arguments[]
+#endif
+)
+{
+  g_StdStream = &g_StdOut;
+  #ifdef _WIN32
+  
+  #ifdef _UNICODE
+  #ifndef _WIN64
+  if (!IsItWindowsNT())
+  {
+    (*g_StdStream) << "This program requires Windows NT/2000/XP/2003/Vista";
+    return NExitCode::kFatalError;
+  }
+  #endif
+  #else
+  g_IsNT = IsItWindowsNT();
+  #endif
+  
+  #endif
+
+  // setlocale(LC_COLLATE, ".OCP");
+  NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
+  int res = 0;
+  try
+  {
+    res = Main2(
+#ifndef _WIN32
+      numArguments, arguments
+#endif
+    );
+  }
+  catch(const CNewException &)
+  {
+    (*g_StdStream) << kMemoryExceptionMessage;
+    return (NExitCode::kMemoryError);
+  }
+  catch(const NConsoleClose::CCtrlBreakException &)
+  {
+    (*g_StdStream) << endl << kUserBreak;
+    return (NExitCode::kUserBreak);
+  }
+  catch(const CArchiveCommandLineException &e)
+  {
+    (*g_StdStream) << kExceptionErrorMessage << e << endl;
+    return (NExitCode::kUserError);
+  }
+  catch(const CSystemException &systemError)
+  {
+    if (systemError.ErrorCode == E_OUTOFMEMORY)
+    {
+      (*g_StdStream) << kMemoryExceptionMessage;
+      return (NExitCode::kMemoryError);
+    }
+    if (systemError.ErrorCode == E_ABORT)
+    {
+      (*g_StdStream) << endl << kUserBreak;
+      return (NExitCode::kUserBreak);
+    }
+    UString message;
+    NError::MyFormatMessage(systemError.ErrorCode, message);
+    (*g_StdStream) << endl << endl << "System error:" << endl << 
+        message << endl;
+    return (NExitCode::kFatalError);
+  }
+  catch(NExitCode::EEnum &exitCode)
+  {
+    (*g_StdStream) << kInternalExceptionMessage << exitCode << endl;
+    return (exitCode);
+  }
+  /*
+  catch(const NExitCode::CMultipleErrors &multipleErrors)
+  {
+    (*g_StdStream) << endl << multipleErrors.NumErrors << " errors" << endl;
+    return (NExitCode::kFatalError);
+  }
+  */
+  catch(const UString &s)
+  {
+    (*g_StdStream) << kExceptionErrorMessage << s << endl;
+    return (NExitCode::kFatalError);
+  }
+  catch(const AString &s)
+  {
+    (*g_StdStream) << kExceptionErrorMessage << s << endl;
+    return (NExitCode::kFatalError);
+  }
+  catch(const char *s)
+  {
+    (*g_StdStream) << kExceptionErrorMessage << s << endl;
+    return (NExitCode::kFatalError);
+  }
+  catch(int t)
+  {
+    (*g_StdStream) << kInternalExceptionMessage << t << endl;
+    return (NExitCode::kFatalError);
+  }
+  catch(...)
+  {
+    (*g_StdStream) << kUnknownExceptionMessage;
+    return (NExitCode::kFatalError);
+  }
+  return  res;
+}
diff --git a/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
new file mode 100644 (file)
index 0000000..06ff165
--- /dev/null
@@ -0,0 +1,58 @@
+// OpenCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "OpenCallbackConsole.h"
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+HRESULT COpenCallbackConsole::CheckBreak()
+{
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  return S_OK;
+}
+
+HRESULT COpenCallbackConsole::SetTotal(const UInt64 *, const UInt64 *)
+{
+  return CheckBreak();
+}
+
+HRESULT COpenCallbackConsole::SetCompleted(const UInt64 *, const UInt64 *)
+{
+  return CheckBreak();
+}
+HRESULT COpenCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+  PasswordWasAsked = true;
+  RINOK(CheckBreak());
+  if (!PasswordIsDefined)
+  {
+    Password = GetPassword(OutStream); 
+    PasswordIsDefined = true;
+  }
+  CMyComBSTR temp(Password);
+  *password = temp.Detach();
+  return S_OK;
+}
+
+HRESULT COpenCallbackConsole::GetPasswordIfAny(UString &password)
+{
+  if (PasswordIsDefined)
+    password = Password;
+  return S_OK;
+}
+
+bool COpenCallbackConsole::WasPasswordAsked()
+{
+  return PasswordWasAsked;
+}
+
+void COpenCallbackConsole::ClearPasswordWasAskedFlag()
+{
+  PasswordWasAsked = false;
+}
+
+  
diff --git a/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.h b/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.h
new file mode 100644 (file)
index 0000000..db0e9bd
--- /dev/null
@@ -0,0 +1,27 @@
+// OpenCallbackConsole.h
+
+#ifndef __OPENCALLBACKCONSOLE_H
+#define __OPENCALLBACKCONSOLE_H
+
+#include "Common/StdOutStream.h"
+#include "../Common/ArchiveOpenCallback.h"
+
+class COpenCallbackConsole: public IOpenCallbackUI
+{
+public:
+  HRESULT CheckBreak();
+  HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes);
+  HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes);
+  HRESULT CryptoGetTextPassword(BSTR *password);
+  HRESULT GetPasswordIfAny(UString &password);
+  bool WasPasswordAsked();
+  void ClearPasswordWasAskedFlag();
+  
+  CStdOutStream *OutStream;
+  bool PasswordIsDefined;
+  UString Password;
+  bool PasswordWasAsked;
+  COpenCallbackConsole(): PasswordIsDefined(false), PasswordWasAsked(false) {}
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/PercentPrinter.cpp b/lzma/CPP/7zip/UI/Console/PercentPrinter.cpp
new file mode 100644 (file)
index 0000000..47aafd7
--- /dev/null
@@ -0,0 +1,90 @@
+// PercentPrinter.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "PercentPrinter.h"
+
+const int kPaddingSize = 2;
+const int kPercentsSize = 4;
+const int kMaxExtraSize = kPaddingSize + 32 + kPercentsSize;
+
+static void ClearPrev(char *p, int num)
+{
+  int i;
+  for (i = 0; i < num; i++) *p++ = '\b';
+  for (i = 0; i < num; i++) *p++ = ' ';
+  for (i = 0; i < num; i++) *p++ = '\b';
+  *p = '\0';
+}
+
+void CPercentPrinter::ClosePrint()
+{
+  if (m_NumExtraChars == 0)
+    return;
+  char s[kMaxExtraSize * 3 + 1];
+  ClearPrev(s, m_NumExtraChars);
+  (*OutStream) << s;
+  m_NumExtraChars = 0;
+}
+
+void CPercentPrinter::PrintString(const char *s)
+{
+  ClosePrint();
+  (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintString(const wchar_t *s)
+{
+  ClosePrint();
+  (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintNewLine()
+{
+  ClosePrint();
+  (*OutStream) << "\n";
+}
+
+void CPercentPrinter::RePrintRatio()
+{
+  char s[32];
+  ConvertUInt64ToString(((m_Total == 0) ? 0 : (m_CurValue * 100 / m_Total)), s);
+  int size = (int)strlen(s);
+  s[size++] = '%';
+  s[size] = '\0';
+
+  int extraSize = kPaddingSize + MyMax(size, kPercentsSize);
+  if (extraSize < m_NumExtraChars)
+    extraSize = m_NumExtraChars;
+
+  char fullString[kMaxExtraSize * 3];
+  char *p = fullString;
+  int i;
+  if (m_NumExtraChars == 0)
+  {
+    for (i = 0; i < extraSize; i++) 
+      *p++ = ' ';
+    m_NumExtraChars = extraSize;
+  }
+
+  for (i = 0; i < m_NumExtraChars; i++) 
+    *p++ = '\b';
+  m_NumExtraChars = extraSize;
+  for (; size < m_NumExtraChars; size++)
+    *p++ = ' ';
+  MyStringCopy(p, s);
+  (*OutStream) << fullString;
+  OutStream->Flush(); 
+  m_PrevValue = m_CurValue;
+}
+
+void CPercentPrinter::PrintRatio()
+{
+  if (m_CurValue < m_PrevValue + m_MinStepSize && 
+      m_CurValue + m_MinStepSize > m_PrevValue && m_NumExtraChars != 0)
+    return;
+  RePrintRatio();
+}
diff --git a/lzma/CPP/7zip/UI/Console/PercentPrinter.h b/lzma/CPP/7zip/UI/Console/PercentPrinter.h
new file mode 100644 (file)
index 0000000..e8b4091
--- /dev/null
@@ -0,0 +1,31 @@
+// PercentPrinter.h
+
+#ifndef __PERCENTPRINTER_H
+#define __PERCENTPRINTER_H
+
+#include "Common/Types.h"
+#include "Common/StdOutStream.h"
+
+class CPercentPrinter
+{
+  UInt64 m_MinStepSize;
+  UInt64 m_PrevValue;
+  UInt64 m_CurValue;
+  UInt64 m_Total;
+  int m_NumExtraChars;
+public:
+  CStdOutStream *OutStream;
+
+  CPercentPrinter(UInt64 minStepSize = 1): m_MinStepSize(minStepSize), 
+      m_PrevValue(0), m_CurValue(0), m_Total(1), m_NumExtraChars(0) {}
+  void SetTotal(UInt64 total) { m_Total = total; m_PrevValue = 0; }
+  void SetRatio(UInt64 doneValue) { m_CurValue = doneValue; }
+  void PrintString(const char *s);
+  void PrintString(const wchar_t *s);
+  void PrintNewLine();
+  void ClosePrint();
+  void RePrintRatio();
+  void PrintRatio();
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/StdAfx.cpp b/lzma/CPP/7zip/UI/Console/StdAfx.cpp
new file mode 100644 (file)
index 0000000..d0feea8
--- /dev/null
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/UI/Console/StdAfx.h b/lzma/CPP/7zip/UI/Console/StdAfx.h
new file mode 100644 (file)
index 0000000..8531cc9
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif 
diff --git a/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
new file mode 100644 (file)
index 0000000..1d4420d
--- /dev/null
@@ -0,0 +1,208 @@
+// UpdateCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateCallbackConsole.h"
+
+#include "Windows/Error.h"
+#ifdef COMPRESS_MT
+#include "Windows/Synchronization.h"
+#endif
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+using namespace NWindows;
+
+#ifdef COMPRESS_MT
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+static const char *kCreatingArchiveMessage = "Creating archive ";
+static const char *kUpdatingArchiveMessage = "Updating archive ";
+static const char *kScanningMessage = "Scanning";
+
+
+HRESULT CUpdateCallbackConsole::OpenResult(const wchar_t *name, HRESULT result)
+{
+  (*OutStream) << endl;
+  if (result != S_OK)
+    (*OutStream) << "Error: " << name << " is not supported archive" << endl;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartScanning()
+{
+  (*OutStream) << kScanningMessage;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError)
+{
+  CantFindFiles.Add(name);
+  CantFindCodes.Add(systemError);
+  // m_PercentPrinter.ClosePrint();
+  if (!m_WarningsMode)
+  {
+    (*OutStream) << endl << endl;
+    m_PercentPrinter.PrintNewLine();
+    m_WarningsMode = true;
+  }
+  m_PercentPrinter.PrintString(name);
+  m_PercentPrinter.PrintString(":  WARNING: ");
+  m_PercentPrinter.PrintString(NError::MyFormatMessageW(systemError));
+  m_PercentPrinter.PrintNewLine();
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishScanning()
+{
+  (*OutStream) << endl << endl;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
+{
+  if(updating)
+    (*OutStream) << kUpdatingArchiveMessage;
+  else
+    (*OutStream) << kCreatingArchiveMessage; 
+  if (name != 0)
+    (*OutStream) << name;
+  else
+    (*OutStream) << "StdOut";
+  (*OutStream) << endl << endl;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishArchive()
+{
+  (*OutStream) << endl;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CheckBreak()
+{
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::Finilize()
+{
+  MT_LOCK
+  if (m_NeedBeClosed)
+  {
+    if (EnablePercents)
+    {
+      m_PercentPrinter.ClosePrint();
+    }
+    if (!StdOutMode && m_NeedNewLine)
+    {
+      m_PercentPrinter.PrintNewLine();
+      m_NeedNewLine = false;
+    }
+    m_NeedBeClosed = false;
+  }
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
+{
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
+{
+  MT_LOCK
+  if (EnablePercents)
+    m_PercentPrinter.SetTotal(size);
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+  MT_LOCK
+  if (completeValue != NULL)
+  {
+    if (EnablePercents)
+    {
+      m_PercentPrinter.SetRatio(*completeValue);
+      m_PercentPrinter.PrintRatio();
+      m_NeedBeClosed = true;
+    }
+  }
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
+{
+  /*
+  if (NConsoleClose::TestBreakSignal())
+    return E_ABORT;
+  */
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isAnti)
+{
+  MT_LOCK
+  if (StdOutMode)
+    return S_OK;
+  if(isAnti)
+    m_PercentPrinter.PrintString("Anti item    ");
+  else
+    m_PercentPrinter.PrintString("Compressing  ");
+  if (name[0] == 0)
+    name = kEmptyFileAlias;
+  m_PercentPrinter.PrintString(name);
+  if (EnablePercents)
+    m_PercentPrinter.RePrintRatio();
+  return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError)
+{
+  MT_LOCK
+  FailedCodes.Add(systemError);
+  FailedFiles.Add(name);
+  // if (systemError == ERROR_SHARING_VIOLATION)
+  {
+    m_PercentPrinter.ClosePrint();
+    m_PercentPrinter.PrintNewLine();
+    m_PercentPrinter.PrintString("WARNING: ");
+    m_PercentPrinter.PrintString(NError::MyFormatMessageW(systemError));
+    return S_FALSE;
+  }
+  // return systemError;
+}
+
+HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 )
+{
+  m_NeedBeClosed = true;
+  m_NeedNewLine = true;
+  return S_OK;  
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+  if (!PasswordIsDefined) 
+  {
+    if (AskPassword)
+    {
+      Password = GetPassword(OutStream); 
+      PasswordIsDefined = true;
+    }
+  }
+  *passwordIsDefined = BoolToInt(PasswordIsDefined);
+  CMyComBSTR tempName(Password);
+  *password = tempName.Detach();
+  return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.h
new file mode 100644 (file)
index 0000000..d04e1ad
--- /dev/null
@@ -0,0 +1,58 @@
+// UpdateCallbackConsole.h
+
+#ifndef __UPDATECALLBACKCONSOLE_H
+#define __UPDATECALLBACKCONSOLE_H
+
+#include "Common/MyString.h"
+#include "Common/StdOutStream.h"
+#include "PercentPrinter.h"
+#include "../Common/Update.h"
+
+class CUpdateCallbackConsole: public IUpdateCallbackUI2
+{
+  CPercentPrinter m_PercentPrinter;
+  bool m_NeedBeClosed;
+  bool m_NeedNewLine;
+
+  bool m_WarningsMode;
+
+  CStdOutStream *OutStream;
+public:
+  bool EnablePercents;
+  bool StdOutMode;
+
+  bool PasswordIsDefined;
+  UString Password;
+  bool AskPassword;
+
+
+  CUpdateCallbackConsole(): 
+      m_PercentPrinter(1 << 16),
+      PasswordIsDefined(false),
+      AskPassword(false),
+      StdOutMode(false),
+      EnablePercents(true),
+      m_WarningsMode(false)
+      {}
+  
+  ~CUpdateCallbackConsole() { Finilize(); }
+  void Init(CStdOutStream *outStream)
+  {
+    m_NeedBeClosed = false;
+    m_NeedNewLine = false;
+    FailedFiles.Clear();
+    FailedCodes.Clear();
+    OutStream = outStream;
+    m_PercentPrinter.OutStream = outStream;
+  }
+
+  INTERFACE_IUpdateCallbackUI2(;)
+
+  UStringVector FailedFiles;
+  CRecordVector<HRESULT> FailedCodes;
+
+  UStringVector CantFindFiles;
+  CRecordVector<HRESULT> CantFindCodes;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/UserInputUtils.cpp b/lzma/CPP/7zip/UI/Console/UserInputUtils.cpp
new file mode 100644 (file)
index 0000000..164af99
--- /dev/null
@@ -0,0 +1,58 @@
+// UserInputUtils.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StdInStream.h"
+#include "Common/StringConvert.h"
+
+#include "UserInputUtils.h"
+
+static const char kYes = 'Y';
+static const char kNo = 'N';
+static const char kYesAll = 'A';
+static const char kNoAll = 'S';
+static const char kAutoRename = 'U';
+static const char kQuit = 'Q';
+
+static const char *kFirstQuestionMessage = "?\n";
+static const char *kHelpQuestionMessage = 
+  "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename / (Q)uit? ";
+
+// return true if pressed Quite;
+// in: anAll
+// out: anAll, anYes;
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream)
+{
+  (*outStream) << kFirstQuestionMessage;
+  for(;;)
+  {
+    (*outStream) << kHelpQuestionMessage;
+    AString scannedString = g_StdIn.ScanStringUntilNewLine();
+    scannedString.Trim();
+    if(!scannedString.IsEmpty())
+      switch(::MyCharUpper(scannedString[0]))
+      {
+        case kYes:
+          return NUserAnswerMode::kYes;
+        case kNo:
+          return NUserAnswerMode::kNo;
+        case kYesAll:
+          return NUserAnswerMode::kYesAll;
+        case kNoAll:
+          return NUserAnswerMode::kNoAll;
+        case kAutoRename:
+          return NUserAnswerMode::kAutoRename;
+        case kQuit:
+          return NUserAnswerMode::kQuit;
+      }
+  }
+}
+
+UString GetPassword(CStdOutStream *outStream)
+{
+  (*outStream) << "\nEnter password:";
+  outStream->Flush();
+  AString oemPassword = g_StdIn.ScanStringUntilNewLine();
+  return MultiByteToUnicodeString(oemPassword, CP_OEMCP); 
+}
diff --git a/lzma/CPP/7zip/UI/Console/UserInputUtils.h b/lzma/CPP/7zip/UI/Console/UserInputUtils.h
new file mode 100644 (file)
index 0000000..408e93e
--- /dev/null
@@ -0,0 +1,24 @@
+// UserInputUtils.h
+
+#ifndef __USERINPUTUTILS_H
+#define __USERINPUTUTILS_H
+
+#include "Common/StdOutStream.h"
+
+namespace NUserAnswerMode {
+
+enum EEnum
+{
+  kYes,
+  kNo,
+  kYesAll,
+  kNoAll,
+  kAutoRename,
+  kQuit
+};
+}
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream);
+UString GetPassword(CStdOutStream *outStream);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/afxres.h b/lzma/CPP/7zip/UI/Console/afxres.h
new file mode 100644 (file)
index 0000000..c2fadd4
--- /dev/null
@@ -0,0 +1 @@
+#include <winresrc.h>
diff --git a/lzma/CPP/Build.mak b/lzma/CPP/Build.mak
new file mode 100644 (file)
index 0000000..d259556
--- /dev/null
@@ -0,0 +1,68 @@
+!IFDEF CPU
+LIBS = $(LIBS) bufferoverflowU.lib 
+CFLAGS = $(CFLAGS) -GS- -Zc:forScope
+!ENDIF
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+!IF "$(CPU)" != "IA64"
+!IF "$(CPU)" != "AMD64"
+MY_ML = ml
+!ELSE
+MY_ML = ml64
+!ENDIF
+!ENDIF
+
+COMPL_ASM = $(MY_ML) -c -Fo$O/ $**
+
+CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -EHsc -Gz -WX -Gy
+
+!IFDEF MY_STATIC_LINK
+!IFNDEF MY_SINGLE_THREAD
+CFLAGS = $(CFLAGS) -MT
+!ENDIF
+!ELSE
+CFLAGS = $(CFLAGS) -MD
+!ENDIF
+
+!IFDEF NEW_COMPILER
+CFLAGS_O1 = $(CFLAGS) -O1 -W4 -Wp64
+CFLAGS_O2 = $(CFLAGS) -O2 -W4 -Wp64
+!ELSE
+CFLAGS_O1 = $(CFLAGS) -O1 -W3
+CFLAGS_O2 = $(CFLAGS) -O2 -W3
+!ENDIF
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98 -OPT:REF 
+
+!IFDEF DEF_FILE
+LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE)
+!ENDIF
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1   = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2   = $(CPP) $(CFLAGS_O2) $**
+COMPL_PCH  = $(CPP) $(CFLAGS_O1) -Yc"StdAfx.h" -Fp$O/a.pch $** 
+COMPL      = $(CPP) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $**
+
+all: $(PROGPATH) 
+
+clean:
+       -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch 
+
+$O:
+       if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS) $(DEF_FILE)
+       link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+$O\resource.res: $(*B).rc
+       rc -fo$@ $**
+$O\StdAfx.obj: $(*B).cpp
+       $(COMPL_PCH)
diff --git a/lzma/CPP/Common/AutoPtr.h b/lzma/CPP/Common/AutoPtr.h
new file mode 100644 (file)
index 0000000..c5808cb
--- /dev/null
@@ -0,0 +1,35 @@
+// Common/AutoPtr.h
+
+#ifndef __COMMON_AUTOPTR_H
+#define __COMMON_AUTOPTR_H
+
+template<class T> class CMyAutoPtr
+{
+  T *_p;
+public:
+  CMyAutoPtr(T *p = 0) : _p(p) {}
+  CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}
+  CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p) 
+  {
+    reset(p.release());
+    return (*this);
+  }
+  ~CMyAutoPtr() { delete _p; }
+  T& operator*() const { return *_p; }
+  // T* operator->() const { return (&**this); }
+  T* get() const { return _p; }
+  T* release()
+  {
+    T *tmp = _p;
+    _p = 0;
+    return tmp;
+  }
+  void reset(T* p = 0)
+  {
+    if (p != _p)
+      delete _p;
+    _p = p;
+  }
+};
+
+#endif
diff --git a/lzma/CPP/Common/Buffer.h b/lzma/CPP/Common/Buffer.h
new file mode 100644 (file)
index 0000000..78a68a6
--- /dev/null
@@ -0,0 +1,77 @@
+// Common/Buffer.h
+
+#ifndef __COMMON_BUFFER_H
+#define __COMMON_BUFFER_H
+
+#include "Defs.h"
+
+template <class T> class CBuffer
+{    
+protected:
+  size_t _capacity;
+  T *_items;
+public:
+  void Free()
+  {
+    delete []_items;
+    _items = 0;
+    _capacity = 0;
+  }
+  CBuffer(): _capacity(0), _items(0) {};
+  CBuffer(const CBuffer &buffer): _capacity(0), _items(0) { *this = buffer; }
+  CBuffer(size_t size): _items(0),  _capacity(0) {  SetCapacity(size); }
+  virtual ~CBuffer() { delete []_items; }
+  operator T *() { return _items; };
+  operator const T *() const { return _items; };
+  size_t GetCapacity() const { return  _capacity; }
+  void SetCapacity(size_t newCapacity)
+  {
+    if (newCapacity == _capacity)
+      return;
+    T *newBuffer;
+    if (newCapacity > 0)
+    {
+      newBuffer = new T[newCapacity];
+      if(_capacity > 0)
+        memmove(newBuffer, _items, MyMin(_capacity, newCapacity) * sizeof(T));
+    }
+    else
+      newBuffer = 0;
+    delete []_items;
+    _items = newBuffer;
+    _capacity = newCapacity;
+  }
+  CBuffer& operator=(const CBuffer &buffer)
+  {
+    Free();
+    if(buffer._capacity > 0)
+    {
+      SetCapacity(buffer._capacity);
+      memmove(_items, buffer._items, buffer._capacity * sizeof(T));
+    }
+    return *this;
+  }
+};
+
+template <class T>
+bool operator==(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+  if (b1.GetCapacity() != b2.GetCapacity())
+    return false;
+  for (size_t i = 0; i < b1.GetCapacity(); i++)
+    if (b1[i] != b2[i])
+      return false;
+  return true;
+}
+
+template <class T>
+bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+  return !(b1 == b2);
+}
+
+typedef CBuffer<char> CCharBuffer;
+typedef CBuffer<wchar_t> CWCharBuffer;
+typedef CBuffer<unsigned char> CByteBuffer;
+
+#endif
diff --git a/lzma/CPP/Common/CRC.cpp b/lzma/CPP/Common/CRC.cpp
new file mode 100644 (file)
index 0000000..b768128
--- /dev/null
@@ -0,0 +1,14 @@
+// Common/CRC.cpp
+
+#include "StdAfx.h"
+
+extern "C" 
+{ 
+#include "../../C/7zCrc.h"
+}
+
+class CCRCTableInit
+{
+public:
+  CCRCTableInit() { CrcGenerateTable(); }
+} g_CRCTableInit;
diff --git a/lzma/CPP/Common/C_FileIO.cpp b/lzma/CPP/Common/C_FileIO.cpp
new file mode 100644 (file)
index 0000000..3c7f82d
--- /dev/null
@@ -0,0 +1,88 @@
+// Common/C_FileIO.h
+
+#include "C_FileIO.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+bool CFileBase::OpenBinary(const char *name, int flags)
+{
+  #ifdef O_BINARY
+  flags |= O_BINARY;
+  #endif
+  Close();
+  _handle = ::open(name, flags, 0666);
+  return _handle != -1;
+}
+
+bool CFileBase::Close()
+{
+  if(_handle == -1)
+    return true;
+  if (close(_handle) != 0)
+    return false;
+  _handle = -1;
+  return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+  off_t curPos = Seek(0, SEEK_CUR);
+  off_t lengthTemp = Seek(0, SEEK_END);
+  Seek(curPos, SEEK_SET);
+  length = (UInt64)lengthTemp;
+  return true;
+}
+
+off_t CFileBase::Seek(off_t distanceToMove, int moveMethod) const
+{
+  return ::lseek(_handle, distanceToMove, moveMethod);
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(const char *name)
+{
+  return CFileBase::OpenBinary(name, O_RDONLY);
+}
+
+bool CInFile::OpenShared(const char *name, bool)
+{
+  return Open(name);
+}
+
+ssize_t CInFile::Read(void *data, size_t size)
+{
+  return read(_handle, data, size);
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+  if (createAlways)
+  {
+    Close();
+    _handle = ::creat(name, 0666);
+    return _handle != -1;
+  }
+  return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
+}
+
+bool COutFile::Open(const char *name, DWORD creationDisposition)
+{
+  return Create(name, false);
+}
+
+ssize_t COutFile::Write(const void *data, size_t size)
+{
+  return write(_handle, data, size);
+}
+
+}}}
diff --git a/lzma/CPP/Common/C_FileIO.h b/lzma/CPP/Common/C_FileIO.h
new file mode 100644 (file)
index 0000000..27aa568
--- /dev/null
@@ -0,0 +1,47 @@
+// Common/C_FileIO.h
+
+#ifndef __COMMON_C_FILEIO_H
+#define __COMMON_C_FILEIO_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "Types.h"
+#include "MyWindows.h"
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+class CFileBase
+{
+protected:
+  int _handle;
+  bool OpenBinary(const char *name, int flags);
+public:
+  CFileBase(): _handle(-1) {};
+  ~CFileBase() { Close(); }
+  bool Close();
+  bool GetLength(UInt64 &length) const;
+  off_t Seek(off_t distanceToMove, int moveMethod) const;
+};
+
+class CInFile: public CFileBase
+{
+public:
+  bool Open(const char *name);
+  bool OpenShared(const char *name, bool shareForWrite);
+  ssize_t Read(void *data, size_t size);
+};
+
+class COutFile: public CFileBase
+{
+public:
+  bool Create(const char *name, bool createAlways);
+  bool Open(const char *name, DWORD creationDisposition);
+  ssize_t Write(const void *data, size_t size);
+};
+
+}}}
+
+#endif
diff --git a/lzma/CPP/Common/ComTry.h b/lzma/CPP/Common/ComTry.h
new file mode 100644 (file)
index 0000000..5153362
--- /dev/null
@@ -0,0 +1,17 @@
+// ComTry.h
+
+#ifndef __COM_TRY_H
+#define __COM_TRY_H
+
+#include "MyWindows.h"
+// #include "Exception.h"
+// #include "NewHandler.h"
+
+#define COM_TRY_BEGIN try {
+#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; }
+  
+  // catch(const CNewException &) { return E_OUTOFMEMORY; }\
+  // catch(const CSystemException &e) { return e.ErrorCode; }\
+  // catch(...) { return E_FAIL; }
+
+#endif
diff --git a/lzma/CPP/Common/CommandLineParser.cpp b/lzma/CPP/Common/CommandLineParser.cpp
new file mode 100644 (file)
index 0000000..67f7267
--- /dev/null
@@ -0,0 +1,232 @@
+// CommandLineParser.cpp
+
+#include "StdAfx.h"
+
+#include "CommandLineParser.h"
+
+namespace NCommandLineParser {
+
+void SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
+{
+  dest1.Empty();
+  dest2.Empty();
+  bool quoteMode = false;
+  int i;
+  for (i = 0; i < src.Length(); i++)
+  {
+    wchar_t c = src[i];
+    if (c == L'\"')
+      quoteMode = !quoteMode;
+    else if (c == L' ' && !quoteMode)
+    {
+      i++;
+      break;
+    }
+    else 
+      dest1 += c;
+  }
+  dest2 = src.Mid(i);
+}
+
+void SplitCommandLine(const UString &s, UStringVector &parts)
+{
+  UString sTemp = s;
+  sTemp.Trim();
+  parts.Clear();
+  for (;;)
+  {
+    UString s1, s2;
+    SplitCommandLine(sTemp, s1, s2);
+    // s1.Trim();
+    // s2.Trim();
+    if (!s1.IsEmpty())
+      parts.Add(s1);
+    if (s2.IsEmpty())
+      break;
+    sTemp = s2;
+  }
+}
+
+
+static const wchar_t kSwitchID1 = '-';
+// static const wchar_t kSwitchID2 = '/';
+
+static const wchar_t kSwitchMinus = '-';
+static const wchar_t *kStopSwitchParsing = L"--";
+
+static bool IsItSwitchChar(wchar_t c)
+{ 
+  return (c == kSwitchID1 /*|| c == kSwitchID2 */); 
+}
+
+CParser::CParser(int numSwitches):
+  _numSwitches(numSwitches)
+{
+  _switches = new CSwitchResult[_numSwitches];
+}
+
+CParser::~CParser()
+{
+  delete []_switches;
+}
+
+void CParser::ParseStrings(const CSwitchForm *switchForms, 
+  const UStringVector &commandStrings)
+{
+  int numCommandStrings = commandStrings.Size();
+  bool stopSwitch = false;
+  for (int i = 0; i < numCommandStrings; i++)
+  {
+    const UString &s = commandStrings[i];
+    if (stopSwitch)
+      NonSwitchStrings.Add(s);
+    else
+      if (s == kStopSwitchParsing)
+        stopSwitch = true;
+      else
+        if (!ParseString(s, switchForms))
+          NonSwitchStrings.Add(s);
+  }
+}
+
+// if string contains switch then function updates switch structures
+// out: (string is a switch)
+bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
+{
+  int len = s.Length();
+  if (len == 0) 
+    return false;
+  int pos = 0;
+  if (!IsItSwitchChar(s[pos]))
+    return false;
+  while(pos < len)
+  {
+    if (IsItSwitchChar(s[pos]))
+      pos++;
+    const int kNoLen = -1;
+    int matchedSwitchIndex = 0; // GCC Warning
+    int maxLen = kNoLen;
+    for(int switchIndex = 0; switchIndex < _numSwitches; switchIndex++)
+    {
+      int switchLen = MyStringLen(switchForms[switchIndex].IDString);
+      if (switchLen <= maxLen || pos + switchLen > len) 
+        continue;
+
+      UString temp = s + pos;
+      temp = temp.Left(switchLen);
+      if(temp.CompareNoCase(switchForms[switchIndex].IDString) == 0)
+      // if(_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0)
+      {
+        matchedSwitchIndex = switchIndex;
+        maxLen = switchLen;
+      }
+    }
+    if (maxLen == kNoLen)
+      throw "maxLen == kNoLen";
+    CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex];
+    const CSwitchForm &switchForm = switchForms[matchedSwitchIndex];
+    if ((!switchForm.Multi) && matchedSwitch.ThereIs)
+      throw "switch must be single";
+    matchedSwitch.ThereIs = true;
+    pos += maxLen;
+    int tailSize = len - pos;
+    NSwitchType::EEnum type = switchForm.Type;
+    switch(type)
+    {
+      case NSwitchType::kPostMinus:
+        {
+          if (tailSize == 0)
+            matchedSwitch.WithMinus = false;
+          else
+          {
+            matchedSwitch.WithMinus = (s[pos] == kSwitchMinus);
+            if (matchedSwitch.WithMinus)
+              pos++;
+          }
+          break;
+        }
+      case NSwitchType::kPostChar:
+        {
+          if (tailSize < switchForm.MinLen)
+            throw "switch is not full";
+          UString set = switchForm.PostCharSet;
+          const int kEmptyCharValue = -1;
+          if (tailSize == 0)
+            matchedSwitch.PostCharIndex = kEmptyCharValue;
+          else
+          {
+            int index = set.Find(s[pos]);
+            if (index < 0)
+              matchedSwitch.PostCharIndex =  kEmptyCharValue;
+            else
+            {
+              matchedSwitch.PostCharIndex = index;
+              pos++;
+            }
+          }
+          break;
+        }
+      case NSwitchType::kLimitedPostString: 
+      case NSwitchType::kUnLimitedPostString: 
+        {
+          int minLen = switchForm.MinLen;
+          if (tailSize < minLen)
+            throw "switch is not full";
+          if (type == NSwitchType::kUnLimitedPostString)
+          {
+            matchedSwitch.PostStrings.Add(s.Mid(pos));
+            return true;
+          }
+          int maxLen = switchForm.MaxLen;
+          UString stringSwitch = s.Mid(pos, minLen);
+          pos += minLen;
+          for(int i = minLen; i < maxLen && pos < len; i++, pos++)
+          {
+            wchar_t c = s[pos];
+            if (IsItSwitchChar(c))
+              break;
+            stringSwitch += c;
+          }
+          matchedSwitch.PostStrings.Add(stringSwitch);
+          break;
+        }
+      case NSwitchType::kSimple:
+          break;
+    }
+  }
+  return true;
+}
+
+const CSwitchResult& CParser::operator[](size_t index) const
+{
+  return _switches[index];
+}
+
+/////////////////////////////////
+// Command parsing procedures
+
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms, 
+    const UString &commandString, UString &postString)
+{
+  for(int i = 0; i < numCommandForms; i++)
+  {
+    const UString id = commandForms[i].IDString;
+    if (commandForms[i].PostStringMode)
+    {
+      if(commandString.Find(id) == 0)
+      {
+        postString = commandString.Mid(id.Length());
+        return i;
+      }
+    }
+    else
+      if (commandString == id)
+      {
+        postString.Empty();
+        return i;
+      }
+  }
+  return -1;
+}
+   
+}
diff --git a/lzma/CPP/Common/CommandLineParser.h b/lzma/CPP/Common/CommandLineParser.h
new file mode 100644 (file)
index 0000000..a97f58a
--- /dev/null
@@ -0,0 +1,72 @@
+// Common/CommandLineParser.h
+
+#ifndef __COMMON_COMMANDLINEPARSER_H
+#define __COMMON_COMMANDLINEPARSER_H
+
+#include "MyString.h"
+
+namespace NCommandLineParser {
+
+void SplitCommandLine(const UString &src, UString &dest1, UString &dest2);
+void SplitCommandLine(const UString &s, UStringVector &parts);
+
+namespace NSwitchType {
+  enum EEnum
+  { 
+    kSimple,
+    kPostMinus,
+    kLimitedPostString,
+    kUnLimitedPostString,
+    kPostChar
+  };
+}
+
+struct CSwitchForm
+{
+  const wchar_t *IDString;
+  NSwitchType::EEnum Type;
+  bool Multi;
+  int MinLen;
+  int MaxLen;
+  const wchar_t *PostCharSet;
+};
+
+struct CSwitchResult
+{
+  bool ThereIs;
+  bool WithMinus;
+  UStringVector PostStrings;
+  int PostCharIndex;
+  CSwitchResult(): ThereIs(false) {};
+};
+  
+class CParser
+{
+  int _numSwitches;
+  CSwitchResult *_switches;
+  bool ParseString(const UString &s, const CSwitchForm *switchForms); 
+public:
+  UStringVector NonSwitchStrings;
+  CParser(int numSwitches);
+  ~CParser();
+  void ParseStrings(const CSwitchForm *switchForms, 
+    const UStringVector &commandStrings);
+  const CSwitchResult& operator[](size_t index) const;
+};
+
+/////////////////////////////////
+// Command parsing procedures
+
+struct CCommandForm
+{
+  wchar_t *IDString;
+  bool PostStringMode;
+};
+
+// Returns: Index of form and postString; -1, if there is no match
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms, 
+    const UString &commandString, UString &postString);
+
+}
+
+#endif
diff --git a/lzma/CPP/Common/Defs.h b/lzma/CPP/Common/Defs.h
new file mode 100644 (file)
index 0000000..dad3ae8
--- /dev/null
@@ -0,0 +1,20 @@
+// Common/Defs.h
+
+#ifndef __COMMON_DEFS_H
+#define __COMMON_DEFS_H
+
+template <class T> inline T MyMin(T a, T b)
+  {  return a < b ? a : b; }
+template <class T> inline T MyMax(T a, T b)
+  {  return a > b ? a : b; }
+
+template <class T> inline int MyCompare(T a, T b)
+  {  return a < b ? -1 : (a == b ? 0 : 1); }
+
+inline int BoolToInt(bool value)
+  { return (value ? 1: 0); }
+
+inline bool IntToBool(int value)
+  { return (value != 0); }
+
+#endif
diff --git a/lzma/CPP/Common/DynamicBuffer.h b/lzma/CPP/Common/DynamicBuffer.h
new file mode 100644 (file)
index 0000000..1709657
--- /dev/null
@@ -0,0 +1,47 @@
+// Common/DynamicBuffer.h
+
+#ifndef __COMMON_DYNAMICBUFFER_H
+#define __COMMON_DYNAMICBUFFER_H
+
+#include "Buffer.h"
+
+template <class T> class CDynamicBuffer: public CBuffer<T>
+{    
+  void GrowLength(size_t size)
+  {
+    size_t delta;
+    if (this->_capacity > 64)
+      delta = this->_capacity / 4;
+    else if (this->_capacity > 8)
+      delta = 16;
+    else
+      delta = 4;
+    delta = MyMax(delta, size);
+    SetCapacity(this->_capacity + delta);
+  }
+public:
+  CDynamicBuffer(): CBuffer<T>() {};
+  CDynamicBuffer(const CDynamicBuffer &buffer): CBuffer<T>(buffer) {};
+  CDynamicBuffer(size_t size): CBuffer<T>(size) {};
+  CDynamicBuffer& operator=(const CDynamicBuffer &buffer)
+  {
+    this->Free();
+    if(buffer._capacity > 0)
+    {
+      SetCapacity(buffer._capacity);
+      memmove(this->_items, buffer._items, buffer._capacity * sizeof(T));
+    }
+    return *this;
+  }
+  void EnsureCapacity(size_t capacity)
+  {
+    if (this->_capacity < capacity)
+      GrowLength(capacity - this->_capacity);
+  }
+};
+
+typedef CDynamicBuffer<char> CCharDynamicBuffer;
+typedef CDynamicBuffer<wchar_t> CWCharDynamicBuffer;
+typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;
+
+#endif
diff --git a/lzma/CPP/Common/IntToString.cpp b/lzma/CPP/Common/IntToString.cpp
new file mode 100644 (file)
index 0000000..340d865
--- /dev/null
@@ -0,0 +1,63 @@
+// Common/IntToString.cpp
+
+#include "StdAfx.h"
+
+#include "IntToString.h"
+
+void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base)
+{
+  if (base < 2 || base > 36)
+  {
+    *s = '\0';
+    return;
+  }
+  char temp[72];
+  int pos = 0;
+  do 
+  {
+    int delta = (int)(value % base);
+    temp[pos++] = (char)((delta < 10) ? ('0' + delta) : ('a' + (delta - 10)));
+    value /= base;
+  }
+  while (value != 0);
+  do
+    *s++ = temp[--pos];
+  while(pos > 0);
+  *s = '\0';
+}
+
+void ConvertUInt64ToString(UInt64 value, wchar_t *s)
+{
+  wchar_t temp[32];
+  int pos = 0;
+  do 
+  {
+    temp[pos++] = (wchar_t)(L'0' + (int)(value % 10));
+    value /= 10;
+  }
+  while (value != 0);
+  do 
+    *s++ = temp[--pos];
+  while(pos > 0);
+  *s = L'\0';
+}
+
+void ConvertInt64ToString(Int64 value, char *s)
+{
+  if (value < 0)
+  {
+    *s++ = '-';
+    value = -value;
+  }
+  ConvertUInt64ToString(value, s);
+}
+
+void ConvertInt64ToString(Int64 value, wchar_t *s)
+{
+  if (value < 0)
+  {
+    *s++ = L'-';
+    value = -value;
+  }
+  ConvertUInt64ToString(value, s);
+}
diff --git a/lzma/CPP/Common/IntToString.h b/lzma/CPP/Common/IntToString.h
new file mode 100644 (file)
index 0000000..cf86090
--- /dev/null
@@ -0,0 +1,15 @@
+// Common/IntToString.h
+
+#ifndef __COMMON_INTTOSTRING_H
+#define __COMMON_INTTOSTRING_H
+
+#include <stddef.h>
+#include "Types.h"
+
+void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base = 10);
+void ConvertUInt64ToString(UInt64 value, wchar_t *s);
+
+void ConvertInt64ToString(Int64 value, char *s);
+void ConvertInt64ToString(Int64 value, wchar_t *s);
+
+#endif
diff --git a/lzma/CPP/Common/ListFileUtils.cpp b/lzma/CPP/Common/ListFileUtils.cpp
new file mode 100644 (file)
index 0000000..4f8a9e5
--- /dev/null
@@ -0,0 +1,74 @@
+// Common/ListFileUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../Windows/FileIO.h"
+
+#include "ListFileUtils.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+static const char kQuoteChar     = '\"';
+static void RemoveQuote(UString &s)
+{
+  if (s.Length() >= 2)
+    if (s[0] == kQuoteChar && s[s.Length() - 1] == kQuoteChar)
+      s = s.Mid(1, s.Length() - 2);
+}
+
+bool ReadNamesFromListFile(LPCWSTR fileName, UStringVector &resultStrings, UINT codePage)
+{
+  NWindows::NFile::NIO::CInFile file;
+  if (!file.Open(fileName))
+    return false;
+  UInt64 length;
+  if (!file.GetLength(length))
+    return false;
+  if (length > ((UInt32)1 << 31))
+    return false;
+  AString s;
+  char *p = s.GetBuffer((int)length + 1);
+  UInt32 processed;
+  if (!file.Read(p, (UInt32)length, processed))
+    return false;
+  p[(UInt32)length] = 0;
+  s.ReleaseBuffer();
+  file.Close();
+
+  UString u;
+  #ifdef CP_UTF8
+  if (codePage == CP_UTF8)
+  {
+    if (!ConvertUTF8ToUnicode(s, u))
+      return false;
+  }
+  else
+  #endif
+    u = MultiByteToUnicodeString(s, codePage);
+  if (!u.IsEmpty())
+  {
+    if (u[0] == 0xFEFF)
+      u.Delete(0);
+  }
+
+  UString t;
+  for(int i = 0; i < u.Length(); i++)
+  {
+    wchar_t c = u[i];
+    if (c == L'\n' || c == 0xD)
+    {
+      t.Trim();
+      RemoveQuote(t);
+      if (!t.IsEmpty())
+        resultStrings.Add(t);
+      t.Empty();
+    }
+    else
+      t += c;
+  }
+  t.Trim();
+  RemoveQuote(t);
+  if (!t.IsEmpty())
+    resultStrings.Add(t);
+  return true;
+}
diff --git a/lzma/CPP/Common/ListFileUtils.h b/lzma/CPP/Common/ListFileUtils.h
new file mode 100644 (file)
index 0000000..c58a8bd
--- /dev/null
@@ -0,0 +1,11 @@
+// Common/ListFileUtils.h
+
+#ifndef __COMMON_LISTFILEUTILS_H
+#define __COMMON_LISTFILEUTILS_H
+
+#include "MyString.h"
+#include "Types.h"
+
+bool ReadNamesFromListFile(LPCWSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP);
+
+#endif
diff --git a/lzma/CPP/Common/MyCom.h b/lzma/CPP/Common/MyCom.h
new file mode 100644 (file)
index 0000000..dcc94f1
--- /dev/null
@@ -0,0 +1,218 @@
+// MyCom.h
+
+#ifndef __MYCOM_H
+#define __MYCOM_H
+
+#include "MyWindows.h"
+
+#ifndef RINOK
+#define RINOK(x) { HRESULT __result_ = (x); if(__result_ != S_OK) return __result_; }
+#endif
+
+template <class T>
+class CMyComPtr
+{
+  T* _p;
+public:
+  // typedef T _PtrClass;
+  CMyComPtr() { _p = NULL;}
+  CMyComPtr(T* p) {if ((_p = p) != NULL) p->AddRef(); }
+  CMyComPtr(const CMyComPtr<T>& lp)
+  {
+    if ((_p = lp._p) != NULL)
+      _p->AddRef();
+  }
+  ~CMyComPtr() { if (_p) _p->Release(); }
+  void Release() { if (_p) { _p->Release(); _p = NULL; } }
+  operator T*() const {  return (T*)_p;  }
+  // T& operator*() const {  return *_p; }
+  T** operator&() { return &_p; }
+  T* operator->() const { return _p; }
+  T* operator=(T* p) 
+  { 
+    if (p != 0)
+      p->AddRef();
+    if (_p) 
+      _p->Release();
+    _p = p;
+    return p;
+  }
+  T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); }
+  bool operator!() const { return (_p == NULL); }
+  // bool operator==(T* pT) const {  return _p == pT; }
+  // Compare two objects for equivalence
+  void Attach(T* p2)
+  {
+    Release();
+    _p = p2;
+  }
+  T* Detach()
+  {
+    T* pt = _p;
+    _p = NULL;
+    return pt;
+  }
+  #ifdef _WIN32
+  HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+  {
+    return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p);
+  }
+  #endif
+  /*
+  HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+  {
+    CLSID clsid;
+    HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
+    ATLASSERT(_p == NULL);
+    if (SUCCEEDED(hr))
+      hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p);
+    return hr;
+  }
+  */
+  template <class Q>
+  HRESULT QueryInterface(REFGUID iid, Q** pp) const
+  {
+    return _p->QueryInterface(iid, (void**)pp);
+  }
+};
+
+//////////////////////////////////////////////////////////
+
+class CMyComBSTR
+{
+public:
+  BSTR m_str;
+  CMyComBSTR() { m_str = NULL; }
+  CMyComBSTR(LPCOLESTR pSrc) {  m_str = ::SysAllocString(pSrc);  }
+  // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); }
+  // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize);  }
+  CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); }
+  /*
+  CMyComBSTR(REFGUID src)
+  {
+    LPOLESTR szGuid;
+    StringFromCLSID(src, &szGuid);
+    m_str = ::SysAllocString(szGuid);
+    CoTaskMemFree(szGuid);
+  }
+  */
+  ~CMyComBSTR() { ::SysFreeString(m_str); }
+  CMyComBSTR& operator=(const CMyComBSTR& src)
+  {
+    if (m_str != src.m_str)
+    {
+      if (m_str)
+        ::SysFreeString(m_str);
+      m_str = src.MyCopy();
+    }
+    return *this;
+  }
+  CMyComBSTR& operator=(LPCOLESTR pSrc)
+  {
+    ::SysFreeString(m_str);
+    m_str = ::SysAllocString(pSrc);
+    return *this;
+  }
+  unsigned int Length() const { return ::SysStringLen(m_str); }
+  operator BSTR() const { return m_str; }
+  BSTR* operator&() { return &m_str; }
+  BSTR MyCopy() const 
+  { 
+    int byteLen = ::SysStringByteLen(m_str);
+    BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
+    memmove(res, m_str, byteLen);
+    return res;
+  }
+  void Attach(BSTR src) {  m_str = src; }
+  BSTR Detach()
+  {
+    BSTR s = m_str;
+    m_str = NULL;
+    return s;
+  }
+  void Empty()
+  {
+    ::SysFreeString(m_str);
+    m_str = NULL;
+  }
+  bool operator!() const {  return (m_str == NULL); }
+};
+
+
+//////////////////////////////////////////////////////////
+
+class CMyUnknownImp
+{
+public:
+  ULONG __m_RefCount;
+  CMyUnknownImp(): __m_RefCount(0) {}
+};
+
+#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \
+    (REFGUID iid, void **outObject) { 
+
+#define MY_QUERYINTERFACE_ENTRY(i) if (iid == IID_ ## i) \
+    { *outObject = (void *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \
+    { *outObject = (void *)(IUnknown *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \
+    MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
+    MY_QUERYINTERFACE_ENTRY(i)
+
+#define MY_QUERYINTERFACE_END return E_NOINTERFACE; }
+
+#define MY_ADDREF_RELEASE \
+STDMETHOD_(ULONG, AddRef)() { return ++__m_RefCount; } \
+STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0)  \
+  return __m_RefCount; delete this; return 0; }
+
+#define MY_UNKNOWN_IMP_SPEC(i) \
+  MY_QUERYINTERFACE_BEGIN \
+  i \
+  MY_QUERYINTERFACE_END \
+  MY_ADDREF_RELEASE
+
+
+#define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \
+  MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \
+  MY_QUERYINTERFACE_END \
+  MY_ADDREF_RELEASE
+
+#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \
+  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
+  MY_QUERYINTERFACE_ENTRY(i) \
+  )
+
+#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \
+  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+  MY_QUERYINTERFACE_ENTRY(i1) \
+  MY_QUERYINTERFACE_ENTRY(i2) \
+  )
+
+#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \
+  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+  MY_QUERYINTERFACE_ENTRY(i1) \
+  MY_QUERYINTERFACE_ENTRY(i2) \
+  MY_QUERYINTERFACE_ENTRY(i3) \
+  )
+
+#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \
+  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+  MY_QUERYINTERFACE_ENTRY(i1) \
+  MY_QUERYINTERFACE_ENTRY(i2) \
+  MY_QUERYINTERFACE_ENTRY(i3) \
+  MY_QUERYINTERFACE_ENTRY(i4) \
+  )
+
+#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \
+  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+  MY_QUERYINTERFACE_ENTRY(i1) \
+  MY_QUERYINTERFACE_ENTRY(i2) \
+  MY_QUERYINTERFACE_ENTRY(i3) \
+  MY_QUERYINTERFACE_ENTRY(i4) \
+  MY_QUERYINTERFACE_ENTRY(i5) \
+  )
+
+#endif
diff --git a/lzma/CPP/Common/MyException.h b/lzma/CPP/Common/MyException.h
new file mode 100644 (file)
index 0000000..f0ad111
--- /dev/null
@@ -0,0 +1,14 @@
+// Common/Exception.h
+
+#ifndef __COMMON_EXCEPTION_H
+#define __COMMON_EXCEPTION_H
+
+#include "MyWindows.h"
+
+struct CSystemException
+{
+  HRESULT ErrorCode;
+  CSystemException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+
+#endif
diff --git a/lzma/CPP/Common/MyGuidDef.h b/lzma/CPP/Common/MyGuidDef.h
new file mode 100644 (file)
index 0000000..1956269
--- /dev/null
@@ -0,0 +1,54 @@
+// Common/MyGuidDef.h
+
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+
+#include "Types.h"
+
+typedef struct {
+  UInt32 Data1;
+  UInt16 Data2;
+  UInt16 Data3;
+  unsigned char Data4[8];
+} GUID;
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+#define REFCLSID REFGUID
+#define REFIID REFGUID
+
+#ifdef __cplusplus
+inline int operator==(REFGUID g1, REFGUID g2)
+{ 
+  for (int i = 0; i < (int)sizeof(g1); i++)
+    if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i])
+      return 0;
+  return 1;
+}
+inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }
+#endif
+
+#ifdef __cplusplus
+  #define MY_EXTERN_C extern "C"
+#else
+  #define MY_EXTERN_C extern
+#endif
+
+#endif // GUID_DEFINED
+
+
+#ifdef DEFINE_GUID
+#undef DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+  #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+    MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
+#else
+  #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+    MY_EXTERN_C const GUID name
+#endif
diff --git a/lzma/CPP/Common/MyInitGuid.h b/lzma/CPP/Common/MyInitGuid.h
new file mode 100644 (file)
index 0000000..4fc1556
--- /dev/null
@@ -0,0 +1,15 @@
+// Common/MyInitGuid.h
+
+#ifndef __COMMON_MYINITGUID_H
+#define __COMMON_MYINITGUID_H
+
+#ifdef _WIN32
+#include <initguid.h>
+#else
+#define INITGUID
+#include "MyGuidDef.h"
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+#endif
+
+#endif
diff --git a/lzma/CPP/Common/MyString.cpp b/lzma/CPP/Common/MyString.cpp
new file mode 100644 (file)
index 0000000..affdcb0
--- /dev/null
@@ -0,0 +1,198 @@
+// Common/MyString.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include "StringConvert.h"
+#else
+#include <ctype.h>
+#endif
+
+#include "MyString.h"
+
+
+#ifdef _WIN32
+
+#ifndef _UNICODE
+
+wchar_t MyCharUpper(wchar_t c)
+{
+  if (c == 0)
+    return 0;
+  wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned int)c);
+  if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    return (wchar_t)(unsigned int)(UINT_PTR)res;
+  const int kBufferSize = 4;
+  char s[kBufferSize + 1];
+  int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0);
+  if (numChars == 0 || numChars > kBufferSize)
+    return c;
+  s[numChars] = 0;
+  ::CharUpperA(s);
+  ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+  return c;
+}
+
+wchar_t MyCharLower(wchar_t c)
+{
+  if (c == 0)
+    return 0;
+  wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned int)c);
+  if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    return (wchar_t)(unsigned int)(UINT_PTR)res;
+  const int kBufferSize = 4;
+  char s[kBufferSize + 1];
+  int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0);
+  if (numChars == 0 || numChars > kBufferSize)
+    return c;
+  s[numChars] = 0;
+  ::CharLowerA(s);
+  ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+  return c;
+}
+
+wchar_t * MyStringUpper(wchar_t *s)
+{
+  if (s == 0)
+    return 0;
+  wchar_t *res = CharUpperW(s);
+  if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    return res;
+  AString a = UnicodeStringToMultiByte(s);
+  a.MakeUpper();
+  return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+}
+
+wchar_t * MyStringLower(wchar_t *s)
+{ 
+  if (s == 0)
+    return 0;
+  wchar_t *res = CharLowerW(s);
+  if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    return res;
+  AString a = UnicodeStringToMultiByte(s);
+  a.MakeLower();
+  return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+}
+
+#endif
+
+/*
+inline int ConvertCompareResult(int r) { return r - 2; }
+
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2)
+{ 
+  int res = CompareStringW(
+        LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1); 
+  #ifdef _UNICODE
+  return ConvertCompareResult(res);
+  #else
+  if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    return ConvertCompareResult(res);
+  return MyStringCollate(UnicodeStringToMultiByte(s1), 
+        UnicodeStringToMultiByte(s2));
+  #endif
+}
+
+#ifndef _WIN32_WCE
+int MyStringCollate(const char *s1, const char *s2)
+{ 
+  return ConvertCompareResult(CompareStringA(
+    LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1)); 
+}
+
+int MyStringCollateNoCase(const char *s1, const char *s2)
+{ 
+  return ConvertCompareResult(CompareStringA(
+    LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1)); 
+}
+#endif
+
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2)
+{ 
+  int res = CompareStringW(
+        LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1); 
+  #ifdef _UNICODE
+  return ConvertCompareResult(res);
+  #else
+  if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    return ConvertCompareResult(res);
+  return MyStringCollateNoCase(UnicodeStringToMultiByte(s1), 
+      UnicodeStringToMultiByte(s2));
+  #endif
+}
+*/
+
+#else
+
+wchar_t MyCharUpper(wchar_t c)
+{
+  return toupper(c);
+}
+
+/*
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2)
+{ 
+  for (;;)
+  {
+    wchar_t c1 = *s1++;
+    wchar_t c2 = *s2++;
+    wchar_t u1 = MyCharUpper(c1);
+    wchar_t u2 = MyCharUpper(c2);
+
+    if (u1 < u2) return -1;
+    if (u1 > u2) return 1;
+    if (u1 == 0) return 0;
+  }
+}
+*/
+
+#endif
+
+int MyStringCompare(const char *s1, const char *s2)
+{ 
+  for (;;)
+  {
+    unsigned char c1 = (unsigned char)*s1++;
+    unsigned char c2 = (unsigned char)*s2++;
+    if (c1 < c2) return -1;
+    if (c1 > c2) return 1;
+    if (c1 == 0) return 0;
+  }
+}
+
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2)
+{ 
+  for (;;)
+  {
+    wchar_t c1 = *s1++;
+    wchar_t c2 = *s2++;
+    if (c1 < c2) return -1;
+    if (c1 > c2) return 1;
+    if (c1 == 0) return 0;
+  }
+}
+
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2)
+{ 
+  for (;;)
+  {
+    wchar_t c1 = *s1++;
+    wchar_t c2 = *s2++;
+    if (c1 != c2)
+    {
+      wchar_t u1 = MyCharUpper(c1);
+      wchar_t u2 = MyCharUpper(c2);
+      if (u1 < u2) return -1;
+      if (u1 > u2) return 1;
+    }
+    if (c1 == 0) return 0;
+  }
+}
+
+#ifdef _WIN32
+int MyStringCompareNoCase(const char *s1, const char *s2)
+{ 
+  return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
+}
+#endif
diff --git a/lzma/CPP/Common/MyString.h b/lzma/CPP/Common/MyString.h
new file mode 100644 (file)
index 0000000..c46ca54
--- /dev/null
@@ -0,0 +1,636 @@
+// Common/String.h
+
+#ifndef __COMMON_STRING_H
+#define __COMMON_STRING_H
+
+#include <string.h>
+// #include <wchar.h>
+
+#include "MyVector.h"
+
+#ifdef _WIN32
+#include "MyWindows.h"
+#endif
+
+template <class T>
+inline int MyStringLen(const T *s)
+{ 
+  int i;
+  for (i = 0; s[i] != '\0'; i++);
+  return i;
+}
+
+template <class T>
+inline T * MyStringCopy(T *dest, const T *src)
+{ 
+  T *destStart = dest;
+  while((*dest++ = *src++) != 0);
+  return destStart;
+}
+
+inline wchar_t* MyStringGetNextCharPointer(wchar_t *p)
+  { return (p + 1); }
+inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p)
+  { return (p + 1); }
+inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p)
+  { return (p - 1); }
+inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p)
+  { return (p - 1); }
+
+#ifdef _WIN32
+
+inline char* MyStringGetNextCharPointer(char *p)
+  { return CharNextA(p); }
+inline const char* MyStringGetNextCharPointer(const char *p)
+  { return CharNextA(p); }
+
+inline char* MyStringGetPrevCharPointer(char *base, char *p)
+  { return CharPrevA(base, p); }
+inline const char* MyStringGetPrevCharPointer(const char *base, const char *p)
+  { return CharPrevA(base, p); }
+
+inline char MyCharUpper(char c)
+  { return (char)(unsigned int)(UINT_PTR)CharUpperA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
+#ifdef _UNICODE
+inline wchar_t MyCharUpper(wchar_t c)
+  { return (wchar_t)(unsigned int)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned int)c); }
+#else
+wchar_t MyCharUpper(wchar_t c);
+#endif
+
+inline char MyCharLower(char c)
+  { return (char)(unsigned int)(UINT_PTR)CharLowerA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
+#ifdef _UNICODE
+inline wchar_t MyCharLower(wchar_t c)
+  { return (wchar_t)(unsigned int)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned int)c); }
+#else
+wchar_t MyCharLower(wchar_t c);
+#endif
+
+inline char * MyStringUpper(char *s) { return CharUpperA(s); }
+#ifdef _UNICODE
+inline wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
+#else
+wchar_t * MyStringUpper(wchar_t *s);
+#endif
+
+inline char * MyStringLower(char *s) { return CharLowerA(s); }
+#ifdef _UNICODE
+inline wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
+#else
+wchar_t * MyStringLower(wchar_t *s);
+#endif
+
+#else // Standard-C
+wchar_t MyCharUpper(wchar_t c);
+#endif
+
+//////////////////////////////////////
+// Compare
+
+/*
+#ifndef _WIN32_WCE
+int MyStringCollate(const char *s1, const char *s2);
+int MyStringCollateNoCase(const char *s1, const char *s2);
+#endif
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2);
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2);
+*/
+
+int MyStringCompare(const char *s1, const char  *s2);
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2);
+
+#ifdef _WIN32
+int MyStringCompareNoCase(const char *s1, const char  *s2);
+#endif
+
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2);
+
+template <class T>
+class CStringBase
+{
+  void TrimLeftWithCharSet(const CStringBase &charSet)
+  {
+    const T *p = _chars;
+    while (charSet.Find(*p) >= 0 && (*p != 0))
+      p = GetNextCharPointer(p);
+    Delete(0, (int)(p - _chars));
+  }
+  void TrimRightWithCharSet(const CStringBase &charSet)
+  {
+    const T *p = _chars;
+    const T *pLast = NULL;
+    while (*p != 0)
+    {
+      if (charSet.Find(*p) >= 0)
+      {
+        if (pLast == NULL)
+          pLast = p;
+      }
+      else
+        pLast = NULL;
+      p = GetNextCharPointer(p);
+    }
+    if(pLast != NULL)
+    {
+      int i = (int)(pLast - _chars);
+      Delete(i, _length - i);
+    }
+
+  }
+  void MoveItems(int destIndex, int srcIndex)
+  {
+    memmove(_chars + destIndex, _chars + srcIndex, 
+        sizeof(T) * (_length - srcIndex + 1));
+  }
+  
+  void InsertSpace(int &index, int size)
+  {
+    CorrectIndex(index);
+    GrowLength(size);
+    MoveItems(index + size, index);
+  }
+
+  static T *GetNextCharPointer(T *p)
+    { return MyStringGetNextCharPointer(p); }
+  static const T *GetNextCharPointer(const T *p)
+    { return MyStringGetNextCharPointer(p); }
+  static T *GetPrevCharPointer(T *base, T *p)
+    { return MyStringGetPrevCharPointer(base, p); }
+  static const T *GetPrevCharPointer(const T *base, const T *p)
+    { return MyStringGetPrevCharPointer(base, p); }
+protected:
+  T *_chars;
+  int _length;
+  int _capacity;
+  
+  void SetCapacity(int newCapacity)
+  {
+    int realCapacity = newCapacity + 1;
+    if(realCapacity == _capacity)
+      return;
+    /*
+    const int kMaxStringSize = 0x20000000;
+    #ifndef _WIN32_WCE
+    if(newCapacity > kMaxStringSize || newCapacity < _length)
+      throw 1052337;
+    #endif
+    */
+    T *newBuffer = new T[realCapacity];
+    if(_capacity > 0)
+    {
+      for (int i = 0; i < (_length + 1); i++)
+        newBuffer[i] = _chars[i];
+      delete []_chars;
+      _chars = newBuffer;
+    }
+    else
+    {
+      _chars = newBuffer;
+      _chars[0] = 0;
+    }
+    _capacity = realCapacity;
+  }
+
+  void GrowLength(int n)
+  {
+    int freeSize = _capacity - _length - 1;
+    if (n <= freeSize) 
+      return;
+    int delta;
+    if (_capacity > 64)
+      delta = _capacity / 2;
+    else if (_capacity > 8)
+      delta = 16;
+    else
+      delta = 4;
+    if (freeSize + delta < n)
+      delta = n - freeSize;
+    SetCapacity(_capacity + delta);
+  }
+
+  void CorrectIndex(int &index) const
+  {
+    if (index > _length)
+      index = _length;
+  }
+
+public:
+  CStringBase(): _chars(0), _length(0), _capacity(0)
+    { SetCapacity(16 - 1); }
+  CStringBase(T c):  _chars(0), _length(0), _capacity(0)
+  {
+    SetCapacity(1);
+    _chars[0] = c;
+    _chars[1] = 0;
+    _length = 1;
+  }
+  CStringBase(const T *chars): _chars(0), _length(0), _capacity(0)
+  {
+    int length = MyStringLen(chars);
+    SetCapacity(length);
+    MyStringCopy(_chars, chars); // can be optimized by memove()
+    _length = length;
+  }
+  CStringBase(const CStringBase &s):  _chars(0), _length(0), _capacity(0)
+  {
+    SetCapacity(s._length);
+    MyStringCopy(_chars, s._chars);
+    _length = s._length;
+  }
+  ~CStringBase() {  delete []_chars; }
+
+  operator const T*() const { return _chars;} 
+
+  // The minimum size of the character buffer in characters. 
+  // This value does not include space for a null terminator.
+  T* GetBuffer(int minBufLength)
+  {
+    if(minBufLength >= _capacity)
+      SetCapacity(minBufLength + 1);
+    return _chars;
+  }
+  void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
+  void ReleaseBuffer(int newLength)
+  {
+    /*
+    #ifndef _WIN32_WCE
+    if(newLength >= _capacity)
+      throw 282217;
+    #endif
+    */
+    _chars[newLength] = 0;
+    _length = newLength;
+  }
+
+  CStringBase& operator=(T c)
+  {
+    Empty();
+    SetCapacity(1);
+    _chars[0] = c;
+    _chars[1] = 0;
+    _length = 1;
+    return *this;
+  }
+  CStringBase& operator=(const T *chars)
+  {
+    Empty();
+    int length = MyStringLen(chars);
+    SetCapacity(length);
+    MyStringCopy(_chars, chars);
+    _length = length; 
+    return *this;
+  }  
+  CStringBase& operator=(const CStringBase& s)
+  {
+    if(&s == this)
+      return *this;
+    Empty();
+    SetCapacity(s._length);
+    MyStringCopy(_chars, s._chars);
+    _length = s._length;
+    return *this;
+  }
+  
+  CStringBase& operator+=(T c)
+  {
+    GrowLength(1);
+    _chars[_length] = c;
+    _chars[++_length] = 0;
+    return *this;
+  }
+  CStringBase& operator+=(const T *s)
+  {
+    int len = MyStringLen(s);
+    GrowLength(len);
+    MyStringCopy(_chars + _length, s);
+    _length += len;
+    return *this;
+  }
+  CStringBase& operator+=(const CStringBase &s)
+  {
+    GrowLength(s._length);
+    MyStringCopy(_chars + _length, s._chars);
+    _length += s._length;
+    return *this;
+  }
+  void Empty()
+  {
+    _length = 0;
+    _chars[0] = 0;
+  }
+  int Length() const { return _length; }
+  bool IsEmpty() const { return (_length == 0); }
+
+  CStringBase Mid(int startIndex) const
+    { return Mid(startIndex, _length - startIndex); }
+  CStringBase Mid(int startIndex, int count ) const
+  {
+    if (startIndex + count > _length)
+      count = _length - startIndex;
+    
+    if (startIndex == 0 && startIndex + count == _length)
+      return *this;
+    
+    CStringBase<T> result;
+    result.SetCapacity(count);
+    // MyStringNCopy(result._chars, _chars + startIndex, count);
+    for (int i = 0; i < count; i++)
+      result._chars[i] = _chars[startIndex + i];
+    result._chars[count] = 0;
+    result._length = count;
+    return result;
+  }
+  CStringBase Left(int count) const
+    { return Mid(0, count); }
+  CStringBase Right(int count) const
+  {
+    if (count > _length)
+      count = _length;
+    return Mid(_length - count, count);
+  }
+
+  void MakeUpper()
+    { MyStringUpper(_chars); }
+  void MakeLower()
+    { MyStringLower(_chars); }
+
+  int Compare(const CStringBase& s) const
+    { return MyStringCompare(_chars, s._chars); }
+
+  int Compare(const T *s) const
+    { return MyStringCompare(_chars, s); }
+
+  int CompareNoCase(const CStringBase& s) const
+    { return MyStringCompareNoCase(_chars, s._chars); }
+
+  int CompareNoCase(const T *s) const
+    { return MyStringCompareNoCase(_chars, s); }
+
+  /*
+  int Collate(const CStringBase& s) const
+    { return MyStringCollate(_chars, s._chars); }
+  int CollateNoCase(const CStringBase& s) const
+    { return MyStringCollateNoCase(_chars, s._chars); }
+  */
+
+  int Find(T c) const { return Find(c, 0); }
+  int Find(T c, int startIndex) const
+  {
+    T *p = _chars + startIndex;
+    for (;;)
+    {
+      if (*p == c)
+        return (int)(p - _chars);
+      if (*p == 0)
+        return -1;
+      p = GetNextCharPointer(p);
+    }
+  }
+  int Find(const CStringBase &s) const { return Find(s, 0); }
+  int Find(const CStringBase &s, int startIndex) const
+  {
+    if (s.IsEmpty())
+      return startIndex;
+    for (; startIndex < _length; startIndex++)
+    {
+      int j;
+      for (j = 0; j < s._length && startIndex + j < _length; j++)
+        if (_chars[startIndex+j] != s._chars[j])
+          break;
+      if (j == s._length)
+        return startIndex;
+    }
+    return -1;
+  }
+  int ReverseFind(T c) const
+  {
+    if (_length == 0)
+      return -1;
+    T *p = _chars + _length - 1;
+    for (;;)
+    {
+      if (*p == c)
+        return (int)(p - _chars);
+      if (p == _chars)
+        return -1;
+      p = GetPrevCharPointer(_chars, p);
+    }
+  }
+  int FindOneOf(const CStringBase &s) const
+  {
+    for(int i = 0; i < _length; i++)
+      if (s.Find(_chars[i]) >= 0)
+        return i;
+      return -1;
+  }
+
+  void TrimLeft(T c)
+  {
+    const T *p = _chars;
+    while (c == *p)
+      p = GetNextCharPointer(p);
+    Delete(0, p - _chars);
+  }
+  private:
+  CStringBase GetTrimDefaultCharSet()
+  {
+    CStringBase<T> charSet;
+    charSet += (T)' ';
+    charSet += (T)'\n';
+    charSet += (T)'\t';
+    return charSet;
+  }
+  public:
+
+  void TrimLeft()
+  {
+    TrimLeftWithCharSet(GetTrimDefaultCharSet());
+  }
+  void TrimRight()
+  {
+    TrimRightWithCharSet(GetTrimDefaultCharSet());
+  }
+  void TrimRight(T c)
+  {
+    const T *p = _chars;
+    const T *pLast = NULL;
+    while (*p != 0)
+    {
+      if (*p == c)
+      {
+        if (pLast == NULL)
+          pLast = p;
+      }
+      else
+        pLast = NULL;
+      p = GetNextCharPointer(p);
+    }
+    if(pLast != NULL)
+    {
+      int i = pLast - _chars;
+      Delete(i, _length - i);
+    }
+  }
+  void Trim()
+  {
+    TrimRight();
+    TrimLeft();
+  }
+
+  int Insert(int index, T c)
+  {
+    InsertSpace(index, 1);
+    _chars[index] = c;
+    _length++;
+    return _length;
+  }
+  int Insert(int index, const CStringBase &s)
+  {
+    CorrectIndex(index);
+    if (s.IsEmpty())
+      return _length;
+    int numInsertChars = s.Length();
+    InsertSpace(index, numInsertChars);
+    for(int i = 0; i < numInsertChars; i++)
+      _chars[index + i] = s[i];
+    _length += numInsertChars;
+    return _length;
+  }
+
+  // !!!!!!!!!!!!!!! test it if newChar = '\0'
+  int Replace(T oldChar, T newChar)
+  {
+    if (oldChar == newChar)
+      return 0;
+    int number  = 0;
+    int pos  = 0;
+    while (pos < Length())
+    {
+      pos = Find(oldChar, pos);
+      if (pos < 0) 
+        break;
+      _chars[pos] = newChar;
+      pos++;
+      number++;
+    }
+    return number;
+  }
+  int Replace(const CStringBase &oldString, const CStringBase &newString)
+  {
+    if (oldString.IsEmpty())
+      return 0;
+    if (oldString == newString)
+      return 0;
+    int oldStringLength = oldString.Length();
+    int newStringLength = newString.Length();
+    int number  = 0;
+    int pos  = 0;
+    while (pos < _length)
+    {
+      pos = Find(oldString, pos);
+      if (pos < 0) 
+        break;
+      Delete(pos, oldStringLength);
+      Insert(pos, newString);
+      pos += newStringLength;
+      number++;
+    }
+    return number;
+  }
+  int Delete(int index, int count = 1 )
+  {
+    if (index + count > _length)
+      count = _length - index;
+    if (count > 0)
+    {
+      MoveItems(index, index + count);
+      _length -= count;
+    }
+    return _length;
+  }
+};
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s1, const CStringBase<T>& s2)
+{
+  CStringBase<T> result(s1);
+  result += s2;
+  return result; 
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, T c)
+{
+  CStringBase<T> result(s);
+  result += c;
+  return result; 
+}
+
+template <class T>
+CStringBase<T> operator+(T c, const CStringBase<T>& s)
+{
+  CStringBase<T> result(c);
+  result += s;
+  return result; 
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, const T * chars)
+{
+  CStringBase<T> result(s);
+  result += chars;
+  return result; 
+}
+
+template <class T>
+CStringBase<T> operator+(const T * chars, const CStringBase<T>& s)
+{
+  CStringBase<T> result(chars);
+  result += s;
+  return result; 
+}
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const CStringBase<T>& s2)
+  { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator<(const CStringBase<T>& s1, const CStringBase<T>& s2)
+  { return (s1.Compare(s2) < 0); }
+
+template <class T>
+bool operator==(const T *s1, const CStringBase<T>& s2)
+  { return (s2.Compare(s1) == 0); }
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const T *s2)
+  { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const CStringBase<T>& s2)
+  { return (s1.Compare(s2) != 0); }
+
+template <class T>
+bool operator!=(const T *s1, const CStringBase<T>& s2)
+  { return (s2.Compare(s1) != 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const T *s2)
+  { return (s1.Compare(s2) != 0); }
+
+typedef CStringBase<char> AString;
+typedef CStringBase<wchar_t> UString;
+
+typedef CObjectVector<AString> AStringVector;
+typedef CObjectVector<UString> UStringVector;
+
+#ifdef _UNICODE
+  typedef UString CSysString;
+#else
+  typedef AString CSysString;
+#endif
+
+typedef CObjectVector<CSysString> CSysStringVector;
+
+#endif
diff --git a/lzma/CPP/Common/MyUnknown.h b/lzma/CPP/Common/MyUnknown.h
new file mode 100644 (file)
index 0000000..d28d854
--- /dev/null
@@ -0,0 +1,24 @@
+// MyUnknown.h
+
+#ifndef __MYUNKNOWN_H
+#define __MYUNKNOWN_H
+
+#ifdef _WIN32
+
+#ifdef _WIN32_WCE
+#if (_WIN32_WCE > 300)
+#include <basetyps.h>
+#else
+#define MIDL_INTERFACE(x) struct 
+#endif
+#else
+#include <basetyps.h>
+#endif
+
+#include <unknwn.h>
+
+#else 
+#include "MyWindows.h"
+#endif
+  
+#endif
diff --git a/lzma/CPP/Common/MyVector.cpp b/lzma/CPP/Common/MyVector.cpp
new file mode 100644 (file)
index 0000000..def2a58
--- /dev/null
@@ -0,0 +1,78 @@
+// Common/MyVector.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "MyVector.h"
+
+CBaseRecordVector::~CBaseRecordVector() { Free(); }
+
+void CBaseRecordVector::Free()
+{ 
+  delete []((unsigned char *)_items); 
+  _capacity = 0;
+  _size = 0;
+  _items = 0;
+}
+
+void CBaseRecordVector::Clear() { DeleteFrom(0); }
+void CBaseRecordVector::DeleteBack() { Delete(_size - 1); }
+void CBaseRecordVector::DeleteFrom(int index) { Delete(index, _size - index); }
+
+void CBaseRecordVector::ReserveOnePosition()
+{
+  if (_size != _capacity)
+    return;
+  int delta;
+  if (_capacity > 64)
+    delta = _capacity / 2;
+  else if (_capacity > 8)
+    delta = 8;
+  else
+    delta = 4;
+  Reserve(_capacity + delta);
+}
+
+void CBaseRecordVector::Reserve(int newCapacity)
+{
+  if (newCapacity <= _capacity)
+    return;
+  if ((unsigned)newCapacity >= ((unsigned)1 << (sizeof(unsigned) * 8 - 1)))
+    throw 1052353;
+  size_t newSize = (size_t)(unsigned)newCapacity * _itemSize;
+  if (newSize / _itemSize != (size_t)(unsigned)newCapacity)
+    throw 1052354;
+  unsigned char *p = new unsigned char[newSize];
+  if (p == 0)
+    throw 1052355;
+  int numRecordsToMove = _capacity;
+  memmove(p, _items, _itemSize * numRecordsToMove);
+  delete [](unsigned char *)_items;
+  _items = p;
+  _capacity = newCapacity;
+}
+
+void CBaseRecordVector::MoveItems(int destIndex, int srcIndex)
+{
+  memmove(((unsigned char *)_items) + destIndex * _itemSize, 
+    ((unsigned char  *)_items) + srcIndex * _itemSize, 
+    _itemSize * (_size - srcIndex));
+}
+
+void CBaseRecordVector::InsertOneItem(int index)
+{
+  ReserveOnePosition();
+  MoveItems(index + 1, index);
+  _size++;
+}
+
+void CBaseRecordVector::Delete(int index, int num)
+{
+  TestIndexAndCorrectNum(index, num);
+  if (num > 0)
+  {
+    MoveItems(index, index + num);
+    _size -= num;
+  }
+}
diff --git a/lzma/CPP/Common/MyVector.h b/lzma/CPP/Common/MyVector.h
new file mode 100644 (file)
index 0000000..ce370a5
--- /dev/null
@@ -0,0 +1,254 @@
+// Common/Vector.h
+
+#ifndef __COMMON_VECTOR_H
+#define __COMMON_VECTOR_H
+
+#include "Defs.h"
+
+class CBaseRecordVector
+{
+  void MoveItems(int destIndex, int srcIndex);
+protected:
+  int _capacity;
+  int _size;
+  void *_items;
+  size_t _itemSize;
+  
+  void ReserveOnePosition();
+  void InsertOneItem(int index);
+  void TestIndexAndCorrectNum(int index, int &num) const
+    { if (index + num > _size) num = _size - index; } 
+public:
+  CBaseRecordVector(size_t itemSize):
+      _capacity(0), _size(0), _items(0), _itemSize(itemSize) {}
+  virtual ~CBaseRecordVector();
+  void Free();
+  int Size() const { return _size; }
+  bool IsEmpty() const { return (_size == 0); }
+  void Reserve(int newCapacity);
+  virtual void Delete(int index, int num = 1);
+  void Clear();
+  void DeleteFrom(int index);
+  void DeleteBack();
+};
+
+template <class T>
+class CRecordVector: public CBaseRecordVector
+{
+public:
+  CRecordVector():CBaseRecordVector(sizeof(T)){};
+  CRecordVector(const CRecordVector &v):
+    CBaseRecordVector(sizeof(T)) { *this = v;}
+  CRecordVector& operator=(const CRecordVector &v)
+  {
+    Clear();
+    return (*this += v);
+  }
+  CRecordVector& operator+=(const CRecordVector &v)
+  {
+    int size = v.Size();
+    Reserve(Size() + size);
+    for(int i = 0; i < size; i++)
+      Add(v[i]);
+    return *this;
+  }
+  int Add(T item)
+  {
+    ReserveOnePosition();
+    ((T *)_items)[_size] = item;
+    return _size++;
+  }
+  void Insert(int index, T item)
+  {
+    InsertOneItem(index);
+    ((T *)_items)[index] = item;
+  }
+  // T* GetPointer() const { return (T*)_items; }
+  // operator const T *() const { return _items; };
+  const T& operator[](int index) const { return ((T *)_items)[index]; }
+  T& operator[](int index) { return ((T *)_items)[index]; }
+  const T& Front() const { return operator[](0); }
+  T& Front()   { return operator[](0); }
+  const T& Back() const { return operator[](_size - 1); }
+  T& Back()   { return operator[](_size - 1); }
+
+  void Swap(int i, int j)
+  {
+    T temp = operator[](i);
+    operator[](i) = operator[](j);
+    operator[](j) = temp;
+  }
+
+  int FindInSorted(const T& item) const
+  {
+    int left = 0, right = Size(); 
+    while (left != right)
+    {
+      int mid = (left + right) / 2;
+      const T& midValue = (*this)[mid];
+      if (item == midValue)
+        return mid;
+      if (item < midValue)
+        right = mid;
+      else
+        left = mid + 1;
+    }
+    return -1;
+  }
+
+  int AddToUniqueSorted(const T& item)
+  {
+    int left = 0, right = Size(); 
+    while (left != right)
+    {
+      int mid = (left + right) / 2;
+      const T& midValue = (*this)[mid];
+      if (item == midValue)
+        return mid;
+      if (item < midValue)
+        right = mid;
+      else
+        left = mid + 1;
+    }
+    Insert(right, item);
+    return right;
+  }
+
+  static void SortRefDown(T* p, int k, int size, int (*compare)(const T*, const T*, void *), void *param)
+  { 
+    T temp = p[k];
+    for (;;)
+    {
+      int s = (k << 1);
+      if (s > size)
+        break;
+      if (s < size && compare(p + s + 1, p + s, param) > 0)
+        s++;
+      if (compare(&temp, p + s, param) >= 0)
+        break;
+      p[k] = p[s]; 
+      k = s;
+    } 
+    p[k] = temp; 
+  }
+
+  void Sort(int (*compare)(const T*, const T*, void *), void *param)
+  {
+    int size = _size;
+    if (size <= 1)
+      return;
+    T* p = (&Front()) - 1;
+    {
+      int i = size / 2;
+      do
+        SortRefDown(p, i, size, compare, param);
+      while(--i != 0);
+    }
+    do
+    {
+      T temp = p[size];
+      p[size--] = p[1];
+      p[1] = temp;
+      SortRefDown(p, 1, size, compare, param);
+    }
+    while (size > 1);
+  }
+};
+
+typedef CRecordVector<int> CIntVector;
+typedef CRecordVector<unsigned int> CUIntVector;
+typedef CRecordVector<bool> CBoolVector;
+typedef CRecordVector<unsigned char> CByteVector;
+typedef CRecordVector<void *> CPointerVector;
+
+template <class T>
+class CObjectVector: public CPointerVector
+{
+public:
+  CObjectVector(){};
+  ~CObjectVector() { Clear(); }
+  CObjectVector(const CObjectVector &objectVector)
+    { *this = objectVector; }
+  CObjectVector& operator=(const CObjectVector &objectVector)
+  {
+    Clear();
+    return (*this += objectVector);
+  }
+  CObjectVector& operator+=(const CObjectVector &objectVector)
+  {
+    int size = objectVector.Size();
+    Reserve(Size() + size);
+    for(int i = 0; i < size; i++)
+      Add(objectVector[i]);
+    return *this;
+  }
+  const T& operator[](int index) const { return *((T *)CPointerVector::operator[](index)); }
+  T& operator[](int index) { return *((T *)CPointerVector::operator[](index)); }
+  T& Front() { return operator[](0); }
+  const T& Front() const { return operator[](0); }
+  T& Back() { return operator[](_size - 1); }
+  const T& Back() const { return operator[](_size - 1); }
+  int Add(const T& item)
+    { return CPointerVector::Add(new T(item)); }
+  void Insert(int index, const T& item)
+    { CPointerVector::Insert(index, new T(item)); }
+  virtual void Delete(int index, int num = 1)
+  {
+    TestIndexAndCorrectNum(index, num);
+    for(int i = 0; i < num; i++)
+      delete (T *)(((void **)_items)[index + i]);
+    CPointerVector::Delete(index, num);
+  }
+  int Find(const T& item) const
+  {
+    for(int i = 0; i < Size(); i++)
+      if (item == (*this)[i])
+        return i;
+      return -1;
+  }
+  int FindInSorted(const T& item) const
+  {
+    int left = 0, right = Size(); 
+    while (left != right)
+    {
+      int mid = (left + right) / 2;
+      const T& midValue = (*this)[mid];
+      if (item == midValue)
+        return mid;
+      if (item < midValue)
+        right = mid;
+      else
+        left = mid + 1;
+    }
+    return -1;
+  }
+  int AddToSorted(const T& item)
+  {
+    int left = 0, right = Size(); 
+    while (left != right)
+    {
+      int mid = (left + right) / 2;
+      const T& midValue = (*this)[mid];
+      if (item == midValue)
+      {
+        right = mid + 1;
+        break;
+      }
+      if (item < midValue)
+        right = mid;
+      else
+        left = mid + 1;
+    }
+    Insert(right, item);
+    return right;
+  }
+
+  void Sort(int (*compare)(void *const *, void *const *, void *), void *param) 
+    { CPointerVector::Sort(compare, param); }
+
+  static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */)
+    { return MyCompare(*(*((const T **)a1)), *(*((const T **)a2))); }
+  void Sort() { CPointerVector::Sort(CompareObjectItems, 0); }
+};
+
+#endif 
diff --git a/lzma/CPP/Common/MyWindows.h b/lzma/CPP/Common/MyWindows.h
new file mode 100644 (file)
index 0000000..e388fb0
--- /dev/null
@@ -0,0 +1,214 @@
+// MyWindows.h
+
+#ifndef __MYWINDOWS_H
+#define __MYWINDOWS_H
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#include <stddef.h> // for wchar_t
+#include <string.h>
+
+#include "MyGuidDef.h"
+
+typedef char CHAR;
+typedef unsigned char UCHAR;
+
+#undef BYTE
+typedef unsigned char BYTE;
+
+typedef short SHORT;
+typedef unsigned short USHORT;
+
+#undef WORD
+typedef unsigned short WORD;
+typedef short VARIANT_BOOL;
+
+typedef int INT;
+typedef Int32 INT32;
+typedef unsigned int UINT;
+typedef UInt32 UINT32;
+typedef INT32 LONG;   // LONG, ULONG and DWORD must be 32-bit
+typedef UINT32 ULONG;
+
+#undef DWORD
+typedef UINT32 DWORD;
+
+typedef Int64 LONGLONG;
+typedef UInt64 ULONGLONG;
+
+typedef struct LARGE_INTEGER { LONGLONG QuadPart; }LARGE_INTEGER;
+typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER;
+
+typedef const CHAR *LPCSTR;
+typedef CHAR TCHAR;
+typedef const TCHAR *LPCTSTR;
+typedef wchar_t WCHAR;
+typedef WCHAR OLECHAR;
+typedef const WCHAR *LPCWSTR;
+typedef OLECHAR *BSTR;
+typedef const OLECHAR *LPCOLESTR;
+typedef OLECHAR *LPOLESTR;
+
+typedef struct _FILETIME
+{
+  DWORD dwLowDateTime;
+  DWORD dwHighDateTime;
+}FILETIME;
+
+#define HRESULT LONG
+#define FAILED(Status) ((HRESULT)(Status)<0)
+typedef ULONG PROPID;
+typedef LONG SCODE;
+
+#define S_OK    ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_NOTIMPL ((HRESULT)0x80004001L)
+#define E_NOINTERFACE ((HRESULT)0x80004002L)
+#define E_ABORT ((HRESULT)0x80004004L)
+#define E_FAIL ((HRESULT)0x80004005L)
+#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+
+#ifdef _MSC_VER
+#define STDMETHODCALLTYPE __stdcall 
+#else
+#define STDMETHODCALLTYPE 
+#endif
+
+#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f
+#define STDMETHOD(f) STDMETHOD_(HRESULT, f)
+#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
+#define STDMETHODIMP STDMETHODIMP_(HRESULT)
+
+#define PURE = 0
+
+#define MIDL_INTERFACE(x) struct 
+
+#ifdef __cplusplus
+
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+struct IUnknown
+{
+  STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;
+  STDMETHOD_(ULONG, AddRef)() PURE;
+  STDMETHOD_(ULONG, Release)() PURE;
+  #ifndef _WIN32
+  virtual ~IUnknown() {}
+  #endif
+};
+
+typedef IUnknown *LPUNKNOWN;
+
+#endif
+
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#define VARIANT_FALSE ((VARIANT_BOOL)0)
+
+enum VARENUM
+{
+  VT_EMPTY = 0,
+  VT_NULL = 1,
+  VT_I2 = 2,
+  VT_I4 = 3,
+  VT_R4 = 4,
+  VT_R8 = 5,
+  VT_CY = 6,
+  VT_DATE = 7,
+  VT_BSTR = 8,
+  VT_DISPATCH = 9,
+  VT_ERROR = 10,
+  VT_BOOL = 11,
+  VT_VARIANT = 12,
+  VT_UNKNOWN = 13,
+  VT_DECIMAL = 14,
+  VT_I1 = 16,
+  VT_UI1 = 17,
+  VT_UI2 = 18,
+  VT_UI4 = 19,
+  VT_I8 = 20,
+  VT_UI8 = 21,
+  VT_INT = 22,
+  VT_UINT = 23,
+  VT_VOID = 24,
+  VT_HRESULT = 25,
+  VT_FILETIME = 64
+};
+
+typedef unsigned short VARTYPE;
+typedef WORD PROPVAR_PAD1;
+typedef WORD PROPVAR_PAD2;
+typedef WORD PROPVAR_PAD3;
+
+#ifdef __cplusplus
+
+typedef struct tagPROPVARIANT
+{
+  VARTYPE vt;
+  PROPVAR_PAD1 wReserved1;
+  PROPVAR_PAD2 wReserved2;
+  PROPVAR_PAD3 wReserved3;
+  union 
+  {
+    CHAR cVal;
+    UCHAR bVal;
+    SHORT iVal;
+    USHORT uiVal;
+    LONG lVal;
+    ULONG ulVal;
+    INT intVal;
+    UINT uintVal;
+    LARGE_INTEGER hVal;
+    ULARGE_INTEGER uhVal;
+    VARIANT_BOOL boolVal;
+    SCODE scode;
+    FILETIME filetime;
+    BSTR bstrVal;
+  };
+} PROPVARIANT;
+
+typedef PROPVARIANT tagVARIANT;
+typedef tagVARIANT VARIANT;
+typedef VARIANT VARIANTARG;
+
+MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop);
+MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src);
+
+#endif
+
+MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
+MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz);
+MY_EXTERN_C void SysFreeString(BSTR bstr);
+MY_EXTERN_C UINT SysStringByteLen(BSTR bstr);
+MY_EXTERN_C UINT SysStringLen(BSTR bstr);
+
+MY_EXTERN_C DWORD GetLastError();
+MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);
+
+#define CP_ACP    0
+#define CP_OEMCP  1
+
+typedef enum tagSTREAM_SEEK
+{
+  STREAM_SEEK_SET = 0,
+  STREAM_SEEK_CUR = 1,
+  STREAM_SEEK_END = 2
+} STREAM_SEEK;
+
+#endif
+#endif
diff --git a/lzma/CPP/Common/NewHandler.cpp b/lzma/CPP/Common/NewHandler.cpp
new file mode 100644 (file)
index 0000000..094eb64
--- /dev/null
@@ -0,0 +1,116 @@
+// NewHandler.cpp
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "NewHandler.h"
+
+// #define DEBUG_MEMORY_LEAK
+
+#ifndef DEBUG_MEMORY_LEAK
+
+#ifdef _WIN32
+void * 
+#ifdef _MSC_VER
+__cdecl 
+#endif
+operator new(size_t size)
+{
+  // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
+  void *p = ::malloc(size);
+  if (p == 0)
+    throw CNewException();
+  return p;
+}
+
+void 
+#ifdef _MSC_VER
+__cdecl 
+#endif
+operator delete(void *p) throw()
+{
+  /*
+  if (p == 0)
+    return;
+  ::HeapFree(::GetProcessHeap(), 0, p);
+  */
+  ::free(p);
+}
+#endif
+
+#else
+
+#pragma init_seg(lib)
+const int kDebugSize = 1000000;
+static void *a[kDebugSize];
+static int index = 0;
+
+static int numAllocs = 0;
+void * __cdecl operator new(size_t size)
+{
+  numAllocs++;
+  void *p = HeapAlloc(GetProcessHeap(), 0, size);
+  if (index == 40)
+  {
+    int t = 1;
+  }
+  if (index < kDebugSize)
+  {
+    a[index] = p;
+    index++;
+  }
+  if (p == 0)
+    throw CNewException();
+  printf("Alloc %6d, size = %8d\n", numAllocs, size);
+  return p;
+}
+
+class CC
+{
+public:
+  CC()
+  {
+    for (int i = 0; i < kDebugSize; i++)
+      a[i] = 0;
+  }
+  ~CC()
+  {
+    for (int i = 0; i < kDebugSize; i++)
+      if (a[i] != 0)
+        return;
+  }
+} g_CC;
+
+
+void __cdecl operator delete(void *p)
+{
+  if (p == 0)
+    return;
+  /*
+  for (int i = 0; i < index; i++)
+    if (a[i] == p)
+      a[i] = 0;
+  */
+  HeapFree(GetProcessHeap(), 0, p);
+  numAllocs--;
+  printf("Free %d\n", numAllocs);
+}
+
+#endif
+
+/*
+int MemErrorVC(size_t)
+{
+  throw CNewException();
+  // return 1;
+}
+CNewHandlerSetter::CNewHandlerSetter()
+{
+  // MemErrorOldVCFunction = _set_new_handler(MemErrorVC);
+}
+CNewHandlerSetter::~CNewHandlerSetter()
+{
+  // _set_new_handler(MemErrorOldVCFunction);
+}
+*/
diff --git a/lzma/CPP/Common/NewHandler.h b/lzma/CPP/Common/NewHandler.h
new file mode 100644 (file)
index 0000000..0619fc6
--- /dev/null
@@ -0,0 +1,16 @@
+// Common/NewHandler.h
+
+#ifndef __COMMON_NEWHANDLER_H
+#define __COMMON_NEWHANDLER_H
+
+class CNewException {};
+
+#ifdef _WIN32
+void 
+#ifdef _MSC_VER
+__cdecl 
+#endif
+operator delete(void *p) throw();
+#endif 
+
+#endif 
diff --git a/lzma/CPP/Common/StdAfx.h b/lzma/CPP/Common/StdAfx.h
new file mode 100644 (file)
index 0000000..681ee93
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+// #include "MyWindows.h"
+#include "NewHandler.h"
+
+#endif 
diff --git a/lzma/CPP/Common/StdInStream.cpp b/lzma/CPP/Common/StdInStream.cpp
new file mode 100644 (file)
index 0000000..8fed7bc
--- /dev/null
@@ -0,0 +1,84 @@
+// Common/StdInStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+#include "StdInStream.h"
+
+#ifdef _MSC_VER
+// "was declared deprecated" disabling
+#pragma warning(disable : 4996 )
+#endif
+
+static const char kIllegalChar = '\0';
+static const char kNewLineChar = '\n';
+
+static const char *kEOFMessage = "Unexpected end of input stream";
+static const char *kReadErrorMessage  ="Error reading input stream"; 
+static const char *kIllegalCharMessage = "Illegal character in input stream";
+
+static LPCTSTR kFileOpenMode = TEXT("r");
+
+CStdInStream g_StdIn(stdin);
+
+bool CStdInStream::Open(LPCTSTR fileName)
+{
+  Close();
+  _stream = _tfopen(fileName, kFileOpenMode);
+  _streamIsOpen = (_stream != 0);
+  return _streamIsOpen;
+}
+
+bool CStdInStream::Close()
+{
+  if(!_streamIsOpen)
+    return true;
+  _streamIsOpen = (fclose(_stream) != 0);
+  return !_streamIsOpen;
+}
+
+CStdInStream::~CStdInStream()
+{
+  Close();
+}
+
+AString CStdInStream::ScanStringUntilNewLine()
+{
+  AString s;
+  for (;;)
+  {
+    int intChar = GetChar();
+    if(intChar == EOF)
+      throw kEOFMessage;
+    char c = char(intChar);
+    if (c == kIllegalChar)
+      throw kIllegalCharMessage;
+    if(c == kNewLineChar)
+      break;
+    s += c;
+  }
+  return s;
+}
+
+void CStdInStream::ReadToString(AString &resultString)
+{
+  resultString.Empty();
+  int c;
+  while((c = GetChar()) != EOF)
+    resultString += char(c);
+}
+
+bool CStdInStream::Eof()
+{
+  return (feof(_stream) != 0);
+}
+
+int CStdInStream::GetChar()
+{
+  int c = fgetc(_stream); // getc() doesn't work in BeOS?
+  if(c == EOF && !Eof())
+    throw kReadErrorMessage;
+  return c;
+}
+
+
diff --git a/lzma/CPP/Common/StdInStream.h b/lzma/CPP/Common/StdInStream.h
new file mode 100644 (file)
index 0000000..e0fb3df
--- /dev/null
@@ -0,0 +1,31 @@
+// Common/StdInStream.h
+
+#ifndef __COMMON_STDINSTREAM_H
+#define __COMMON_STDINSTREAM_H
+
+#include <stdio.h>
+
+#include "MyString.h"
+#include "Types.h"
+
+class CStdInStream 
+{
+  bool _streamIsOpen;
+  FILE *_stream;
+public:
+  CStdInStream(): _streamIsOpen(false) {};
+  CStdInStream(FILE *stream): _streamIsOpen(false), _stream(stream) {};
+  ~CStdInStream();
+  bool Open(LPCTSTR fileName);
+  bool Close();
+
+  AString ScanStringUntilNewLine();
+  void ReadToString(AString &resultString);
+
+  bool Eof();
+  int GetChar();
+};
+
+extern CStdInStream g_StdIn;
+
+#endif
diff --git a/lzma/CPP/Common/StdOutStream.cpp b/lzma/CPP/Common/StdOutStream.cpp
new file mode 100644 (file)
index 0000000..5498c0c
--- /dev/null
@@ -0,0 +1,93 @@
+// Common/StdOutStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+
+#include "StdOutStream.h"
+#include "IntToString.h"
+#include "StringConvert.h"
+
+#ifdef _MSC_VER
+// "was declared deprecated" disabling
+#pragma warning(disable : 4996 )
+#endif
+
+static const char kNewLineChar =  '\n';
+
+static const char *kFileOpenMode = "wt";
+
+CStdOutStream  g_StdOut(stdout);
+CStdOutStream  g_StdErr(stderr);
+
+bool CStdOutStream::Open(const char *fileName)
+{
+  Close();
+  _stream = fopen(fileName, kFileOpenMode);
+  _streamIsOpen = (_stream != 0);
+  return _streamIsOpen;
+}
+
+bool CStdOutStream::Close()
+{
+  if(!_streamIsOpen)
+    return true;
+  if (fclose(_stream) != 0)
+    return false;
+  _stream = 0;
+  _streamIsOpen = false;
+  return true;
+}
+
+bool CStdOutStream::Flush()
+{
+  return (fflush(_stream) == 0);
+}
+
+CStdOutStream::~CStdOutStream ()
+{
+  Close();
+}
+
+CStdOutStream & CStdOutStream::operator<<(CStdOutStream & (*aFunction)(CStdOutStream  &))
+{
+  (*aFunction)(*this);    
+  return *this;
+}
+
+CStdOutStream & endl(CStdOutStream & outStream)
+{
+  return outStream << kNewLineChar;
+}
+
+CStdOutStream & CStdOutStream::operator<<(const char *string)
+{
+  fputs(string, _stream);
+  return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(const wchar_t *string)
+{
+  *this << (const char *)UnicodeStringToMultiByte(string, CP_OEMCP);
+  return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(char c)
+{
+  fputc(c, _stream);
+  return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(int number)
+{
+  char textString[32];
+  ConvertInt64ToString(number, textString);
+  return operator<<(textString);
+}
+
+CStdOutStream & CStdOutStream::operator<<(UInt64 number)
+{
+  char textString[32];
+  ConvertUInt64ToString(number, textString);
+  return operator<<(textString);
+}
diff --git a/lzma/CPP/Common/StdOutStream.h b/lzma/CPP/Common/StdOutStream.h
new file mode 100644 (file)
index 0000000..8490736
--- /dev/null
@@ -0,0 +1,35 @@
+// Common/StdOutStream.h
+
+#ifndef __COMMON_STDOUTSTREAM_H
+#define __COMMON_STDOUTSTREAM_H
+
+#include <stdio.h>
+
+#include "Types.h"
+
+class CStdOutStream 
+{
+  bool _streamIsOpen;
+  FILE *_stream;
+public:
+  CStdOutStream (): _streamIsOpen(false), _stream(0) {};
+  CStdOutStream (FILE *stream): _streamIsOpen(false), _stream(stream) {};
+  ~CStdOutStream ();
+  operator FILE *() { return _stream; }
+  bool Open(const char *fileName);
+  bool Close();
+  bool Flush();
+  CStdOutStream & operator<<(CStdOutStream & (* aFunction)(CStdOutStream  &));
+  CStdOutStream & operator<<(const char *string);
+  CStdOutStream & operator<<(const wchar_t *string);
+  CStdOutStream & operator<<(char c);
+  CStdOutStream & operator<<(int number);
+  CStdOutStream & operator<<(UInt64 number);
+};
+
+CStdOutStream & endl(CStdOutStream & outStream);
+
+extern CStdOutStream g_StdOut;
+extern CStdOutStream g_StdErr;
+
+#endif
diff --git a/lzma/CPP/Common/StringConvert.cpp b/lzma/CPP/Common/StringConvert.cpp
new file mode 100644 (file)
index 0000000..c0b19e1
--- /dev/null
@@ -0,0 +1,94 @@
+// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+
+#include "StringConvert.h"
+
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#ifdef _WIN32
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+  UString resultString;
+  if(!srcString.IsEmpty())
+  {
+    int numChars = MultiByteToWideChar(codePage, 0, srcString, 
+      srcString.Length(), resultString.GetBuffer(srcString.Length()), 
+      srcString.Length() + 1);
+    #ifndef _WIN32_WCE
+    if(numChars == 0)
+      throw 282228;
+    #endif
+    resultString.ReleaseBuffer(numChars);
+  }
+  return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+  AString resultString;
+  if(!srcString.IsEmpty())
+  {
+    int numRequiredBytes = srcString.Length() * 2;
+    char defaultChar = '_';
+    int numChars = WideCharToMultiByte(codePage, 0, srcString, 
+      srcString.Length(), resultString.GetBuffer(numRequiredBytes), 
+      numRequiredBytes + 1, &defaultChar, NULL);
+    #ifndef _WIN32_WCE
+    if(numChars == 0)
+      throw 282229;
+    #endif
+    resultString.ReleaseBuffer(numChars);
+  }
+  return resultString;
+}
+
+#ifndef _WIN32_WCE
+AString SystemStringToOemString(const CSysString &srcString)
+{
+  AString result;
+  CharToOem(srcString, result.GetBuffer(srcString.Length() * 2));
+  result.ReleaseBuffer();
+  return result;
+}
+#endif
+
+#else
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+  UString resultString;
+  for (int i = 0; i < srcString.Length(); i++)
+    resultString += wchar_t(srcString[i]);
+  /*
+  if(!srcString.IsEmpty())
+  {
+    int numChars = mbstowcs(resultString.GetBuffer(srcString.Length()), srcString, srcString.Length() + 1);
+    if (numChars < 0) throw "Your environment does not support UNICODE";
+    resultString.ReleaseBuffer(numChars);
+  }
+  */
+  return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+  AString resultString;
+  for (int i = 0; i < srcString.Length(); i++)
+    resultString += char(srcString[i]);
+  /*
+  if(!srcString.IsEmpty())
+  {
+    int numRequiredBytes = srcString.Length() * 6 + 1;
+    int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes), srcString, numRequiredBytes);
+    if (numChars < 0) throw "Your environment does not support UNICODE";
+    resultString.ReleaseBuffer(numChars);
+  }
+  */
+  return resultString;
+}
+
+#endif
+
diff --git a/lzma/CPP/Common/StringConvert.h b/lzma/CPP/Common/StringConvert.h
new file mode 100644 (file)
index 0000000..32d8a3a
--- /dev/null
@@ -0,0 +1,71 @@
+// Common/StringConvert.h
+
+#ifndef __COMMON_STRINGCONVERT_H
+#define __COMMON_STRINGCONVERT_H
+
+#include "MyWindows.h"
+#include "MyString.h"
+#include "Types.h"
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP);
+
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString)
+  { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString)
+  { return unicodeString; }
+inline UString GetUnicodeString(const AString &ansiString)
+  { return MultiByteToUnicodeString(ansiString); }
+inline UString GetUnicodeString(const AString &multiByteString, UINT codePage)
+  { return MultiByteToUnicodeString(multiByteString, codePage); }
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT)
+  { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString, UINT)
+  { return unicodeString; }
+
+inline const char* GetAnsiString(const char* ansiString)
+  { return ansiString; }
+inline const AString& GetAnsiString(const AString &ansiString)
+  { return ansiString; }
+inline AString GetAnsiString(const UString &unicodeString)
+  { return UnicodeStringToMultiByte(unicodeString); }
+
+inline const char* GetOemString(const char* oemString)
+  { return oemString; }
+inline const AString& GetOemString(const AString &oemString)
+  { return oemString; }
+inline AString GetOemString(const UString &unicodeString)
+  { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); }
+
+
+#ifdef _UNICODE
+  inline const wchar_t* GetSystemString(const wchar_t* unicodeString)
+    { return unicodeString;}
+  inline const UString& GetSystemString(const UString &unicodeString)
+    { return unicodeString;}
+  inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT /* codePage */)
+    { return unicodeString;}
+  inline const UString& GetSystemString(const UString &unicodeString, UINT /* codePage */)
+    { return unicodeString;}
+  inline UString GetSystemString(const AString &multiByteString, UINT codePage)
+    { return MultiByteToUnicodeString(multiByteString, codePage);}
+  inline UString GetSystemString(const AString &multiByteString)
+    { return MultiByteToUnicodeString(multiByteString);}
+#else
+  inline const char* GetSystemString(const char *ansiString)
+    { return ansiString; }
+  inline const AString& GetSystemString(const AString &multiByteString, UINT)
+    { return multiByteString; }
+  inline const char * GetSystemString(const char *multiByteString, UINT)
+    { return multiByteString; }
+  inline AString GetSystemString(const UString &unicodeString)
+    { return UnicodeStringToMultiByte(unicodeString); }
+  inline AString GetSystemString(const UString &unicodeString, UINT codePage)
+    { return UnicodeStringToMultiByte(unicodeString, codePage); }
+#endif
+
+#ifndef _WIN32_WCE
+AString SystemStringToOemString(const CSysString &srcString);
+#endif
+
+#endif
diff --git a/lzma/CPP/Common/StringToInt.cpp b/lzma/CPP/Common/StringToInt.cpp
new file mode 100644 (file)
index 0000000..ec6733e
--- /dev/null
@@ -0,0 +1,68 @@
+// Common/StringToInt.cpp
+
+#include "StdAfx.h"
+
+#include "StringToInt.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end)
+{
+  UInt64 result = 0;
+  for (;;)
+  {
+    char c = *s;
+    if (c < '0' || c > '9')
+    {
+      if (end != NULL)
+        *end = s;
+      return result;
+    }
+    result *= 10;
+    result += (c - '0');
+    s++;
+  }
+}
+
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end)
+{
+  UInt64 result = 0;
+  for (;;)
+  {
+    char c = *s;
+    if (c < '0' || c > '7')
+    {
+      if (end != NULL)
+        *end = s;
+      return result;
+    }
+    result <<= 3;
+    result += (c - '0');
+    s++;
+  }
+}
+
+
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end)
+{
+  UInt64 result = 0;
+  for (;;)
+  {
+    wchar_t c = *s;
+    if (c < '0' || c > '9')
+    {
+      if (end != NULL)
+        *end = s;
+      return result;
+    }
+    result *= 10;
+    result += (c - '0');
+    s++;
+  }
+}
+
+
+Int64 ConvertStringToInt64(const char *s, const char **end)
+{
+  if (*s == '-')
+    return -(Int64)ConvertStringToUInt64(s + 1, end);
+  return ConvertStringToUInt64(s, end);
+}
diff --git a/lzma/CPP/Common/StringToInt.h b/lzma/CPP/Common/StringToInt.h
new file mode 100644 (file)
index 0000000..bb971f6
--- /dev/null
@@ -0,0 +1,17 @@
+// Common/StringToInt.h
+
+#ifndef __COMMON_STRINGTOINT_H
+#define __COMMON_STRINGTOINT_H
+
+#include <string.h>
+#include "Types.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end);
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end);
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end);
+
+Int64 ConvertStringToInt64(const char *s, const char **end);
+
+#endif
+
+
diff --git a/lzma/CPP/Common/Types.h b/lzma/CPP/Common/Types.h
new file mode 100644 (file)
index 0000000..41d785e
--- /dev/null
@@ -0,0 +1,57 @@
+// Common/Types.h
+
+#ifndef __COMMON_TYPES_H
+#define __COMMON_TYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_INT16_DEFINED
+#define _7ZIP_INT16_DEFINED
+typedef short Int16;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_INT32_DEFINED
+#define _7ZIP_INT32_DEFINED
+typedef int Int32;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+typedef unsigned int UInt32;
+#endif 
+
+#ifdef _MSC_VER
+
+#ifndef _7ZIP_INT64_DEFINED
+#define _7ZIP_INT64_DEFINED
+typedef __int64 Int64;
+#endif 
+
+#ifndef _7ZIP_UINT64_DEFINED
+#define _7ZIP_UINT64_DEFINED
+typedef unsigned __int64 UInt64;
+#endif 
+
+#else
+
+#ifndef _7ZIP_INT64_DEFINED
+#define _7ZIP_INT64_DEFINED
+typedef long long int Int64;
+#endif 
+
+#ifndef _7ZIP_UINT64_DEFINED
+#define _7ZIP_UINT64_DEFINED
+typedef unsigned long long int UInt64;
+#endif 
+
+#endif
+
+#endif
diff --git a/lzma/CPP/Common/UTFConvert.cpp b/lzma/CPP/Common/UTFConvert.cpp
new file mode 100644 (file)
index 0000000..e15695b
--- /dev/null
@@ -0,0 +1,91 @@
+// UTFConvert.cpp
+
+#include "StdAfx.h"
+
+#include "UTFConvert.h"
+#include "Types.h"
+
+static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+// These functions are for UTF8 <-> UTF16 conversion.
+
+bool ConvertUTF8ToUnicode(const AString &src, UString &dest)
+{
+  dest.Empty();
+  for(int i = 0; i < src.Length();)
+  {
+    Byte c = (Byte)src[i++];
+    if (c < 0x80)
+    {
+      dest += (wchar_t)c;
+      continue;
+    }
+    if(c < 0xC0)
+      return false;
+    int numAdds;
+    for (numAdds = 1; numAdds < 5; numAdds++)
+      if (c < kUtf8Limits[numAdds])
+        break;
+    UInt32 value = (c - kUtf8Limits[numAdds - 1]);
+    do
+    {
+      if (i >= src.Length())
+        return false;
+      Byte c2 = (Byte)src[i++];
+      if (c2 < 0x80 || c2 >= 0xC0)
+        return false;
+      value <<= 6;
+      value |= (c2 - 0x80);
+      numAdds--;
+    }
+    while(numAdds > 0);
+    if (value < 0x10000)
+      dest += (wchar_t)(value);
+    else
+    {
+      value -= 0x10000;
+      if (value >= 0x100000)
+        return false;
+      dest += (wchar_t)(0xD800 + (value >> 10));
+      dest += (wchar_t)(0xDC00 + (value & 0x3FF));
+    }
+  }
+  return true; 
+}
+
+bool ConvertUnicodeToUTF8(const UString &src, AString &dest)
+{
+  dest.Empty();
+  for(int i = 0; i < src.Length();)
+  {
+    UInt32 value = (UInt32)src[i++];
+    if (value < 0x80)
+    {
+      dest += (char)value;
+      continue;
+    }
+    if (value >= 0xD800 && value < 0xE000)
+    {
+      if (value >= 0xDC00)
+        return false;
+      if (i >= src.Length())
+        return false;
+      UInt32 c2 = (UInt32)src[i++];
+      if (c2 < 0xDC00 || c2 >= 0xE000)
+        return false;
+      value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+    }
+    int numAdds;
+    for (numAdds = 1; numAdds < 5; numAdds++)
+      if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+        break;
+    dest += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+    do
+    {
+      numAdds--;
+      dest += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+    }
+    while(numAdds > 0);
+  }
+  return true;
+}
diff --git a/lzma/CPP/Common/UTFConvert.h b/lzma/CPP/Common/UTFConvert.h
new file mode 100644 (file)
index 0000000..2a14600
--- /dev/null
@@ -0,0 +1,11 @@
+// Common/UTFConvert.h
+
+#ifndef __COMMON_UTFCONVERT_H
+#define __COMMON_UTFCONVERT_H
+
+#include "MyString.h"
+
+bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString);
+bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString);
+
+#endif
diff --git a/lzma/CPP/Common/Wildcard.cpp b/lzma/CPP/Common/Wildcard.cpp
new file mode 100644 (file)
index 0000000..9feebbe
--- /dev/null
@@ -0,0 +1,458 @@
+// Common/Wildcard.cpp
+
+#include "StdAfx.h"
+
+#include "Wildcard.h"
+
+bool g_CaseSensitive = 
+  #ifdef _WIN32
+    false;
+  #else
+    true;
+  #endif
+
+static const wchar_t kAnyCharsChar = L'*';
+static const wchar_t kAnyCharChar = L'?';
+
+#ifdef _WIN32
+static const wchar_t kDirDelimiter1 = L'\\';
+#endif
+static const wchar_t kDirDelimiter2 = L'/';
+
+static const UString kWildCardCharSet = L"?*";
+
+static const UString kIllegalWildCardFileNameChars=
+  L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
+  L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+  L"\"/:<>\\|";
+
+
+static inline bool IsCharDirLimiter(wchar_t c)
+{
+  return (
+    #ifdef _WIN32
+    c == kDirDelimiter1 || 
+    #endif
+    c == kDirDelimiter2);
+}
+
+int CompareFileNames(const UString &s1, const UString &s2)
+{
+  if (g_CaseSensitive)
+    return s1.Compare(s2);
+  return s1.CompareNoCase(s2);
+}
+
+// -----------------------------------------
+// this function compares name with mask
+// ? - any char
+// * - any char or empty
+
+static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
+{
+  for (;;)
+  {
+    wchar_t m = *mask;
+    wchar_t c = *name;
+    if (m == 0) 
+      return (c == 0);
+    if (m == kAnyCharsChar)
+    {
+      if (EnhancedMaskTest(mask + 1, name))
+        return true;
+      if (c == 0) 
+        return false;
+    }
+    else
+    {
+      if (m == kAnyCharChar)
+      {
+        if (c == 0) 
+          return false;
+      }
+      else if (m != c)
+        if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))
+          return false;
+      mask++;
+    }
+    name++;
+  }
+}
+
+// --------------------------------------------------
+// Splits path to strings
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts)
+{
+  pathParts.Clear();
+  UString name;
+  int len = path.Length();
+  if (len == 0)
+    return;
+  for (int i = 0; i < len; i++)
+  {
+    wchar_t c = path[i];
+    if (IsCharDirLimiter(c))
+    {
+      pathParts.Add(name);
+      name.Empty();
+    }
+    else
+      name += c;
+  }
+  pathParts.Add(name);
+}
+
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
+{
+  int i;
+  for(i = path.Length() - 1; i >= 0; i--)
+    if(IsCharDirLimiter(path[i]))
+      break;
+  dirPrefix = path.Left(i + 1);
+  name = path.Mid(i + 1);
+}
+
+UString ExtractDirPrefixFromPath(const UString &path)
+{
+  int i;
+  for(i = path.Length() - 1; i >= 0; i--)
+    if(IsCharDirLimiter(path[i]))
+      break;
+  return path.Left(i + 1);
+}
+
+UString ExtractFileNameFromPath(const UString &path)
+{
+  int i;
+  for(i = path.Length() - 1; i >= 0; i--)
+    if(IsCharDirLimiter(path[i]))
+      break;
+  return path.Mid(i + 1);
+}
+
+
+bool CompareWildCardWithName(const UString &mask, const UString &name)
+{
+  return EnhancedMaskTest(mask, name);
+}
+
+bool DoesNameContainWildCard(const UString &path)
+{
+  return (path.FindOneOf(kWildCardCharSet) >= 0);
+}
+
+
+// ----------------------------------------------------------'
+// NWildcard
+
+namespace NWildcard {
+
+
+/*
+M = MaskParts.Size();
+N = TestNameParts.Size();
+
+                           File                          Dir
+ForFile     req   M<=N  [N-M, N)                          -
+         nonreq   M=N   [0, M)                            -  
+ForDir      req   M<N   [0, M) ... [N-M-1, N-1)  same as ForBoth-File
+         nonreq         [0, M)                   same as ForBoth-File
+
+ForBoth     req   m<=N  [0, M) ... [N-M, N)      same as ForBoth-File
+         nonreq         [0, M)                   same as ForBoth-File
+
+*/
+
+bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
+{
+  if (!isFile && !ForDir)
+    return false;
+  int delta = (int)pathParts.Size() - (int)PathParts.Size();
+  if (delta < 0)
+    return false;
+  int start = 0;
+  int finish = 0;
+  if (isFile)
+  {
+    if (!ForDir && !Recursive && delta !=0)
+      return false;
+    if (!ForFile && delta == 0)
+      return false;
+    if (!ForDir && Recursive)
+      start = delta;
+  }
+  if (Recursive)
+  {
+    finish = delta;
+    if (isFile && !ForFile)
+      finish = delta - 1;
+  }
+  for (int d = start; d <= finish; d++)
+  {
+    int i;
+    for (i = 0; i < PathParts.Size(); i++)
+      if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
+        break;
+    if (i == PathParts.Size())
+      return true;
+  }
+  return false;
+}
+
+int CCensorNode::FindSubNode(const UString &name) const
+{
+  for (int i = 0; i < SubNodes.Size(); i++)
+    if (CompareFileNames(SubNodes[i].Name, name) == 0)
+      return i;
+  return -1;
+}
+
+void CCensorNode::AddItemSimple(bool include, CItem &item)
+{
+  if (include)
+    IncludeItems.Add(item);
+  else
+    ExcludeItems.Add(item);
+}
+
+void CCensorNode::AddItem(bool include, CItem &item)
+{
+  if (item.PathParts.Size() <= 1)
+  {
+    AddItemSimple(include, item);
+    return;
+  }
+  const UString &front = item.PathParts.Front();
+  if (DoesNameContainWildCard(front))
+  {
+    AddItemSimple(include, item);
+    return;
+  }
+  int index = FindSubNode(front);
+  if (index < 0)
+    index = SubNodes.Add(CCensorNode(front, this));
+  item.PathParts.Delete(0);
+  SubNodes[index].AddItem(include, item);
+}
+
+void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
+{
+  CItem item;
+  SplitPathToParts(path, item.PathParts);
+  item.Recursive = recursive;
+  item.ForFile = forFile;
+  item.ForDir = forDir;
+  AddItem(include, item);
+}
+
+bool CCensorNode::NeedCheckSubDirs() const
+{
+  for (int i = 0; i < IncludeItems.Size(); i++)
+  {
+    const CItem &item = IncludeItems[i];
+    if (item.Recursive || item.PathParts.Size() > 1)
+      return true;
+  }
+  return false;
+}
+
+bool CCensorNode::AreThereIncludeItems() const
+{
+  if (IncludeItems.Size() > 0)
+    return true;
+  for (int i = 0; i < SubNodes.Size(); i++)
+    if (SubNodes[i].AreThereIncludeItems())
+      return true;
+  return false;
+}
+
+bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
+{
+  const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
+  for (int i = 0; i < items.Size(); i++)
+    if (items[i].CheckPath(pathParts, isFile))
+      return true;
+  return false;
+}
+
+bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
+{
+  if (CheckPathCurrent(false, pathParts, isFile))
+  {
+    include = false;
+    return true;
+  }
+  include = true;
+  bool finded = CheckPathCurrent(true, pathParts, isFile);
+  if (pathParts.Size() == 1)
+    return finded;
+  int index = FindSubNode(pathParts.Front());
+  if (index >= 0)
+  {
+    UStringVector pathParts2 = pathParts;
+    pathParts2.Delete(0);
+    if (SubNodes[index].CheckPath(pathParts2, isFile, include))
+      return true;
+  }
+  return finded;
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
+{
+  UStringVector pathParts; 
+  SplitPathToParts(path, pathParts);
+  return CheckPath(pathParts, isFile, include);
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile) const
+{
+  bool include;
+  if(CheckPath(path, isFile, include))
+    return include;
+  return false;
+}
+
+bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
+{
+  if (CheckPathCurrent(include, pathParts, isFile))
+    return true;
+  if (Parent == 0)
+    return false;
+  pathParts.Insert(0, Name);
+  return Parent->CheckPathToRoot(include, pathParts, isFile);
+}
+
+/*
+bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
+{
+  UStringVector pathParts; 
+  SplitPathToParts(path, pathParts);
+  return CheckPathToRoot(include, pathParts, isFile);
+}
+*/
+
+void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
+{
+  if (path.IsEmpty())
+    return;
+  bool forFile = true;
+  bool forFolder = true;
+  UString path2 = path;
+  if (IsCharDirLimiter(path[path.Length() - 1]))
+  {
+    path2.Delete(path.Length() - 1);
+    forFile = false;
+  }
+  AddItem(include, path2, recursive, forFile, forFolder);
+}
+
+void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
+{
+  ExcludeItems += fromNodes.ExcludeItems;
+  for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
+  {
+    const CCensorNode &node = fromNodes.SubNodes[i];
+    int subNodeIndex = FindSubNode(node.Name);
+    if (subNodeIndex < 0)
+      subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));
+    SubNodes[subNodeIndex].ExtendExclude(node);
+  }
+}
+
+int CCensor::FindPrefix(const UString &prefix) const
+{
+  for (int i = 0; i < Pairs.Size(); i++)
+    if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
+      return i;
+  return -1;
+}
+
+void CCensor::AddItem(bool include, const UString &path, bool recursive)
+{
+  UStringVector pathParts;
+  SplitPathToParts(path, pathParts);
+  bool forFile = true;
+  if (pathParts.Back().IsEmpty())
+  {
+    forFile = false;
+    pathParts.DeleteBack();
+  }
+  const UString &front = pathParts.Front();
+  bool isAbs = false;
+  if (front.IsEmpty())
+    isAbs = true;
+  else if (front.Length() == 2 && front[1] == L':')
+    isAbs = true;
+  else
+  {
+    for (int i = 0; i < pathParts.Size(); i++)
+    {
+      const UString &part = pathParts[i];
+      if (part == L".." || part == L".")
+      {
+        isAbs = true;
+        break;
+      }
+    }
+  }
+  int numAbsParts = 0;
+  if (isAbs)
+    if (pathParts.Size() > 1)
+      numAbsParts = pathParts.Size() - 1;
+    else
+      numAbsParts = 1;
+  UString prefix;
+  for (int i = 0; i < numAbsParts; i++)
+  {
+    const UString &front = pathParts.Front();
+    if (DoesNameContainWildCard(front))
+      break;
+    prefix += front;
+    prefix += WCHAR_PATH_SEPARATOR;
+    pathParts.Delete(0);
+  }
+  int index = FindPrefix(prefix);
+  if (index < 0)
+    index = Pairs.Add(CPair(prefix));
+
+  CItem item;
+  item.PathParts = pathParts;
+  item.ForDir = true;
+  item.ForFile = forFile;
+  item.Recursive = recursive;
+  Pairs[index].Head.AddItem(include, item);
+}
+
+bool CCensor::CheckPath(const UString &path, bool isFile) const
+{
+  bool finded = false;
+  for (int i = 0; i < Pairs.Size(); i++)
+  {
+    bool include;
+    if (Pairs[i].Head.CheckPath(path, isFile, include))
+    {
+      if (!include)
+        return false;
+      finded = true;
+    }
+  }
+  return finded;
+}
+
+void CCensor::ExtendExclude()
+{
+  int i;
+  for (i = 0; i < Pairs.Size(); i++)
+    if (Pairs[i].Prefix.IsEmpty())
+      break;
+  if (i == Pairs.Size())
+    return;
+  int index = i;
+  for (i = 0; i < Pairs.Size(); i++)
+    if (index != i)
+      Pairs[i].Head.ExtendExclude(Pairs[index].Head);
+}
+
+}
diff --git a/lzma/CPP/Common/Wildcard.h b/lzma/CPP/Common/Wildcard.h
new file mode 100644 (file)
index 0000000..6d4cbce
--- /dev/null
@@ -0,0 +1,80 @@
+// Common/Wildcard.h
+
+#ifndef __COMMON_WILDCARD_H
+#define __COMMON_WILDCARD_H
+
+#include "MyString.h"
+
+int CompareFileNames(const UString &s1, const UString &s2);
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts);
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name);
+UString ExtractDirPrefixFromPath(const UString &path);
+UString ExtractFileNameFromPath(const UString &path);
+bool DoesNameContainWildCard(const UString &path);
+bool CompareWildCardWithName(const UString &mask, const UString &name);
+
+namespace NWildcard {
+
+struct CItem
+{
+  UStringVector PathParts;
+  bool Recursive;
+  bool ForFile;
+  bool ForDir;
+  bool CheckPath(const UStringVector &pathParts, bool isFile) const;
+};
+
+class CCensorNode
+{
+  CCensorNode *Parent;
+  bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const;
+  void AddItemSimple(bool include, CItem &item);
+  bool CheckPath(UStringVector &pathParts, bool isFile, bool &include) const;
+public:
+  CCensorNode(): Parent(0) { };
+  CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { };
+  UString Name;
+  CObjectVector<CCensorNode> SubNodes;
+  CObjectVector<CItem> IncludeItems;
+  CObjectVector<CItem> ExcludeItems;
+
+  int FindSubNode(const UString &path) const;
+
+  void AddItem(bool include, CItem &item);
+  void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir);
+  void AddItem2(bool include, const UString &path, bool recursive);
+
+  bool NeedCheckSubDirs() const;
+  bool AreThereIncludeItems() const;
+
+  bool CheckPath(const UString &path, bool isFile, bool &include) const;
+  bool CheckPath(const UString &path, bool isFile) const;
+
+  bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const;
+  // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const;
+  void ExtendExclude(const CCensorNode &fromNodes);
+};
+
+struct CPair
+{
+  UString Prefix;
+  CCensorNode Head;
+  CPair(const UString &prefix): Prefix(prefix) { };
+};
+
+class CCensor
+{
+  int FindPrefix(const UString &prefix) const;
+public:
+  CObjectVector<CPair> Pairs;
+  bool AllAreRelative() const
+    { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); }
+  void AddItem(bool include, const UString &path, bool recursive);
+  bool CheckPath(const UString &path, bool isFile) const;
+  void ExtendExclude();
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/Windows/DLL.cpp b/lzma/CPP/Windows/DLL.cpp
new file mode 100644 (file)
index 0000000..9e92dc2
--- /dev/null
@@ -0,0 +1,115 @@
+// Windows/DLL.cpp
+
+#include "StdAfx.h"
+
+#include "DLL.h"
+#include "Defs.h"
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NDLL {
+
+CLibrary::~CLibrary()
+{
+  Free();
+}
+
+bool CLibrary::Free()
+{
+  if (_module == 0)
+    return true;
+  // MessageBox(0, TEXT(""), TEXT("Free"), 0);
+  // Sleep(5000);
+  if (!::FreeLibrary(_module))
+    return false;
+  _module = 0;
+  return true;
+}
+
+bool CLibrary::LoadOperations(HMODULE newModule)
+{
+  if (newModule == NULL)
+    return false;
+  if(!Free())
+    return false;
+  _module = newModule;
+  return true;
+}
+
+bool CLibrary::LoadEx(LPCTSTR fileName, DWORD flags)
+{
+  // MessageBox(0, fileName, TEXT("LoadEx"), 0);
+  return LoadOperations(::LoadLibraryEx(fileName, NULL, flags));
+}
+
+bool CLibrary::Load(LPCTSTR fileName)
+{
+  // MessageBox(0, fileName, TEXT("Load"), 0);
+  // Sleep(5000);
+  // OutputDebugString(fileName);
+  // OutputDebugString(TEXT("\n"));
+  return LoadOperations(::LoadLibrary(fileName));
+}
+
+#ifndef _UNICODE
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } 
+CSysString GetSysPath(LPCWSTR sysPath)
+  { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
+
+bool CLibrary::LoadEx(LPCWSTR fileName, DWORD flags)
+{
+  if (g_IsNT)
+    return LoadOperations(::LoadLibraryExW(fileName, NULL, flags));
+  return LoadEx(GetSysPath(fileName), flags);
+}
+bool CLibrary::Load(LPCWSTR fileName)
+{
+  if (g_IsNT)
+    return LoadOperations(::LoadLibraryW(fileName));
+  return Load(GetSysPath(fileName));
+}
+#endif
+
+bool MyGetModuleFileName(HMODULE hModule, CSysString &result)
+{
+  result.Empty();
+  TCHAR fullPath[MAX_PATH + 2];
+  DWORD size = ::GetModuleFileName(hModule, fullPath, MAX_PATH + 1);
+  if (size <= MAX_PATH && size != 0)
+  {
+    result = fullPath;
+    return true;
+  }
+  return false;
+}
+
+#ifndef _UNICODE
+bool MyGetModuleFileName(HMODULE hModule, UString &result)
+{
+  result.Empty();
+  if (g_IsNT)
+  {
+    wchar_t fullPath[MAX_PATH + 2];
+    DWORD size = ::GetModuleFileNameW(hModule, fullPath, MAX_PATH + 1);
+    if (size <= MAX_PATH && size != 0)
+    {
+      result = fullPath;
+      return true;
+    }
+    return false;
+  }
+  CSysString resultSys;
+  if (!MyGetModuleFileName(hModule, resultSys))
+    return false;
+  result = MultiByteToUnicodeString(resultSys, GetCurrentCodePage());
+  return true;
+}
+#endif
+
+}}
diff --git a/lzma/CPP/Windows/DLL.h b/lzma/CPP/Windows/DLL.h
new file mode 100644 (file)
index 0000000..4c2ffa2
--- /dev/null
@@ -0,0 +1,54 @@
+// Windows/DLL.h
+
+#ifndef __WINDOWS_DLL_H
+#define __WINDOWS_DLL_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NDLL {
+
+class CLibrary
+{
+  bool LoadOperations(HMODULE newModule);
+protected:
+  HMODULE _module;
+public:
+  operator HMODULE() const { return _module; }
+  HMODULE* operator&() { return &_module; }
+
+  CLibrary():_module(NULL) {};
+  ~CLibrary();
+  void Attach(HMODULE m)
+  {
+    Free();
+    _module = m;
+  }
+  HMODULE Detach()
+  {
+    HMODULE m = _module;
+    _module = NULL;
+    return m;
+  }
+
+  // operator HMODULE() const { return _module; };
+  bool IsLoaded() const { return (_module != NULL); };
+  bool Free();
+  bool LoadEx(LPCTSTR fileName, DWORD flags = LOAD_LIBRARY_AS_DATAFILE);
+  bool Load(LPCTSTR fileName);
+  #ifndef _UNICODE
+  bool LoadEx(LPCWSTR fileName, DWORD flags = LOAD_LIBRARY_AS_DATAFILE);
+  bool Load(LPCWSTR fileName);
+  #endif
+  FARPROC GetProcAddress(LPCSTR procName) const
+    { return ::GetProcAddress(_module, procName); }
+};
+
+bool MyGetModuleFileName(HMODULE hModule, CSysString &result);
+#ifndef _UNICODE
+bool MyGetModuleFileName(HMODULE hModule, UString &result);
+#endif
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Defs.h b/lzma/CPP/Windows/Defs.h
new file mode 100644 (file)
index 0000000..898be8d
--- /dev/null
@@ -0,0 +1,23 @@
+// Windows/Defs.h
+
+#ifndef __WINDOWS_DEFS_H
+#define __WINDOWS_DEFS_H
+
+inline bool BOOLToBool(BOOL value)
+  { return (value != FALSE); }
+
+#ifdef _WIN32
+inline bool LRESULTToBool(LRESULT value)
+  { return (value != FALSE); }
+#endif
+
+inline BOOL BoolToBOOL(bool value)
+  { return (value ? TRUE: FALSE); }
+
+inline VARIANT_BOOL BoolToVARIANT_BOOL(bool value)
+  { return (value ? VARIANT_TRUE: VARIANT_FALSE); }
+
+inline bool VARIANT_BOOLToBool(VARIANT_BOOL value)
+  { return (value != VARIANT_FALSE); }
+
+#endif
diff --git a/lzma/CPP/Windows/Error.cpp b/lzma/CPP/Windows/Error.cpp
new file mode 100644 (file)
index 0000000..e559c4c
--- /dev/null
@@ -0,0 +1,50 @@
+// Windows/Error.h
+
+#include "StdAfx.h"
+
+#include "Windows/Error.h"
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NError {
+
+bool MyFormatMessage(DWORD messageID, CSysString &message)
+{
+  LPVOID msgBuf;
+  if(::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+      NULL,messageID, 0, (LPTSTR) &msgBuf,0, NULL) == 0)
+    return false;
+  message = (LPCTSTR)msgBuf;
+  ::LocalFree(msgBuf);
+  return true;
+}
+
+#ifndef _UNICODE
+bool MyFormatMessage(DWORD messageID, UString &message)
+{
+  if (g_IsNT)
+  {
+    LPVOID msgBuf;
+    if(::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL, messageID, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
+      return false;
+    message = (LPCWSTR)msgBuf;
+    ::LocalFree(msgBuf);
+    return true;
+  }
+  CSysString messageSys;
+  bool result = MyFormatMessage(messageID, messageSys);
+  message = GetUnicodeString(messageSys);
+  return result;
+}
+#endif
+
+}}
diff --git a/lzma/CPP/Windows/Error.h b/lzma/CPP/Windows/Error.h
new file mode 100644 (file)
index 0000000..05b5cd0
--- /dev/null
@@ -0,0 +1,33 @@
+// Windows/Error.h
+
+#ifndef __WINDOWS_ERROR_H
+#define __WINDOWS_ERROR_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+namespace NError {
+
+bool MyFormatMessage(DWORD messageID, CSysString &message);
+inline CSysString MyFormatMessage(DWORD messageID)
+{
+  CSysString message;
+  MyFormatMessage(messageID, message);
+  return message;
+}
+#ifdef _UNICODE
+inline UString MyFormatMessageW(DWORD messageID)
+  { return MyFormatMessage(messageID); }
+#else
+bool MyFormatMessage(DWORD messageID, UString &message);
+inline UString MyFormatMessageW(DWORD messageID)
+{
+  UString message;
+  MyFormatMessage(messageID, message);
+  return message;
+}
+#endif
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/FileDir.cpp b/lzma/CPP/Windows/FileDir.cpp
new file mode 100644 (file)
index 0000000..6d56170
--- /dev/null
@@ -0,0 +1,841 @@
+// Windows/FileDir.cpp
+
+#include "StdAfx.h"
+
+#include "FileDir.h"
+#include "FileName.h"
+#include "FileFind.h"
+#include "Defs.h"
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+#if defined(WIN_LONG_PATH) && defined(_UNICODE)
+#define WIN_LONG_PATH2
+#endif
+
+// SetCurrentDirectory doesn't support \\?\ prefix
+
+#ifdef WIN_LONG_PATH
+bool GetLongPathBase(LPCWSTR fileName, UString &res);
+bool GetLongPath(LPCWSTR fileName, UString &res);
+#endif
+
+namespace NDirectory {
+
+#ifndef _UNICODE
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } 
+static UString GetUnicodePath(const CSysString &sysPath)
+  { return MultiByteToUnicodeString(sysPath, GetCurrentCodePage()); }
+static CSysString GetSysPath(LPCWSTR sysPath)
+  { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
+#endif
+
+bool MyGetWindowsDirectory(CSysString &path)
+{
+  UINT needLength = ::GetWindowsDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+  path.ReleaseBuffer();
+  return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+bool MyGetSystemDirectory(CSysString &path)
+{
+  UINT needLength = ::GetSystemDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+  path.ReleaseBuffer();
+  return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+#ifndef _UNICODE
+bool MyGetWindowsDirectory(UString &path)
+{
+  if (g_IsNT)
+  {
+    UINT needLength = ::GetWindowsDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+    path.ReleaseBuffer();
+    return (needLength > 0 && needLength <= MAX_PATH);
+  }
+  CSysString sysPath;
+  if (!MyGetWindowsDirectory(sysPath))
+    return false;
+  path = GetUnicodePath(sysPath);
+  return true;
+}
+
+bool MyGetSystemDirectory(UString &path)
+{
+  if (g_IsNT)
+  {
+    UINT needLength = ::GetSystemDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+    path.ReleaseBuffer();
+    return (needLength > 0 && needLength <= MAX_PATH);
+  }
+  CSysString sysPath;
+  if (!MyGetSystemDirectory(sysPath))
+    return false;
+  path = GetUnicodePath(sysPath);
+  return true;
+}
+#endif
+
+bool SetDirTime(LPCWSTR fileName, const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
+{
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return false;
+  }
+  #endif 
+  HANDLE hDir = ::CreateFileW(fileName, GENERIC_WRITE,
+      FILE_SHARE_READ | FILE_SHARE_WRITE,
+      NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  #ifdef WIN_LONG_PATH
+  if (hDir == INVALID_HANDLE_VALUE)
+  {
+    UString longPath;
+    if (GetLongPath(fileName, longPath))
+      hDir = ::CreateFileW(longPath, GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  }
+  #endif
+
+  bool res = false;
+  if (hDir != INVALID_HANDLE_VALUE)
+  {
+    res = BOOLToBool(::SetFileTime(hDir, creationTime, lastAccessTime, lastWriteTime));
+    ::CloseHandle(hDir);
+  }
+  return res;
+}
+
+bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
+{
+  if (::SetFileAttributes(fileName, fileAttributes))
+    return true;
+  #ifdef WIN_LONG_PATH2
+  UString longPath;
+  if (GetLongPath(fileName, longPath))
+    return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
+  #endif
+  return false;
+}
+
+bool MyRemoveDirectory(LPCTSTR pathName)
+{ 
+  if (::RemoveDirectory(pathName))
+    return true;
+  #ifdef WIN_LONG_PATH2
+  UString longPath;
+  if (GetLongPath(pathName, longPath))
+    return BOOLToBool(::RemoveDirectoryW(longPath));
+  #endif
+  return false;
+}
+
+#ifdef WIN_LONG_PATH
+bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2)
+{
+  if (!GetLongPathBase(s1, d1) || !GetLongPathBase(s2, d2))
+    return false;
+  if (d1.IsEmpty() && d2.IsEmpty()) return false;
+  if (d1.IsEmpty()) d1 = s1;
+  if (d2.IsEmpty()) d2 = s2;
+  return true;
+}
+#endif
+
+bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName)
+{ 
+  if (::MoveFile(existFileName, newFileName))
+    return true;
+  #ifdef WIN_LONG_PATH2
+  UString d1, d2;
+  if (GetLongPaths(existFileName, newFileName, d1, d2)) 
+    return BOOLToBool(::MoveFileW(d1, d2));
+  #endif
+  return false;
+}
+
+#ifndef _UNICODE
+bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
+{  
+  if (!g_IsNT)
+    return MySetFileAttributes(GetSysPath(fileName), fileAttributes);
+  if (::SetFileAttributesW(fileName, fileAttributes))
+    return true;
+  #ifdef WIN_LONG_PATH
+  UString longPath;
+  if (GetLongPath(fileName, longPath))
+    return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
+  #endif
+  return false;
+}
+
+
+bool MyRemoveDirectory(LPCWSTR pathName)
+{  
+  if (!g_IsNT)
+    return MyRemoveDirectory(GetSysPath(pathName));
+  if (::RemoveDirectoryW(pathName))
+    return true;
+  #ifdef WIN_LONG_PATH
+  UString longPath;
+  if (GetLongPath(pathName, longPath))
+    return BOOLToBool(::RemoveDirectoryW(longPath));
+  #endif
+  return false;
+}
+
+bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName)
+{  
+  if (!g_IsNT)
+    return MyMoveFile(GetSysPath(existFileName), GetSysPath(newFileName));
+  if (::MoveFileW(existFileName, newFileName))
+    return true;
+  #ifdef WIN_LONG_PATH
+  UString d1, d2;
+  if (GetLongPaths(existFileName, newFileName, d1, d2)) 
+    return BOOLToBool(::MoveFileW(d1, d2));
+  #endif
+  return false;
+}
+#endif
+
+bool MyCreateDirectory(LPCTSTR pathName) 
+{ 
+  if (::CreateDirectory(pathName, NULL))
+    return true;
+  #ifdef WIN_LONG_PATH2
+  if (::GetLastError() != ERROR_ALREADY_EXISTS)
+  {
+    UString longPath;
+    if (GetLongPath(pathName, longPath))
+      return BOOLToBool(::CreateDirectoryW(longPath, NULL));
+  }
+  #endif
+  return false;
+}
+
+#ifndef _UNICODE
+bool MyCreateDirectory(LPCWSTR pathName)
+{  
+  if (!g_IsNT)
+    return MyCreateDirectory(GetSysPath(pathName));
+  if (::CreateDirectoryW(pathName, NULL))
+    return true;
+  #ifdef WIN_LONG_PATH
+  if (::GetLastError() != ERROR_ALREADY_EXISTS)
+  {
+    UString longPath;
+    if (GetLongPath(pathName, longPath))
+      return BOOLToBool(::CreateDirectoryW(longPath, NULL));
+  }
+  #endif
+  return false;
+}
+#endif
+
+/*
+bool CreateComplexDirectory(LPCTSTR pathName)
+{
+  NName::CParsedPath path;
+  path.ParsePath(pathName);
+  CSysString fullPath = path.Prefix;
+  DWORD errorCode = ERROR_SUCCESS;
+  for(int i = 0; i < path.PathParts.Size(); i++)
+  {
+    const CSysString &string = path.PathParts[i];
+    if(string.IsEmpty())
+    {
+      if(i != path.PathParts.Size() - 1)
+        return false;
+      return true;
+    }
+    fullPath += path.PathParts[i];
+    if (!MyCreateDirectory(fullPath))
+    {
+      DWORD errorCode = GetLastError();
+      if(errorCode != ERROR_ALREADY_EXISTS)
+        return false;
+    }
+    fullPath += NName::kDirDelimiter;
+  }
+  return true;
+}
+*/
+
+bool CreateComplexDirectory(LPCTSTR _aPathName)
+{
+  CSysString pathName = _aPathName;
+  int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+  if (pos > 0 && pos == pathName.Length() - 1)
+  {
+    if (pathName.Length() == 3 && pathName[1] == ':')
+      return true; // Disk folder;
+    pathName.Delete(pos);
+  }
+  CSysString pathName2 = pathName;
+  pos = pathName.Length();
+  for (;;)
+  {
+    if(MyCreateDirectory(pathName))
+      break;
+    if (::GetLastError() == ERROR_ALREADY_EXISTS)
+    {
+      NFind::CFileInfo fileInfo;
+      if (!NFind::FindFile(pathName, fileInfo)) // For network folders
+        return true;
+      if (!fileInfo.IsDirectory())
+        return false;
+      break;
+    }
+    pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+    if (pos < 0 || pos == 0)
+      return false;
+    if (pathName[pos - 1] == ':')
+      return false;
+    pathName = pathName.Left(pos);
+  }
+  pathName = pathName2;
+  while(pos < pathName.Length())
+  {
+    pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1);
+    if (pos < 0)
+      pos = pathName.Length();
+    if (!MyCreateDirectory(pathName.Left(pos)))
+      return false;
+  }
+  return true;
+}
+
+#ifndef _UNICODE
+
+bool CreateComplexDirectory(LPCWSTR _aPathName)
+{
+  UString pathName = _aPathName;
+  int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
+  if (pos > 0 && pos == pathName.Length() - 1)
+  {
+    if (pathName.Length() == 3 && pathName[1] == L':')
+      return true; // Disk folder;
+    pathName.Delete(pos);
+  }
+  UString pathName2 = pathName;
+  pos = pathName.Length();
+  for (;;)
+  {
+    if(MyCreateDirectory(pathName))
+      break;
+    if (::GetLastError() == ERROR_ALREADY_EXISTS)
+    {
+      NFind::CFileInfoW fileInfo;
+      if (!NFind::FindFile(pathName, fileInfo)) // For network folders
+        return true;
+      if (!fileInfo.IsDirectory())
+        return false;
+      break;
+    }
+    pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
+    if (pos < 0 || pos == 0)
+      return false;
+    if (pathName[pos - 1] == L':')
+      return false;
+    pathName = pathName.Left(pos);
+  }
+  pathName = pathName2;
+  while(pos < pathName.Length())
+  {
+    pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1);
+    if (pos < 0)
+      pos = pathName.Length();
+    if (!MyCreateDirectory(pathName.Left(pos)))
+      return false;
+  }
+  return true;
+}
+
+#endif
+
+bool DeleteFileAlways(LPCTSTR name)
+{
+  if (!MySetFileAttributes(name, 0))
+    return false;
+  if (::DeleteFile(name))
+    return true;
+  #ifdef WIN_LONG_PATH2
+  UString longPath;
+  if (GetLongPath(name, longPath))
+    return BOOLToBool(::DeleteFileW(longPath));
+  #endif
+  return false;
+}
+
+#ifndef _UNICODE
+bool DeleteFileAlways(LPCWSTR name)
+{  
+  if (!g_IsNT)
+    return DeleteFileAlways(GetSysPath(name));
+  if (!MySetFileAttributes(name, 0))
+    return false;
+  if (::DeleteFileW(name))
+    return true;
+  #ifdef WIN_LONG_PATH
+  UString longPath;
+  if (GetLongPath(name, longPath))
+    return BOOLToBool(::DeleteFileW(longPath));
+  #endif
+  return false;
+}
+#endif
+
+static bool RemoveDirectorySubItems2(const CSysString pathPrefix, const NFind::CFileInfo &fileInfo)
+{
+  if(fileInfo.IsDirectory())
+    return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
+  return DeleteFileAlways(pathPrefix + fileInfo.Name);
+}
+
+bool RemoveDirectoryWithSubItems(const CSysString &path)
+{
+  NFind::CFileInfo fileInfo;
+  CSysString pathPrefix = path + NName::kDirDelimiter;
+  {
+    NFind::CEnumerator enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard));
+    while(enumerator.Next(fileInfo))
+      if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
+        return false;
+  }
+  if (!MySetFileAttributes(path, 0))
+    return false;
+  return MyRemoveDirectory(path);
+}
+
+#ifndef _UNICODE
+static bool RemoveDirectorySubItems2(const UString pathPrefix, const NFind::CFileInfoW &fileInfo)
+{
+  if(fileInfo.IsDirectory())
+    return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
+  return DeleteFileAlways(pathPrefix + fileInfo.Name);
+}
+bool RemoveDirectoryWithSubItems(const UString &path)
+{
+  NFind::CFileInfoW fileInfo;
+  UString pathPrefix = path + UString(NName::kDirDelimiter);
+  {
+    NFind::CEnumeratorW enumerator(pathPrefix + UString(NName::kAnyStringWildcard));
+    while(enumerator.Next(fileInfo))
+      if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
+        return false;
+  }
+  if (!MySetFileAttributes(path, 0))
+    return false;
+  return MyRemoveDirectory(path);
+}
+#endif
+
+#ifndef _WIN32_WCE
+
+bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath)
+{
+  DWORD needLength = ::GetShortPathName(longPath, shortPath.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+  shortPath.ReleaseBuffer();
+  return (needLength > 0 && needLength < MAX_PATH);
+}
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex)
+{
+  resultPath.Empty();
+  LPTSTR fileNamePointer = 0;
+  LPTSTR buffer = resultPath.GetBuffer(MAX_PATH);
+  DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
+  resultPath.ReleaseBuffer();
+  if (needLength == 0)
+    return false;
+  if (needLength >= MAX_PATH)
+  {
+    #ifdef WIN_LONG_PATH2
+    needLength++;
+    buffer = resultPath.GetBuffer(needLength + 1);
+    DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
+    resultPath.ReleaseBuffer();
+    if (needLength2 == 0 || needLength2 > needLength)
+    #endif
+      return false;
+  }
+  if (fileNamePointer == 0)
+    fileNamePartStartIndex = lstrlen(fileName);
+  else
+    fileNamePartStartIndex = (int)(fileNamePointer - buffer);
+  return true;
+}
+
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
+{
+  resultPath.Empty();
+  if (g_IsNT)
+  {
+    LPWSTR fileNamePointer = 0;
+    LPWSTR buffer = resultPath.GetBuffer(MAX_PATH);
+    DWORD needLength = ::GetFullPathNameW(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
+    resultPath.ReleaseBuffer();
+    if (needLength == 0)
+      return false;
+    if (needLength >= MAX_PATH)
+    {
+      #ifdef WIN_LONG_PATH
+      needLength++;
+      buffer = resultPath.GetBuffer(needLength + 1);
+      DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
+      resultPath.ReleaseBuffer();
+      if (needLength2 == 0 || needLength2 > needLength)
+      #endif
+        return false;
+    }
+    if (fileNamePointer == 0)
+      fileNamePartStartIndex = MyStringLen(fileName);
+    else
+      fileNamePartStartIndex = (int)(fileNamePointer - buffer);
+  }
+  else
+  {
+    CSysString sysPath;
+    if (!MyGetFullPathName(GetSysPath(fileName), sysPath, fileNamePartStartIndex))
+      return false;
+    UString resultPath1 = GetUnicodePath(sysPath.Left(fileNamePartStartIndex));
+    UString resultPath2 = GetUnicodePath(sysPath.Mid(fileNamePartStartIndex));
+    fileNamePartStartIndex = resultPath1.Length();
+    resultPath = resultPath1 + resultPath2;
+  }
+  return true;
+}
+#endif
+
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
+{
+  int index;
+  return MyGetFullPathName(fileName, path, index);
+}
+
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &path)
+{
+  int index;
+  return MyGetFullPathName(fileName, path, index);
+}
+#endif
+
+bool GetOnlyName(LPCTSTR fileName, CSysString &resultName)
+{
+  int index;
+  if (!MyGetFullPathName(fileName, resultName, index))
+    return false;
+  resultName = resultName.Mid(index);
+  return true;
+}
+
+#ifndef _UNICODE
+bool GetOnlyName(LPCWSTR fileName, UString &resultName)
+{
+  int index;
+  if (!MyGetFullPathName(fileName, resultName, index))
+    return false;
+  resultName = resultName.Mid(index);
+  return true;
+}
+#endif
+
+bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName)
+{
+  int index;
+  if (!MyGetFullPathName(fileName, resultName, index))
+    return false;
+  resultName = resultName.Left(index);
+  return true;
+}
+
+#ifndef _UNICODE
+bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName)
+{
+  int index;
+  if (!MyGetFullPathName(fileName, resultName, index))
+    return false;
+  resultName = resultName.Left(index);
+  return true;
+}
+#endif
+
+bool MyGetCurrentDirectory(CSysString &path)
+{
+  DWORD needLength = ::GetCurrentDirectory(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+  path.ReleaseBuffer();
+  return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+#ifndef _UNICODE
+bool MySetCurrentDirectory(LPCWSTR path)
+{
+  if (g_IsNT)
+    return BOOLToBool(::SetCurrentDirectoryW(path));
+  return MySetCurrentDirectory(GetSysPath(path));
+}
+bool MyGetCurrentDirectory(UString &path)
+{
+  if (g_IsNT)
+  {
+    DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+    path.ReleaseBuffer();
+    return (needLength > 0 && needLength <= MAX_PATH);
+  }
+  CSysString sysPath;
+  if (!MyGetCurrentDirectory(sysPath))
+    return false;
+  path = GetUnicodePath(sysPath);
+  return true;
+}
+#endif
+#endif
+
+bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, 
+  CSysString &resultPath, UINT32 &filePart)
+{
+  LPTSTR filePartPointer;
+  DWORD value = ::SearchPath(path, fileName, extension, 
+    MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
+  filePart = (UINT32)(filePartPointer - (LPCTSTR)resultPath);
+  resultPath.ReleaseBuffer();
+  return (value > 0 && value <= MAX_PATH);
+}
+
+#ifndef _UNICODE
+bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, 
+  UString &resultPath, UINT32 &filePart)
+{
+  if (g_IsNT)
+  {
+    LPWSTR filePartPointer = 0;
+    DWORD value = ::SearchPathW(path, fileName, extension, 
+        MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
+    filePart = (UINT32)(filePartPointer - (LPCWSTR)resultPath);
+    resultPath.ReleaseBuffer();
+    return (value > 0 && value <= MAX_PATH);
+  }
+  
+  CSysString sysPath;
+  if (!MySearchPath(
+      path != 0 ? (LPCTSTR)GetSysPath(path): 0,
+      fileName != 0 ? (LPCTSTR)GetSysPath(fileName): 0,
+      extension != 0 ? (LPCTSTR)GetSysPath(extension): 0,
+      sysPath, filePart))
+    return false;
+  UString resultPath1 = GetUnicodePath(sysPath.Left(filePart));
+  UString resultPath2 = GetUnicodePath(sysPath.Mid(filePart));
+  filePart = resultPath1.Length();
+  resultPath = resultPath1 + resultPath2;
+  return true;
+}
+#endif
+
+bool MyGetTempPath(CSysString &path)
+{
+  DWORD needLength = ::GetTempPath(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+  path.ReleaseBuffer();
+  return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+#ifndef _UNICODE
+bool MyGetTempPath(UString &path)
+{
+  path.Empty();
+  if (g_IsNT)
+  {
+    DWORD needLength = ::GetTempPathW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+    path.ReleaseBuffer();
+    return (needLength > 0 && needLength <= MAX_PATH);
+  }
+  CSysString sysPath;
+  if (!MyGetTempPath(sysPath))
+    return false;
+  path = GetUnicodePath(sysPath);
+  return true;
+}
+#endif
+
+UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &path)
+{
+  UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH + 1));
+  path.ReleaseBuffer();
+  return number;
+}
+
+#ifndef _UNICODE
+UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &path)
+{
+  if (g_IsNT)
+  {
+    UINT number = ::GetTempFileNameW(dirPath, prefix, 0, path.GetBuffer(MAX_PATH));
+    path.ReleaseBuffer();
+    return number;
+  }
+  CSysString sysPath;
+  UINT number = MyGetTempFileName(
+      dirPath ? (LPCTSTR)GetSysPath(dirPath): 0, 
+      prefix ? (LPCTSTR)GetSysPath(prefix): 0, 
+      sysPath);
+  path = GetUnicodePath(sysPath);
+  return number;
+}
+#endif
+
+UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath)
+{
+  Remove();
+  UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
+  if(number != 0)
+  {
+    _fileName = resultPath;
+    _mustBeDeleted = true;
+  }
+  return number;
+}
+
+bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath)
+{
+  CSysString tempPath;
+  if (!MyGetTempPath(tempPath))
+    return false;
+  if (Create(tempPath, prefix, resultPath) != 0)
+    return true;
+  if (!MyGetWindowsDirectory(tempPath))
+    return false;
+  return (Create(tempPath, prefix, resultPath) != 0);
+}
+
+bool CTempFile::Remove()
+{
+  if (!_mustBeDeleted)
+    return true;
+  _mustBeDeleted = !DeleteFileAlways(_fileName);
+  return !_mustBeDeleted;
+}
+
+#ifndef _UNICODE
+
+UINT CTempFileW::Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath)
+{
+  Remove();
+  UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
+  if(number != 0)
+  {
+    _fileName = resultPath;
+    _mustBeDeleted = true;
+  }
+  return number;
+}
+
+bool CTempFileW::Create(LPCWSTR prefix, UString &resultPath)
+{
+  UString tempPath;
+  if (!MyGetTempPath(tempPath))
+    return false;
+  if (Create(tempPath, prefix, resultPath) != 0)
+    return true;
+  if (!MyGetWindowsDirectory(tempPath))
+    return false;
+  return (Create(tempPath, prefix, resultPath) != 0);
+}
+
+bool CTempFileW::Remove()
+{
+  if (!_mustBeDeleted)
+    return true;
+  _mustBeDeleted = !DeleteFileAlways(_fileName);
+  return !_mustBeDeleted;
+}
+
+#endif
+
+bool CreateTempDirectory(LPCTSTR prefix, CSysString &dirName)
+{
+  /*
+  CSysString prefix = tempPath + prefixChars;
+  CRandom random;
+  random.Init();
+  */
+  for (;;)
+  {
+    CTempFile tempFile;
+    if (!tempFile.Create(prefix, dirName))
+      return false;
+    if (!::DeleteFile(dirName))
+      return false;
+    /*
+    UINT32 randomNumber = random.Generate();
+    TCHAR randomNumberString[32];
+    _stprintf(randomNumberString, _T("%04X"), randomNumber);
+    dirName = prefix + randomNumberString;
+    */
+    if(NFind::DoesFileExist(dirName))
+      continue;
+    if (MyCreateDirectory(dirName))
+      return true;
+    if (::GetLastError() != ERROR_ALREADY_EXISTS)
+      return false;
+  }
+}
+
+bool CTempDirectory::Create(LPCTSTR prefix)
+{ 
+  Remove();
+  return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir)); 
+}
+
+#ifndef _UNICODE
+
+bool CreateTempDirectory(LPCWSTR prefix, UString &dirName)
+{
+  /*
+  CSysString prefix = tempPath + prefixChars;
+  CRandom random;
+  random.Init();
+  */
+  for (;;)
+  {
+    CTempFileW tempFile;
+    if (!tempFile.Create(prefix, dirName))
+      return false;
+    if (!DeleteFileAlways(dirName))
+      return false;
+    /*
+    UINT32 randomNumber = random.Generate();
+    TCHAR randomNumberString[32];
+    _stprintf(randomNumberString, _T("%04X"), randomNumber);
+    dirName = prefix + randomNumberString;
+    */
+    if(NFind::DoesFileExist(dirName))
+      continue;
+    if (MyCreateDirectory(dirName))
+      return true;
+    if (::GetLastError() != ERROR_ALREADY_EXISTS)
+      return false;
+  }
+}
+
+bool CTempDirectoryW::Create(LPCWSTR prefix)
+{ 
+  Remove();
+  return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir)); 
+}
+
+#endif
+
+}}}
diff --git a/lzma/CPP/Windows/FileDir.h b/lzma/CPP/Windows/FileDir.h
new file mode 100644 (file)
index 0000000..b6f8135
--- /dev/null
@@ -0,0 +1,178 @@
+// Windows/FileDir.h
+
+#ifndef __WINDOWS_FILEDIR_H
+#define __WINDOWS_FILEDIR_H
+
+#include "../Common/MyString.h"
+#include "Defs.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NDirectory {
+
+#ifdef WIN_LONG_PATH
+bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2);
+#endif
+
+bool MyGetWindowsDirectory(CSysString &path);
+bool MyGetSystemDirectory(CSysString &path);
+#ifndef _UNICODE
+bool MyGetWindowsDirectory(UString &path);
+bool MyGetSystemDirectory(UString &path);
+#endif
+
+bool SetDirTime(LPCWSTR fileName, const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime);
+
+bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes);
+bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName);
+bool MyRemoveDirectory(LPCTSTR pathName);
+bool MyCreateDirectory(LPCTSTR pathName);
+bool CreateComplexDirectory(LPCTSTR pathName);
+bool DeleteFileAlways(LPCTSTR name);
+bool RemoveDirectoryWithSubItems(const CSysString &path);
+
+#ifndef _UNICODE
+bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes);
+bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName);
+bool MyRemoveDirectory(LPCWSTR pathName);
+bool MyCreateDirectory(LPCWSTR pathName);
+bool CreateComplexDirectory(LPCWSTR pathName);
+bool DeleteFileAlways(LPCWSTR name);
+bool RemoveDirectoryWithSubItems(const UString &path);
+#endif
+
+#ifndef _WIN32_WCE
+bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath);
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, 
+    int &fileNamePartStartIndex);
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath);
+bool GetOnlyName(LPCTSTR fileName, CSysString &resultName);
+bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName);
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, 
+    int &fileNamePartStartIndex);
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath);
+bool GetOnlyName(LPCWSTR fileName, UString &resultName);
+bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName);
+#endif
+
+inline bool MySetCurrentDirectory(LPCTSTR path)
+  { return BOOLToBool(::SetCurrentDirectory(path)); }
+bool MyGetCurrentDirectory(CSysString &resultPath);
+#ifndef _UNICODE
+bool MySetCurrentDirectory(LPCWSTR path);
+bool MyGetCurrentDirectory(UString &resultPath);
+#endif
+#endif
+
+bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, 
+  CSysString &resultPath, UINT32 &filePart);
+#ifndef _UNICODE
+bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, 
+  UString &resultPath, UINT32 &filePart);
+#endif
+
+inline bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, 
+  CSysString &resultPath)
+{
+  UINT32 value;
+  return MySearchPath(path, fileName, extension, resultPath, value);
+}
+
+#ifndef _UNICODE
+inline bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, 
+  UString &resultPath)
+{
+  UINT32 value;
+  return MySearchPath(path, fileName, extension, resultPath, value);
+}
+#endif
+
+bool MyGetTempPath(CSysString &resultPath);
+#ifndef _UNICODE
+bool MyGetTempPath(UString &resultPath);
+#endif
+
+UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath);
+#ifndef _UNICODE
+UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath);
+#endif
+
+class CTempFile
+{
+  bool _mustBeDeleted;
+  CSysString _fileName;
+public:
+  CTempFile(): _mustBeDeleted(false) {}
+  ~CTempFile() { Remove(); }
+  void DisableDeleting() { _mustBeDeleted = false; }
+  UINT Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath);
+  bool Create(LPCTSTR prefix, CSysString &resultPath);
+  bool Remove();
+};
+
+#ifdef _UNICODE
+typedef CTempFile CTempFileW;
+#else
+class CTempFileW
+{
+  bool _mustBeDeleted;
+  UString _fileName;
+public:
+  CTempFileW(): _mustBeDeleted(false) {}
+  ~CTempFileW() { Remove(); }
+  void DisableDeleting() { _mustBeDeleted = false; }
+  UINT Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath);
+  bool Create(LPCWSTR prefix, UString &resultPath);
+  bool Remove();
+};
+#endif
+
+bool CreateTempDirectory(LPCTSTR prefixChars, CSysString &dirName);
+
+class CTempDirectory
+{
+  bool _mustBeDeleted;
+  CSysString _tempDir;
+public:
+  const CSysString &GetPath() const { return _tempDir; }
+  CTempDirectory(): _mustBeDeleted(false) {}
+  ~CTempDirectory() { Remove();  }
+  bool Create(LPCTSTR prefix) ;
+  bool Remove()
+  {
+    if (!_mustBeDeleted)
+      return true;
+    _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir);
+    return (!_mustBeDeleted);
+  }
+  void DisableDeleting() { _mustBeDeleted = false; }
+};
+
+#ifdef _UNICODE
+typedef CTempDirectory CTempDirectoryW;
+#else
+class CTempDirectoryW
+{
+  bool _mustBeDeleted;
+  UString _tempDir;
+public:
+  const UString &GetPath() const { return _tempDir; }
+  CTempDirectoryW(): _mustBeDeleted(false) {}
+  ~CTempDirectoryW() { Remove();  }
+  bool Create(LPCWSTR prefix) ;
+  bool Remove()
+  {
+    if (!_mustBeDeleted)
+      return true;
+    _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir);
+    return (!_mustBeDeleted);
+  }
+  void DisableDeleting() { _mustBeDeleted = false; }
+};
+#endif
+
+}}}
+
+#endif
diff --git a/lzma/CPP/Windows/FileFind.cpp b/lzma/CPP/Windows/FileFind.cpp
new file mode 100644 (file)
index 0000000..3b5bdf7
--- /dev/null
@@ -0,0 +1,408 @@
+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+#include "FileFind.h"
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+#if defined(WIN_LONG_PATH) && defined(_UNICODE)
+#define WIN_LONG_PATH2
+#endif
+
+bool GetLongPath(LPCWSTR fileName, UString &res);
+
+namespace NFind {
+
+static const TCHAR kDot = TEXT('.');
+
+bool CFileInfo::IsDots() const
+{ 
+  if (!IsDirectory() || Name.IsEmpty())
+    return false;
+  if (Name[0] != kDot)
+    return false;
+  return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+
+#ifndef _UNICODE
+bool CFileInfoW::IsDots() const
+{ 
+  if (!IsDirectory() || Name.IsEmpty())
+    return false;
+  if (Name[0] != kDot)
+    return false;
+  return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+#endif
+
+static void ConvertWIN32_FIND_DATA_To_FileInfo(
+    const WIN32_FIND_DATA &findData,
+    CFileInfo &fileInfo)
+{
+  fileInfo.Attributes = findData.dwFileAttributes; 
+  fileInfo.CreationTime = findData.ftCreationTime;  
+  fileInfo.LastAccessTime = findData.ftLastAccessTime; 
+  fileInfo.LastWriteTime = findData.ftLastWriteTime;
+  fileInfo.Size  = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; 
+  fileInfo.Name = findData.cFileName;
+  #ifndef _WIN32_WCE
+  fileInfo.ReparseTag = findData.dwReserved0;
+  #else
+  fileInfo.ObjectID = findData.dwOID;
+  #endif
+}
+
+#ifndef _UNICODE
+
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } 
+
+static void ConvertWIN32_FIND_DATA_To_FileInfo(
+    const WIN32_FIND_DATAW &findData,
+    CFileInfoW &fileInfo)
+{
+  fileInfo.Attributes = findData.dwFileAttributes; 
+  fileInfo.CreationTime = findData.ftCreationTime;  
+  fileInfo.LastAccessTime = findData.ftLastAccessTime; 
+  fileInfo.LastWriteTime = findData.ftLastWriteTime;
+  fileInfo.Size  = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; 
+  fileInfo.Name = findData.cFileName;
+  #ifndef _WIN32_WCE
+  fileInfo.ReparseTag = findData.dwReserved0;
+  #else
+  fileInfo.ObjectID = findData.dwOID;
+  #endif
+}
+
+static void ConvertWIN32_FIND_DATA_To_FileInfo(
+    const WIN32_FIND_DATA &findData,
+    CFileInfoW &fileInfo)
+{
+  fileInfo.Attributes = findData.dwFileAttributes; 
+  fileInfo.CreationTime = findData.ftCreationTime;  
+  fileInfo.LastAccessTime = findData.ftLastAccessTime; 
+  fileInfo.LastWriteTime = findData.ftLastWriteTime;
+  fileInfo.Size  = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; 
+  fileInfo.Name = GetUnicodeString(findData.cFileName, GetCurrentCodePage());
+  #ifndef _WIN32_WCE
+  fileInfo.ReparseTag = findData.dwReserved0;
+  #else
+  fileInfo.ObjectID = findData.dwOID;
+  #endif
+}
+#endif
+  
+////////////////////////////////
+// CFindFile
+
+bool CFindFile::Close()
+{
+  if (_handle == INVALID_HANDLE_VALUE)
+    return true;
+  if (!::FindClose(_handle))
+    return false;
+  _handle = INVALID_HANDLE_VALUE;
+  return true;
+}
+
+          
+bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo)
+{
+  if (!Close())
+    return false;
+  WIN32_FIND_DATA findData;
+  _handle = ::FindFirstFile(wildcard, &findData);
+  #ifdef WIN_LONG_PATH2
+  if (_handle == INVALID_HANDLE_VALUE)
+  {
+    UString longPath;
+    if (GetLongPath(wildcard, longPath))
+      _handle = ::FindFirstFileW(longPath, &findData);
+  }
+  #endif
+  if (_handle == INVALID_HANDLE_VALUE)
+    return false;
+  ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo);
+  return true;
+}
+
+#ifndef _UNICODE
+bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo)
+{
+  if (!Close())
+    return false;
+  if (g_IsNT)
+  {
+    WIN32_FIND_DATAW findData;
+    _handle = ::FindFirstFileW(wildcard, &findData);
+    #ifdef WIN_LONG_PATH
+    if (_handle == INVALID_HANDLE_VALUE)
+    {
+      UString longPath;
+      if (GetLongPath(wildcard, longPath))
+        _handle = ::FindFirstFileW(longPath, &findData);
+    }
+    #endif
+    if (_handle != INVALID_HANDLE_VALUE)
+      ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo);
+  }
+  else
+  {
+    WIN32_FIND_DATAA findData;
+    _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, 
+        GetCurrentCodePage()), &findData);
+    if (_handle != INVALID_HANDLE_VALUE)
+      ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo);
+  }
+  return (_handle != INVALID_HANDLE_VALUE);
+}
+#endif
+
+bool CFindFile::FindNext(CFileInfo &fileInfo)
+{
+  WIN32_FIND_DATA findData;
+  bool result = BOOLToBool(::FindNextFile(_handle, &findData));
+  if (result)
+    ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo);
+  return result;
+}
+
+#ifndef _UNICODE
+bool CFindFile::FindNext(CFileInfoW &fileInfo)
+{
+  if (g_IsNT)
+  {
+    WIN32_FIND_DATAW findData;
+    if (!::FindNextFileW(_handle, &findData))
+      return false;
+    ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo);
+  }
+  else
+  {
+    WIN32_FIND_DATAA findData;
+    if (!::FindNextFileA(_handle, &findData))
+      return false;
+    ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo);
+  }
+  return true;
+}
+#endif
+
+bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo)
+{
+  CFindFile finder;
+  return finder.FindFirst(wildcard, fileInfo);
+}
+
+#ifndef _UNICODE
+bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo)
+{
+  CFindFile finder;
+  return finder.FindFirst(wildcard, fileInfo);
+}
+#endif
+
+bool DoesFileExist(LPCTSTR name)
+{
+  CFileInfo fileInfo;
+  return FindFile(name, fileInfo);
+}
+
+#ifndef _UNICODE
+bool DoesFileExist(LPCWSTR name)
+{
+  CFileInfoW fileInfo;
+  return FindFile(name, fileInfo);
+}
+#endif
+
+/////////////////////////////////////
+// CEnumerator
+
+bool CEnumerator::NextAny(CFileInfo &fileInfo)
+{
+  if (_findFile.IsHandleAllocated())
+    return _findFile.FindNext(fileInfo);
+  else
+    return _findFile.FindFirst(_wildcard, fileInfo);
+}
+
+bool CEnumerator::Next(CFileInfo &fileInfo)
+{
+  for (;;)
+  {
+    if (!NextAny(fileInfo))
+      return false;
+    if (!fileInfo.IsDots())
+      return true;
+  }
+}
+
+bool CEnumerator::Next(CFileInfo &fileInfo, bool &found)
+{
+  if (Next(fileInfo))
+  {
+    found = true;
+    return true;
+  }
+  found = false;
+  return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+#ifndef _UNICODE
+bool CEnumeratorW::NextAny(CFileInfoW &fileInfo)
+{
+  if (_findFile.IsHandleAllocated())
+    return _findFile.FindNext(fileInfo);
+  else
+    return _findFile.FindFirst(_wildcard, fileInfo);
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fileInfo)
+{
+  for (;;)
+  {
+    if (!NextAny(fileInfo))
+      return false;
+    if (!fileInfo.IsDots())
+      return true;
+  }
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found)
+{
+  if (Next(fileInfo))
+  {
+    found = true;
+    return true;
+  }
+  found = false;
+  return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+#endif
+
+////////////////////////////////
+// CFindChangeNotification
+// FindFirstChangeNotification can return 0. MSDN doesn't tell about it.
+
+bool CFindChangeNotification::Close()
+{
+  if (!IsHandleAllocated())
+    return true;
+  if (!::FindCloseChangeNotification(_handle))
+    return false;
+  _handle = INVALID_HANDLE_VALUE;
+  return true;
+}
+           
+HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter)
+{
+  _handle = ::FindFirstChangeNotification(pathName, BoolToBOOL(watchSubtree), notifyFilter);
+  #ifdef WIN_LONG_PATH2
+  if (!IsHandleAllocated())
+  {
+    UString longPath;
+    if (GetLongPath(pathName, longPath))
+      _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter);
+  }
+  #endif
+  return _handle;
+}
+
+#ifndef _UNICODE
+HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter)
+{
+  if (!g_IsNT)
+    return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter);
+  _handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter);
+  #ifdef WIN_LONG_PATH
+  if (!IsHandleAllocated())
+  {
+    UString longPath;
+    if (GetLongPath(pathName, longPath))
+      _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter);
+  }
+  #endif
+  return _handle;
+}
+#endif
+
+#ifndef _WIN32_WCE
+bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings)
+{
+  driveStrings.Clear();
+  UINT32 size = GetLogicalDriveStrings(0, NULL); 
+  if (size == 0)
+    return false;
+  CSysString buffer;
+  UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); 
+  if (newSize == 0)
+    return false;
+  if (newSize > size)
+    return false;
+  CSysString string;
+  for(UINT32 i = 0; i < newSize; i++)
+  {
+    TCHAR c = buffer[i];
+    if (c == TEXT('\0'))
+    {
+      driveStrings.Add(string);
+      string.Empty();
+    }
+    else
+      string += c;
+  }
+  if (!string.IsEmpty())
+    return false;
+  return true;
+}
+
+#ifndef _UNICODE
+bool MyGetLogicalDriveStrings(UStringVector &driveStrings)
+{
+  driveStrings.Clear();
+  if (g_IsNT)
+  {
+    UINT32 size = GetLogicalDriveStringsW(0, NULL); 
+    if (size == 0)
+      return false;
+    UString buffer;
+    UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); 
+    if (newSize == 0)
+      return false;
+    if (newSize > size)
+      return false;
+    UString string;
+    for(UINT32 i = 0; i < newSize; i++)
+    {
+      WCHAR c = buffer[i];
+      if (c == L'\0')
+      {
+        driveStrings.Add(string);
+        string.Empty();
+      }
+      else
+        string += c;
+    }
+    return string.IsEmpty();
+  }
+  CSysStringVector driveStringsA;
+  bool res = MyGetLogicalDriveStrings(driveStringsA);
+  for (int i = 0; i < driveStringsA.Size(); i++)
+    driveStrings.Add(GetUnicodeString(driveStringsA[i]));
+  return res;
+}
+#endif
+
+#endif
+
+}}}
diff --git a/lzma/CPP/Windows/FileFind.h b/lzma/CPP/Windows/FileFind.h
new file mode 100644 (file)
index 0000000..87846fd
--- /dev/null
@@ -0,0 +1,153 @@
+// Windows/FileFind.h
+
+#ifndef __WINDOWS_FILEFIND_H
+#define __WINDOWS_FILEFIND_H
+
+#include "../Common/MyString.h"
+#include "../Common/Types.h"
+#include "FileName.h"
+#include "Defs.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NFind {
+
+namespace NAttributes
+{
+  inline bool IsReadOnly(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_READONLY) != 0; }
+  inline bool IsHidden(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_HIDDEN) != 0; }
+  inline bool IsSystem(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_SYSTEM) != 0; }
+  inline bool IsDirectory(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; }
+  inline bool IsArchived(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_ARCHIVE) != 0; }
+  inline bool IsCompressed(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_COMPRESSED) != 0; }
+  inline bool IsEncrypted(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
+}
+
+class CFileInfoBase
+{ 
+  bool MatchesMask(UINT32 mask) const  { return ((Attributes & mask) != 0); }
+public:
+  DWORD Attributes;
+  FILETIME CreationTime;  
+  FILETIME LastAccessTime; 
+  FILETIME LastWriteTime;
+  UInt64 Size;
+  
+  #ifndef _WIN32_WCE
+  UINT32 ReparseTag;
+  #else
+  DWORD ObjectID; 
+  #endif
+
+  bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
+  bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
+  bool IsDirectory() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
+  bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); }
+  bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); }
+  bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); }
+  bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); }
+  bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); }
+  bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); }
+  bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); }
+  bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
+  bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
+};
+
+class CFileInfo: public CFileInfoBase
+{ 
+public:
+  CSysString Name;
+  bool IsDots() const;
+};
+
+#ifdef _UNICODE
+typedef CFileInfo CFileInfoW;
+#else
+class CFileInfoW: public CFileInfoBase
+{ 
+public:
+  UString Name;
+  bool IsDots() const;
+};
+#endif
+
+class CFindFile
+{
+  friend class CEnumerator;
+  HANDLE _handle;
+public:
+  bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; }
+  CFindFile(): _handle(INVALID_HANDLE_VALUE) {}
+  ~CFindFile() {  Close(); }
+  bool FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo);
+  bool FindNext(CFileInfo &fileInfo);
+  #ifndef _UNICODE
+  bool FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo);
+  bool FindNext(CFileInfoW &fileInfo);
+  #endif
+  bool Close();
+};
+
+bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo);
+
+bool DoesFileExist(LPCTSTR name);
+#ifndef _UNICODE
+bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo);
+bool DoesFileExist(LPCWSTR name);
+#endif
+
+class CEnumerator
+{
+  CFindFile _findFile;
+  CSysString _wildcard;
+  bool NextAny(CFileInfo &fileInfo);
+public:
+  CEnumerator(): _wildcard(NName::kAnyStringWildcard) {}
+  CEnumerator(const CSysString &wildcard): _wildcard(wildcard) {}
+  bool Next(CFileInfo &fileInfo);
+  bool Next(CFileInfo &fileInfo, bool &found);
+};
+
+#ifdef _UNICODE
+typedef CEnumerator CEnumeratorW;
+#else
+class CEnumeratorW
+{
+  CFindFile _findFile;
+  UString _wildcard;
+  bool NextAny(CFileInfoW &fileInfo);
+public:
+  CEnumeratorW(): _wildcard(NName::kAnyStringWildcard) {}
+  CEnumeratorW(const UString &wildcard): _wildcard(wildcard) {}
+  bool Next(CFileInfoW &fileInfo);
+  bool Next(CFileInfoW &fileInfo, bool &found);
+};
+#endif
+
+class CFindChangeNotification
+{
+  HANDLE _handle;
+public:
+  operator HANDLE () { return _handle; }
+  bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; }
+  CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {}
+  ~CFindChangeNotification() { Close(); }
+  bool Close();
+  HANDLE FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter);
+  #ifndef _UNICODE
+  HANDLE FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter);
+  #endif
+  bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); }
+};
+
+#ifndef _WIN32_WCE
+bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings);
+#ifndef _UNICODE
+bool MyGetLogicalDriveStrings(UStringVector &driveStrings);
+#endif
+#endif
+
+}}}
+
+#endif
+
diff --git a/lzma/CPP/Windows/FileIO.cpp b/lzma/CPP/Windows/FileIO.cpp
new file mode 100644 (file)
index 0000000..effd486
--- /dev/null
@@ -0,0 +1,318 @@
+// Windows/FileIO.cpp
+
+#include "StdAfx.h"
+
+#include "FileIO.h"
+#include "Defs.h"
+#ifdef WIN_LONG_PATH
+#include "../Common/MyString.h"
+#endif
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+#if defined(WIN_LONG_PATH) && defined(_UNICODE)
+#define WIN_LONG_PATH2
+#endif
+
+#ifdef WIN_LONG_PATH
+bool GetLongPathBase(LPCWSTR s, UString &res)
+{
+  res.Empty();
+  int len = MyStringLen(s);
+  wchar_t c = s[0];
+  if (len < 1 || c == L'\\' || c == L'.' && (len == 1 || len == 2 && s[1] == L'.'))
+    return true;
+  UString curDir;
+  bool isAbs = false;
+  if (len > 3)
+    isAbs = (s[1] == L':' && s[2] == L'\\' && (c >= L'a' && c <= L'z' || c >= L'A' && c <= L'Z'));
+
+  if (!isAbs)
+    {
+      DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, curDir.GetBuffer(MAX_PATH + 1));
+      curDir.ReleaseBuffer();
+      if (needLength == 0 || needLength > MAX_PATH)
+        return false;
+      if (curDir[curDir.Length() - 1] != L'\\')
+        curDir += L'\\';
+    }
+  res = UString(L"\\\\?\\") + curDir + s;
+  return true;
+}
+
+bool GetLongPath(LPCWSTR path, UString &longPath)
+{
+  if (GetLongPathBase(path, longPath)) 
+    return !longPath.IsEmpty();
+  return false;
+}
+#endif
+
+namespace NIO {
+
+CFileBase::~CFileBase() { Close(); }
+
+bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess,
+    DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+  if (!Close())
+    return false;
+  _handle = ::CreateFile(fileName, desiredAccess, shareMode, 
+      (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
+      flagsAndAttributes, (HANDLE)NULL);
+  #ifdef WIN_LONG_PATH2
+  if (_handle == INVALID_HANDLE_VALUE)
+  {
+    UString longPath;
+    if (GetLongPath(fileName, longPath))
+      _handle = ::CreateFileW(longPath, desiredAccess, shareMode, 
+        (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
+        flagsAndAttributes, (HANDLE)NULL);
+  }
+  #endif
+  return (_handle != INVALID_HANDLE_VALUE);
+}
+
+#ifndef _UNICODE
+bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess,
+    DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+  if (!g_IsNT)
+    return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP), 
+      desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
+  if (!Close())
+    return false;
+  _handle = ::CreateFileW(fileName, desiredAccess, shareMode, 
+    (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
+    flagsAndAttributes, (HANDLE)NULL);
+  #ifdef WIN_LONG_PATH
+  if (_handle == INVALID_HANDLE_VALUE)
+  {
+    UString longPath;
+    if (GetLongPath(fileName, longPath))
+      _handle = ::CreateFileW(longPath, desiredAccess, shareMode, 
+        (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, 
+        flagsAndAttributes, (HANDLE)NULL);
+  }
+  #endif
+  return (_handle != INVALID_HANDLE_VALUE);
+}
+#endif
+
+bool CFileBase::Close()
+{
+  if (_handle == INVALID_HANDLE_VALUE)
+    return true;
+  if (!::CloseHandle(_handle))
+    return false;
+  _handle = INVALID_HANDLE_VALUE;
+  return true;
+}
+
+bool CFileBase::GetPosition(UInt64 &position) const
+{
+  return Seek(0, FILE_CURRENT, position);
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+  DWORD sizeHigh;
+  DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);
+  if(sizeLow == 0xFFFFFFFF)
+    if(::GetLastError() != NO_ERROR)
+      return false;
+  length = (((UInt64)sizeHigh) << 32) + sizeLow;
+  return true;
+}
+
+bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const
+{
+  LARGE_INTEGER value;
+  value.QuadPart = distanceToMove;
+  value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod);
+  if (value.LowPart == 0xFFFFFFFF)
+    if(::GetLastError() != NO_ERROR) 
+      return false;
+  newPosition = value.QuadPart;
+  return true;
+}
+
+bool CFileBase::Seek(UInt64 position, UInt64 &newPosition)
+{
+  return Seek(position, FILE_BEGIN, newPosition);
+}
+
+bool CFileBase::SeekToBegin()
+{
+  UInt64 newPosition;
+  return Seek(0, newPosition);
+}
+
+bool CFileBase::SeekToEnd(UInt64 &newPosition)
+{
+  return Seek(0, FILE_END, newPosition);
+}
+
+bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const
+{
+  BY_HANDLE_FILE_INFORMATION winFileInfo;
+  if(!::GetFileInformationByHandle(_handle, &winFileInfo))
+    return false;
+  fileInfo.Attributes = winFileInfo.dwFileAttributes;
+  fileInfo.CreationTime = winFileInfo.ftCreationTime;
+  fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime;
+  fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime;
+  fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes; 
+  fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) +  winFileInfo.nFileSizeLow;
+  fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks;
+  fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow;
+  return true;
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+  { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool CInFile::OpenShared(LPCTSTR fileName, bool shareForWrite)
+{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+
+bool CInFile::Open(LPCTSTR fileName)
+  { return OpenShared(fileName, false); }
+
+#ifndef _UNICODE
+bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+  { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool CInFile::OpenShared(LPCWSTR fileName, bool shareForWrite)
+{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+
+bool CInFile::Open(LPCWSTR fileName)
+  { return OpenShared(fileName, false); }
+#endif
+
+// ReadFile and WriteFile functions in Windows have BUG:
+// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 
+// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 
+// (Insufficient system resources exist to complete the requested service).
+
+// Probably in some version of Windows there are problems with other sizes: 
+// for 32 MB (maybe also for 16 MB). 
+// And message can be "Network connection was lost"
+
+static UInt32 kChunkSizeMax = (1 << 22);
+
+bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize)
+{
+  if (size > kChunkSizeMax)
+    size = kChunkSizeMax;
+  DWORD processedLoc = 0;
+  bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
+  processedSize = (UInt32)processedLoc;
+  return res;
+}
+
+bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize)
+{
+  processedSize = 0;
+  do
+  {
+    UInt32 processedLoc = 0;
+    bool res = ReadPart(data, size, processedLoc);
+    processedSize += processedLoc;
+    if (!res)
+      return false;
+    if (processedLoc == 0)
+      return true;
+    data = (void *)((unsigned char *)data + processedLoc);
+    size -= processedLoc;
+  }
+  while (size > 0);
+  return true;
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+  { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+static inline DWORD GetCreationDisposition(bool createAlways)
+  { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
+
+bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition)
+  { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(LPCTSTR fileName, bool createAlways)
+  { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+#ifndef _UNICODE
+
+bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+  { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode,      creationDisposition, flagsAndAttributes); }
+
+bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition)
+  { return Open(fileName, FILE_SHARE_READ,  creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(LPCWSTR fileName, bool createAlways)
+  { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+#endif
+
+bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
+  { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); }
+
+bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime)
+  {  return SetTime(NULL, NULL, lastWriteTime); }
+
+bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize)
+{
+  if (size > kChunkSizeMax)
+    size = kChunkSizeMax;
+  DWORD processedLoc = 0;
+  bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
+  processedSize = (UInt32)processedLoc;
+  return res;
+}
+
+bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize)
+{
+  processedSize = 0;
+  do
+  {
+    UInt32 processedLoc = 0;
+    bool res = WritePart(data, size, processedLoc);
+    processedSize += processedLoc;
+    if (!res)
+      return false;
+    if (processedLoc == 0)
+      return true;
+    data = (const void *)((const unsigned char *)data + processedLoc);
+    size -= processedLoc;
+  }
+  while (size > 0);
+  return true;
+}
+
+bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); }
+
+bool COutFile::SetLength(UInt64 length)
+{
+  UInt64 newPosition;
+  if(!Seek(length, newPosition))
+    return false;
+  if(newPosition != length)
+    return false;
+  return SetEndOfFile();
+}
+
+}}}
diff --git a/lzma/CPP/Windows/FileIO.h b/lzma/CPP/Windows/FileIO.h
new file mode 100644 (file)
index 0000000..a7ee880
--- /dev/null
@@ -0,0 +1,99 @@
+// Windows/FileIO.h
+
+#ifndef __WINDOWS_FILEIO_H
+#define __WINDOWS_FILEIO_H
+
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NIO {
+
+struct CByHandleFileInfo
+{ 
+  DWORD    Attributes; 
+  FILETIME CreationTime; 
+  FILETIME LastAccessTime; 
+  FILETIME LastWriteTime; 
+  DWORD    VolumeSerialNumber; 
+  UInt64   Size;
+  DWORD    NumberOfLinks; 
+  UInt64   FileIndex; 
+};
+
+class CFileBase
+{
+protected:
+  HANDLE _handle;
+  bool Create(LPCTSTR fileName, DWORD desiredAccess,
+      DWORD shareMode, DWORD creationDisposition,  DWORD flagsAndAttributes);
+  #ifndef _UNICODE
+  bool Create(LPCWSTR fileName, DWORD desiredAccess,
+      DWORD shareMode, DWORD creationDisposition,  DWORD flagsAndAttributes);
+  #endif
+
+public:
+  CFileBase(): _handle(INVALID_HANDLE_VALUE){};
+  ~CFileBase();
+
+  bool Close();
+
+  bool GetPosition(UInt64 &position) const;
+  bool GetLength(UInt64 &length) const;
+
+  bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const;
+  bool Seek(UInt64 position, UInt64 &newPosition); 
+  bool SeekToBegin(); 
+  bool SeekToEnd(UInt64 &newPosition); 
+  
+  bool GetFileInformation(CByHandleFileInfo &fileInfo) const;
+};
+
+class CInFile: public CFileBase
+{
+public:
+  bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+  bool OpenShared(LPCTSTR fileName, bool shareForWrite);
+  bool Open(LPCTSTR fileName);
+  #ifndef _UNICODE
+  bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+  bool OpenShared(LPCWSTR fileName, bool shareForWrite);
+  bool Open(LPCWSTR fileName);
+  #endif
+  bool ReadPart(void *data, UInt32 size, UInt32 &processedSize);
+  bool Read(void *data, UInt32 size, UInt32 &processedSize);
+};
+
+class COutFile: public CFileBase
+{
+  // DWORD m_CreationDisposition;
+public:
+  // COutFile(): m_CreationDisposition(CREATE_NEW){};
+  bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+  bool Open(LPCTSTR fileName, DWORD creationDisposition);
+  bool Create(LPCTSTR fileName, bool createAlways);
+
+  #ifndef _UNICODE
+  bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+  bool Open(LPCWSTR fileName, DWORD creationDisposition);
+  bool Create(LPCWSTR fileName, bool createAlways);
+  #endif
+
+  /*
+  void SetOpenCreationDisposition(DWORD creationDisposition)
+    { m_CreationDisposition = creationDisposition; }
+  void SetOpenCreationDispositionCreateAlways()
+    { m_CreationDisposition = CREATE_ALWAYS; }
+  */
+
+  bool SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime);
+  bool SetLastWriteTime(const FILETIME *lastWriteTime);
+  bool WritePart(const void *data, UInt32 size, UInt32 &processedSize);
+  bool Write(const void *data, UInt32 size, UInt32 &processedSize);
+  bool SetEndOfFile();
+  bool SetLength(UInt64 length);
+};
+
+}}}
+
+#endif
diff --git a/lzma/CPP/Windows/FileMapping.cpp b/lzma/CPP/Windows/FileMapping.cpp
new file mode 100644 (file)
index 0000000..d884afb
--- /dev/null
@@ -0,0 +1,14 @@
+// Windows/FileMapping.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileMapping.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NMapping {
+
+
+
+
+}}}
\ No newline at end of file
diff --git a/lzma/CPP/Windows/FileMapping.h b/lzma/CPP/Windows/FileMapping.h
new file mode 100644 (file)
index 0000000..22db8f1
--- /dev/null
@@ -0,0 +1,50 @@
+// Windows/FileMapping.h
+
+#ifndef __WINDOWS_FILEMAPPING_H
+#define __WINDOWS_FILEMAPPING_H
+
+#include "Windows/Handle.h"
+#include "Windows/Defs.h"
+
+namespace NWindows {
+// namespace NFile {
+// namespace NMapping {
+
+class CFileMapping: public CHandle
+{
+public:
+  bool Create(HANDLE file, LPSECURITY_ATTRIBUTES attributes,
+    DWORD protect, UINT64 maximumSize, LPCTSTR name)
+  {
+    _handle = ::CreateFileMapping(file, attributes,
+      protect, DWORD(maximumSize >> 32), DWORD(maximumSize), name);
+    return (_handle != NULL);
+  }
+
+  bool Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+  {
+    _handle = ::OpenFileMapping(desiredAccess, BoolToBOOL(inheritHandle), name);
+    return (_handle != NULL);
+  }
+
+  LPVOID MapViewOfFile(DWORD desiredAccess, UINT64 fileOffset, 
+      SIZE_T numberOfBytesToMap)
+  {
+    return ::MapViewOfFile(_handle, desiredAccess, 
+        DWORD(fileOffset >> 32), DWORD(fileOffset), numberOfBytesToMap);
+  }
+
+  LPVOID MapViewOfFileEx(DWORD desiredAccess, UINT64 fileOffset, 
+      SIZE_T numberOfBytesToMap, LPVOID baseAddress)
+  {
+    return ::MapViewOfFileEx(_handle, desiredAccess, 
+      DWORD(fileOffset >> 32), DWORD(fileOffset), 
+      numberOfBytesToMap, baseAddress);
+  }
+  
+
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/Windows/FileName.cpp b/lzma/CPP/Windows/FileName.cpp
new file mode 100644 (file)
index 0000000..57c357f
--- /dev/null
@@ -0,0 +1,54 @@
+// Windows/FileName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileName.h"
+#include "Common/Wildcard.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+void NormalizeDirPathPrefix(CSysString &dirPath)
+{
+  if (dirPath.IsEmpty())
+    return;
+  if (dirPath.ReverseFind(kDirDelimiter) != dirPath.Length() - 1)
+    dirPath += kDirDelimiter;
+}
+
+#ifndef _UNICODE
+void NormalizeDirPathPrefix(UString &dirPath)
+{
+  if (dirPath.IsEmpty())
+    return;
+  if (dirPath.ReverseFind(wchar_t(kDirDelimiter)) != dirPath.Length() - 1)
+    dirPath += wchar_t(kDirDelimiter);
+}
+#endif
+
+#ifdef _WIN32
+
+const wchar_t kExtensionDelimiter = L'.';
+
+void SplitNameToPureNameAndExtension(const UString &fullName, 
+    UString &pureName, UString &extensionDelimiter, UString &extension)
+{
+  int index = fullName.ReverseFind(kExtensionDelimiter);
+  if (index < 0)
+  {
+    pureName = fullName;
+    extensionDelimiter.Empty();
+    extension.Empty();
+  }
+  else
+  {
+    pureName = fullName.Left(index);
+    extensionDelimiter = kExtensionDelimiter;
+    extension = fullName.Mid(index + 1);
+  }
+}
+
+#endif
+
+}}}
diff --git a/lzma/CPP/Windows/FileName.h b/lzma/CPP/Windows/FileName.h
new file mode 100644 (file)
index 0000000..2eab267
--- /dev/null
@@ -0,0 +1,27 @@
+// Windows/FileName.h
+
+#ifndef __WINDOWS_FILENAME_H
+#define __WINDOWS_FILENAME_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+const TCHAR kDirDelimiter = CHAR_PATH_SEPARATOR;
+const TCHAR kAnyStringWildcard = '*';
+
+void NormalizeDirPathPrefix(CSysString &dirPath); // ensures that it ended with '\\'
+#ifndef _UNICODE
+void NormalizeDirPathPrefix(UString &dirPath); // ensures that it ended with '\\'
+#endif
+
+#ifdef _WIN32
+void SplitNameToPureNameAndExtension(const UString &fullName, 
+    UString &pureName, UString &extensionDelimiter, UString &extension); 
+#endif
+
+}}}
+
+#endif
diff --git a/lzma/CPP/Windows/Handle.h b/lzma/CPP/Windows/Handle.h
new file mode 100644 (file)
index 0000000..d4d8aae
--- /dev/null
@@ -0,0 +1,37 @@
+// Windows/Handle.h
+
+#ifndef __WINDOWS_HANDLE_H
+#define __WINDOWS_HANDLE_H
+
+namespace NWindows {
+
+class CHandle
+{
+protected:
+  HANDLE _handle;
+public:
+  operator HANDLE() { return _handle; }
+  CHandle(): _handle(NULL) {}
+  ~CHandle() { Close(); }
+  bool Close()
+  {
+    if (_handle == NULL)
+      return true;
+    if (!::CloseHandle(_handle))
+      return false;
+    _handle = NULL;
+    return true;
+  }
+  void Attach(HANDLE handle) 
+    { _handle = handle; }
+  HANDLE Detach() 
+  { 
+    HANDLE handle = _handle;
+    _handle = NULL; 
+    return handle;
+  }
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/Windows/MemoryLock.cpp b/lzma/CPP/Windows/MemoryLock.cpp
new file mode 100644 (file)
index 0000000..b468e52
--- /dev/null
@@ -0,0 +1,78 @@
+// Common/MemoryLock.cpp
+
+#include "StdAfx.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+#ifndef _UNICODE
+typedef BOOL (WINAPI * OpenProcessTokenP)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
+typedef BOOL (WINAPI * LookupPrivilegeValueP)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID  lpLuid);
+typedef BOOL (WINAPI * AdjustTokenPrivilegesP)(HANDLE TokenHandle, BOOL DisableAllPrivileges,
+    PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength);
+#endif
+
+#ifdef _UNICODE
+bool EnableLockMemoryPrivilege(
+#else
+static bool EnableLockMemoryPrivilege2(HMODULE hModule,
+#endif
+bool enable)
+{
+  #ifndef _UNICODE
+  if (hModule == NULL)
+    return false;
+  OpenProcessTokenP openProcessToken = (OpenProcessTokenP)GetProcAddress(hModule, "OpenProcessToken");
+  LookupPrivilegeValueP lookupPrivilegeValue = (LookupPrivilegeValueP)GetProcAddress(hModule, "LookupPrivilegeValueA" );
+  AdjustTokenPrivilegesP adjustTokenPrivileges = (AdjustTokenPrivilegesP)GetProcAddress(hModule, "AdjustTokenPrivileges");
+  if (openProcessToken == NULL || adjustTokenPrivileges == NULL || lookupPrivilegeValue == NULL)
+    return false;
+  #endif
+
+  HANDLE token;
+  if (!
+    #ifdef _UNICODE
+    ::OpenProcessToken
+    #else
+    openProcessToken
+    #endif
+    (::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
+    return false;
+  TOKEN_PRIVILEGES tp;
+  bool res = false;
+  if (
+    #ifdef _UNICODE
+    ::LookupPrivilegeValue
+    #else
+    lookupPrivilegeValue
+    #endif
+    (NULL, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)))
+  {
+    tp.PrivilegeCount = 1;
+    tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED: 0;
+    if (
+      #ifdef _UNICODE
+      ::AdjustTokenPrivileges
+      #else
+      adjustTokenPrivileges
+      #endif
+      (token, FALSE, &tp, 0, NULL, NULL))
+      res = (GetLastError() == ERROR_SUCCESS);
+  }
+  ::CloseHandle(token);
+  return res;
+}
+
+#ifndef _UNICODE
+bool EnableLockMemoryPrivilege(bool enable)
+{
+  HMODULE hModule = LoadLibrary(TEXT("Advapi32.dll"));
+  if(hModule == NULL)
+    return false;
+  bool res = EnableLockMemoryPrivilege2(hModule, enable);
+  ::FreeLibrary(hModule);
+  return res;
+}
+#endif
+
+}}
diff --git a/lzma/CPP/Windows/MemoryLock.h b/lzma/CPP/Windows/MemoryLock.h
new file mode 100644 (file)
index 0000000..03a88b4
--- /dev/null
@@ -0,0 +1,13 @@
+// Windows/MemoryLock.h
+
+#ifndef __WINDOWS_MEMORYLOCK_H
+#define __WINDOWS_MEMORYLOCK_H
+
+namespace NWindows {
+namespace NSecurity {
+
+bool EnableLockMemoryPrivilege(bool enable = true);
+
+}}
+
+#endif 
diff --git a/lzma/CPP/Windows/PropVariant.cpp b/lzma/CPP/Windows/PropVariant.cpp
new file mode 100644 (file)
index 0000000..690e2b6
--- /dev/null
@@ -0,0 +1,312 @@
+// Windows/PropVariant.cpp
+
+#include "StdAfx.h"
+
+#include "PropVariant.h"
+
+#include "../Common/Defs.h"
+
+namespace NWindows {
+namespace NCOM {
+
+CPropVariant::CPropVariant(const PROPVARIANT& varSrc)
+{
+  vt = VT_EMPTY;
+  InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(const CPropVariant& varSrc)
+{
+  vt = VT_EMPTY;
+  InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(BSTR bstrSrc)
+{
+  vt = VT_EMPTY;
+  *this = bstrSrc;
+}
+
+CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
+{
+  vt = VT_EMPTY;
+  *this = lpszSrc;
+}
+
+CPropVariant& CPropVariant::operator=(const CPropVariant& varSrc)
+{
+  InternalCopy(&varSrc);
+  return *this;
+}
+CPropVariant& CPropVariant::operator=(const PROPVARIANT& varSrc)
+{
+  InternalCopy(&varSrc);
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
+{
+  *this = (LPCOLESTR)bstrSrc;
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
+{
+  InternalClear();
+  vt = VT_BSTR;
+  wReserved1 = 0;
+  bstrVal = ::SysAllocString(lpszSrc);
+  if (bstrVal == NULL && lpszSrc != NULL)
+  {
+    vt = VT_ERROR;
+    scode = E_OUTOFMEMORY;
+  }
+  return *this;
+}
+
+
+CPropVariant& CPropVariant::operator=(bool bSrc)
+{
+  if (vt != VT_BOOL)
+  {
+    InternalClear();
+    vt = VT_BOOL;
+  }
+  boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(UInt32 value)
+{
+  if (vt != VT_UI4)
+  {
+    InternalClear();
+    vt = VT_UI4;
+  }
+  ulVal = value;
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(UInt64 value)
+{
+  if (vt != VT_UI8)
+  {
+    InternalClear();
+    vt = VT_UI8;
+  }
+  uhVal.QuadPart = value;
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(const FILETIME &value)
+{
+  if (vt != VT_FILETIME)
+  {
+    InternalClear();
+    vt = VT_FILETIME;
+  }
+  filetime = value;
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(Int32 value)
+{
+  if (vt != VT_I4)
+  {
+    InternalClear();
+    vt = VT_I4;
+  }
+  lVal = value;
+  
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(Byte value)
+{
+  if (vt != VT_UI1)
+  {
+    InternalClear();
+    vt = VT_UI1;
+  }
+  bVal = value;
+  return *this;
+}
+
+CPropVariant& CPropVariant::operator=(Int16 value)
+{
+  if (vt != VT_I2)
+  {
+    InternalClear();
+    vt = VT_I2;
+  }
+  iVal = value;
+  return *this;
+}
+
+/*
+CPropVariant& CPropVariant::operator=(LONG value)
+{
+  if (vt != VT_I4)
+  {
+    InternalClear();
+    vt = VT_I4;
+  }
+  lVal = value;
+  return *this;
+}
+*/
+
+static HRESULT MyPropVariantClear(PROPVARIANT *propVariant) 
+{ 
+  switch(propVariant->vt)
+  {
+    case VT_UI1:
+    case VT_I1:
+    case VT_I2:
+    case VT_UI2:
+    case VT_BOOL:
+    case VT_I4:
+    case VT_UI4:
+    case VT_R4:
+    case VT_INT:
+    case VT_UINT:
+    case VT_ERROR:
+    case VT_FILETIME:
+    case VT_UI8:
+    case VT_R8:
+    case VT_CY:
+    case VT_DATE:
+      propVariant->vt = VT_EMPTY;
+      propVariant->wReserved1 = 0; 
+      return S_OK;
+  }
+  return ::VariantClear((VARIANTARG *)propVariant); 
+}
+
+HRESULT CPropVariant::Clear() 
+{ 
+  return MyPropVariantClear(this);
+}
+
+HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) 
+{ 
+  ::VariantClear((tagVARIANT *)this); 
+  switch(pSrc->vt)
+  {
+    case VT_UI1:
+    case VT_I1:
+    case VT_I2:
+    case VT_UI2:
+    case VT_BOOL:
+    case VT_I4:
+    case VT_UI4:
+    case VT_R4:
+    case VT_INT:
+    case VT_UINT:
+    case VT_ERROR:
+    case VT_FILETIME:
+    case VT_UI8:
+    case VT_R8:
+    case VT_CY:
+    case VT_DATE:
+      memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
+      return S_OK;
+  }
+  return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)(pSrc)); 
+}
+
+
+HRESULT CPropVariant::Attach(PROPVARIANT* pSrc)
+{
+  HRESULT hr = Clear();
+  if (FAILED(hr))
+    return hr;
+  memcpy(this, pSrc, sizeof(PROPVARIANT));
+  pSrc->vt = VT_EMPTY;
+  return S_OK;
+}
+
+HRESULT CPropVariant::Detach(PROPVARIANT* pDest)
+{
+  HRESULT hr = MyPropVariantClear(pDest);
+  if (FAILED(hr))
+    return hr;
+  memcpy(pDest, this, sizeof(PROPVARIANT));
+  vt = VT_EMPTY;
+  return S_OK;
+}
+
+HRESULT CPropVariant::InternalClear()
+{
+  HRESULT hr = Clear();
+  if (FAILED(hr))
+  {
+    vt = VT_ERROR;
+    scode = hr;
+  }
+  return hr;
+}
+
+void CPropVariant::InternalCopy(const PROPVARIANT* pSrc)
+{
+  HRESULT hr = Copy(pSrc);
+  if (FAILED(hr))
+  {
+    vt = VT_ERROR;
+    scode = hr;
+  }
+}
+
+int CPropVariant::Compare(const CPropVariant &a)
+{
+  if(vt != a.vt)
+    return 0; // it's mean some bug
+  switch (vt)
+  {
+    case VT_EMPTY:
+      return 0;
+    
+    /*
+    case VT_I1:
+      return MyCompare(cVal, a.cVal);
+    */
+    case VT_UI1:
+      return MyCompare(bVal, a.bVal);
+
+    case VT_I2:
+      return MyCompare(iVal, a.iVal);
+    case VT_UI2:
+      return MyCompare(uiVal, a.uiVal);
+    
+    case VT_I4:
+      return MyCompare(lVal, a.lVal);
+    /*
+    case VT_INT:
+      return MyCompare(intVal, a.intVal);
+    */
+    case VT_UI4:
+      return MyCompare(ulVal, a.ulVal);
+    /*
+    case VT_UINT:
+      return MyCompare(uintVal, a.uintVal);
+    */
+    case VT_I8:
+      return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
+    case VT_UI8:
+      return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
+
+    case VT_BOOL:    
+      return -MyCompare(boolVal, a.boolVal);
+
+    case VT_FILETIME:
+      return ::CompareFileTime(&filetime, &a.filetime);
+    case VT_BSTR:
+      return 0; // Not implemented 
+      // return MyCompare(aPropVarint.cVal);
+
+    default:
+      return 0;
+  }
+}
+
+}}
diff --git a/lzma/CPP/Windows/PropVariant.h b/lzma/CPP/Windows/PropVariant.h
new file mode 100644 (file)
index 0000000..d44215f
--- /dev/null
@@ -0,0 +1,57 @@
+// Windows/PropVariant.h
+
+#ifndef __WINDOWS_PROPVARIANT_H
+#define __WINDOWS_PROPVARIANT_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NCOM {
+
+class CPropVariant : public tagPROPVARIANT
+{
+public:
+  CPropVariant() { vt = VT_EMPTY; wReserved1 = 0; }
+  ~CPropVariant() { Clear(); }
+  CPropVariant(const PROPVARIANT& varSrc);
+  CPropVariant(const CPropVariant& varSrc);
+  CPropVariant(BSTR bstrSrc);
+  CPropVariant(LPCOLESTR lpszSrc);
+  CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); };
+  CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }
+  CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal = *(ULARGE_INTEGER*)&value; }
+  CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; }
+  CPropVariant(Int32 value) { vt = VT_I4; wReserved1 = 0; lVal = value; }
+  CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; }
+  CPropVariant(Int16 value) { vt = VT_I2; wReserved1 = 0; iVal = value; }
+  // CPropVariant(LONG value, VARTYPE vtSrc = VT_I4) { vt = vtSrc; lVal = value; }
+
+  CPropVariant& operator=(const CPropVariant& varSrc);
+  CPropVariant& operator=(const PROPVARIANT& varSrc);
+  CPropVariant& operator=(BSTR bstrSrc);
+  CPropVariant& operator=(LPCOLESTR lpszSrc);
+  CPropVariant& operator=(bool bSrc);
+  CPropVariant& operator=(UInt32 value);
+  CPropVariant& operator=(UInt64 value);
+  CPropVariant& operator=(const FILETIME &value);
+
+  CPropVariant& operator=(Int32 value);
+  CPropVariant& operator=(Byte value);
+  CPropVariant& operator=(Int16 value);
+  // CPropVariant& operator=(LONG  value);
+
+  HRESULT Clear();
+  HRESULT Copy(const PROPVARIANT* pSrc);
+  HRESULT Attach(PROPVARIANT* pSrc);
+  HRESULT Detach(PROPVARIANT* pDest);
+
+  HRESULT InternalClear();
+  void InternalCopy(const PROPVARIANT* pSrc);
+
+  int Compare(const CPropVariant &a1);
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/PropVariantConversions.cpp b/lzma/CPP/Windows/PropVariantConversions.cpp
new file mode 100644 (file)
index 0000000..993dac7
--- /dev/null
@@ -0,0 +1,150 @@
+// PropVariantConversions.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "PropVariantConversions.h"
+
+#include "Windows/Defs.h"
+
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+
+static UString ConvertUInt64ToString(UInt64 value)
+{
+  wchar_t buffer[32];
+  ConvertUInt64ToString(value, buffer);
+  return buffer;
+}
+
+static UString ConvertInt64ToString(Int64 value)
+{
+  wchar_t buffer[32];
+  ConvertInt64ToString(value, buffer);
+  return buffer;
+}
+
+static char *UIntToStringSpec(UInt32 value, char *s, int numPos)
+{
+  char temp[16];
+  int pos = 0;
+  do 
+  {
+    temp[pos++] = (char)('0' + value % 10);
+    value /= 10;
+  }
+  while (value != 0);
+  int i;
+  for (i = 0; i < numPos - pos; i++)
+    *s++ = '0';
+  do
+    *s++ = temp[--pos];
+  while (pos > 0);
+  *s = '\0';
+  return s;
+}
+
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds)
+{
+  s[0] = '\0';
+  SYSTEMTIME st;
+  if(!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
+    return false;
+  s = UIntToStringSpec(st.wYear, s, 4);
+  *s++ = '-';
+  s = UIntToStringSpec(st.wMonth, s, 2);
+  *s++ = '-';
+  s = UIntToStringSpec(st.wDay, s, 2);
+  if (includeTime)
+  {
+    *s++ = ' ';
+    s = UIntToStringSpec(st.wHour, s, 2);
+    *s++ = ':';
+    s = UIntToStringSpec(st.wMinute, s, 2);
+    if (includeSeconds)
+    {
+      *s++ = ':';
+      UIntToStringSpec(st.wSecond, s, 2);
+    }
+  }
+  /*
+  sprintf(s, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
+  if (includeTime)
+  {
+    sprintf(s + strlen(s), " %02d:%02d", st.wHour, st.wMinute);
+    if (includeSeconds)
+      sprintf(s + strlen(s), ":%02d", st.wSecond);
+  }
+  */
+  return true;
+}
+
+UString ConvertFileTimeToString(const FILETIME &fileTime, bool includeTime, bool includeSeconds)
+{
+  char s[32];
+  ConvertFileTimeToString(fileTime, s,  includeTime, includeSeconds);
+  return GetUnicodeString(s);
+}
+
+UString ConvertPropVariantToString(const PROPVARIANT &propVariant)
+{
+  switch (propVariant.vt)
+  {
+    case VT_EMPTY:
+      return UString();
+    case VT_BSTR:
+      return propVariant.bstrVal;
+    case VT_UI1:
+      return ConvertUInt64ToString(propVariant.bVal);
+    case VT_UI2:
+      return ConvertUInt64ToString(propVariant.uiVal);
+    case VT_UI4:
+      return ConvertUInt64ToString(propVariant.ulVal);
+    case VT_UI8:
+      return ConvertUInt64ToString(propVariant.uhVal.QuadPart);
+    case VT_FILETIME:
+      return ConvertFileTimeToString(propVariant.filetime, true, true);
+    /*
+    case VT_I1:
+      return ConvertInt64ToString(propVariant.cVal);
+    */
+    case VT_I2:
+      return ConvertInt64ToString(propVariant.iVal);
+    case VT_I4:
+      return ConvertInt64ToString(propVariant.lVal);
+    case VT_I8:
+      return ConvertInt64ToString(propVariant.hVal.QuadPart);
+
+    case VT_BOOL:
+      return VARIANT_BOOLToBool(propVariant.boolVal) ? L"+" : L"-";
+    default:
+      #ifndef _WIN32_WCE
+      throw 150245;
+      #else
+      return UString();
+      #endif
+  }
+}
+
+UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &propVariant)
+{
+  switch (propVariant.vt)
+  {
+    case VT_UI1:
+      return propVariant.bVal;
+    case VT_UI2:
+      return propVariant.uiVal;
+    case VT_UI4:
+      return propVariant.ulVal;
+    case VT_UI8:
+      return (UInt64)propVariant.uhVal.QuadPart;
+    default:
+      #ifndef _WIN32_WCE
+      throw 151199;
+      #else
+      return 0;
+      #endif
+  }
+}
diff --git a/lzma/CPP/Windows/PropVariantConversions.h b/lzma/CPP/Windows/PropVariantConversions.h
new file mode 100644 (file)
index 0000000..68ad961
--- /dev/null
@@ -0,0 +1,14 @@
+// Windows/PropVariantConversions.h
+
+#ifndef __PROPVARIANTCONVERSIONS_H
+#define __PROPVARIANTCONVERSIONS_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true);
+UString ConvertFileTimeToString(const FILETIME &ft, bool includeTime = true, bool includeSeconds = true);
+UString ConvertPropVariantToString(const PROPVARIANT &propVariant);
+UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &propVariant);
+
+#endif
diff --git a/lzma/CPP/Windows/StdAfx.h b/lzma/CPP/Windows/StdAfx.h
new file mode 100644 (file)
index 0000000..e7924c8
--- /dev/null
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/NewHandler.h"
+
+#endif 
diff --git a/lzma/CPP/Windows/Synchronization.cpp b/lzma/CPP/Windows/Synchronization.cpp
new file mode 100644 (file)
index 0000000..5f86d1e
--- /dev/null
@@ -0,0 +1,10 @@
+// Windows/Synchronization.cpp
+
+#include "StdAfx.h"
+
+#include "Synchronization.h"
+
+namespace NWindows {
+namespace NSynchronization {
+
+}}
diff --git a/lzma/CPP/Windows/Synchronization.h b/lzma/CPP/Windows/Synchronization.h
new file mode 100644 (file)
index 0000000..c16f7b4
--- /dev/null
@@ -0,0 +1,168 @@
+// Windows/Synchronization.h
+
+#ifndef __WINDOWS_SYNCHRONIZATION_H
+#define __WINDOWS_SYNCHRONIZATION_H
+
+#include "Defs.h"
+
+extern "C" 
+{ 
+#include "../../C/Threads.h"
+}
+
+#ifdef _WIN32
+#include "Handle.h"
+#endif
+
+namespace NWindows {
+namespace NSynchronization {
+
+class CBaseEvent
+{
+protected:
+  ::CEvent _object;
+public:
+  bool IsCreated() { return Event_IsCreated(&_object) != 0; }
+  operator HANDLE() { return _object.handle; }
+  CBaseEvent() { Event_Construct(&_object); }
+  ~CBaseEvent() { Close(); }
+  HRes Close() { return Event_Close(&_object); }
+  #ifdef _WIN32
+  HRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL,
+      LPSECURITY_ATTRIBUTES securityAttributes = NULL)
+  {
+    _object.handle = ::CreateEvent(securityAttributes, BoolToBOOL(manualReset),
+        BoolToBOOL(initiallyOwn), name);
+    if (_object.handle != 0)
+      return 0;
+    return ::GetLastError();
+  }
+  HRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+  {
+    _object.handle = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
+    if (_object.handle != 0)
+      return 0;
+    return ::GetLastError();
+  }
+  #endif
+
+  HRes Set() { return Event_Set(&_object); }
+  // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
+  HRes Reset() { return Event_Reset(&_object); }
+  HRes Lock() { return Event_Wait(&_object); }
+};
+
+class CManualResetEvent: public CBaseEvent
+{
+public:
+  HRes Create(bool initiallyOwn = false)
+  {
+    return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
+  }
+  HRes CreateIfNotCreated()
+  {
+    if (IsCreated())
+      return 0;
+    return ManualResetEvent_CreateNotSignaled(&_object);
+  }
+  #ifdef _WIN32
+  HRes CreateWithName(bool initiallyOwn, LPCTSTR name)
+  {
+    return CBaseEvent::Create(true, initiallyOwn, name);
+  }
+  #endif
+};
+
+class CAutoResetEvent: public CBaseEvent
+{
+public:
+  HRes Create()
+  {
+    return AutoResetEvent_CreateNotSignaled(&_object);
+  }
+  HRes CreateIfNotCreated()
+  {
+    if (IsCreated())
+      return 0;
+    return AutoResetEvent_CreateNotSignaled(&_object);
+  }
+};
+
+#ifdef _WIN32
+class CObject: public CHandle
+{
+public:
+  HRes Lock(DWORD timeoutInterval = INFINITE)
+    { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
+};
+class CMutex: public CObject
+{
+public:
+  HRes Create(bool initiallyOwn, LPCTSTR name = NULL,
+      LPSECURITY_ATTRIBUTES securityAttributes = NULL)
+  {
+    _handle = ::CreateMutex(securityAttributes, BoolToBOOL(initiallyOwn), name);
+    if (_handle != 0)
+      return 0;
+    return ::GetLastError();
+  }
+  HRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+  {
+    _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
+    if (_handle != 0)
+      return 0;
+    return ::GetLastError();
+  }
+  HRes Release() 
+  { 
+    return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
+  }
+};
+class CMutexLock
+{
+  CMutex *_object;
+public:
+  CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } 
+  ~CMutexLock() { _object->Release(); }
+};
+#endif
+
+class CSemaphore
+{
+  ::CSemaphore _object;
+public:
+  CSemaphore() { Semaphore_Construct(&_object); }
+  ~CSemaphore() { Close(); }
+  HRes Close() {  return Semaphore_Close(&_object); }
+  operator HANDLE() { return _object.handle; }
+  HRes Create(UInt32 initiallyCount, UInt32 maxCount)
+  {
+    return Semaphore_Create(&_object, initiallyCount, maxCount);
+  }
+  HRes Release() { return Semaphore_Release1(&_object); }
+  HRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
+  HRes Lock() { return Semaphore_Wait(&_object); }
+};
+
+class CCriticalSection
+{
+  ::CCriticalSection _object;
+public:
+  CCriticalSection() { CriticalSection_Init(&_object); }
+  ~CCriticalSection() { CriticalSection_Delete(&_object); }
+  void Enter() { CriticalSection_Enter(&_object); }
+  void Leave() { CriticalSection_Leave(&_object); }
+};
+
+class CCriticalSectionLock
+{
+  CCriticalSection *_object;
+  void Unlock()  { _object->Leave(); }
+public:
+  CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } 
+  ~CCriticalSectionLock() { Unlock(); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/System.cpp b/lzma/CPP/Windows/System.cpp
new file mode 100644 (file)
index 0000000..8e4069c
--- /dev/null
@@ -0,0 +1,64 @@
+// Windows/System.cpp
+
+#include "StdAfx.h"
+
+#include "System.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors()
+{
+  SYSTEM_INFO systemInfo;
+  GetSystemInfo(&systemInfo);
+  return (UInt32)systemInfo.dwNumberOfProcessors;
+}
+
+#if !defined(_WIN64) && defined(__GNUC__)
+
+typedef struct _MY_MEMORYSTATUSEX {
+  DWORD dwLength;
+  DWORD dwMemoryLoad;
+  DWORDLONG ullTotalPhys;
+  DWORDLONG ullAvailPhys;
+  DWORDLONG ullTotalPageFile;
+  DWORDLONG ullAvailPageFile;
+  DWORDLONG ullTotalVirtual;
+  DWORDLONG ullAvailVirtual;
+  DWORDLONG ullAvailExtendedVirtual;
+} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX;
+
+#else
+
+#define MY_MEMORYSTATUSEX MEMORYSTATUSEX
+#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX
+
+#endif
+
+typedef BOOL (WINAPI *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer);
+
+UInt64 GetRamSize()
+{
+  MY_MEMORYSTATUSEX stat;
+  stat.dwLength = sizeof(stat);
+  #ifdef _WIN64
+  if (!::GlobalMemoryStatusEx(&stat))
+    return 0;
+  return stat.ullTotalPhys;
+  #else
+  GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP)
+        ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")),
+        "GlobalMemoryStatusEx");
+  if (globalMemoryStatusEx != 0)
+    if (globalMemoryStatusEx(&stat))
+      return stat.ullTotalPhys;
+  {
+    MEMORYSTATUS stat;
+    stat.dwLength = sizeof(stat);
+    GlobalMemoryStatus(&stat);
+    return stat.dwTotalPhys;
+  }
+  #endif
+}
+
+}}
diff --git a/lzma/CPP/Windows/System.h b/lzma/CPP/Windows/System.h
new file mode 100644 (file)
index 0000000..e006715
--- /dev/null
@@ -0,0 +1,16 @@
+// Windows/System.h
+
+#ifndef __WINDOWS_SYSTEM_H
+#define __WINDOWS_SYSTEM_H
+
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors();
+UInt64 GetRamSize();
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Thread.h b/lzma/CPP/Windows/Thread.h
new file mode 100644 (file)
index 0000000..a46a568
--- /dev/null
@@ -0,0 +1,38 @@
+// Windows/Thread.h
+
+#ifndef __WINDOWS_THREAD_H
+#define __WINDOWS_THREAD_H
+
+#include "Defs.h"
+
+extern "C" 
+{ 
+#include "../../C/Threads.h"
+}
+
+namespace NWindows {
+
+class CThread
+{
+  ::CThread thread;
+public:
+  CThread() { Thread_Construct(&thread); }
+  ~CThread() { Close(); }
+  bool IsCreated() { return Thread_WasCreated(&thread) != 0; }
+  HRes Close()  { return Thread_Close(&thread); }
+  HRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+    { return Thread_Create(&thread, startAddress, parameter); }
+  HRes Wait() { return Thread_Wait(&thread); }
+  
+  #ifdef _WIN32
+  DWORD Resume() { return ::ResumeThread(thread.handle); }
+  DWORD Suspend() { return ::SuspendThread(thread.handle); }
+  bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread.handle, exitCode)); }
+  int GetPriority() { return ::GetThreadPriority(thread.handle); }
+  bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread.handle, priority)); }
+  #endif
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/Windows/Time.h b/lzma/CPP/Windows/Time.h
new file mode 100644 (file)
index 0000000..fbba2dd
--- /dev/null
@@ -0,0 +1,66 @@
+// Windows/Time.h
+
+#ifndef __WINDOWS_TIME_H
+#define __WINDOWS_TIME_H
+
+#include "Common/Types.h"
+#include "Windows/Defs.h"
+
+namespace NWindows {
+namespace NTime {
+
+inline bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime)
+{
+  return BOOLToBool(::DosDateTimeToFileTime(UInt16(dosTime >> 16), 
+      UInt16(dosTime & 0xFFFF), &fileTime));
+}
+
+const UInt32 kHighDosTime = 0xFF9FBF7D;
+const UInt32 kLowDosTime = 0x210000;
+
+inline bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime)
+{
+  WORD datePart, timePart;
+  if (!::FileTimeToDosDateTime(&fileTime, &datePart, &timePart))
+  {
+    if (fileTime.dwHighDateTime >= 0x01C00000) // 2000
+      dosTime = kHighDosTime;
+    else
+      dosTime = kLowDosTime;
+    return false;
+  }
+  dosTime = (((UInt32)datePart) << 16) + timePart;
+  return true;
+}
+
+const UInt32 kNumTimeQuantumsInSecond = 10000000;
+const UInt64 kUnixTimeStartValue = ((UInt64)kNumTimeQuantumsInSecond) * 60 * 60 * 24 * 134774;
+
+inline void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime)
+{
+  UInt64 v = kUnixTimeStartValue + ((UInt64)unixTime) * kNumTimeQuantumsInSecond;
+  fileTime.dwLowDateTime = (DWORD)v;
+  fileTime.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+inline bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime)
+{
+  UInt64 winTime = (((UInt64)fileTime.dwHighDateTime) << 32) + fileTime.dwLowDateTime;
+  if (winTime < kUnixTimeStartValue)
+  {
+    unixTime = 0;
+    return false;
+  }
+  winTime = (winTime - kUnixTimeStartValue) / kNumTimeQuantumsInSecond;
+  if (winTime > 0xFFFFFFFF)
+  {
+    unixTime = 0xFFFFFFFF;
+    return false;
+  }
+  unixTime = (UInt32)winTime;
+  return true;
+}
+
+}}
+
+#endif
diff --git a/lzma/CS/7zip/Common/CRC.cs b/lzma/CS/7zip/Common/CRC.cs
new file mode 100644 (file)
index 0000000..82cc857
--- /dev/null
@@ -0,0 +1,55 @@
+// Common/CRC.cs
+
+namespace SevenZip
+{
+       class CRC
+       {
+               public static readonly uint[] Table;
+
+               static CRC()
+               {
+                       Table = new uint[256];
+                       const uint kPoly = 0xEDB88320;
+                       for (uint i = 0; i < 256; i++)
+                       {
+                               uint r = i;
+                               for (int j = 0; j < 8; j++)
+                                       if ((r & 1) != 0)
+                                               r = (r >> 1) ^ kPoly;
+                                       else
+                                               r >>= 1;
+                               Table[i] = r;
+                       }
+               }
+
+               uint _value = 0xFFFFFFFF;
+
+               public void Init() { _value = 0xFFFFFFFF; }
+
+               public void UpdateByte(byte b)
+               {
+                       _value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
+               }
+
+               public void Update(byte[] data, uint offset, uint size)
+               {
+                       for (uint i = 0; i < size; i++)
+                               _value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);
+               }
+
+               public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
+
+               static uint CalculateDigest(byte[] data, uint offset, uint size)
+               {
+                       CRC crc = new CRC();
+                       // crc.Init();
+                       crc.Update(data, offset, size);
+                       return crc.GetDigest();
+               }
+
+               static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
+               {
+                       return (CalculateDigest(data, offset, size) == digest);
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Common/CommandLineParser.cs b/lzma/CS/7zip/Common/CommandLineParser.cs
new file mode 100644 (file)
index 0000000..8eabf59
--- /dev/null
@@ -0,0 +1,274 @@
+// CommandLineParser.cs
+
+using System;
+using System.Collections;
+
+namespace SevenZip.CommandLineParser
+{
+       public enum SwitchType
+       {
+               Simple,
+               PostMinus,
+               LimitedPostString,
+               UnLimitedPostString,
+               PostChar
+       }
+
+       public class SwitchForm
+       {
+               public string IDString;
+               public SwitchType Type;
+               public bool Multi;
+               public int MinLen;
+               public int MaxLen;
+               public string PostCharSet;
+
+               public SwitchForm(string idString, SwitchType type, bool multi,
+                       int minLen, int maxLen, string postCharSet)
+               {
+                       IDString = idString;
+                       Type = type;
+                       Multi = multi;
+                       MinLen = minLen;
+                       MaxLen = maxLen;
+                       PostCharSet = postCharSet;
+               }
+               public SwitchForm(string idString, SwitchType type, bool multi, int minLen):
+                       this(idString, type, multi, minLen, 0, "")
+               {
+               }
+               public SwitchForm(string idString, SwitchType type, bool multi):
+                       this(idString, type, multi, 0)
+               {
+               }
+       }
+
+       public class SwitchResult
+       {
+               public bool ThereIs;
+               public bool WithMinus;
+               public ArrayList PostStrings = new ArrayList();
+               public int PostCharIndex;
+               public SwitchResult()
+               {
+                       ThereIs = false;
+               }
+       }
+
+       public class Parser
+       {
+               public ArrayList NonSwitchStrings = new ArrayList();
+               SwitchResult[] _switches;
+
+               public Parser(int numSwitches)
+               {
+                       _switches = new SwitchResult[numSwitches];
+                       for (int i = 0; i < numSwitches; i++)
+                               _switches[i] = new SwitchResult();
+               }
+
+               bool ParseString(string srcString, SwitchForm[] switchForms)
+               {
+                       int len = srcString.Length;
+                       if (len == 0)
+                               return false;
+                       int pos = 0;
+                       if (!IsItSwitchChar(srcString[pos]))
+                               return false;
+                       while (pos < len)
+                       {
+                               if (IsItSwitchChar(srcString[pos]))
+                                       pos++;
+                               const int kNoLen = -1;
+                               int matchedSwitchIndex = 0;
+                               int maxLen = kNoLen;
+                               for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
+                               {
+                                       int switchLen = switchForms[switchIndex].IDString.Length;
+                                       if (switchLen <= maxLen || pos + switchLen > len)
+                                               continue;
+                                       if (String.Compare(switchForms[switchIndex].IDString, 0,
+                                                       srcString, pos, switchLen, true) == 0)
+                                       {
+                                               matchedSwitchIndex = switchIndex;
+                                               maxLen = switchLen;
+                                       }
+                               }
+                               if (maxLen == kNoLen)
+                                       throw new Exception("maxLen == kNoLen");
+                               SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
+                               SwitchForm switchForm = switchForms[matchedSwitchIndex];
+                               if ((!switchForm.Multi) && matchedSwitch.ThereIs)
+                                       throw new Exception("switch must be single");
+                               matchedSwitch.ThereIs = true;
+                               pos += maxLen;
+                               int tailSize = len - pos;
+                               SwitchType type = switchForm.Type;
+                               switch (type)
+                               {
+                                       case SwitchType.PostMinus:
+                                               {
+                                                       if (tailSize == 0)
+                                                               matchedSwitch.WithMinus = false;
+                                                       else
+                                                       {
+                                                               matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus);
+                                                               if (matchedSwitch.WithMinus)
+                                                                       pos++;
+                                                       }
+                                                       break;
+                                               }
+                                       case SwitchType.PostChar:
+                                               {
+                                                       if (tailSize < switchForm.MinLen)
+                                                               throw new Exception("switch is not full");
+                                                       string charSet = switchForm.PostCharSet;
+                                                       const int kEmptyCharValue = -1;
+                                                       if (tailSize == 0)
+                                                               matchedSwitch.PostCharIndex = kEmptyCharValue;
+                                                       else
+                                                       {
+                                                               int index = charSet.IndexOf(srcString[pos]);
+                                                               if (index < 0)
+                                                                       matchedSwitch.PostCharIndex = kEmptyCharValue;
+                                                               else
+                                                               {
+                                                                       matchedSwitch.PostCharIndex = index;
+                                                                       pos++;
+                                                               }
+                                                       }
+                                                       break;
+                                               }
+                                       case SwitchType.LimitedPostString:
+                                       case SwitchType.UnLimitedPostString:
+                                               {
+                                                       int minLen = switchForm.MinLen;
+                                                       if (tailSize < minLen)
+                                                               throw new Exception("switch is not full");
+                                                       if (type == SwitchType.UnLimitedPostString)
+                                                       {
+                                                               matchedSwitch.PostStrings.Add(srcString.Substring(pos));
+                                                               return true;
+                                                       }
+                                                       String stringSwitch = srcString.Substring(pos, minLen);
+                                                       pos += minLen;
+                                                       for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
+                                                       {
+                                                               char c = srcString[pos];
+                                                               if (IsItSwitchChar(c))
+                                                                       break;
+                                                               stringSwitch += c;
+                                                       }
+                                                       matchedSwitch.PostStrings.Add(stringSwitch);
+                                                       break;
+                                               }
+                               }
+                       }
+                       return true;
+
+               }
+
+               public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
+               {
+                       int numCommandStrings = commandStrings.Length;
+                       bool stopSwitch = false;
+                       for (int i = 0; i < numCommandStrings; i++)
+                       {
+                               string s = commandStrings[i];
+                               if (stopSwitch)
+                                       NonSwitchStrings.Add(s);
+                               else
+                                       if (s == kStopSwitchParsing)
+                                       stopSwitch = true;
+                               else
+                                       if (!ParseString(s, switchForms))
+                                       NonSwitchStrings.Add(s);
+                       }
+               }
+
+               public SwitchResult this[int index] { get { return _switches[index]; } }
+
+               public static int ParseCommand(CommandForm[] commandForms, string commandString,
+                       out string postString)
+               {
+                       for (int i = 0; i < commandForms.Length; i++)
+                       {
+                               string id = commandForms[i].IDString;
+                               if (commandForms[i].PostStringMode)
+                               {
+                                       if (commandString.IndexOf(id) == 0)
+                                       {
+                                               postString = commandString.Substring(id.Length);
+                                               return i;
+                                       }
+                               }
+                               else
+                                       if (commandString == id)
+                               {
+                                       postString = "";
+                                       return i;
+                               }
+                       }
+                       postString = "";
+                       return -1;
+               }
+
+               static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
+                       string commandString, ArrayList indices)
+               {
+                       indices.Clear();
+                       int numUsedChars = 0;
+                       for (int i = 0; i < numForms; i++)
+                       {
+                               CommandSubCharsSet charsSet = forms[i];
+                               int currentIndex = -1;
+                               int len = charsSet.Chars.Length;
+                               for (int j = 0; j < len; j++)
+                               {
+                                       char c = charsSet.Chars[j];
+                                       int newIndex = commandString.IndexOf(c);
+                                       if (newIndex >= 0)
+                                       {
+                                               if (currentIndex >= 0)
+                                                       return false;
+                                               if (commandString.IndexOf(c, newIndex + 1) >= 0)
+                                                       return false;
+                                               currentIndex = j;
+                                               numUsedChars++;
+                                       }
+                               }
+                               if (currentIndex == -1 && !charsSet.EmptyAllowed)
+                                       return false;
+                               indices.Add(currentIndex);
+                       }
+                       return (numUsedChars == commandString.Length);
+               }
+               const char kSwitchID1 = '-';
+               const char kSwitchID2 = '/';
+
+               const char kSwitchMinus = '-';
+               const string kStopSwitchParsing = "--";
+
+               static bool IsItSwitchChar(char c)
+               {
+                       return (c == kSwitchID1 || c == kSwitchID2);
+               }
+       }
+
+       public class CommandForm
+       {
+               public string IDString = "";
+               public bool PostStringMode = false;
+               public CommandForm(string idString, bool postStringMode)
+               {
+                       IDString = idString;
+                       PostStringMode = postStringMode;
+               }
+       }
+
+       class CommandSubCharsSet
+       {
+               public string Chars = "";
+               public bool EmptyAllowed = false;
+       }
+}
diff --git a/lzma/CS/7zip/Common/InBuffer.cs b/lzma/CS/7zip/Common/InBuffer.cs
new file mode 100644 (file)
index 0000000..7c51f0b
--- /dev/null
@@ -0,0 +1,72 @@
+// InBuffer.cs
+
+namespace SevenZip.Buffer
+{
+       public class InBuffer
+       {
+               byte[] m_Buffer;
+               uint m_Pos;
+               uint m_Limit;
+               uint m_BufferSize;
+               System.IO.Stream m_Stream;
+               bool m_StreamWasExhausted;
+               ulong m_ProcessedSize;
+
+               public InBuffer(uint bufferSize)
+               {
+                       m_Buffer = new byte[bufferSize];
+                       m_BufferSize = bufferSize;
+               }
+
+               public void Init(System.IO.Stream stream)
+               {
+                       m_Stream = stream;
+                       m_ProcessedSize = 0;
+                       m_Limit = 0;
+                       m_Pos = 0;
+                       m_StreamWasExhausted = false;
+               }
+
+               public bool ReadBlock()
+               {
+                       if (m_StreamWasExhausted)
+                               return false;
+                       m_ProcessedSize += m_Pos;
+                       int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
+                       m_Pos = 0;
+                       m_Limit = (uint)aNumProcessedBytes;
+                       m_StreamWasExhausted = (aNumProcessedBytes == 0);
+                       return (!m_StreamWasExhausted);
+               }
+
+
+               public void ReleaseStream()
+               {
+                       // m_Stream.Close(); 
+                       m_Stream = null;
+               }
+
+               public bool ReadByte(byte b) // check it
+               {
+                       if (m_Pos >= m_Limit)
+                               if (!ReadBlock())
+                                       return false;
+                       b = m_Buffer[m_Pos++];
+                       return true;
+               }
+
+               public byte ReadByte()
+               {
+                       // return (byte)m_Stream.ReadByte();
+                       if (m_Pos >= m_Limit)
+                               if (!ReadBlock())
+                                       return 0xFF;
+                       return m_Buffer[m_Pos++];
+               }
+
+               public ulong GetProcessedSize()
+               {
+                       return m_ProcessedSize + m_Pos;
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Common/OutBuffer.cs b/lzma/CS/7zip/Common/OutBuffer.cs
new file mode 100644 (file)
index 0000000..2da16e1
--- /dev/null
@@ -0,0 +1,47 @@
+// OutBuffer.cs
+
+namespace SevenZip.Buffer
+{
+       public class OutBuffer
+       {
+               byte[] m_Buffer;
+               uint m_Pos;
+               uint m_BufferSize;
+               System.IO.Stream m_Stream;
+               ulong m_ProcessedSize;
+
+               public OutBuffer(uint bufferSize)
+               {
+                       m_Buffer = new byte[bufferSize];
+                       m_BufferSize = bufferSize;
+               }
+
+               public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
+               public void FlushStream() { m_Stream.Flush(); }
+               public void CloseStream() { m_Stream.Close(); }
+               public void ReleaseStream() { m_Stream = null; }
+
+               public void Init()
+               {
+                       m_ProcessedSize = 0;
+                       m_Pos = 0;
+               }
+
+               public void WriteByte(byte b)
+               {
+                       m_Buffer[m_Pos++] = b;
+                       if (m_Pos >= m_BufferSize)
+                               FlushData();
+               }
+
+               public void FlushData()
+               {
+                       if (m_Pos == 0)
+                               return;
+                       m_Stream.Write(m_Buffer, 0, (int)m_Pos);
+                       m_Pos = 0;
+               }
+
+               public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZ/IMatchFinder.cs b/lzma/CS/7zip/Compress/LZ/IMatchFinder.cs
new file mode 100644 (file)
index 0000000..10ca2b3
--- /dev/null
@@ -0,0 +1,24 @@
+// IMatchFinder.cs
+
+using System;
+
+namespace SevenZip.Compression.LZ
+{
+       interface IInWindowStream
+       {
+               void SetStream(System.IO.Stream inStream);
+               void Init();
+               void ReleaseStream();
+               Byte GetIndexByte(Int32 index);
+               UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
+               UInt32 GetNumAvailableBytes();
+       }
+
+       interface IMatchFinder : IInWindowStream
+       {
+               void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
+                               UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
+               UInt32 GetMatches(UInt32[] distances);
+               void Skip(UInt32 num);
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZ/LzBinTree.cs b/lzma/CS/7zip/Compress/LZ/LzBinTree.cs
new file mode 100644 (file)
index 0000000..c1c006b
--- /dev/null
@@ -0,0 +1,367 @@
+// LzBinTree.cs
+
+using System;
+
+namespace SevenZip.Compression.LZ
+{
+       public class BinTree : InWindow, IMatchFinder
+       {
+               UInt32 _cyclicBufferPos;
+               UInt32 _cyclicBufferSize = 0;
+               UInt32 _matchMaxLen;
+
+               UInt32[] _son;
+               UInt32[] _hash;
+
+               UInt32 _cutValue = 0xFF;
+               UInt32 _hashMask;
+               UInt32 _hashSizeSum = 0;
+
+               bool HASH_ARRAY = true;
+
+               const UInt32 kHash2Size = 1 << 10;
+               const UInt32 kHash3Size = 1 << 16;
+               const UInt32 kBT2HashSize = 1 << 16;
+               const UInt32 kStartMaxLen = 1;
+               const UInt32 kHash3Offset = kHash2Size;
+               const UInt32 kEmptyHashValue = 0;
+               const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
+       
+               UInt32 kNumHashDirectBytes = 0;
+               UInt32 kMinMatchCheck = 4;
+               UInt32 kFixHashSize = kHash2Size + kHash3Size;
+               
+               public void SetType(int numHashBytes)
+               {
+                       HASH_ARRAY = (numHashBytes > 2);
+                       if (HASH_ARRAY)
+                       {
+                               kNumHashDirectBytes = 0;
+                               kMinMatchCheck = 4;
+                               kFixHashSize = kHash2Size + kHash3Size;
+                       }
+                       else
+                       {
+                               kNumHashDirectBytes = 2;
+                               kMinMatchCheck = 2 + 1;
+                               kFixHashSize = 0;
+                       }
+               }
+
+               public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
+               public new void ReleaseStream() { base.ReleaseStream(); }
+               
+               public new void Init()
+               {
+                       base.Init();
+                       for (UInt32 i = 0; i < _hashSizeSum; i++)
+                               _hash[i] = kEmptyHashValue;
+                       _cyclicBufferPos = 0;
+                       ReduceOffsets(-1);
+               }
+
+               public new void MovePos()
+               {
+                       if (++_cyclicBufferPos >= _cyclicBufferSize)
+                               _cyclicBufferPos = 0;
+                       base.MovePos();
+                       if (_pos == kMaxValForNormalize)
+                               Normalize();
+               }
+
+               public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
+
+               public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
+               { return base.GetMatchLen(index, distance, limit); }
+
+               public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
+
+               public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
+                               UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
+               {
+                       if (historySize > kMaxValForNormalize - 256)
+                               throw new Exception();
+                       _cutValue = 16 + (matchMaxLen >> 1);
+                               
+                       UInt32 windowReservSize = (historySize + keepAddBufferBefore +
+                                       matchMaxLen + keepAddBufferAfter) / 2 + 256;
+
+                       base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
+
+                       _matchMaxLen = matchMaxLen;
+
+                       UInt32 cyclicBufferSize = historySize + 1;
+                       if (_cyclicBufferSize != cyclicBufferSize)
+                               _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
+
+                       UInt32 hs = kBT2HashSize;
+
+                       if (HASH_ARRAY)
+                       {
+                               hs = historySize - 1;
+                               hs |= (hs >> 1);
+                               hs |= (hs >> 2);
+                               hs |= (hs >> 4);
+                               hs |= (hs >> 8);
+                               hs >>= 1;
+                               hs |= 0xFFFF;
+                               if (hs > (1 << 24))
+                                       hs >>= 1;
+                               _hashMask = hs;
+                               hs++;
+                               hs += kFixHashSize;
+                       }
+                       if (hs != _hashSizeSum)
+                               _hash = new UInt32[_hashSizeSum = hs];
+               }
+
+               public UInt32 GetMatches(UInt32[] distances)
+               {
+                       UInt32 lenLimit;
+                       if (_pos + _matchMaxLen <= _streamPos)
+                               lenLimit = _matchMaxLen;
+                       else
+                       {
+                               lenLimit = _streamPos - _pos;
+                               if (lenLimit < kMinMatchCheck)
+                               {
+                                       MovePos();
+                                       return 0;
+                               }
+                       }
+
+                       UInt32 offset = 0;
+                       UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+                       UInt32 cur = _bufferOffset + _pos;
+                       UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
+                       UInt32 hashValue, hash2Value = 0, hash3Value = 0;
+
+                       if (HASH_ARRAY)
+                       {
+                               UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
+                               hash2Value = temp & (kHash2Size - 1);
+                               temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
+                               hash3Value = temp & (kHash3Size - 1);
+                               hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
+                       }
+                       else
+                               hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
+
+                       UInt32 curMatch = _hash[kFixHashSize + hashValue];
+                       if (HASH_ARRAY)
+                       {
+                               UInt32 curMatch2 = _hash[hash2Value];
+                               UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
+                               _hash[hash2Value] = _pos;
+                               _hash[kHash3Offset + hash3Value] = _pos;
+                               if (curMatch2 > matchMinPos)
+                                       if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
+                                       {
+                                               distances[offset++] = maxLen = 2;
+                                               distances[offset++] = _pos - curMatch2 - 1;
+                                       }
+                               if (curMatch3 > matchMinPos)
+                                       if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
+                                       {
+                                               if (curMatch3 == curMatch2)
+                                                       offset -= 2;
+                                               distances[offset++] = maxLen = 3;
+                                               distances[offset++] = _pos - curMatch3 - 1;
+                                               curMatch2 = curMatch3;
+                                       }
+                               if (offset != 0 && curMatch2 == curMatch)
+                               {
+                                       offset -= 2;
+                                       maxLen = kStartMaxLen;
+                               }
+                       }
+
+                       _hash[kFixHashSize + hashValue] = _pos;
+
+                       UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
+                       UInt32 ptr1 = (_cyclicBufferPos << 1);
+
+                       UInt32 len0, len1;
+                       len0 = len1 = kNumHashDirectBytes;
+                       
+                       if (kNumHashDirectBytes != 0)
+                       {
+                               if (curMatch > matchMinPos)
+                               {
+                                       if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
+                                                       _bufferBase[cur + kNumHashDirectBytes])
+                                       {
+                                               distances[offset++] = maxLen = kNumHashDirectBytes;
+                                               distances[offset++] = _pos - curMatch - 1;
+                                       }
+                               }
+                       }
+                       
+                       UInt32 count = _cutValue;
+                       
+                       while(true)
+                       {
+                               if(curMatch <= matchMinPos || count-- == 0)
+                               {
+                                       _son[ptr0] = _son[ptr1] = kEmptyHashValue;
+                                       break;
+                               }
+                               UInt32 delta = _pos - curMatch;
+                               UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
+                                                       (_cyclicBufferPos - delta) :
+                                                       (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
+
+                               UInt32 pby1 = _bufferOffset + curMatch;
+                               UInt32 len = Math.Min(len0, len1);
+                               if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
+                               {
+                                       while(++len != lenLimit)
+                                               if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
+                                                       break;
+                                       if (maxLen < len)
+                                       {
+                                               distances[offset++] = maxLen = len;
+                                               distances[offset++] = delta - 1;
+                                               if (len == lenLimit)
+                                               {
+                                                       _son[ptr1] = _son[cyclicPos];
+                                                       _son[ptr0] = _son[cyclicPos + 1];
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
+                               {
+                                       _son[ptr1] = curMatch;
+                                       ptr1 = cyclicPos + 1;
+                                       curMatch = _son[ptr1];
+                                       len1 = len;
+                               }
+                               else
+                               {
+                                       _son[ptr0] = curMatch;
+                                       ptr0 = cyclicPos;
+                                       curMatch = _son[ptr0];
+                                       len0 = len;
+                               }
+                       }
+                       MovePos();
+                       return offset;
+               }
+
+               public void Skip(UInt32 num)
+               {
+                       do
+                       {
+                               UInt32 lenLimit;
+                               if (_pos + _matchMaxLen <= _streamPos)
+                                       lenLimit = _matchMaxLen;
+                               else
+                               {
+                                       lenLimit = _streamPos - _pos;
+                                       if (lenLimit < kMinMatchCheck)
+                                       {
+                                               MovePos();
+                                               continue;
+                                       }
+                               }
+
+                               UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+                               UInt32 cur = _bufferOffset + _pos;
+
+                               UInt32 hashValue;
+
+                               if (HASH_ARRAY)
+                               {
+                                       UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
+                                       UInt32 hash2Value = temp & (kHash2Size - 1);
+                                       _hash[hash2Value] = _pos;
+                                       temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
+                                       UInt32 hash3Value = temp & (kHash3Size - 1);
+                                       _hash[kHash3Offset + hash3Value] = _pos;
+                                       hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
+                               }
+                               else
+                                       hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
+
+                               UInt32 curMatch = _hash[kFixHashSize + hashValue];
+                               _hash[kFixHashSize + hashValue] = _pos;
+
+                               UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
+                               UInt32 ptr1 = (_cyclicBufferPos << 1);
+
+                               UInt32 len0, len1;
+                               len0 = len1 = kNumHashDirectBytes;
+
+                               UInt32 count = _cutValue;
+                               while (true)
+                               {
+                                       if (curMatch <= matchMinPos || count-- == 0)
+                                       {
+                                               _son[ptr0] = _son[ptr1] = kEmptyHashValue;
+                                               break;
+                                       }
+
+                                       UInt32 delta = _pos - curMatch;
+                                       UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
+                                                               (_cyclicBufferPos - delta) :
+                                                               (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
+
+                                       UInt32 pby1 = _bufferOffset + curMatch;
+                                       UInt32 len = Math.Min(len0, len1);
+                                       if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
+                                       {
+                                               while (++len != lenLimit)
+                                                       if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
+                                                               break;
+                                               if (len == lenLimit)
+                                               {
+                                                       _son[ptr1] = _son[cyclicPos];
+                                                       _son[ptr0] = _son[cyclicPos + 1];
+                                                       break;
+                                               }
+                                       }
+                                       if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
+                                       {
+                                               _son[ptr1] = curMatch;
+                                               ptr1 = cyclicPos + 1;
+                                               curMatch = _son[ptr1];
+                                               len1 = len;
+                                       }
+                                       else
+                                       {
+                                               _son[ptr0] = curMatch;
+                                               ptr0 = cyclicPos;
+                                               curMatch = _son[ptr0];
+                                               len0 = len;
+                                       }
+                               }
+                               MovePos();
+                       }
+                       while (--num != 0);
+               }
+
+               void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
+               {
+                       for (UInt32 i = 0; i < numItems; i++)
+                       {
+                               UInt32 value = items[i];
+                               if (value <= subValue)
+                                       value = kEmptyHashValue;
+                               else
+                                       value -= subValue;
+                               items[i] = value;
+                       }
+               }
+
+               void Normalize()
+               {
+                       UInt32 subValue = _pos - _cyclicBufferSize;
+                       NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
+                       NormalizeLinks(_hash, _hashSizeSum, subValue);
+                       ReduceOffsets((Int32)subValue);
+               }
+
+               public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZ/LzInWindow.cs b/lzma/CS/7zip/Compress/LZ/LzInWindow.cs
new file mode 100644 (file)
index 0000000..52d23ce
--- /dev/null
@@ -0,0 +1,132 @@
+// LzInWindow.cs
+
+using System;
+
+namespace SevenZip.Compression.LZ
+{
+       public class InWindow
+       {
+               public Byte[] _bufferBase = null; // pointer to buffer with data
+               System.IO.Stream _stream;
+               UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
+               bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
+
+               UInt32 _pointerToLastSafePosition;
+
+               public UInt32 _bufferOffset;
+
+               public UInt32 _blockSize; // Size of Allocated memory block
+               public UInt32 _pos; // offset (from _buffer) of curent byte
+               UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
+               UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
+               public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
+
+               public void MoveBlock()
+               {
+                       UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;
+                       // we need one additional byte, since MovePos moves on 1 byte.
+                       if (offset > 0)
+                               offset--;
+                       
+                       UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;
+
+                       // check negative offset ????
+                       for (UInt32 i = 0; i < numBytes; i++)
+                               _bufferBase[i] = _bufferBase[offset + i];
+                       _bufferOffset -= offset;
+               }
+
+               public virtual void ReadBlock()
+               {
+                       if (_streamEndWasReached)
+                               return;
+                       while (true)
+                       {
+                               int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);
+                               if (size == 0)
+                                       return;
+                               int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
+                               if (numReadBytes == 0)
+                               {
+                                       _posLimit = _streamPos;
+                                       UInt32 pointerToPostion = _bufferOffset + _posLimit;
+                                       if (pointerToPostion > _pointerToLastSafePosition)
+                                               _posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);
+
+                                       _streamEndWasReached = true;
+                                       return;
+                               }
+                               _streamPos += (UInt32)numReadBytes;
+                               if (_streamPos >= _pos + _keepSizeAfter)
+                                       _posLimit = _streamPos - _keepSizeAfter;
+                       }
+               }
+
+               void Free() { _bufferBase = null; }
+
+               public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
+               {
+                       _keepSizeBefore = keepSizeBefore;
+                       _keepSizeAfter = keepSizeAfter;
+                       UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
+                       if (_bufferBase == null || _blockSize != blockSize)
+                       {
+                               Free();
+                               _blockSize = blockSize;
+                               _bufferBase = new Byte[_blockSize];
+                       }
+                       _pointerToLastSafePosition = _blockSize - keepSizeAfter;
+               }
+
+               public void SetStream(System.IO.Stream stream) { _stream = stream; }
+               public void ReleaseStream() { _stream = null; }
+
+               public void Init()
+               {
+                       _bufferOffset = 0;
+                       _pos = 0;
+                       _streamPos = 0;
+                       _streamEndWasReached = false;
+                       ReadBlock();
+               }
+
+               public void MovePos()
+               {
+                       _pos++;
+                       if (_pos > _posLimit)
+                       {
+                               UInt32 pointerToPostion = _bufferOffset + _pos;
+                               if (pointerToPostion > _pointerToLastSafePosition)
+                                       MoveBlock();
+                               ReadBlock();
+                       }
+               }
+
+               public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
+
+               // index + limit have not to exceed _keepSizeAfter;
+               public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
+               {
+                       if (_streamEndWasReached)
+                               if ((_pos + index) + limit > _streamPos)
+                                       limit = _streamPos - (UInt32)(_pos + index);
+                       distance++;
+                       // Byte *pby = _buffer + (size_t)_pos + index;
+                       UInt32 pby = _bufferOffset + _pos + (UInt32)index;
+
+                       UInt32 i;
+                       for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
+                       return i;
+               }
+
+               public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
+
+               public void ReduceOffsets(Int32 subValue)
+               {
+                       _bufferOffset += (UInt32)subValue;
+                       _posLimit -= (UInt32)subValue;
+                       _pos -= (UInt32)subValue;
+                       _streamPos -= (UInt32)subValue;
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZ/LzOutWindow.cs b/lzma/CS/7zip/Compress/LZ/LzOutWindow.cs
new file mode 100644 (file)
index 0000000..c998584
--- /dev/null
@@ -0,0 +1,110 @@
+// LzOutWindow.cs
+
+namespace SevenZip.Compression.LZ
+{
+       public class OutWindow
+       {
+               byte[] _buffer = null;
+               uint _pos;
+               uint _windowSize = 0;
+               uint _streamPos;
+               System.IO.Stream _stream;
+
+               public uint TrainSize = 0;
+
+               public void Create(uint windowSize)
+               {
+                       if (_windowSize != windowSize)
+                       {
+                               // System.GC.Collect();
+                               _buffer = new byte[windowSize];
+                       }
+                       _windowSize = windowSize;
+                       _pos = 0;
+                       _streamPos = 0;
+               }
+
+               public void Init(System.IO.Stream stream, bool solid)
+               {
+                       ReleaseStream();
+                       _stream = stream;
+                       if (!solid)
+                       {
+                               _streamPos = 0;
+                               _pos = 0;
+                               TrainSize = 0;
+                       }
+               }
+       
+               public bool Train(System.IO.Stream stream)
+               {
+                       long len = stream.Length;
+                       uint size = (len < _windowSize) ? (uint)len : _windowSize;
+                       TrainSize = size;
+                       stream.Position = len - size;
+                       _streamPos = _pos = 0;
+                       while (size > 0)
+                       {
+                               uint curSize = _windowSize - _pos;
+                               if (size < curSize)
+                                       curSize = size;
+                               int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
+                               if (numReadBytes == 0)
+                                       return false;
+                               size -= (uint)numReadBytes;
+                               _pos += (uint)numReadBytes;
+                               _streamPos += (uint)numReadBytes;
+                               if (_pos == _windowSize)
+                                       _streamPos = _pos = 0;
+                       }
+                       return true;
+               }
+
+               public void ReleaseStream()
+               {
+                       Flush();
+                       _stream = null;
+               }
+
+               public void Flush()
+               {
+                       uint size = _pos - _streamPos;
+                       if (size == 0)
+                               return;
+                       _stream.Write(_buffer, (int)_streamPos, (int)size);
+                       if (_pos >= _windowSize)
+                               _pos = 0;
+                       _streamPos = _pos;
+               }
+
+               public void CopyBlock(uint distance, uint len)
+               {
+                       uint pos = _pos - distance - 1;
+                       if (pos >= _windowSize)
+                               pos += _windowSize;
+                       for (; len > 0; len--)
+                       {
+                               if (pos >= _windowSize)
+                                       pos = 0;
+                               _buffer[_pos++] = _buffer[pos++];
+                               if (_pos >= _windowSize)
+                                       Flush();
+                       }
+               }
+
+               public void PutByte(byte b)
+               {
+                       _buffer[_pos++] = b;
+                       if (_pos >= _windowSize)
+                               Flush();
+               }
+
+               public byte GetByte(uint distance)
+               {
+                       uint pos = _pos - distance - 1;
+                       if (pos >= _windowSize)
+                               pos += _windowSize;
+                       return _buffer[pos];
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZMA/LzmaBase.cs b/lzma/CS/7zip/Compress/LZMA/LzmaBase.cs
new file mode 100644 (file)
index 0000000..c7bca86
--- /dev/null
@@ -0,0 +1,76 @@
+// LzmaBase.cs
+
+namespace SevenZip.Compression.LZMA
+{
+       internal abstract class Base
+       {
+               public const uint kNumRepDistances = 4;
+               public const uint kNumStates = 12;
+
+               // static byte []kLiteralNextStates  = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
+               // static byte []kMatchNextStates    = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+               // static byte []kRepNextStates      = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+               // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+               public struct State
+               {
+                       public uint Index;
+                       public void Init() { Index = 0; }
+                       public void UpdateChar()
+                       {
+                               if (Index < 4) Index = 0;
+                               else if (Index < 10) Index -= 3;
+                               else Index -= 6;
+                       }
+                       public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
+                       public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
+                       public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
+                       public bool IsCharState() { return Index < 7; }
+               }
+
+               public const int kNumPosSlotBits = 6;
+               public const int kDicLogSizeMin = 0;
+               // public const int kDicLogSizeMax = 30;
+               // public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
+
+               public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
+               public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
+
+               public const uint kMatchMinLen = 2;
+
+               public static uint GetLenToPosState(uint len)
+               {
+                       len -= kMatchMinLen;
+                       if (len < kNumLenToPosStates)
+                               return len;
+                       return (uint)(kNumLenToPosStates - 1);
+               }
+
+               public const int kNumAlignBits = 4;
+               public const uint kAlignTableSize = 1 << kNumAlignBits;
+               public const uint kAlignMask = (kAlignTableSize - 1);
+
+               public const uint kStartPosModelIndex = 4;
+               public const uint kEndPosModelIndex = 14;
+               public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
+
+               public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
+
+               public const uint kNumLitPosStatesBitsEncodingMax = 4;
+               public const uint kNumLitContextBitsMax = 8;
+
+               public const int kNumPosStatesBitsMax = 4;
+               public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
+               public const int kNumPosStatesBitsEncodingMax = 4;
+               public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
+
+               public const int kNumLowLenBits = 3;
+               public const int kNumMidLenBits = 3;
+               public const int kNumHighLenBits = 8;
+               public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
+               public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
+               public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
+                               (1 << kNumHighLenBits);
+               public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZMA/LzmaDecoder.cs b/lzma/CS/7zip/Compress/LZMA/LzmaDecoder.cs
new file mode 100644 (file)
index 0000000..a9be39f
--- /dev/null
@@ -0,0 +1,398 @@
+// LzmaDecoder.cs
+
+using System;
+
+namespace SevenZip.Compression.LZMA
+{
+       using RangeCoder;
+
+       public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
+       {
+               class LenDecoder
+               {
+                       BitDecoder m_Choice = new BitDecoder();
+                       BitDecoder m_Choice2 = new BitDecoder();
+                       BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
+                       BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
+                       BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
+                       uint m_NumPosStates = 0;
+
+                       public void Create(uint numPosStates)
+                       {
+                               for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
+                               {
+                                       m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
+                                       m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
+                               }
+                               m_NumPosStates = numPosStates;
+                       }
+
+                       public void Init()
+                       {
+                               m_Choice.Init();
+                               for (uint posState = 0; posState < m_NumPosStates; posState++)
+                               {
+                                       m_LowCoder[posState].Init();
+                                       m_MidCoder[posState].Init();
+                               }
+                               m_Choice2.Init();
+                               m_HighCoder.Init();
+                       }
+
+                       public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
+                       {
+                               if (m_Choice.Decode(rangeDecoder) == 0)
+                                       return m_LowCoder[posState].Decode(rangeDecoder);
+                               else
+                               {
+                                       uint symbol = Base.kNumLowLenSymbols;
+                                       if (m_Choice2.Decode(rangeDecoder) == 0)
+                                               symbol += m_MidCoder[posState].Decode(rangeDecoder);
+                                       else
+                                       {
+                                               symbol += Base.kNumMidLenSymbols;
+                                               symbol += m_HighCoder.Decode(rangeDecoder);
+                                       }
+                                       return symbol;
+                               }
+                       }
+               }
+
+               class LiteralDecoder
+               {
+                       struct Decoder2
+                       {
+                               BitDecoder[] m_Decoders;
+                               public void Create() { m_Decoders = new BitDecoder[0x300]; }
+                               public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }
+
+                               public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
+                               {
+                                       uint symbol = 1;
+                                       do
+                                               symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
+                                       while (symbol < 0x100);
+                                       return (byte)symbol;
+                               }
+
+                               public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
+                               {
+                                       uint symbol = 1;
+                                       do
+                                       {
+                                               uint matchBit = (uint)(matchByte >> 7) & 1;
+                                               matchByte <<= 1;
+                                               uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
+                                               symbol = (symbol << 1) | bit;
+                                               if (matchBit != bit)
+                                               {
+                                                       while (symbol < 0x100)
+                                                               symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
+                                                       break;
+                                               }
+                                       }
+                                       while (symbol < 0x100);
+                                       return (byte)symbol;
+                               }
+                       }
+
+                       Decoder2[] m_Coders;
+                       int m_NumPrevBits;
+                       int m_NumPosBits;
+                       uint m_PosMask;
+
+                       public void Create(int numPosBits, int numPrevBits)
+                       {
+                               if (m_Coders != null && m_NumPrevBits == numPrevBits &&
+                                       m_NumPosBits == numPosBits)
+                                       return;
+                               m_NumPosBits = numPosBits;
+                               m_PosMask = ((uint)1 << numPosBits) - 1;
+                               m_NumPrevBits = numPrevBits;
+                               uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
+                               m_Coders = new Decoder2[numStates];
+                               for (uint i = 0; i < numStates; i++)
+                                       m_Coders[i].Create();
+                       }
+
+                       public void Init()
+                       {
+                               uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
+                               for (uint i = 0; i < numStates; i++)
+                                       m_Coders[i].Init();
+                       }
+
+                       uint GetState(uint pos, byte prevByte)
+                       { return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
+
+                       public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
+                       { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
+
+                       public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
+                       { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
+               };
+
+               LZ.OutWindow m_OutWindow = new LZ.OutWindow();
+               RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();
+
+               BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
+               BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
+               BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
+               BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
+               BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
+               BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
+
+               BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
+               BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
+
+               BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
+
+               LenDecoder m_LenDecoder = new LenDecoder();
+               LenDecoder m_RepLenDecoder = new LenDecoder();
+
+               LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
+
+               uint m_DictionarySize;
+               uint m_DictionarySizeCheck;
+
+               uint m_PosStateMask;
+
+               public Decoder()
+               {
+                       m_DictionarySize = 0xFFFFFFFF;
+                       for (int i = 0; i < Base.kNumLenToPosStates; i++)
+                               m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
+               }
+
+               void SetDictionarySize(uint dictionarySize)
+               {
+                       if (m_DictionarySize != dictionarySize)
+                       {
+                               m_DictionarySize = dictionarySize;
+                               m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
+                               uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
+                               m_OutWindow.Create(blockSize);
+                       }
+               }
+
+               void SetLiteralProperties(int lp, int lc)
+               {
+                       if (lp > 8)
+                               throw new InvalidParamException();
+                       if (lc > 8)
+                               throw new InvalidParamException();
+                       m_LiteralDecoder.Create(lp, lc);
+               }
+
+               void SetPosBitsProperties(int pb)
+               {
+                       if (pb > Base.kNumPosStatesBitsMax)
+                               throw new InvalidParamException();
+                       uint numPosStates = (uint)1 << pb;
+                       m_LenDecoder.Create(numPosStates);
+                       m_RepLenDecoder.Create(numPosStates);
+                       m_PosStateMask = numPosStates - 1;
+               }
+
+               bool _solid = false;
+               void Init(System.IO.Stream inStream, System.IO.Stream outStream)
+               {
+                       m_RangeDecoder.Init(inStream);
+                       m_OutWindow.Init(outStream, _solid);
+
+                       uint i;
+                       for (i = 0; i < Base.kNumStates; i++)
+                       {
+                               for (uint j = 0; j <= m_PosStateMask; j++)
+                               {
+                                       uint index = (i << Base.kNumPosStatesBitsMax) + j;
+                                       m_IsMatchDecoders[index].Init();
+                                       m_IsRep0LongDecoders[index].Init();
+                               }
+                               m_IsRepDecoders[i].Init();
+                               m_IsRepG0Decoders[i].Init();
+                               m_IsRepG1Decoders[i].Init();
+                               m_IsRepG2Decoders[i].Init();
+                       }
+
+                       m_LiteralDecoder.Init();
+                       for (i = 0; i < Base.kNumLenToPosStates; i++)
+                               m_PosSlotDecoder[i].Init();
+                       // m_PosSpecDecoder.Init();
+                       for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
+                               m_PosDecoders[i].Init();
+
+                       m_LenDecoder.Init();
+                       m_RepLenDecoder.Init();
+                       m_PosAlignDecoder.Init();
+               }
+
+               public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
+                       Int64 inSize, Int64 outSize, ICodeProgress progress)
+               {
+                       Init(inStream, outStream);
+
+                       Base.State state = new Base.State();
+                       state.Init();
+                       uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
+
+                       UInt64 nowPos64 = 0;
+                       UInt64 outSize64 = (UInt64)outSize;
+                       if (nowPos64 < outSize64)
+                       {
+                               if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
+                                       throw new DataErrorException();
+                               state.UpdateChar();
+                               byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
+                               m_OutWindow.PutByte(b);
+                               nowPos64++;
+                       }
+                       while (nowPos64 < outSize64)
+                       {
+                               // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
+                                       // while(nowPos64 < next)
+                               {
+                                       uint posState = (uint)nowPos64 & m_PosStateMask;
+                                       if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
+                                       {
+                                               byte b;
+                                               byte prevByte = m_OutWindow.GetByte(0);
+                                               if (!state.IsCharState())
+                                                       b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
+                                                               (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));
+                                               else
+                                                       b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
+                                               m_OutWindow.PutByte(b);
+                                               state.UpdateChar();
+                                               nowPos64++;
+                                       }
+                                       else
+                                       {
+                                               uint len;
+                                               if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
+                                               {
+                                                       if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
+                                                       {
+                                                               if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
+                                                               {
+                                                                       state.UpdateShortRep();
+                                                                       m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
+                                                                       nowPos64++;
+                                                                       continue;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               UInt32 distance;
+                                                               if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
+                                                               {
+                                                                       distance = rep1;
+                                                               }
+                                                               else
+                                                               {
+                                                                       if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
+                                                                               distance = rep2;
+                                                                       else
+                                                                       {
+                                                                               distance = rep3;
+                                                                               rep3 = rep2;
+                                                                       }
+                                                                       rep2 = rep1;
+                                                               }
+                                                               rep1 = rep0;
+                                                               rep0 = distance;
+                                                       }
+                                                       len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
+                                                       state.UpdateRep();
+                                               }
+                                               else
+                                               {
+                                                       rep3 = rep2;
+                                                       rep2 = rep1;
+                                                       rep1 = rep0;
+                                                       len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
+                                                       state.UpdateMatch();
+                                                       uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
+                                                       if (posSlot >= Base.kStartPosModelIndex)
+                                                       {
+                                                               int numDirectBits = (int)((posSlot >> 1) - 1);
+                                                               rep0 = ((2 | (posSlot & 1)) << numDirectBits);
+                                                               if (posSlot < Base.kEndPosModelIndex)
+                                                                       rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
+                                                                                       rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
+                                                               else
+                                                               {
+                                                                       rep0 += (m_RangeDecoder.DecodeDirectBits(
+                                                                               numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
+                                                                       rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
+                                                               }
+                                                       }
+                                                       else
+                                                               rep0 = posSlot;
+                                               }
+                                               if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
+                                               {
+                                                       if (rep0 == 0xFFFFFFFF)
+                                                               break;
+                                                       throw new DataErrorException();
+                                               }
+                                               m_OutWindow.CopyBlock(rep0, len);
+                                               nowPos64 += len;
+                                       }
+                               }
+                       }
+                       m_OutWindow.Flush();
+                       m_OutWindow.ReleaseStream();
+                       m_RangeDecoder.ReleaseStream();
+               }
+
+               public void SetDecoderProperties(byte[] properties)
+               {
+                       if (properties.Length < 5)
+                               throw new InvalidParamException();
+                       int lc = properties[0] % 9;
+                       int remainder = properties[0] / 9;
+                       int lp = remainder % 5;
+                       int pb = remainder / 5;
+                       if (pb > Base.kNumPosStatesBitsMax)
+                               throw new InvalidParamException();
+                       UInt32 dictionarySize = 0;
+                       for (int i = 0; i < 4; i++)
+                               dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
+                       SetDictionarySize(dictionarySize);
+                       SetLiteralProperties(lp, lc);
+                       SetPosBitsProperties(pb);
+               }
+
+               public bool Train(System.IO.Stream stream)
+               {
+                       _solid = true;
+                       return m_OutWindow.Train(stream);
+               }
+
+               /*
+               public override bool CanRead { get { return true; }}
+               public override bool CanWrite { get { return true; }}
+               public override bool CanSeek { get { return true; }}
+               public override long Length { get { return 0; }}
+               public override long Position
+               {
+                       get { return 0; }
+                       set { }
+               }
+               public override void Flush() { }
+               public override int Read(byte[] buffer, int offset, int count) 
+               {
+                       return 0;
+               }
+               public override void Write(byte[] buffer, int offset, int count)
+               {
+               }
+               public override long Seek(long offset, System.IO.SeekOrigin origin)
+               {
+                       return 0;
+               }
+               public override void SetLength(long value) {}
+               */
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LZMA/LzmaEncoder.cs b/lzma/CS/7zip/Compress/LZMA/LzmaEncoder.cs
new file mode 100644 (file)
index 0000000..a8d6723
--- /dev/null
@@ -0,0 +1,1480 @@
+// LzmaEncoder.cs
+
+using System;
+
+namespace SevenZip.Compression.LZMA
+{
+       using RangeCoder;
+
+       public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
+       {
+               enum EMatchFinderType
+               {
+                       BT2,
+                       BT4,
+               };
+
+               const UInt32 kIfinityPrice = 0xFFFFFFF;
+
+               static Byte[] g_FastPos = new Byte[1 << 11];
+
+               static Encoder()
+               {
+                       const Byte kFastSlots = 22;
+                       int c = 2;
+                       g_FastPos[0] = 0;
+                       g_FastPos[1] = 1;
+                       for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
+                       {
+                               UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1));
+                               for (UInt32 j = 0; j < k; j++, c++)
+                                       g_FastPos[c] = slotFast;
+                       }
+               }
+
+               static UInt32 GetPosSlot(UInt32 pos)
+               {
+                       if (pos < (1 << 11))
+                               return g_FastPos[pos];
+                       if (pos < (1 << 21))
+                               return (UInt32)(g_FastPos[pos >> 10] + 20);
+                       return (UInt32)(g_FastPos[pos >> 20] + 40);
+               }
+
+               static UInt32 GetPosSlot2(UInt32 pos)
+               {
+                       if (pos < (1 << 17))
+                               return (UInt32)(g_FastPos[pos >> 6] + 12);
+                       if (pos < (1 << 27))
+                               return (UInt32)(g_FastPos[pos >> 16] + 32);
+                       return (UInt32)(g_FastPos[pos >> 26] + 52);
+               }
+
+               Base.State _state = new Base.State();
+               Byte _previousByte;
+               UInt32[] _repDistances = new UInt32[Base.kNumRepDistances];
+
+               void BaseInit()
+               {
+                       _state.Init();
+                       _previousByte = 0;
+                       for (UInt32 i = 0; i < Base.kNumRepDistances; i++)
+                               _repDistances[i] = 0;
+               }
+
+               const int kDefaultDictionaryLogSize = 22;
+               const UInt32 kNumFastBytesDefault = 0x20;
+
+               class LiteralEncoder
+               {
+                       public struct Encoder2
+                       {
+                               BitEncoder[] m_Encoders;
+
+                               public void Create() { m_Encoders = new BitEncoder[0x300]; }
+
+                               public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); }
+
+                               public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol)
+                               {
+                                       uint context = 1;
+                                       for (int i = 7; i >= 0; i--)
+                                       {
+                                               uint bit = (uint)((symbol >> i) & 1);
+                                               m_Encoders[context].Encode(rangeEncoder, bit);
+                                               context = (context << 1) | bit;
+                                       }
+                               }
+
+                               public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)
+                               {
+                                       uint context = 1;
+                                       bool same = true;
+                                       for (int i = 7; i >= 0; i--)
+                                       {
+                                               uint bit = (uint)((symbol >> i) & 1);
+                                               uint state = context;
+                                               if (same)
+                                               {
+                                                       uint matchBit = (uint)((matchByte >> i) & 1);
+                                                       state += ((1 + matchBit) << 8);
+                                                       same = (matchBit == bit);
+                                               }
+                                               m_Encoders[state].Encode(rangeEncoder, bit);
+                                               context = (context << 1) | bit;
+                                       }
+                               }
+
+                               public uint GetPrice(bool matchMode, byte matchByte, byte symbol)
+                               {
+                                       uint price = 0;
+                                       uint context = 1;
+                                       int i = 7;
+                                       if (matchMode)
+                                       {
+                                               for (; i >= 0; i--)
+                                               {
+                                                       uint matchBit = (uint)(matchByte >> i) & 1;
+                                                       uint bit = (uint)(symbol >> i) & 1;
+                                                       price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit);
+                                                       context = (context << 1) | bit;
+                                                       if (matchBit != bit)
+                                                       {
+                                                               i--;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       for (; i >= 0; i--)
+                                       {
+                                               uint bit = (uint)(symbol >> i) & 1;
+                                               price += m_Encoders[context].GetPrice(bit);
+                                               context = (context << 1) | bit;
+                                       }
+                                       return price;
+                               }
+                       }
+
+                       Encoder2[] m_Coders;
+                       int m_NumPrevBits;
+                       int m_NumPosBits;
+                       uint m_PosMask;
+
+                       public void Create(int numPosBits, int numPrevBits)
+                       {
+                               if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
+                                       return;
+                               m_NumPosBits = numPosBits;
+                               m_PosMask = ((uint)1 << numPosBits) - 1;
+                               m_NumPrevBits = numPrevBits;
+                               uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
+                               m_Coders = new Encoder2[numStates];
+                               for (uint i = 0; i < numStates; i++)
+                                       m_Coders[i].Create();
+                       }
+
+                       public void Init()
+                       {
+                               uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
+                               for (uint i = 0; i < numStates; i++)
+                                       m_Coders[i].Init();
+                       }
+
+                       public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte)
+                       { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; }
+               }
+
+               class LenEncoder
+               {
+                       RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder();
+                       RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder();
+                       RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
+                       RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
+                       RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits);
+
+                       public LenEncoder()
+                       {
+                               for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
+                               {
+                                       _lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits);
+                                       _midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits);
+                               }
+                       }
+
+                       public void Init(UInt32 numPosStates)
+                       {
+                               _choice.Init();
+                               _choice2.Init();
+                               for (UInt32 posState = 0; posState < numPosStates; posState++)
+                               {
+                                       _lowCoder[posState].Init();
+                                       _midCoder[posState].Init();
+                               }
+                               _highCoder.Init();
+                       }
+
+                       public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
+                       {
+                               if (symbol < Base.kNumLowLenSymbols)
+                               {
+                                       _choice.Encode(rangeEncoder, 0);
+                                       _lowCoder[posState].Encode(rangeEncoder, symbol);
+                               }
+                               else
+                               {
+                                       symbol -= Base.kNumLowLenSymbols;
+                                       _choice.Encode(rangeEncoder, 1);
+                                       if (symbol < Base.kNumMidLenSymbols)
+                                       {
+                                               _choice2.Encode(rangeEncoder, 0);
+                                               _midCoder[posState].Encode(rangeEncoder, symbol);
+                                       }
+                                       else
+                                       {
+                                               _choice2.Encode(rangeEncoder, 1);
+                                               _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
+                                       }
+                               }
+                       }
+
+                       public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st)
+                       {
+                               UInt32 a0 = _choice.GetPrice0();
+                               UInt32 a1 = _choice.GetPrice1();
+                               UInt32 b0 = a1 + _choice2.GetPrice0();
+                               UInt32 b1 = a1 + _choice2.GetPrice1();
+                               UInt32 i = 0;
+                               for (i = 0; i < Base.kNumLowLenSymbols; i++)
+                               {
+                                       if (i >= numSymbols)
+                                               return;
+                                       prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
+                               }
+                               for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
+                               {
+                                       if (i >= numSymbols)
+                                               return;
+                                       prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
+                               }
+                               for (; i < numSymbols; i++)
+                                       prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
+                       }
+               };
+
+               const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
+
+               class LenPriceTableEncoder : LenEncoder
+               {
+                       UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax];
+                       UInt32 _tableSize;
+                       UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax];
+
+                       public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
+
+                       public UInt32 GetPrice(UInt32 symbol, UInt32 posState)
+                       {
+                               return _prices[posState * Base.kNumLenSymbols + symbol];
+                       }
+
+                       void UpdateTable(UInt32 posState)
+                       {
+                               SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
+                               _counters[posState] = _tableSize;
+                       }
+
+                       public void UpdateTables(UInt32 numPosStates)
+                       {
+                               for (UInt32 posState = 0; posState < numPosStates; posState++)
+                                       UpdateTable(posState);
+                       }
+
+                       public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
+                       {
+                               base.Encode(rangeEncoder, symbol, posState);
+                               if (--_counters[posState] == 0)
+                                       UpdateTable(posState);
+                       }
+               }
+
+               const UInt32 kNumOpts = 1 << 12;
+               class Optimal
+               {
+                       public Base.State State;
+
+                       public bool Prev1IsChar;
+                       public bool Prev2;
+
+                       public UInt32 PosPrev2;
+                       public UInt32 BackPrev2;
+
+                       public UInt32 Price;
+                       public UInt32 PosPrev;
+                       public UInt32 BackPrev;
+
+                       public UInt32 Backs0;
+                       public UInt32 Backs1;
+                       public UInt32 Backs2;
+                       public UInt32 Backs3;
+
+                       public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; }
+                       public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
+                       public bool IsShortRep() { return (BackPrev == 0); }
+               };
+               Optimal[] _optimum = new Optimal[kNumOpts];
+               LZ.IMatchFinder _matchFinder = null;
+               RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder();
+
+               RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
+               RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates];
+               RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates];
+               RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates];
+               RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates];
+               RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
+
+               RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates];
+               
+               RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
+               RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits);
+
+               LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
+               LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
+
+               LiteralEncoder _literalEncoder = new LiteralEncoder();
+
+               UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2];
+               
+               UInt32 _numFastBytes = kNumFastBytesDefault;
+               UInt32 _longestMatchLength;
+               UInt32 _numDistancePairs;
+
+               UInt32 _additionalOffset;
+
+               UInt32 _optimumEndIndex;
+               UInt32 _optimumCurrentIndex;
+
+               bool _longestMatchWasFound;
+
+               UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)];
+               UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits];
+               UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize];
+               UInt32 _alignPriceCount;
+
+               UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2);
+
+               int _posStateBits = 2;
+               UInt32 _posStateMask = (4 - 1);
+               int _numLiteralPosStateBits = 0;
+               int _numLiteralContextBits = 3;
+
+               UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize);
+               UInt32 _dictionarySizePrev = 0xFFFFFFFF;
+               UInt32 _numFastBytesPrev = 0xFFFFFFFF;
+
+               Int64 nowPos64;
+               bool _finished;
+               System.IO.Stream _inStream;
+
+               EMatchFinderType _matchFinderType = EMatchFinderType.BT4;
+               bool _writeEndMark = false;
+               
+               bool _needReleaseMFStream;
+
+               void Create()
+               {
+                       if (_matchFinder == null)
+                       {
+                               LZ.BinTree bt = new LZ.BinTree();
+                               int numHashBytes = 4;
+                               if (_matchFinderType == EMatchFinderType.BT2)
+                                       numHashBytes = 2;
+                               bt.SetType(numHashBytes);
+                               _matchFinder = bt;
+                       }
+                       _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
+
+                       if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
+                               return;
+                       _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
+                       _dictionarySizePrev = _dictionarySize;
+                       _numFastBytesPrev = _numFastBytes;
+               }
+
+               public Encoder()
+               {
+                       for (int i = 0; i < kNumOpts; i++)
+                               _optimum[i] = new Optimal();
+                       for (int i = 0; i < Base.kNumLenToPosStates; i++)
+                               _posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits);
+               }
+
+               void SetWriteEndMarkerMode(bool writeEndMarker)
+               {
+                       _writeEndMark = writeEndMarker;
+               }
+
+               void Init()
+               {
+                       BaseInit();
+                       _rangeEncoder.Init();
+
+                       uint i;
+                       for (i = 0; i < Base.kNumStates; i++)
+                       {
+                               for (uint j = 0; j <= _posStateMask; j++)
+                               {
+                                       uint complexState = (i << Base.kNumPosStatesBitsMax) + j;
+                                       _isMatch[complexState].Init();
+                                       _isRep0Long[complexState].Init();
+                               }
+                               _isRep[i].Init();
+                               _isRepG0[i].Init();
+                               _isRepG1[i].Init();
+                               _isRepG2[i].Init();
+                       }
+                       _literalEncoder.Init();
+                       for (i = 0; i < Base.kNumLenToPosStates; i++)
+                               _posSlotEncoder[i].Init();
+                       for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
+                               _posEncoders[i].Init();
+
+                       _lenEncoder.Init((UInt32)1 << _posStateBits);
+                       _repMatchLenEncoder.Init((UInt32)1 << _posStateBits);
+
+                       _posAlignEncoder.Init();
+
+                       _longestMatchWasFound = false;
+                       _optimumEndIndex = 0;
+                       _optimumCurrentIndex = 0;
+                       _additionalOffset = 0;
+               }
+
+               void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs)
+               {
+                       lenRes = 0;
+                       numDistancePairs = _matchFinder.GetMatches(_matchDistances);
+                       if (numDistancePairs > 0)
+                       {
+                               lenRes = _matchDistances[numDistancePairs - 2];
+                               if (lenRes == _numFastBytes)
+                                       lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1],
+                                               Base.kMatchMaxLen - lenRes);
+                       }
+                       _additionalOffset++;
+               }
+
+
+               void MovePos(UInt32 num)
+               {
+                       if (num > 0)
+                       {
+                               _matchFinder.Skip(num);
+                               _additionalOffset += num;
+                       }
+               }
+
+               UInt32 GetRepLen1Price(Base.State state, UInt32 posState)
+               {
+                       return _isRepG0[state.Index].GetPrice0() +
+                                       _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0();
+               }
+
+               UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState)
+               {
+                       UInt32 price;
+                       if (repIndex == 0)
+                       {
+                               price = _isRepG0[state.Index].GetPrice0();
+                               price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
+                       }
+                       else
+                       {
+                               price = _isRepG0[state.Index].GetPrice1();
+                               if (repIndex == 1)
+                                       price += _isRepG1[state.Index].GetPrice0();
+                               else
+                               {
+                                       price += _isRepG1[state.Index].GetPrice1();
+                                       price += _isRepG2[state.Index].GetPrice(repIndex - 2);
+                               }
+                       }
+                       return price;
+               }
+
+               UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState)
+               {
+                       UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
+                       return price + GetPureRepPrice(repIndex, state, posState);
+               }
+       
+               UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState)
+               {
+                       UInt32 price;
+                       UInt32 lenToPosState = Base.GetLenToPosState(len);
+                       if (pos < Base.kNumFullDistances)
+                               price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
+                       else
+                               price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
+                                       _alignPrices[pos & Base.kAlignMask];
+                       return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
+               }
+
+               UInt32 Backward(out UInt32 backRes, UInt32 cur)
+               {
+                       _optimumEndIndex = cur;
+                       UInt32 posMem = _optimum[cur].PosPrev;
+                       UInt32 backMem = _optimum[cur].BackPrev;
+                       do
+                       {
+                               if (_optimum[cur].Prev1IsChar)
+                               {
+                                       _optimum[posMem].MakeAsChar();
+                                       _optimum[posMem].PosPrev = posMem - 1;
+                                       if (_optimum[cur].Prev2)
+                                       {
+                                               _optimum[posMem - 1].Prev1IsChar = false;
+                                               _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
+                                               _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
+                                       }
+                               }
+                               UInt32 posPrev = posMem;
+                               UInt32 backCur = backMem;
+
+                               backMem = _optimum[posPrev].BackPrev;
+                               posMem = _optimum[posPrev].PosPrev;
+
+                               _optimum[posPrev].BackPrev = backCur;
+                               _optimum[posPrev].PosPrev = cur;
+                               cur = posPrev;
+                       }
+                       while (cur > 0);
+                       backRes = _optimum[0].BackPrev;
+                       _optimumCurrentIndex = _optimum[0].PosPrev;
+                       return _optimumCurrentIndex;
+               }
+
+               UInt32[] reps = new UInt32[Base.kNumRepDistances];
+               UInt32[] repLens = new UInt32[Base.kNumRepDistances];
+
+
+               UInt32 GetOptimum(UInt32 position, out UInt32 backRes)
+               {
+                       if (_optimumEndIndex != _optimumCurrentIndex)
+                       {
+                               UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
+                               backRes = _optimum[_optimumCurrentIndex].BackPrev;
+                               _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
+                               return lenRes;
+                       }
+                       _optimumCurrentIndex = _optimumEndIndex = 0;
+
+                       UInt32 lenMain, numDistancePairs;
+                       if (!_longestMatchWasFound)
+                       {
+                               ReadMatchDistances(out lenMain, out numDistancePairs);
+                       }
+                       else
+                       {
+                               lenMain = _longestMatchLength;
+                               numDistancePairs = _numDistancePairs;
+                               _longestMatchWasFound = false;
+                       }
+
+                       UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
+                       if (numAvailableBytes < 2)
+                       {
+                               backRes = 0xFFFFFFFF;
+                               return 1;
+                       }
+                       if (numAvailableBytes > Base.kMatchMaxLen)
+                               numAvailableBytes = Base.kMatchMaxLen;
+
+                       UInt32 repMaxIndex = 0;
+                       UInt32 i;                       
+                       for (i = 0; i < Base.kNumRepDistances; i++)
+                       {
+                               reps[i] = _repDistances[i];
+                               repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
+                               if (repLens[i] > repLens[repMaxIndex])
+                                       repMaxIndex = i;
+                       }
+                       if (repLens[repMaxIndex] >= _numFastBytes)
+                       {
+                               backRes = repMaxIndex;
+                               UInt32 lenRes = repLens[repMaxIndex];
+                               MovePos(lenRes - 1);
+                               return lenRes;
+                       }
+
+                       if (lenMain >= _numFastBytes)
+                       {
+                               backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
+                               MovePos(lenMain - 1);
+                               return lenMain;
+                       }
+                       
+                       Byte currentByte = _matchFinder.GetIndexByte(0 - 1);
+                       Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1));
+
+                       if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
+                       {
+                               backRes = (UInt32)0xFFFFFFFF;
+                               return 1;
+                       }
+
+                       _optimum[0].State = _state;
+
+                       UInt32 posState = (position & _posStateMask);
+
+                       _optimum[1].Price = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
+                                       _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), matchByte, currentByte);
+                       _optimum[1].MakeAsChar();
+
+                       UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
+                       UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
+
+                       if (matchByte == currentByte)
+                       {
+                               UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
+                               if (shortRepPrice < _optimum[1].Price)
+                               {
+                                       _optimum[1].Price = shortRepPrice;
+                                       _optimum[1].MakeAsShortRep();
+                               }
+                       }
+
+                       UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
+
+                       if(lenEnd < 2)
+                       {
+                               backRes = _optimum[1].BackPrev;
+                               return 1;
+                       }
+                       
+                       _optimum[1].PosPrev = 0;
+
+                       _optimum[0].Backs0 = reps[0];
+                       _optimum[0].Backs1 = reps[1];
+                       _optimum[0].Backs2 = reps[2];
+                       _optimum[0].Backs3 = reps[3];
+
+                       UInt32 len = lenEnd;
+                       do
+                               _optimum[len--].Price = kIfinityPrice;
+                       while (len >= 2);
+
+                       for (i = 0; i < Base.kNumRepDistances; i++)
+                       {
+                               UInt32 repLen = repLens[i];
+                               if (repLen < 2)
+                                       continue;
+                               UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
+                               do
+                               {
+                                       UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
+                                       Optimal optimum = _optimum[repLen];
+                                       if (curAndLenPrice < optimum.Price)
+                                       {
+                                               optimum.Price = curAndLenPrice;
+                                               optimum.PosPrev = 0;
+                                               optimum.BackPrev = i;
+                                               optimum.Prev1IsChar = false;
+                                       }
+                               }
+                               while (--repLen >= 2);
+                       }
+
+                       UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
+                       
+                       len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+                       if (len <= lenMain)
+                       {
+                               UInt32 offs = 0;
+                               while (len > _matchDistances[offs])
+                                       offs += 2;
+                               for (; ; len++)
+                               {
+                                       UInt32 distance = _matchDistances[offs + 1];
+                                       UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
+                                       Optimal optimum = _optimum[len];
+                                       if (curAndLenPrice < optimum.Price)
+                                       {
+                                               optimum.Price = curAndLenPrice;
+                                               optimum.PosPrev = 0;
+                                               optimum.BackPrev = distance + Base.kNumRepDistances;
+                                               optimum.Prev1IsChar = false;
+                                       }
+                                       if (len == _matchDistances[offs])
+                                       {
+                                               offs += 2;
+                                               if (offs == numDistancePairs)
+                                                       break;
+                                       }
+                               }
+                       }
+
+                       UInt32 cur = 0;
+
+                       while (true)
+                       {
+                               cur++;
+                               if (cur == lenEnd)
+                                       return Backward(out backRes, cur);
+                               UInt32 newLen;
+                               ReadMatchDistances(out newLen, out numDistancePairs);
+                               if (newLen >= _numFastBytes)
+                               {
+                                       _numDistancePairs = numDistancePairs;
+                                       _longestMatchLength = newLen;
+                                       _longestMatchWasFound = true;
+                                       return Backward(out backRes, cur);
+                               }
+                               position++;
+                               UInt32 posPrev = _optimum[cur].PosPrev;
+                               Base.State state;
+                               if (_optimum[cur].Prev1IsChar)
+                               {
+                                       posPrev--;
+                                       if (_optimum[cur].Prev2)
+                                       {
+                                               state = _optimum[_optimum[cur].PosPrev2].State;
+                                               if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
+                                                       state.UpdateRep();
+                                               else
+                                                       state.UpdateMatch();
+                                       }
+                                       else
+                                               state = _optimum[posPrev].State;
+                                       state.UpdateChar();
+                               }
+                               else
+                                       state = _optimum[posPrev].State;
+                               if (posPrev == cur - 1)
+                               {
+                                       if (_optimum[cur].IsShortRep())
+                                               state.UpdateShortRep();
+                                       else
+                                               state.UpdateChar();
+                               }
+                               else
+                               {
+                                       UInt32 pos;
+                                       if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
+                                       {
+                                               posPrev = _optimum[cur].PosPrev2;
+                                               pos = _optimum[cur].BackPrev2;
+                                               state.UpdateRep();
+                                       }
+                                       else
+                                       {
+                                               pos = _optimum[cur].BackPrev;
+                                               if (pos < Base.kNumRepDistances)
+                                                       state.UpdateRep();
+                                               else
+                                                       state.UpdateMatch();
+                                       }
+                                       Optimal opt = _optimum[posPrev];
+                                       if (pos < Base.kNumRepDistances)
+                                       {
+                                               if (pos == 0)
+                                               {
+                                                       reps[0] = opt.Backs0;
+                                                       reps[1] = opt.Backs1;
+                                                       reps[2] = opt.Backs2;
+                                                       reps[3] = opt.Backs3;
+                                               }
+                                               else if (pos == 1)
+                                               {
+                                                       reps[0] = opt.Backs1;
+                                                       reps[1] = opt.Backs0;
+                                                       reps[2] = opt.Backs2;
+                                                       reps[3] = opt.Backs3;
+                                               }
+                                               else if (pos == 2)
+                                               {
+                                                       reps[0] = opt.Backs2;
+                                                       reps[1] = opt.Backs0;
+                                                       reps[2] = opt.Backs1;
+                                                       reps[3] = opt.Backs3;
+                                               }
+                                               else
+                                               {
+                                                       reps[0] = opt.Backs3;
+                                                       reps[1] = opt.Backs0;
+                                                       reps[2] = opt.Backs1;
+                                                       reps[3] = opt.Backs2;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               reps[0] = (pos - Base.kNumRepDistances);
+                                               reps[1] = opt.Backs0;
+                                               reps[2] = opt.Backs1;
+                                               reps[3] = opt.Backs2;
+                                       }
+                               }
+                               _optimum[cur].State = state;
+                               _optimum[cur].Backs0 = reps[0];
+                               _optimum[cur].Backs1 = reps[1];
+                               _optimum[cur].Backs2 = reps[2];
+                               _optimum[cur].Backs3 = reps[3];
+                               UInt32 curPrice = _optimum[cur].Price;
+
+                               currentByte = _matchFinder.GetIndexByte(0 - 1);
+                               matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1));
+
+                               posState = (position & _posStateMask);
+
+                               UInt32 curAnd1Price = curPrice +
+                                       _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
+                                       _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
+                                       GetPrice(!state.IsCharState(), matchByte, currentByte);
+
+                               Optimal nextOptimum = _optimum[cur + 1];
+
+                               bool nextIsChar = false;
+                               if (curAnd1Price < nextOptimum.Price)
+                               {
+                                       nextOptimum.Price = curAnd1Price;
+                                       nextOptimum.PosPrev = cur;
+                                       nextOptimum.MakeAsChar();
+                                       nextIsChar = true;
+                               }
+
+                               matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
+                               repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
+
+                               if (matchByte == currentByte &&
+                                       !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
+                               {
+                                       UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
+                                       if (shortRepPrice <= nextOptimum.Price)
+                                       {
+                                               nextOptimum.Price = shortRepPrice;
+                                               nextOptimum.PosPrev = cur;
+                                               nextOptimum.MakeAsShortRep();
+                                               nextIsChar = true;
+                                       }
+                               }
+
+                               UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
+                               numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull);
+                               numAvailableBytes = numAvailableBytesFull;
+
+                               if (numAvailableBytes < 2)
+                                       continue;
+                               if (numAvailableBytes > _numFastBytes)
+                                       numAvailableBytes = _numFastBytes;
+                               if (!nextIsChar && matchByte != currentByte)
+                               {
+                                       // try Literal + rep0
+                                       UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes);
+                                       UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
+                                       if (lenTest2 >= 2)
+                                       {
+                                               Base.State state2 = state;
+                                               state2.UpdateChar();
+                                               UInt32 posStateNext = (position + 1) & _posStateMask;
+                                               UInt32 nextRepMatchPrice = curAnd1Price +
+                                                       _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() +
+                                                       _isRep[state2.Index].GetPrice1();
+                                               {
+                                                       UInt32 offset = cur + 1 + lenTest2;
+                                                       while (lenEnd < offset)
+                                                               _optimum[++lenEnd].Price = kIfinityPrice;
+                                                       UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+                                                               0, lenTest2, state2, posStateNext);
+                                                       Optimal optimum = _optimum[offset];
+                                                       if (curAndLenPrice < optimum.Price)
+                                                       {
+                                                               optimum.Price = curAndLenPrice;
+                                                               optimum.PosPrev = cur + 1;
+                                                               optimum.BackPrev = 0;
+                                                               optimum.Prev1IsChar = true;
+                                                               optimum.Prev2 = false;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               UInt32 startLen = 2; // speed optimization 
+
+                               for (UInt32 repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
+                               {
+                                       UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
+                                       if (lenTest < 2)
+                                               continue;
+                                       UInt32 lenTestTemp = lenTest;
+                                       do
+                                       {
+                                               while (lenEnd < cur + lenTest)
+                                                       _optimum[++lenEnd].Price = kIfinityPrice;
+                                               UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
+                                               Optimal optimum = _optimum[cur + lenTest];
+                                               if (curAndLenPrice < optimum.Price)
+                                               {
+                                                       optimum.Price = curAndLenPrice;
+                                                       optimum.PosPrev = cur;
+                                                       optimum.BackPrev = repIndex;
+                                                       optimum.Prev1IsChar = false;
+                                               }
+                                       }
+                                       while(--lenTest >= 2);
+                                       lenTest = lenTestTemp;
+
+                                       if (repIndex == 0)
+                                               startLen = lenTest + 1;
+
+                                       // if (_maxMode)
+                                       if (lenTest < numAvailableBytesFull)
+                                       {
+                                               UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
+                                               UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t);
+                                               if (lenTest2 >= 2)
+                                               {
+                                                       Base.State state2 = state;
+                                                       state2.UpdateRep();
+                                                       UInt32 posStateNext = (position + lenTest) & _posStateMask;
+                                                       UInt32 curAndLenCharPrice = 
+                                                                       repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + 
+                                                                       _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
+                                                                       _literalEncoder.GetSubCoder(position + lenTest, 
+                                                                       _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true,
+                                                                       _matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))), 
+                                                                       _matchFinder.GetIndexByte((Int32)lenTest - 1));
+                                                       state2.UpdateChar();
+                                                       posStateNext = (position + lenTest + 1) & _posStateMask;
+                                                       UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
+                                                       UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
+                                                       
+                                                       // for(; lenTest2 >= 2; lenTest2--)
+                                                       {
+                                                               UInt32 offset = lenTest + 1 + lenTest2;
+                                                               while(lenEnd < cur + offset)
+                                                                       _optimum[++lenEnd].Price = kIfinityPrice;
+                                                               UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
+                                                               Optimal optimum = _optimum[cur + offset];
+                                                               if (curAndLenPrice < optimum.Price) 
+                                                               {
+                                                                       optimum.Price = curAndLenPrice;
+                                                                       optimum.PosPrev = cur + lenTest + 1;
+                                                                       optimum.BackPrev = 0;
+                                                                       optimum.Prev1IsChar = true;
+                                                                       optimum.Prev2 = true;
+                                                                       optimum.PosPrev2 = cur;
+                                                                       optimum.BackPrev2 = repIndex;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               if (newLen > numAvailableBytes)
+                               {
+                                       newLen = numAvailableBytes;
+                                       for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
+                                       _matchDistances[numDistancePairs] = newLen;
+                                       numDistancePairs += 2;
+                               }
+                               if (newLen >= startLen)
+                               {
+                                       normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
+                                       while (lenEnd < cur + newLen)
+                                               _optimum[++lenEnd].Price = kIfinityPrice;
+
+                                       UInt32 offs = 0;
+                                       while (startLen > _matchDistances[offs])
+                                               offs += 2;
+
+                                       for (UInt32 lenTest = startLen; ; lenTest++)
+                                       {
+                                               UInt32 curBack = _matchDistances[offs + 1];
+                                               UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
+                                               Optimal optimum = _optimum[cur + lenTest];
+                                               if (curAndLenPrice < optimum.Price)
+                                               {
+                                                       optimum.Price = curAndLenPrice;
+                                                       optimum.PosPrev = cur;
+                                                       optimum.BackPrev = curBack + Base.kNumRepDistances;
+                                                       optimum.Prev1IsChar = false;
+                                               }
+
+                                               if (lenTest == _matchDistances[offs])
+                                               {
+                                                       if (lenTest < numAvailableBytesFull)
+                                                       {
+                                                               UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
+                                                               UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t);
+                                                               if (lenTest2 >= 2)
+                                                               {
+                                                                       Base.State state2 = state;
+                                                                       state2.UpdateMatch();
+                                                                       UInt32 posStateNext = (position + lenTest) & _posStateMask;
+                                                                       UInt32 curAndLenCharPrice = curAndLenPrice +
+                                                                               _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
+                                                                               _literalEncoder.GetSubCoder(position + lenTest,
+                                                                               _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).
+                                                                               GetPrice(true,
+                                                                               _matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1),
+                                                                               _matchFinder.GetIndexByte((Int32)lenTest - 1));
+                                                                       state2.UpdateChar();
+                                                                       posStateNext = (position + lenTest + 1) & _posStateMask;
+                                                                       UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
+                                                                       UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
+
+                                                                       UInt32 offset = lenTest + 1 + lenTest2;
+                                                                       while (lenEnd < cur + offset)
+                                                                               _optimum[++lenEnd].Price = kIfinityPrice;
+                                                                       curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
+                                                                       optimum = _optimum[cur + offset];
+                                                                       if (curAndLenPrice < optimum.Price)
+                                                                       {
+                                                                               optimum.Price = curAndLenPrice;
+                                                                               optimum.PosPrev = cur + lenTest + 1;
+                                                                               optimum.BackPrev = 0;
+                                                                               optimum.Prev1IsChar = true;
+                                                                               optimum.Prev2 = true;
+                                                                               optimum.PosPrev2 = cur;
+                                                                               optimum.BackPrev2 = curBack + Base.kNumRepDistances;
+                                                                       }
+                                                               }
+                                                       }
+                                                       offs += 2;
+                                                       if (offs == numDistancePairs)
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               bool ChangePair(UInt32 smallDist, UInt32 bigDist)
+               {
+                       const int kDif = 7;
+                       return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif));
+               }
+
+               void WriteEndMarker(UInt32 posState)
+               {
+                       if (!_writeEndMark)
+                               return;
+
+                       _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 1);
+                       _isRep[_state.Index].Encode(_rangeEncoder, 0);
+                       _state.UpdateMatch();
+                       UInt32 len = Base.kMatchMinLen;
+                       _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
+                       UInt32 posSlot = (1 << Base.kNumPosSlotBits) - 1;
+                       UInt32 lenToPosState = Base.GetLenToPosState(len);
+                       _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
+                       int footerBits = 30;
+                       UInt32 posReduced = (((UInt32)1) << footerBits) - 1;
+                       _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
+                       _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
+               }
+
+               void Flush(UInt32 nowPos)
+               {
+                       ReleaseMFStream();
+                       WriteEndMarker(nowPos & _posStateMask);
+                       _rangeEncoder.FlushData();
+                       _rangeEncoder.FlushStream();
+               }
+
+               public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished)
+               {
+                       inSize = 0;
+                       outSize = 0;
+                       finished = true;
+
+                       if (_inStream != null)
+                       {
+                               _matchFinder.SetStream(_inStream);
+                               _matchFinder.Init();
+                               _needReleaseMFStream = true;
+                               _inStream = null;
+                               if (_trainSize > 0)
+                                       _matchFinder.Skip(_trainSize);
+                       }
+
+                       if (_finished)
+                               return;
+                       _finished = true;
+
+
+                       Int64 progressPosValuePrev = nowPos64;
+                       if (nowPos64 == 0)
+                       {
+                               if (_matchFinder.GetNumAvailableBytes() == 0)
+                               {
+                                       Flush((UInt32)nowPos64);
+                                       return;
+                               }
+                               UInt32 len, numDistancePairs; // it's not used
+                               ReadMatchDistances(out len, out numDistancePairs);
+                               UInt32 posState = (UInt32)(nowPos64) & _posStateMask;
+                               _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0);
+                               _state.UpdateChar();
+                               Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
+                               _literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
+                               _previousByte = curByte;
+                               _additionalOffset--;
+                               nowPos64++;
+                       }
+                       if (_matchFinder.GetNumAvailableBytes() == 0)
+                       {
+                               Flush((UInt32)nowPos64);
+                               return;
+                       }
+                       while (true)
+                       {
+                               UInt32 pos;
+                               UInt32 len = GetOptimum((UInt32)nowPos64, out pos);
+                               
+                               UInt32 posState = ((UInt32)nowPos64) & _posStateMask;
+                               UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState;
+                               if (len == 1 && pos == 0xFFFFFFFF)
+                               {
+                                       _isMatch[complexState].Encode(_rangeEncoder, 0);
+                                       Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
+                                       LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte);
+                                       if (!_state.IsCharState())
+                                       {
+                                               Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset));
+                                               subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
+                                       }
+                                       else
+                                               subCoder.Encode(_rangeEncoder, curByte);
+                                       _previousByte = curByte;
+                                       _state.UpdateChar();
+                               }
+                               else
+                               {
+                                       _isMatch[complexState].Encode(_rangeEncoder, 1);
+                                       if (pos < Base.kNumRepDistances)
+                                       {
+                                               _isRep[_state.Index].Encode(_rangeEncoder, 1);
+                                               if (pos == 0)
+                                               {
+                                                       _isRepG0[_state.Index].Encode(_rangeEncoder, 0);
+                                                       if (len == 1)
+                                                               _isRep0Long[complexState].Encode(_rangeEncoder, 0);
+                                                       else
+                                                               _isRep0Long[complexState].Encode(_rangeEncoder, 1);
+                                               }
+                                               else
+                                               {
+                                                       _isRepG0[_state.Index].Encode(_rangeEncoder, 1);
+                                                       if (pos == 1)
+                                                               _isRepG1[_state.Index].Encode(_rangeEncoder, 0);
+                                                       else
+                                                       {
+                                                               _isRepG1[_state.Index].Encode(_rangeEncoder, 1);
+                                                               _isRepG2[_state.Index].Encode(_rangeEncoder, pos - 2);
+                                                       }
+                                               }
+                                               if (len == 1)
+                                                       _state.UpdateShortRep();
+                                               else
+                                               {
+                                                       _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
+                                                       _state.UpdateRep();
+                                               }
+                                               UInt32 distance = _repDistances[pos];
+                                               if (pos != 0)
+                                               {
+                                                       for (UInt32 i = pos; i >= 1; i--)
+                                                               _repDistances[i] = _repDistances[i - 1];
+                                                       _repDistances[0] = distance;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               _isRep[_state.Index].Encode(_rangeEncoder, 0);
+                                               _state.UpdateMatch();
+                                               _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
+                                               pos -= Base.kNumRepDistances;
+                                               UInt32 posSlot = GetPosSlot(pos);
+                                               UInt32 lenToPosState = Base.GetLenToPosState(len);
+                                               _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
+
+                                               if (posSlot >= Base.kStartPosModelIndex)
+                                               {
+                                                       int footerBits = (int)((posSlot >> 1) - 1);
+                                                       UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
+                                                       UInt32 posReduced = pos - baseVal;
+
+                                                       if (posSlot < Base.kEndPosModelIndex)
+                                                               RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders,
+                                                                               baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
+                                                       else
+                                                       {
+                                                               _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
+                                                               _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
+                                                               _alignPriceCount++;
+                                                       }
+                                               }
+                                               UInt32 distance = pos;
+                                               for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--)
+                                                       _repDistances[i] = _repDistances[i - 1];
+                                               _repDistances[0] = distance;
+                                               _matchPriceCount++;
+                                       }
+                                       _previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset));
+                               }
+                               _additionalOffset -= len;
+                               nowPos64 += len;
+                               if (_additionalOffset == 0)
+                               {
+                                       // if (!_fastMode)
+                                       if (_matchPriceCount >= (1 << 7))
+                                               FillDistancesPrices();
+                                       if (_alignPriceCount >= Base.kAlignTableSize)
+                                               FillAlignPrices();
+                                       inSize = nowPos64;
+                                       outSize = _rangeEncoder.GetProcessedSizeAdd();
+                                       if (_matchFinder.GetNumAvailableBytes() == 0)
+                                       {
+                                               Flush((UInt32)nowPos64);
+                                               return;
+                                       }
+
+                                       if (nowPos64 - progressPosValuePrev >= (1 << 12))
+                                       {
+                                               _finished = false;
+                                               finished = false;
+                                               return;
+                                       }
+                               }
+                       }
+               }
+
+               void ReleaseMFStream()
+               {
+                       if (_matchFinder != null && _needReleaseMFStream)
+                       {
+                               _matchFinder.ReleaseStream();
+                               _needReleaseMFStream = false;
+                       }
+               }
+
+               void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); }
+               void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); }
+
+               void ReleaseStreams()
+               {
+                       ReleaseMFStream();
+                       ReleaseOutStream();
+               }
+
+               void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream,
+                               Int64 inSize, Int64 outSize)
+               {
+                       _inStream = inStream;
+                       _finished = false;
+                       Create();
+                       SetOutStream(outStream);
+                       Init();
+
+                       // if (!_fastMode)
+                       {
+                               FillDistancesPrices();
+                               FillAlignPrices();
+                       }
+
+                       _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
+                       _lenEncoder.UpdateTables((UInt32)1 << _posStateBits);
+                       _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
+                       _repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits);
+
+                       nowPos64 = 0;
+               }
+
+
+               public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
+                       Int64 inSize, Int64 outSize, ICodeProgress progress)
+               {
+                       _needReleaseMFStream = false;
+                       try
+                       {
+                               SetStreams(inStream, outStream, inSize, outSize);
+                               while (true)
+                               {
+                                       Int64 processedInSize;
+                                       Int64 processedOutSize;
+                                       bool finished;
+                                       CodeOneBlock(out processedInSize, out processedOutSize, out finished);
+                                       if (finished)
+                                               return;
+                                       if (progress != null)
+                                       {
+                                               progress.SetProgress(processedInSize, processedOutSize);
+                                       }
+                               }
+                       }
+                       finally
+                       {
+                               ReleaseStreams();
+                       }
+               }
+
+               const int kPropSize = 5;
+               Byte[] properties = new Byte[kPropSize];
+
+               public void WriteCoderProperties(System.IO.Stream outStream)
+               {
+                       properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
+                       for (int i = 0; i < 4; i++)
+                               properties[1 + i] = (Byte)(_dictionarySize >> (8 * i));
+                       outStream.Write(properties, 0, kPropSize);
+               }
+               
+               UInt32[] tempPrices = new UInt32[Base.kNumFullDistances];
+               UInt32 _matchPriceCount;
+
+               void FillDistancesPrices()
+               {
+                       for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
+                       { 
+                               UInt32 posSlot = GetPosSlot(i);
+                               int footerBits = (int)((posSlot >> 1) - 1);
+                               UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
+                               tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders, 
+                                       baseVal - posSlot - 1, footerBits, i - baseVal);
+                       }
+
+                       for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
+                       {
+                               UInt32 posSlot;
+                               RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
+                       
+                               UInt32 st = (lenToPosState << Base.kNumPosSlotBits);
+                               for (posSlot = 0; posSlot < _distTableSize; posSlot++)
+                                       _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
+                               for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
+                                       _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits);
+
+                               UInt32 st2 = lenToPosState * Base.kNumFullDistances;
+                               UInt32 i;
+                               for (i = 0; i < Base.kStartPosModelIndex; i++)
+                                       _distancesPrices[st2 + i] = _posSlotPrices[st + i];
+                               for (; i < Base.kNumFullDistances; i++)
+                                       _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
+                       }
+                       _matchPriceCount = 0;
+               }
+
+               void FillAlignPrices()
+               {
+                       for (UInt32 i = 0; i < Base.kAlignTableSize; i++)
+                               _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
+                       _alignPriceCount = 0;
+               }
+
+
+               static string[] kMatchFinderIDs = 
+               {
+                       "BT2",
+                       "BT4",
+               };
+
+               static int FindMatchFinder(string s)
+               {
+                       for (int m = 0; m < kMatchFinderIDs.Length; m++)
+                               if (s == kMatchFinderIDs[m])
+                                       return m;
+                       return -1;
+               }
+       
+               public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)
+               {
+                       for (UInt32 i = 0; i < properties.Length; i++)
+                       {
+                               object prop = properties[i];
+                               switch (propIDs[i])
+                               {
+                                       case CoderPropID.NumFastBytes:
+                                       {
+                                               if (!(prop is Int32))
+                                                       throw new InvalidParamException();
+                                               Int32 numFastBytes = (Int32)prop;
+                                               if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
+                                                       throw new InvalidParamException();
+                                               _numFastBytes = (UInt32)numFastBytes;
+                                               break;
+                                       }
+                                       case CoderPropID.Algorithm:
+                                       {
+                                               /*
+                                               if (!(prop is Int32))
+                                                       throw new InvalidParamException();
+                                               Int32 maximize = (Int32)prop;
+                                               _fastMode = (maximize == 0);
+                                               _maxMode = (maximize >= 2);
+                                               */
+                                               break;
+                                       }
+                                       case CoderPropID.MatchFinder:
+                                       {
+                                               if (!(prop is String))
+                                                       throw new InvalidParamException();
+                                               EMatchFinderType matchFinderIndexPrev = _matchFinderType;
+                                               int m = FindMatchFinder(((string)prop).ToUpper());
+                                               if (m < 0)
+                                                       throw new InvalidParamException();
+                                               _matchFinderType = (EMatchFinderType)m;
+                                               if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
+                                                       {
+                                                       _dictionarySizePrev = 0xFFFFFFFF;
+                                                       _matchFinder = null;
+                                                       }
+                                               break;
+                                       }
+                                       case CoderPropID.DictionarySize:
+                                       {
+                                               const int kDicLogSizeMaxCompress = 30;
+                                               if (!(prop is Int32))
+                                                       throw new InvalidParamException(); ;
+                                               Int32 dictionarySize = (Int32)prop;
+                                               if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) ||
+                                                       dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress))
+                                                       throw new InvalidParamException();
+                                               _dictionarySize = (UInt32)dictionarySize;
+                                               int dicLogSize;
+                                               for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
+                                                       if (dictionarySize <= ((UInt32)(1) << dicLogSize))
+                                                               break;
+                                               _distTableSize = (UInt32)dicLogSize * 2;
+                                               break;
+                                       }
+                                       case CoderPropID.PosStateBits:
+                                       {
+                                               if (!(prop is Int32))
+                                                       throw new InvalidParamException();
+                                               Int32 v = (Int32)prop;
+                                               if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax)
+                                                       throw new InvalidParamException();
+                                               _posStateBits = (int)v;
+                                               _posStateMask = (((UInt32)1) << (int)_posStateBits) - 1;
+                                               break;
+                                       }
+                                       case CoderPropID.LitPosBits:
+                                       {
+                                               if (!(prop is Int32))
+                                                       throw new InvalidParamException();
+                                               Int32 v = (Int32)prop;
+                                               if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax)
+                                                       throw new InvalidParamException();
+                                               _numLiteralPosStateBits = (int)v;
+                                               break;
+                                       }
+                                       case CoderPropID.LitContextBits:
+                                       {
+                                               if (!(prop is Int32))
+                                                       throw new InvalidParamException();
+                                               Int32 v = (Int32)prop;
+                                               if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax)
+                                                       throw new InvalidParamException(); ;
+                                               _numLiteralContextBits = (int)v;
+                                               break;
+                                       }
+                                       case CoderPropID.EndMarker:
+                                       {
+                                               if (!(prop is Boolean))
+                                                       throw new InvalidParamException();
+                                               SetWriteEndMarkerMode((Boolean)prop);
+                                               break;
+                                       }
+                                       default:
+                                               throw new InvalidParamException();
+                               }
+                       }
+               }
+
+               uint _trainSize = 0;
+               public void SetTrainSize(uint trainSize)
+               {
+                       _trainSize = trainSize;
+               }
+               
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
new file mode 100644 (file)
index 0000000..38018a2
--- /dev/null
@@ -0,0 +1,364 @@
+using System;
+using System.IO;
+namespace SevenZip
+{
+       using CommandLineParser;
+       
+       public class CDoubleStream: Stream
+       {
+               public System.IO.Stream s1;
+               public System.IO.Stream s2;
+               public int fileIndex;
+               public long skipSize;
+               
+               public override bool CanRead { get { return true; }}
+               public override bool CanWrite { get { return false; }}
+               public override bool CanSeek { get { return false; }}
+               public override long Length { get { return s1.Length + s2.Length - skipSize; } }
+               public override long Position
+               {
+                       get { return 0; }
+                       set { }
+               }
+               public override void Flush() { }
+               public override int Read(byte[] buffer, int offset, int count) 
+               {
+                       int numTotal = 0;
+                       while (count > 0)
+                       {
+                               if (fileIndex == 0)
+                               {
+                                       int num = s1.Read(buffer, offset, count);
+                                       offset += num;
+                                       count -= num;
+                                       numTotal += num;
+                                       if (num == 0)
+                                               fileIndex++;
+                               }
+                               if (fileIndex == 1)
+                               {
+                                       numTotal += s2.Read(buffer, offset, count);
+                                       return numTotal;
+                               }
+                       }
+                       return numTotal;
+               }
+               public override void Write(byte[] buffer, int offset, int count)
+               {
+                       throw (new Exception("can't Write"));
+               }
+               public override long Seek(long offset, System.IO.SeekOrigin origin)
+               {
+                       throw (new Exception("can't Seek"));
+               }
+               public override void SetLength(long value)
+               {
+                       throw (new Exception("can't SetLength"));
+               }
+       }
+       
+       class LzmaAlone
+       {
+               enum Key
+               {
+                       Help1 = 0,
+                       Help2,
+                       Mode,
+                       Dictionary,
+                       FastBytes,
+                       LitContext,
+                       LitPos,
+                       PosBits,
+                       MatchFinder,
+                       EOS,
+                       StdIn,
+                       StdOut,
+                       Train
+               };
+
+               static void PrintHelp()
+               {
+                       System.Console.WriteLine("\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +
+                               "  e: encode file\n" +
+                               "  d: decode file\n" +
+                               "  b: Benchmark\n" +
+                               "<Switches>\n" +
+                               // "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +
+                               "  -d{N}:  set dictionary - [0, 29], default: 23 (8MB)\n" +
+                               "  -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
+                               "  -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
+                               "  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
+                               "  -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
+                               "  -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
+                               "  -eos:   write End Of Stream marker\n"
+                               // + "  -si:    read data from stdin\n"
+                               // + "  -so:    write data to stdout\n"
+                               );
+               }
+
+               static bool GetNumber(string s, out Int32 v)
+               {
+                       v = 0;
+                       for (int i = 0; i < s.Length; i++)
+                       {
+                               char c = s[i];
+                               if (c < '0' || c > '9')
+                                       return false;
+                               v *= 10;
+                               v += (Int32)(c - '0');
+                       }
+                       return true;
+               }
+
+               static int IncorrectCommand()
+               {
+                       throw (new Exception("Command line error"));
+                       // System.Console.WriteLine("\nCommand line error\n");
+                       // return 1;
+               }
+               static int Main2(string[] args)
+               {
+                       System.Console.WriteLine("\nLZMA# 4.49 Copyright (c) 1999-2007 Igor Pavlov  2006-07-05\n");
+
+                       if (args.Length == 0)
+                       {
+                               PrintHelp();
+                               return 0;
+                       }
+
+                       SwitchForm[] kSwitchForms = new SwitchForm[13];
+                       int sw = 0;
+                       kSwitchForms[sw++] = new SwitchForm("?", SwitchType.Simple, false);
+                       kSwitchForms[sw++] = new SwitchForm("H", SwitchType.Simple, false);
+                       kSwitchForms[sw++] = new SwitchForm("A", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("D", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("FB", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("LC", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("LP", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("PB", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("MF", SwitchType.UnLimitedPostString, false, 1);
+                       kSwitchForms[sw++] = new SwitchForm("EOS", SwitchType.Simple, false);
+                       kSwitchForms[sw++] = new SwitchForm("SI", SwitchType.Simple, false);
+                       kSwitchForms[sw++] = new SwitchForm("SO", SwitchType.Simple, false);
+                       kSwitchForms[sw++] = new SwitchForm("T", SwitchType.UnLimitedPostString, false, 1);
+
+
+                       Parser parser = new Parser(sw);
+                       try
+                       {
+                               parser.ParseStrings(kSwitchForms, args);
+                       }
+                       catch
+                       {
+                               return IncorrectCommand();
+                       }
+
+                       if (parser[(int)Key.Help1].ThereIs || parser[(int)Key.Help2].ThereIs)
+                       {
+                               PrintHelp();
+                               return 0;
+                       }
+
+                       System.Collections.ArrayList nonSwitchStrings = parser.NonSwitchStrings;
+
+                       int paramIndex = 0;
+                       if (paramIndex >= nonSwitchStrings.Count)
+                               return IncorrectCommand();
+                       string command = (string)nonSwitchStrings[paramIndex++];
+                       command = command.ToLower();
+
+                       bool dictionaryIsDefined = false;
+                       Int32 dictionary = 1 << 21;
+                       if (parser[(int)Key.Dictionary].ThereIs)
+                       {
+                               Int32 dicLog;
+                               if (!GetNumber((string)parser[(int)Key.Dictionary].PostStrings[0], out dicLog))
+                                       IncorrectCommand();
+                               dictionary = (Int32)1 << dicLog;
+                               dictionaryIsDefined = true;
+                       }
+                       string mf = "bt4";
+                       if (parser[(int)Key.MatchFinder].ThereIs)
+                               mf = (string)parser[(int)Key.MatchFinder].PostStrings[0];
+                       mf = mf.ToLower();
+
+                       if (command == "b")
+                       {
+                               const Int32 kNumDefaultItereations = 10;
+                               Int32 numIterations = kNumDefaultItereations;
+                               if (paramIndex < nonSwitchStrings.Count)
+                                       if (!GetNumber((string)nonSwitchStrings[paramIndex++], out numIterations))
+                                               numIterations = kNumDefaultItereations;
+                               return LzmaBench.LzmaBenchmark(numIterations, (UInt32)dictionary);
+                       }
+
+                       string train = "";
+                       if (parser[(int)Key.Train].ThereIs)
+                               train = (string)parser[(int)Key.Train].PostStrings[0];
+
+                       bool encodeMode = false;
+                       if (command == "e")
+                               encodeMode = true;
+                       else if (command == "d")
+                               encodeMode = false;
+                       else
+                               IncorrectCommand();
+
+                       bool stdInMode = parser[(int)Key.StdIn].ThereIs;
+                       bool stdOutMode = parser[(int)Key.StdOut].ThereIs;
+
+                       Stream inStream = null;
+                       if (stdInMode)
+                       {
+                               throw (new Exception("Not implemeted"));
+                       }
+                       else
+                       {
+                               if (paramIndex >= nonSwitchStrings.Count)
+                                       IncorrectCommand();
+                               string inputName = (string)nonSwitchStrings[paramIndex++];
+                               inStream = new FileStream(inputName, FileMode.Open, FileAccess.Read);
+                       }
+
+                       FileStream outStream = null;
+                       if (stdOutMode)
+                       {
+                               throw (new Exception("Not implemeted"));
+                       }
+                       else
+                       {
+                               if (paramIndex >= nonSwitchStrings.Count)
+                                       IncorrectCommand();
+                               string outputName = (string)nonSwitchStrings[paramIndex++];
+                               outStream = new FileStream(outputName, FileMode.Create, FileAccess.Write);
+                       }
+
+                       FileStream trainStream = null;
+                       if (train.Length != 0)
+                               trainStream = new FileStream(train, FileMode.Open, FileAccess.Read);
+
+                       if (encodeMode)
+                       {
+                               if (!dictionaryIsDefined)
+                                       dictionary = 1 << 23;
+
+                               Int32 posStateBits = 2;
+                               Int32 litContextBits = 3; // for normal files
+                               // UInt32 litContextBits = 0; // for 32-bit data
+                               Int32 litPosBits = 0;
+                               // UInt32 litPosBits = 2; // for 32-bit data
+                               Int32 algorithm = 2;
+                               Int32 numFastBytes = 128;
+
+                               bool eos = parser[(int)Key.EOS].ThereIs || stdInMode;
+
+                               if (parser[(int)Key.Mode].ThereIs)
+                                       if (!GetNumber((string)parser[(int)Key.Mode].PostStrings[0], out algorithm))
+                                               IncorrectCommand();
+
+                               if (parser[(int)Key.FastBytes].ThereIs)
+                                       if (!GetNumber((string)parser[(int)Key.FastBytes].PostStrings[0], out numFastBytes))
+                                               IncorrectCommand();
+                               if (parser[(int)Key.LitContext].ThereIs)
+                                       if (!GetNumber((string)parser[(int)Key.LitContext].PostStrings[0], out litContextBits))
+                                               IncorrectCommand();
+                               if (parser[(int)Key.LitPos].ThereIs)
+                                       if (!GetNumber((string)parser[(int)Key.LitPos].PostStrings[0], out litPosBits))
+                                               IncorrectCommand();
+                               if (parser[(int)Key.PosBits].ThereIs)
+                                       if (!GetNumber((string)parser[(int)Key.PosBits].PostStrings[0], out posStateBits))
+                                               IncorrectCommand();
+
+                               CoderPropID[] propIDs = 
+                               {
+                                       CoderPropID.DictionarySize,
+                                       CoderPropID.PosStateBits,
+                                       CoderPropID.LitContextBits,
+                                       CoderPropID.LitPosBits,
+                                       CoderPropID.Algorithm,
+                                       CoderPropID.NumFastBytes,
+                                       CoderPropID.MatchFinder,
+                                       CoderPropID.EndMarker
+                               };
+                               object[] properties = 
+                               {
+                                       (Int32)(dictionary),
+                                       (Int32)(posStateBits),
+                                       (Int32)(litContextBits),
+                                       (Int32)(litPosBits),
+                                       (Int32)(algorithm),
+                                       (Int32)(numFastBytes),
+                                       mf,
+                                       eos
+                               };
+
+                               Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
+                               encoder.SetCoderProperties(propIDs, properties);
+                               encoder.WriteCoderProperties(outStream);
+                               Int64 fileSize;
+                               if (eos || stdInMode)
+                                       fileSize = -1;
+                               else
+                                       fileSize = inStream.Length;
+                               for (int i = 0; i < 8; i++)
+                                       outStream.WriteByte((Byte)(fileSize >> (8 * i)));
+                               if (trainStream != null)
+                               {
+                                       CDoubleStream doubleStream = new CDoubleStream();
+                                       doubleStream.s1 = trainStream;
+                                       doubleStream.s2 = inStream;
+                                       doubleStream.fileIndex = 0;
+                                       inStream = doubleStream;
+                                       long trainFileSize = trainStream.Length;
+                                       doubleStream.skipSize = 0;
+                                       if (trainFileSize > dictionary)
+                                               doubleStream.skipSize = trainFileSize - dictionary;
+                                       trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);
+                                       encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));
+                               }
+                               encoder.Code(inStream, outStream, -1, -1, null);
+                       }
+                       else if (command == "d")
+                       {
+                               byte[] properties = new byte[5];
+                               if (inStream.Read(properties, 0, 5) != 5)
+                                       throw (new Exception("input .lzma is too short"));
+                               Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
+                               decoder.SetDecoderProperties(properties);
+                               if (trainStream != null)
+                               {
+                                       if (!decoder.Train(trainStream))
+                                               throw (new Exception("can't train"));
+                               }
+                               long outSize = 0;
+                               for (int i = 0; i < 8; i++)
+                               {
+                                       int v = inStream.ReadByte();
+                                       if (v < 0)
+                                               throw (new Exception("Can't Read 1"));
+                                       outSize |= ((long)(byte)v) << (8 * i);
+                               }
+                               long compressedSize = inStream.Length - inStream.Position;
+                               decoder.Code(inStream, outStream, compressedSize, outSize, null);
+                       }
+                       else
+                               throw (new Exception("Command Error"));
+                       return 0;
+               }
+
+               [STAThread]
+               static int Main(string[] args)
+               {
+                       try
+                       {
+                               return Main2(args);
+                       }
+                       catch (Exception e)
+                       {
+                               Console.WriteLine("{0} Caught exception #1.", e);
+                               // throw e;
+                               return 1;
+                       }
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
new file mode 100644 (file)
index 0000000..6d87b61
--- /dev/null
@@ -0,0 +1,90 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.50727</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>LzmaAlone</RootNamespace>
+    <AssemblyName>Lzma#</AssemblyName>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>.\bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugSymbols>false</DebugSymbols>
+    <Optimize>true</Optimize>
+    <OutputPath>.\bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\..\Common\CommandLineParser.cs">
+      <Link>Common\CommandLineParser.cs</Link>
+    </Compile>
+    <Compile Include="..\..\Common\CRC.cs">
+      <Link>Common\CRC.cs</Link>
+    </Compile>
+    <Compile Include="..\..\ICoder.cs">
+      <Link>ICoder.cs</Link>
+    </Compile>
+    <Compile Include="..\LZ\IMatchFinder.cs">
+      <Link>LZ\IMatchFinder.cs</Link>
+    </Compile>
+    <Compile Include="..\LZ\LzBinTree.cs">
+      <Link>LZ\LzBinTree.cs</Link>
+    </Compile>
+    <Compile Include="..\LZ\LzInWindow.cs">
+      <Link>LZ\LzInWindow.cs</Link>
+    </Compile>
+    <Compile Include="..\LZ\LzOutWindow.cs">
+      <Link>LZ\LzOutWindow.cs</Link>
+    </Compile>
+    <Compile Include="..\LZMA\LzmaBase.cs">
+      <Link>LZMA\LzmaBase.cs</Link>
+    </Compile>
+    <Compile Include="..\LZMA\LzmaDecoder.cs">
+      <Link>LZMA\LzmaDecoder.cs</Link>
+    </Compile>
+    <Compile Include="..\LZMA\LzmaEncoder.cs">
+      <Link>LZMA\LzmaEncoder.cs</Link>
+    </Compile>
+    <Compile Include="..\RangeCoder\RangeCoder.cs">
+      <Link>RangeCoder\RangeCoder.cs</Link>
+    </Compile>
+    <Compile Include="..\RangeCoder\RangeCoderBit.cs">
+      <Link>RangeCoder\RangeCoderBit.cs</Link>
+    </Compile>
+    <Compile Include="..\RangeCoder\RangeCoderBitTree.cs">
+      <Link>RangeCoder\RangeCoderBitTree.cs</Link>
+    </Compile>
+    <Compile Include="LzmaAlone.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="LzmaBench.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Settings.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+    </Compile>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.cs</LastGenOutput>
+    </None>
+    <AppDesigner Include="Properties\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+</Project>
\ No newline at end of file
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
new file mode 100644 (file)
index 0000000..376cd27
--- /dev/null
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C# Express 2005
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LzmaAlone", "LzmaAlone.csproj", "{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/LzmaBench.cs b/lzma/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
new file mode 100644 (file)
index 0000000..f7b6bd0
--- /dev/null
@@ -0,0 +1,340 @@
+// LzmaBench.cs
+
+using System;
+using System.IO;
+
+namespace SevenZip
+{
+       /// <summary>
+       /// LZMA Benchmark
+       /// </summary>
+       internal abstract class LzmaBench
+       {
+               const UInt32 kAdditionalSize = (6 << 20);
+               const UInt32 kCompressedAdditionalSize = (1 << 10);
+               const UInt32 kMaxLzmaPropSize = 10;
+
+               class CRandomGenerator
+               {
+                       UInt32 A1;
+                       UInt32 A2;
+                       public CRandomGenerator() { Init(); }
+                       public void Init() { A1 = 362436069; A2 = 521288629; }
+                       public UInt32 GetRnd()
+                       {
+                               return
+                                       ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
+                                       ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)));
+                       }
+               };
+
+               class CBitRandomGenerator
+               {
+                       CRandomGenerator RG = new CRandomGenerator();
+                       UInt32 Value;
+                       int NumBits;
+                       public void Init()
+                       {
+                               Value = 0;
+                               NumBits = 0;
+                       }
+                       public UInt32 GetRnd(int numBits)
+                       {
+                               UInt32 result;
+                               if (NumBits > numBits)
+                               {
+                                       result = Value & (((UInt32)1 << numBits) - 1);
+                                       Value >>= numBits;
+                                       NumBits -= numBits;
+                                       return result;
+                               }
+                               numBits -= NumBits;
+                               result = (Value << numBits);
+                               Value = RG.GetRnd();
+                               result |= Value & (((UInt32)1 << numBits) - 1);
+                               Value >>= numBits;
+                               NumBits = 32 - numBits;
+                               return result;
+                       }
+               };
+
+               class CBenchRandomGenerator
+               {
+                       CBitRandomGenerator RG = new CBitRandomGenerator();
+                       UInt32 Pos;
+                       UInt32 Rep0;
+                       
+                       public UInt32 BufferSize;
+                       public Byte[] Buffer = null;
+
+                       public CBenchRandomGenerator() { }
+
+                       public void Set(UInt32 bufferSize)
+                       {
+                               Buffer = new Byte[bufferSize];
+                               Pos = 0;
+                               BufferSize = bufferSize;
+                       }
+                       UInt32 GetRndBit() { return RG.GetRnd(1); }
+                       UInt32 GetLogRandBits(int numBits)
+                       {
+                               UInt32 len = RG.GetRnd(numBits);
+                               return RG.GetRnd((int)len);
+                       }
+                       UInt32 GetOffset()
+                       {
+                               if (GetRndBit() == 0)
+                                       return GetLogRandBits(4);
+                               return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
+                       }
+                       UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
+                       UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
+                       public void Generate()
+                       {
+                               RG.Init();
+                               Rep0 = 1;
+                               while (Pos < BufferSize)
+                               {
+                                       if (GetRndBit() == 0 || Pos < 1)
+                                               Buffer[Pos++] = (Byte)RG.GetRnd(8);
+                                       else
+                                       {
+                                               UInt32 len;
+                                               if (RG.GetRnd(3) == 0)
+                                                       len = 1 + GetLen1();
+                                               else
+                                               {
+                                                       do
+                                                               Rep0 = GetOffset();
+                                                       while (Rep0 >= Pos);
+                                                       Rep0++;
+                                                       len = 2 + GetLen2();
+                                               }
+                                               for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)
+                                                       Buffer[Pos] = Buffer[Pos - Rep0];
+                                       }
+                               }
+                       }
+               };
+
+               class CrcOutStream : System.IO.Stream
+               {
+                       public CRC CRC = new CRC();
+                       public void Init() { CRC.Init(); }
+                       public UInt32 GetDigest() { return CRC.GetDigest(); }
+
+                       public override bool CanRead { get { return false; } }
+                       public override bool CanSeek { get { return false; } }
+                       public override bool CanWrite { get { return true; } }
+                       public override Int64 Length { get { return 0; } }
+                       public override Int64 Position { get { return 0; } set { } }
+                       public override void Flush() { }
+                       public override long Seek(long offset, SeekOrigin origin) { return 0; }
+                       public override void SetLength(long value) { }
+                       public override int Read(byte[] buffer, int offset, int count) { return 0; }
+
+                       public override void WriteByte(byte b)
+                       {
+                               CRC.UpdateByte(b);
+                       }
+                       public override void Write(byte[] buffer, int offset, int count)
+                       {
+                               CRC.Update(buffer, (uint)offset, (uint)count);
+                       }
+               };
+
+               class CProgressInfo : ICodeProgress
+               {
+                       public Int64 ApprovedStart;
+                       public Int64 InSize;
+                       public System.DateTime Time;
+                       public void Init() { InSize = 0; }
+                       public void SetProgress(Int64 inSize, Int64 outSize)
+                       {
+                               if (inSize >= ApprovedStart && InSize == 0)
+                               {
+                                       Time = DateTime.UtcNow;
+                                       InSize = inSize;
+                               }
+                       }
+               }
+               const int kSubBits = 8;
+
+               static UInt32 GetLogSize(UInt32 size)
+               {
+                       for (int i = kSubBits; i < 32; i++)
+                               for (UInt32 j = 0; j < (1 << kSubBits); j++)
+                                       if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
+                                               return (UInt32)(i << kSubBits) + j;
+                       return (32 << kSubBits);
+               }
+
+               static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
+               {
+                       UInt64 freq = TimeSpan.TicksPerSecond;
+                       UInt64 elTime = elapsedTime;
+                       while (freq > 1000000)
+                       {
+                               freq >>= 1;
+                               elTime >>= 1;
+                       }
+                       if (elTime == 0)
+                               elTime = 1;
+                       return value * freq / elTime;
+               }
+
+               static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size)
+               {
+                       UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits);
+                       UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
+                       UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
+                       return MyMultDiv64(numCommands, elapsedTime);
+               }
+
+               static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize)
+               {
+                       UInt64 numCommands = inSize * 220 + outSize * 20;
+                       return MyMultDiv64(numCommands, elapsedTime);
+               }
+
+               static UInt64 GetTotalRating(
+                       UInt32 dictionarySize,
+                       UInt64 elapsedTimeEn, UInt64 sizeEn,
+                       UInt64 elapsedTimeDe,
+                       UInt64 inSizeDe, UInt64 outSizeDe)
+               {
+                       return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
+                               GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
+               }
+
+               static void PrintValue(UInt64 v)
+               {
+                       string s = v.ToString();
+                       for (int i = 0; i + s.Length < 6; i++)
+                               System.Console.Write(" ");
+                       System.Console.Write(s);
+               }
+
+               static void PrintRating(UInt64 rating)
+               {
+                       PrintValue(rating / 1000000);
+                       System.Console.Write(" MIPS");
+               }
+
+               static void PrintResults(
+                       UInt32 dictionarySize,
+                       UInt64 elapsedTime,
+                       UInt64 size,
+                       bool decompressMode, UInt64 secondSize)
+               {
+                       UInt64 speed = MyMultDiv64(size, elapsedTime);
+                       PrintValue(speed / 1024);
+                       System.Console.Write(" KB/s  ");
+                       UInt64 rating;
+                       if (decompressMode)
+                               rating = GetDecompressRating(elapsedTime, size, secondSize);
+                       else
+                               rating = GetCompressRating(dictionarySize, elapsedTime, size);
+                       PrintRating(rating);
+               }
+
+               static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize)
+               {
+                       if (numIterations <= 0)
+                               return 0;
+                       if (dictionarySize < (1 << 18))
+                       {
+                               System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)");
+                               return 1;
+                       }
+                       System.Console.Write("\n       Compressing                Decompressing\n\n");
+
+                       Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
+                       Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
+
+
+                       CoderPropID[] propIDs = 
+                       { 
+                               CoderPropID.DictionarySize,
+                       };
+                       object[] properties = 
+                       {
+                               (Int32)(dictionarySize),
+                       };
+
+                       UInt32 kBufferSize = dictionarySize + kAdditionalSize;
+                       UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+
+                       encoder.SetCoderProperties(propIDs, properties);
+                       System.IO.MemoryStream propStream = new System.IO.MemoryStream();
+                       encoder.WriteCoderProperties(propStream);
+                       byte[] propArray = propStream.ToArray();
+
+                       CBenchRandomGenerator rg = new CBenchRandomGenerator();
+
+                       rg.Set(kBufferSize);
+                       rg.Generate();
+                       CRC crc = new CRC();
+                       crc.Init();
+                       crc.Update(rg.Buffer, 0, rg.BufferSize);
+
+                       CProgressInfo progressInfo = new CProgressInfo();
+                       progressInfo.ApprovedStart = dictionarySize;
+
+                       UInt64 totalBenchSize = 0;
+                       UInt64 totalEncodeTime = 0;
+                       UInt64 totalDecodeTime = 0;
+                       UInt64 totalCompressedSize = 0;
+
+                       MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize);
+                       MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize);
+                       CrcOutStream crcOutStream = new CrcOutStream();
+                       for (Int32 i = 0; i < numIterations; i++)
+                       {
+                               progressInfo.Init();
+                               inStream.Seek(0, SeekOrigin.Begin);
+                               compressedStream.Seek(0, SeekOrigin.Begin);
+                               encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
+                               TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time;
+                               UInt64 encodeTime = (UInt64)sp2.Ticks;
+
+                               long compressedSize = compressedStream.Position;
+                               if (progressInfo.InSize == 0)
+                                       throw (new Exception("Internal ERROR 1282"));
+
+                               UInt64 decodeTime = 0;
+                               for (int j = 0; j < 2; j++)
+                               {
+                                       compressedStream.Seek(0, SeekOrigin.Begin);
+                                       crcOutStream.Init();
+
+                                       decoder.SetDecoderProperties(propArray);
+                                       UInt64 outSize = kBufferSize;
+                                       System.DateTime startTime = DateTime.UtcNow;
+                                       decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null);
+                                       TimeSpan sp = (DateTime.UtcNow - startTime);
+                                       decodeTime = (ulong)sp.Ticks;
+                                       if (crcOutStream.GetDigest() != crc.GetDigest())
+                                               throw (new Exception("CRC Error"));
+                               }
+                               UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize;
+                               PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
+                               System.Console.Write("     ");
+                               PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize);
+                               System.Console.WriteLine();
+
+                               totalBenchSize += benchSize;
+                               totalEncodeTime += encodeTime;
+                               totalDecodeTime += decodeTime;
+                               totalCompressedSize += (ulong)compressedSize;
+                       }
+                       System.Console.WriteLine("---------------------------------------------------");
+                       PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
+                       System.Console.Write("     ");
+                       PrintResults(dictionarySize, totalDecodeTime,
+                                       kBufferSize * (UInt64)numIterations, true, totalCompressedSize);
+                       System.Console.WriteLine("    Average");
+                       return 0;
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs b/lzma/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..9614884
--- /dev/null
@@ -0,0 +1,29 @@
+#region Using directives
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+#endregion
+
+// 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("LZMA#")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Igor Pavlov")]
+[assembly: AssemblyProduct("LZMA# SDK")]
+[assembly: AssemblyCopyright("Copyright @ Igor Pavlov 1999-2004")]
+[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("4.12.*")]
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs b/lzma/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
new file mode 100644 (file)
index 0000000..1170cf1
--- /dev/null
@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+// <autogenerated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.40607.42
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </autogenerated>
+//------------------------------------------------------------------------------
+
+namespace LzmaAlone.Properties
+{
+       using System;
+       using System.IO;
+       using System.Resources;
+
+       /// <summary>
+       ///    A strongly-typed resource class, for looking up localized strings, etc.
+       /// </summary>
+       // This class was auto-generated by the Strongly Typed Resource Builder
+       // class via a tool like ResGen or Visual Studio.NET.
+       // To add or remove a member, edit your .ResX file then rerun ResGen
+       // with the /str option, or rebuild your VS project.
+       class Resources
+       {
+
+               private static System.Resources.ResourceManager _resMgr;
+
+               private static System.Globalization.CultureInfo _resCulture;
+
+               /*FamANDAssem*/
+               internal Resources()
+               {
+               }
+
+               /// <summary>
+               ///    Returns the cached ResourceManager instance used by this class.
+               /// </summary>
+               [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+               public static System.Resources.ResourceManager ResourceManager
+               {
+                       get
+                       {
+                               if ((_resMgr == null))
+                               {
+                                       System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Resources", typeof(Resources).Assembly);
+                                       _resMgr = temp;
+                               }
+                               return _resMgr;
+                       }
+               }
+
+               /// <summary>
+               ///    Overrides the current thread's CurrentUICulture property for all
+               ///    resource lookups using this strongly typed resource class.
+               /// </summary>
+               [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+               public static System.Globalization.CultureInfo Culture
+               {
+                       get
+                       {
+                               return _resCulture;
+                       }
+                       set
+                       {
+                               _resCulture = value;
+                       }
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs b/lzma/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
new file mode 100644 (file)
index 0000000..ccfed77
--- /dev/null
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+// <autogenerated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.40607.42
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </autogenerated>
+//------------------------------------------------------------------------------
+
+namespace LzmaAlone.Properties
+{
+       public partial class Settings : System.Configuration.ApplicationSettingsBase
+       {
+               private static Settings m_Value;
+
+               private static object m_SyncObject = new object();
+
+               public static Settings Value
+               {
+                       get
+                       {
+                               if ((Settings.m_Value == null))
+                               {
+                                       System.Threading.Monitor.Enter(Settings.m_SyncObject);
+                                       if ((Settings.m_Value == null))
+                                       {
+                                               try
+                                               {
+                                                       Settings.m_Value = new Settings();
+                                               }
+                                               finally
+                                               {
+                                                       System.Threading.Monitor.Exit(Settings.m_SyncObject);
+                                               }
+                                       }
+                               }
+                               return Settings.m_Value;
+                       }
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/RangeCoder/RangeCoder.cs b/lzma/CS/7zip/Compress/RangeCoder/RangeCoder.cs
new file mode 100644 (file)
index 0000000..949c6bb
--- /dev/null
@@ -0,0 +1,234 @@
+using System;
+
+namespace SevenZip.Compression.RangeCoder
+{
+       class Encoder
+       {
+               public const uint kTopValue = (1 << 24);
+
+               System.IO.Stream Stream;
+
+               public UInt64 Low;
+               public uint Range;
+               uint _cacheSize;
+               byte _cache;
+
+               long StartPosition;
+
+               public void SetStream(System.IO.Stream stream)
+               {
+                       Stream = stream;
+               }
+
+               public void ReleaseStream()
+               {
+                       Stream = null;
+               }
+
+               public void Init()
+               {
+                       StartPosition = Stream.Position;
+
+                       Low = 0;
+                       Range = 0xFFFFFFFF;
+                       _cacheSize = 1;
+                       _cache = 0;
+               }
+
+               public void FlushData()
+               {
+                       for (int i = 0; i < 5; i++)
+                               ShiftLow();
+               }
+
+               public void FlushStream()
+               {
+                       Stream.Flush();
+               }
+
+               public void CloseStream()
+               {
+                       Stream.Close();
+               }
+
+               public void Encode(uint start, uint size, uint total)
+               {
+                       Low += start * (Range /= total);
+                       Range *= size;
+                       while (Range < kTopValue)
+                       {
+                               Range <<= 8;
+                               ShiftLow();
+                       }
+               }
+
+               public void ShiftLow()
+               {
+                       if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
+                       {
+                               byte temp = _cache;
+                               do
+                               {
+                                       Stream.WriteByte((byte)(temp + (Low >> 32)));
+                                       temp = 0xFF;
+                               }
+                               while (--_cacheSize != 0);
+                               _cache = (byte)(((uint)Low) >> 24);
+                       }
+                       _cacheSize++;
+                       Low = ((uint)Low) << 8;
+               }
+
+               public void EncodeDirectBits(uint v, int numTotalBits)
+               {
+                       for (int i = numTotalBits - 1; i >= 0; i--)
+                       {
+                               Range >>= 1;
+                               if (((v >> i) & 1) == 1)
+                                       Low += Range;
+                               if (Range < kTopValue)
+                               {
+                                       Range <<= 8;
+                                       ShiftLow();
+                               }
+                       }
+               }
+
+               public void EncodeBit(uint size0, int numTotalBits, uint symbol)
+               {
+                       uint newBound = (Range >> numTotalBits) * size0;
+                       if (symbol == 0)
+                               Range = newBound;
+                       else
+                       {
+                               Low += newBound;
+                               Range -= newBound;
+                       }
+                       while (Range < kTopValue)
+                       {
+                               Range <<= 8;
+                               ShiftLow();
+                       }
+               }
+
+               public long GetProcessedSizeAdd()
+               {
+                       return _cacheSize +
+                               Stream.Position - StartPosition + 4;
+                       // (long)Stream.GetProcessedSize();
+               }
+       }
+
+       class Decoder
+       {
+               public const uint kTopValue = (1 << 24);
+               public uint Range;
+               public uint Code;
+               // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
+               public System.IO.Stream Stream;
+
+               public void Init(System.IO.Stream stream)
+               {
+                       // Stream.Init(stream);
+                       Stream = stream;
+
+                       Code = 0;
+                       Range = 0xFFFFFFFF;
+                       for (int i = 0; i < 5; i++)
+                               Code = (Code << 8) | (byte)Stream.ReadByte();
+               }
+
+               public void ReleaseStream()
+               {
+                       // Stream.ReleaseStream();
+                       Stream = null;
+               }
+
+               public void CloseStream()
+               {
+                       Stream.Close();
+               }
+
+               public void Normalize()
+               {
+                       while (Range < kTopValue)
+                       {
+                               Code = (Code << 8) | (byte)Stream.ReadByte();
+                               Range <<= 8;
+                       }
+               }
+
+               public void Normalize2()
+               {
+                       if (Range < kTopValue)
+                       {
+                               Code = (Code << 8) | (byte)Stream.ReadByte();
+                               Range <<= 8;
+                       }
+               }
+
+               public uint GetThreshold(uint total)
+               {
+                       return Code / (Range /= total);
+               }
+
+               public void Decode(uint start, uint size, uint total)
+               {
+                       Code -= start * Range;
+                       Range *= size;
+                       Normalize();
+               }
+
+               public uint DecodeDirectBits(int numTotalBits)
+               {
+                       uint range = Range;
+                       uint code = Code;
+                       uint result = 0;
+                       for (int i = numTotalBits; i > 0; i--)
+                       {
+                               range >>= 1;
+                               /*
+                               result <<= 1;
+                               if (code >= range)
+                               {
+                                       code -= range;
+                                       result |= 1;
+                               }
+                               */
+                               uint t = (code - range) >> 31;
+                               code -= range & (t - 1);
+                               result = (result << 1) | (1 - t);
+
+                               if (range < kTopValue)
+                               {
+                                       code = (code << 8) | (byte)Stream.ReadByte();
+                                       range <<= 8;
+                               }
+                       }
+                       Range = range;
+                       Code = code;
+                       return result;
+               }
+
+               public uint DecodeBit(uint size0, int numTotalBits)
+               {
+                       uint newBound = (Range >> numTotalBits) * size0;
+                       uint symbol;
+                       if (Code < newBound)
+                       {
+                               symbol = 0;
+                               Range = newBound;
+                       }
+                       else
+                       {
+                               symbol = 1;
+                               Code -= newBound;
+                               Range -= newBound;
+                       }
+                       Normalize();
+                       return symbol;
+               }
+
+               // ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs b/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
new file mode 100644 (file)
index 0000000..4f0346d
--- /dev/null
@@ -0,0 +1,117 @@
+using System;
+
+namespace SevenZip.Compression.RangeCoder
+{
+       struct BitEncoder
+       {
+               public const int kNumBitModelTotalBits = 11;
+               public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
+               const int kNumMoveBits = 5;
+               const int kNumMoveReducingBits = 2;
+               public const int kNumBitPriceShiftBits = 6;
+
+               uint Prob;
+
+               public void Init() { Prob = kBitModelTotal >> 1; }
+
+               public void UpdateModel(uint symbol)
+               {
+                       if (symbol == 0)
+                               Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
+                       else
+                               Prob -= (Prob) >> kNumMoveBits;
+               }
+
+               public void Encode(Encoder encoder, uint symbol)
+               {
+                       // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
+                       // UpdateModel(symbol);
+                       uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
+                       if (symbol == 0)
+                       {
+                               encoder.Range = newBound;
+                               Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
+                       }
+                       else
+                       {
+                               encoder.Low += newBound;
+                               encoder.Range -= newBound;
+                               Prob -= (Prob) >> kNumMoveBits;
+                       }
+                       if (encoder.Range < Encoder.kTopValue)
+                       {
+                               encoder.Range <<= 8;
+                               encoder.ShiftLow();
+                       }
+               }
+
+               private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
+
+               static BitEncoder()
+               {
+                       const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
+                       for (int i = kNumBits - 1; i >= 0; i--)
+                       {
+                               UInt32 start = (UInt32)1 << (kNumBits - i - 1);
+                               UInt32 end = (UInt32)1 << (kNumBits - i);
+                               for (UInt32 j = start; j < end; j++)
+                                       ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
+                                               (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
+                       }
+               }
+
+               public uint GetPrice(uint symbol)
+               {
+                       return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
+               }
+         public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
+               public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
+       }
+
+       struct BitDecoder
+       {
+               public const int kNumBitModelTotalBits = 11;
+               public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
+               const int kNumMoveBits = 5;
+
+               uint Prob;
+
+               public void UpdateModel(int numMoveBits, uint symbol)
+               {
+                       if (symbol == 0)
+                               Prob += (kBitModelTotal - Prob) >> numMoveBits;
+                       else
+                               Prob -= (Prob) >> numMoveBits;
+               }
+
+               public void Init() { Prob = kBitModelTotal >> 1; }
+
+               public uint Decode(RangeCoder.Decoder rangeDecoder)
+               {
+                       uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;
+                       if (rangeDecoder.Code < newBound)
+                       {
+                               rangeDecoder.Range = newBound;
+                               Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
+                               if (rangeDecoder.Range < Decoder.kTopValue)
+                               {
+                                       rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
+                                       rangeDecoder.Range <<= 8;
+                               }
+                               return 0;
+                       }
+                       else
+                       {
+                               rangeDecoder.Range -= newBound;
+                               rangeDecoder.Code -= newBound;
+                               Prob -= (Prob) >> kNumMoveBits;
+                               if (rangeDecoder.Range < Decoder.kTopValue)
+                               {
+                                       rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
+                                       rangeDecoder.Range <<= 8;
+                               }
+                               return 1;
+                       }
+               }
+       }
+}
diff --git a/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs b/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
new file mode 100644 (file)
index 0000000..4b4506f
--- /dev/null
@@ -0,0 +1,157 @@
+using System;
+
+namespace SevenZip.Compression.RangeCoder
+{
+       struct BitTreeEncoder
+       {
+               BitEncoder[] Models;
+               int NumBitLevels;
+
+               public BitTreeEncoder(int numBitLevels)
+               {
+                       NumBitLevels = numBitLevels;
+                       Models = new BitEncoder[1 << numBitLevels];
+               }
+
+               public void Init()
+               {
+                       for (uint i = 1; i < (1 << NumBitLevels); i++)
+                               Models[i].Init();
+               }
+
+               public void Encode(Encoder rangeEncoder, UInt32 symbol)
+               {
+                       UInt32 m = 1;
+                       for (int bitIndex = NumBitLevels; bitIndex > 0; )
+                       {
+                               bitIndex--;
+                               UInt32 bit = (symbol >> bitIndex) & 1;
+                               Models[m].Encode(rangeEncoder, bit);
+                               m = (m << 1) | bit;
+                       }
+               }
+
+               public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
+               {
+                       UInt32 m = 1;
+                       for (UInt32 i = 0; i < NumBitLevels; i++)
+                       {
+                               UInt32 bit = symbol & 1;
+                               Models[m].Encode(rangeEncoder, bit);
+                               m = (m << 1) | bit;
+                               symbol >>= 1;
+                       }
+               }
+
+               public UInt32 GetPrice(UInt32 symbol)
+               {
+                       UInt32 price = 0;
+                       UInt32 m = 1;
+                       for (int bitIndex = NumBitLevels; bitIndex > 0; )
+                       {
+                               bitIndex--;
+                               UInt32 bit = (symbol >> bitIndex) & 1;
+                               price += Models[m].GetPrice(bit);
+                               m = (m << 1) + bit;
+                       }
+                       return price;
+               }
+
+               public UInt32 ReverseGetPrice(UInt32 symbol)
+               {
+                       UInt32 price = 0;
+                       UInt32 m = 1;
+                       for (int i = NumBitLevels; i > 0; i--)
+                       {
+                               UInt32 bit = symbol & 1;
+                               symbol >>= 1;
+                               price += Models[m].GetPrice(bit);
+                               m = (m << 1) | bit;
+                       }
+                       return price;
+               }
+
+               public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
+                       int NumBitLevels, UInt32 symbol)
+               {
+                       UInt32 price = 0;
+                       UInt32 m = 1;
+                       for (int i = NumBitLevels; i > 0; i--)
+                       {
+                               UInt32 bit = symbol & 1;
+                               symbol >>= 1;
+                               price += Models[startIndex + m].GetPrice(bit);
+                               m = (m << 1) | bit;
+                       }
+                       return price;
+               }
+
+               public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
+                       Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
+               {
+                       UInt32 m = 1;
+                       for (int i = 0; i < NumBitLevels; i++)
+                       {
+                               UInt32 bit = symbol & 1;
+                               Models[startIndex + m].Encode(rangeEncoder, bit);
+                               m = (m << 1) | bit;
+                               symbol >>= 1;
+                       }
+               }
+       }
+
+       struct BitTreeDecoder
+       {
+               BitDecoder[] Models;
+               int NumBitLevels;
+
+               public BitTreeDecoder(int numBitLevels)
+               {
+                       NumBitLevels = numBitLevels;
+                       Models = new BitDecoder[1 << numBitLevels];
+               }
+
+               public void Init()
+               {
+                       for (uint i = 1; i < (1 << NumBitLevels); i++)
+                               Models[i].Init();
+               }
+
+               public uint Decode(RangeCoder.Decoder rangeDecoder)
+               {
+                       uint m = 1;
+                       for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
+                               m = (m << 1) + Models[m].Decode(rangeDecoder);
+                       return m - ((uint)1 << NumBitLevels);
+               }
+
+               public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
+               {
+                       uint m = 1;
+                       uint symbol = 0;
+                       for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+                       {
+                               uint bit = Models[m].Decode(rangeDecoder);
+                               m <<= 1;
+                               m += bit;
+                               symbol |= (bit << bitIndex);
+                       }
+                       return symbol;
+               }
+
+               public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
+                       RangeCoder.Decoder rangeDecoder, int NumBitLevels)
+               {
+                       uint m = 1;
+                       uint symbol = 0;
+                       for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+                       {
+                               uint bit = Models[startIndex + m].Decode(rangeDecoder);
+                               m <<= 1;
+                               m += bit;
+                               symbol |= (bit << bitIndex);
+                       }
+                       return symbol;
+               }
+       }
+}
diff --git a/lzma/CS/7zip/ICoder.cs b/lzma/CS/7zip/ICoder.cs
new file mode 100644 (file)
index 0000000..85bf531
--- /dev/null
@@ -0,0 +1,145 @@
+// ICoder.h
+
+using System;
+
+namespace SevenZip
+{
+       /// <summary>
+       /// The exception that is thrown when an error in input stream occurs during decoding.
+       /// </summary>
+       class DataErrorException : ApplicationException
+       {
+               public DataErrorException(): base("Data Error") { }
+       }
+
+       /// <summary>
+       /// The exception that is thrown when the value of an argument is outside the allowable range.
+       /// </summary>
+       class InvalidParamException : ApplicationException
+       {
+               public InvalidParamException(): base("Invalid Parameter") { }
+       }
+
+       public interface ICodeProgress
+       {
+               /// <summary>
+               /// Callback progress.
+               /// </summary>
+               /// <param name="inSize">
+               /// input size. -1 if unknown.
+               /// </param>
+               /// <param name="outSize">
+               /// output size. -1 if unknown.
+               /// </param>
+               void SetProgress(Int64 inSize, Int64 outSize);
+       };
+
+       public interface ICoder
+       {
+               /// <summary>
+               /// Codes streams.
+               /// </summary>
+               /// <param name="inStream">
+               /// input Stream.
+               /// </param>
+               /// <param name="outStream">
+               /// output Stream.
+               /// </param>
+               /// <param name="inSize">
+               /// input Size. -1 if unknown.
+               /// </param>
+               /// <param name="outSize">
+               /// output Size. -1 if unknown.
+               /// </param>
+               /// <param name="progress">
+               /// callback progress reference.
+               /// </param>
+               /// <exception cref="SevenZip.DataErrorException">
+               /// if input stream is not valid
+               /// </exception>
+               void Code(System.IO.Stream inStream, System.IO.Stream outStream,
+                       Int64 inSize, Int64 outSize, ICodeProgress progress);
+       };
+
+       /*
+       public interface ICoder2
+       {
+                void Code(ISequentialInStream []inStreams,
+                               const UInt64 []inSizes, 
+                               ISequentialOutStream []outStreams, 
+                               UInt64 []outSizes,
+                               ICodeProgress progress);
+       };
+  */
+
+       /// <summary>
+       /// Provides the fields that represent properties idenitifiers for compressing.
+       /// </summary>
+       public enum CoderPropID
+       {
+               /// <summary>
+               /// Specifies size of dictionary.
+               /// </summary>
+               DictionarySize = 0x400,
+               /// <summary>
+               /// Specifies size of memory for PPM*.
+               /// </summary>
+               UsedMemorySize,
+               /// <summary>
+               /// Specifies order for PPM methods.
+               /// </summary>
+               Order,
+               /// <summary>
+               /// Specifies number of postion state bits for LZMA (0 <= x <= 4).
+               /// </summary>
+               PosStateBits = 0x440,
+               /// <summary>
+               /// Specifies number of literal context bits for LZMA (0 <= x <= 8).
+               /// </summary>
+               LitContextBits,
+               /// <summary>
+               /// Specifies number of literal position bits for LZMA (0 <= x <= 4).
+               /// </summary>
+               LitPosBits,
+               /// <summary>
+               /// Specifies number of fast bytes for LZ*.
+               /// </summary>
+               NumFastBytes = 0x450,
+               /// <summary>
+               /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
+               /// </summary>
+               MatchFinder,
+               /// <summary>
+               /// Specifies number of passes.
+               /// </summary>
+               NumPasses = 0x460,
+               /// <summary>
+               /// Specifies number of algorithm.
+               /// </summary>
+               Algorithm = 0x470,
+               /// <summary>
+               /// Specifies multithread mode.
+               /// </summary>
+               MultiThread = 0x480,
+               /// <summary>
+               /// Specifies mode with end marker.
+               /// </summary>
+               EndMarker = 0x490
+       };
+
+
+       public interface ISetCoderProperties
+       {
+               void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
+       };
+
+       public interface IWriteCoderProperties
+       {
+               void WriteCoderProperties(System.IO.Stream outStream);
+       }
+
+       public interface ISetDecoderProperties
+       {
+               void SetDecoderProperties(byte[] properties);
+       }
+}
diff --git a/lzma/Java/SevenZip/CRC.java b/lzma/Java/SevenZip/CRC.java
new file mode 100644 (file)
index 0000000..c55e33c
--- /dev/null
@@ -0,0 +1,52 @@
+// SevenZip/CRC.java
+
+package SevenZip;
+
+public class CRC
+{
+       static public int[] Table = new int[256];
+       
+       static
+       {
+               for (int i = 0; i < 256; i++)
+               {
+                       int r = i;
+                       for (int j = 0; j < 8; j++)
+                               if ((r & 1) != 0)
+                                       r = (r >>> 1) ^ 0xEDB88320;
+                               else
+                                       r >>>= 1;
+                       Table[i] = r;
+               }
+       }
+       
+       int _value = -1;
+       
+       public void Init()
+       {
+               _value = -1;
+       }
+       
+       public void Update(byte[] data, int offset, int size)
+       {
+               for (int i = 0; i < size; i++)
+                       _value = Table[(_value ^ data[offset + i]) & 0xFF] ^ (_value >>> 8);
+       }
+       
+       public void Update(byte[] data)
+       {
+               int size = data.length;
+               for (int i = 0; i < size; i++)
+                       _value = Table[(_value ^ data[i]) & 0xFF] ^ (_value >>> 8);
+       }
+       
+       public void UpdateByte(int b)
+       {
+               _value = Table[(_value ^ b) & 0xFF] ^ (_value >>> 8);
+       }
+       
+       public int GetDigest()
+       {
+               return _value ^ (-1);
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/LZ/BinTree.java b/lzma/Java/SevenZip/Compression/LZ/BinTree.java
new file mode 100644 (file)
index 0000000..e2074e9
--- /dev/null
@@ -0,0 +1,382 @@
+// LZ.BinTree
+
+package SevenZip.Compression.LZ;
+import java.io.IOException;
+
+
+public class BinTree extends InWindow
+{
+       int _cyclicBufferPos;
+       int _cyclicBufferSize = 0;
+       int _matchMaxLen;
+       
+       int[] _son;
+       int[] _hash;
+       
+       int _cutValue = 0xFF;
+       int _hashMask;
+       int _hashSizeSum = 0;
+       
+       boolean HASH_ARRAY = true;
+
+       static final int kHash2Size = 1 << 10;
+       static final int kHash3Size = 1 << 16;
+       static final int kBT2HashSize = 1 << 16;
+       static final int kStartMaxLen = 1;
+       static final int kHash3Offset = kHash2Size;
+       static final int kEmptyHashValue = 0;
+       static final int kMaxValForNormalize = (1 << 30) - 1;
+       
+       int kNumHashDirectBytes = 0;
+       int kMinMatchCheck = 4;
+       int kFixHashSize = kHash2Size + kHash3Size;
+
+       public void SetType(int numHashBytes)
+       {
+               HASH_ARRAY = (numHashBytes > 2);
+               if (HASH_ARRAY)
+               {
+                       kNumHashDirectBytes = 0;
+                       kMinMatchCheck = 4;
+                       kFixHashSize = kHash2Size + kHash3Size;
+               }
+               else
+               {
+                       kNumHashDirectBytes = 2;
+                       kMinMatchCheck = 2 + 1;
+                       kFixHashSize = 0;
+               }
+       }
+       
+
+       
+
+       public void Init() throws IOException
+       {
+               super.Init();
+               for (int i = 0; i < _hashSizeSum; i++)
+                       _hash[i] = kEmptyHashValue;
+               _cyclicBufferPos = 0;
+               ReduceOffsets(-1);
+       }
+       
+       public void MovePos() throws IOException
+       {
+               if (++_cyclicBufferPos >= _cyclicBufferSize)
+                       _cyclicBufferPos = 0;
+               super.MovePos();
+               if (_pos == kMaxValForNormalize)
+                       Normalize();
+       }
+       
+
+       
+       
+       
+       
+       
+       
+       public boolean Create(int historySize, int keepAddBufferBefore,
+                       int matchMaxLen, int keepAddBufferAfter)
+       {
+               if (historySize > kMaxValForNormalize - 256)
+                       return false;
+               _cutValue = 16 + (matchMaxLen >> 1);
+
+               int windowReservSize = (historySize + keepAddBufferBefore +
+                               matchMaxLen + keepAddBufferAfter) / 2 + 256;
+               
+               super.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
+               
+               _matchMaxLen = matchMaxLen;
+
+               int cyclicBufferSize = historySize + 1;
+               if (_cyclicBufferSize != cyclicBufferSize)
+                       _son = new int[(_cyclicBufferSize = cyclicBufferSize) * 2];
+
+               int hs = kBT2HashSize;
+
+               if (HASH_ARRAY)
+               {
+                       hs = historySize - 1;
+                       hs |= (hs >> 1);
+                       hs |= (hs >> 2);
+                       hs |= (hs >> 4);
+                       hs |= (hs >> 8);
+                       hs >>= 1;
+                       hs |= 0xFFFF;
+                       if (hs > (1 << 24))
+                               hs >>= 1;
+                       _hashMask = hs;
+                       hs++;
+                       hs += kFixHashSize;
+               }
+               if (hs != _hashSizeSum)
+                       _hash = new int [_hashSizeSum = hs];
+               return true;
+       }
+       public int GetMatches(int[] distances) throws IOException
+       {
+               int lenLimit;
+               if (_pos + _matchMaxLen <= _streamPos)
+                       lenLimit = _matchMaxLen;
+               else
+               {
+                       lenLimit = _streamPos - _pos;
+                       if (lenLimit < kMinMatchCheck)
+                       {
+                               MovePos();
+                               return 0;
+                       }
+               }
+
+               int offset = 0;
+               int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+               int cur = _bufferOffset + _pos;
+               int maxLen = kStartMaxLen; // to avoid items for len < hashSize;
+               int hashValue, hash2Value = 0, hash3Value = 0;
+               
+               if (HASH_ARRAY)
+               {
+                       int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF);
+                       hash2Value = temp & (kHash2Size - 1);
+                       temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8);
+                       hash3Value = temp & (kHash3Size - 1);
+                       hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask;
+               }
+               else
+                       hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8));
+
+               int curMatch = _hash[kFixHashSize + hashValue];
+               if (HASH_ARRAY)
+               {
+                       int curMatch2 = _hash[hash2Value];
+                       int curMatch3 = _hash[kHash3Offset + hash3Value];
+                       _hash[hash2Value] = _pos;
+                       _hash[kHash3Offset + hash3Value] = _pos;
+                       if (curMatch2 > matchMinPos)
+                               if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
+                               {
+                                       distances[offset++] = maxLen = 2;
+                                       distances[offset++] = _pos - curMatch2 - 1;
+                               }
+                       if (curMatch3 > matchMinPos)
+                               if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
+                               {
+                                       if (curMatch3 == curMatch2)
+                                               offset -= 2;
+                                       distances[offset++] = maxLen = 3;
+                                       distances[offset++] = _pos - curMatch3 - 1;
+                                       curMatch2 = curMatch3;
+                               }
+                       if (offset != 0 && curMatch2 == curMatch)
+                       {
+                               offset -= 2;
+                               maxLen = kStartMaxLen;
+                       }
+               }
+
+               _hash[kFixHashSize + hashValue] = _pos;
+
+               int ptr0 = (_cyclicBufferPos << 1) + 1;
+               int ptr1 = (_cyclicBufferPos << 1);
+
+               int len0, len1;
+               len0 = len1 = kNumHashDirectBytes;
+
+               if (kNumHashDirectBytes != 0)
+               {
+                       if (curMatch > matchMinPos)
+                       {
+                               if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
+                                               _bufferBase[cur + kNumHashDirectBytes])
+                               {
+                                       distances[offset++] = maxLen = kNumHashDirectBytes;
+                                       distances[offset++] = _pos - curMatch - 1;
+                               }
+                       }
+               }
+
+               int count = _cutValue;
+
+               while (true)
+               {
+                       if (curMatch <= matchMinPos || count-- == 0)
+                       {
+                               _son[ptr0] = _son[ptr1] = kEmptyHashValue;
+                               break;
+                       }
+                       int delta = _pos - curMatch;
+                       int cyclicPos = ((delta <= _cyclicBufferPos) ?
+                               (_cyclicBufferPos - delta) :
+                               (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
+
+                       int pby1 = _bufferOffset + curMatch;
+                       int len = Math.min(len0, len1);
+                       if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
+                       {
+                               while(++len != lenLimit)
+                                       if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
+                                               break;
+                               if (maxLen < len)
+                               {
+                                       distances[offset++] = maxLen = len;
+                                       distances[offset++] = delta - 1;
+                                       if (len == lenLimit)
+                                       {
+                                               _son[ptr1] = _son[cyclicPos];
+                                               _son[ptr0] = _son[cyclicPos + 1];
+                                               break;
+                                       }
+                               }
+                       }
+                       if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF))
+                       {
+                               _son[ptr1] = curMatch;
+                               ptr1 = cyclicPos + 1;
+                               curMatch = _son[ptr1];
+                               len1 = len;
+                       }
+                       else
+                       {
+                               _son[ptr0] = curMatch;
+                               ptr0 = cyclicPos;
+                               curMatch = _son[ptr0];
+                               len0 = len;
+                       }
+               }
+               MovePos();
+               return offset;
+       }
+
+       public void Skip(int num) throws IOException
+       {
+               do
+               {
+                       int lenLimit;
+                       if (_pos + _matchMaxLen <= _streamPos)
+                       lenLimit = _matchMaxLen;
+                       else
+                       {
+                               lenLimit = _streamPos - _pos;
+                               if (lenLimit < kMinMatchCheck)
+                               {
+                                       MovePos();
+                                       continue;
+                               }
+                       }
+
+                       int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+                       int cur = _bufferOffset + _pos;
+                       
+                       int hashValue;
+
+                       if (HASH_ARRAY)
+                       {
+                               int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF);
+                               int hash2Value = temp & (kHash2Size - 1);
+                               _hash[hash2Value] = _pos;
+                               temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8);
+                               int hash3Value = temp & (kHash3Size - 1);
+                               _hash[kHash3Offset + hash3Value] = _pos;
+                               hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask;
+                       }
+                       else
+                               hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8));
+
+                       int curMatch = _hash[kFixHashSize + hashValue];
+                       _hash[kFixHashSize + hashValue] = _pos;
+
+                       int ptr0 = (_cyclicBufferPos << 1) + 1;
+                       int ptr1 = (_cyclicBufferPos << 1);
+
+                       int len0, len1;
+                       len0 = len1 = kNumHashDirectBytes;
+
+                       int count = _cutValue;
+                       while (true)
+                       {
+                               if (curMatch <= matchMinPos || count-- == 0)
+                               {
+                                       _son[ptr0] = _son[ptr1] = kEmptyHashValue;
+                                       break;
+                               }
+
+                               int delta = _pos - curMatch;
+                               int cyclicPos = ((delta <= _cyclicBufferPos) ?
+                                       (_cyclicBufferPos - delta) :
+                                       (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
+
+                               int pby1 = _bufferOffset + curMatch;
+                               int len = Math.min(len0, len1);
+                               if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
+                               {
+                                       while (++len != lenLimit)
+                                               if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
+                                                       break;
+                                       if (len == lenLimit)
+                                       {
+                                               _son[ptr1] = _son[cyclicPos];
+                                               _son[ptr0] = _son[cyclicPos + 1];
+                                               break;
+                                       }
+                               }
+                               if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF))
+                               {
+                                       _son[ptr1] = curMatch;
+                                       ptr1 = cyclicPos + 1;
+                                       curMatch = _son[ptr1];
+                                       len1 = len;
+                               }
+                               else
+                               {
+                                       _son[ptr0] = curMatch;
+                                       ptr0 = cyclicPos;
+                                       curMatch = _son[ptr0];
+                                       len0 = len;
+                               }
+                       }
+                       MovePos();
+               }
+               while (--num != 0);
+       }
+       
+       void NormalizeLinks(int[] items, int numItems, int subValue)
+       {
+               for (int i = 0; i < numItems; i++)
+               {
+                       int value = items[i];
+                       if (value <= subValue)
+                               value = kEmptyHashValue;
+                       else
+                               value -= subValue;
+                       items[i] = value;
+               }
+       }
+       
+       void Normalize()
+       {
+               int subValue = _pos - _cyclicBufferSize;
+               NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
+               NormalizeLinks(_hash, _hashSizeSum, subValue);
+               ReduceOffsets(subValue);
+       }
+       
+       public void SetCutValue(int cutValue) { _cutValue = cutValue; }
+
+       private static final int[] CrcTable = new int[256];
+
+       static
+       {
+               for (int i = 0; i < 256; i++)
+               {
+                       int r = i;
+                       for (int j = 0; j < 8; j++)
+                               if ((r & 1) != 0)
+                                       r = (r >>> 1) ^ 0xEDB88320;
+                               else
+                                       r >>>= 1;
+                       CrcTable[i] = r;
+               }
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/LZ/InWindow.java b/lzma/Java/SevenZip/Compression/LZ/InWindow.java
new file mode 100644 (file)
index 0000000..c9efe60
--- /dev/null
@@ -0,0 +1,131 @@
+// LZ.InWindow
+
+package SevenZip.Compression.LZ;
+
+import java.io.IOException;
+
+public class InWindow
+{
+       public byte[] _bufferBase; // pointer to buffer with data
+       java.io.InputStream _stream;
+       int _posLimit;  // offset (from _buffer) of first byte when new block reading must be done
+       boolean _streamEndWasReached; // if (true) then _streamPos shows real end of stream
+       
+       int _pointerToLastSafePosition;
+       
+       public int _bufferOffset;
+       
+       public int _blockSize;  // Size of Allocated memory block
+       public int _pos;             // offset (from _buffer) of curent byte
+       int _keepSizeBefore;  // how many BYTEs must be kept in buffer before _pos
+       int _keepSizeAfter;   // how many BYTEs must be kept buffer after _pos
+       public int _streamPos;   // offset (from _buffer) of first not read byte from Stream
+       
+       public void MoveBlock()
+       {
+               int offset = _bufferOffset + _pos - _keepSizeBefore;
+               // we need one additional byte, since MovePos moves on 1 byte.
+               if (offset > 0)
+                       offset--;
+
+               int numBytes = _bufferOffset + _streamPos - offset;
+               
+               // check negative offset ????
+               for (int i = 0; i < numBytes; i++)
+                       _bufferBase[i] = _bufferBase[offset + i];
+               _bufferOffset -= offset;
+       }
+       
+       public void ReadBlock() throws IOException
+       {
+               if (_streamEndWasReached)
+                       return;
+               while (true)
+               {
+                       int size = (0 - _bufferOffset) + _blockSize - _streamPos;
+                       if (size == 0)
+                               return;
+                       int numReadBytes = _stream.read(_bufferBase, _bufferOffset + _streamPos, size);
+                       if (numReadBytes == -1)
+                       {
+                               _posLimit = _streamPos;
+                               int pointerToPostion = _bufferOffset + _posLimit;
+                               if (pointerToPostion > _pointerToLastSafePosition)
+                                       _posLimit = _pointerToLastSafePosition - _bufferOffset;
+                               
+                               _streamEndWasReached = true;
+                               return;
+                       }
+                       _streamPos += numReadBytes;
+                       if (_streamPos >= _pos + _keepSizeAfter)
+                               _posLimit = _streamPos - _keepSizeAfter;
+               }
+       }
+       
+       void Free() { _bufferBase = null; }
+       
+       public void Create(int keepSizeBefore, int keepSizeAfter, int keepSizeReserv)
+       {
+               _keepSizeBefore = keepSizeBefore;
+               _keepSizeAfter = keepSizeAfter;
+               int blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
+               if (_bufferBase == null || _blockSize != blockSize)
+               {
+                       Free();
+                       _blockSize = blockSize;
+                       _bufferBase = new byte[_blockSize];
+               }
+               _pointerToLastSafePosition = _blockSize - keepSizeAfter;
+       }
+       
+       public void SetStream(java.io.InputStream stream) { _stream = stream;   }
+       public void ReleaseStream() { _stream = null; }
+
+       public void Init() throws IOException
+       {
+               _bufferOffset = 0;
+               _pos = 0;
+               _streamPos = 0;
+               _streamEndWasReached = false;
+               ReadBlock();
+       }
+       
+       public void MovePos() throws IOException
+       {
+               _pos++;
+               if (_pos > _posLimit)
+               {
+                       int pointerToPostion = _bufferOffset + _pos;
+                       if (pointerToPostion > _pointerToLastSafePosition)
+                               MoveBlock();
+                       ReadBlock();
+               }
+       }
+       
+       public byte GetIndexByte(int index)     { return _bufferBase[_bufferOffset + _pos + index]; }
+       
+       // index + limit have not to exceed _keepSizeAfter;
+       public int GetMatchLen(int index, int distance, int limit)
+       {
+               if (_streamEndWasReached)
+                       if ((_pos + index) + limit > _streamPos)
+                               limit = _streamPos - (_pos + index);
+               distance++;
+               // Byte *pby = _buffer + (size_t)_pos + index;
+               int pby = _bufferOffset + _pos + index;
+               
+               int i;
+               for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
+               return i;
+       }
+       
+       public int GetNumAvailableBytes()       { return _streamPos - _pos; }
+       
+       public void ReduceOffsets(int subValue)
+       {
+               _bufferOffset += subValue;
+               _posLimit -= subValue;
+               _pos -= subValue;
+               _streamPos -= subValue;
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/LZ/OutWindow.java b/lzma/Java/SevenZip/Compression/LZ/OutWindow.java
new file mode 100644 (file)
index 0000000..2fd2832
--- /dev/null
@@ -0,0 +1,85 @@
+// LZ.OutWindow
+
+package SevenZip.Compression.LZ;
+
+import java.io.IOException;
+
+public class OutWindow
+{
+       byte[] _buffer;
+       int _pos;
+       int _windowSize = 0;
+       int _streamPos;
+       java.io.OutputStream _stream;
+       
+       public void Create(int windowSize)
+       {
+               if (_buffer == null || _windowSize != windowSize)
+                       _buffer = new byte[windowSize];
+               _windowSize = windowSize;
+               _pos = 0;
+               _streamPos = 0;
+       }
+       
+       public void SetStream(java.io.OutputStream stream) throws IOException
+       {
+               ReleaseStream();
+               _stream = stream;
+       }
+       
+       public void ReleaseStream() throws IOException
+       {
+               Flush();
+               _stream = null;
+       }
+       
+       public void Init(boolean solid)
+       {
+               if (!solid)
+               {
+                       _streamPos = 0;
+                       _pos = 0;
+               }
+       }
+       
+       public void Flush() throws IOException
+       {
+               int size = _pos - _streamPos;
+               if (size == 0)
+                       return;
+               _stream.write(_buffer, _streamPos, size);
+               if (_pos >= _windowSize)
+                       _pos = 0;
+               _streamPos = _pos;
+       }
+       
+       public void CopyBlock(int distance, int len) throws IOException
+       {
+               int pos = _pos - distance - 1;
+               if (pos < 0)
+                       pos += _windowSize;
+               for (; len != 0; len--)
+               {
+                       if (pos >= _windowSize)
+                               pos = 0;
+                       _buffer[_pos++] = _buffer[pos++];
+                       if (_pos >= _windowSize)
+                               Flush();
+               }
+       }
+       
+       public void PutByte(byte b) throws IOException
+       {
+               _buffer[_pos++] = b;
+               if (_pos >= _windowSize)
+                       Flush();
+       }
+       
+       public byte GetByte(int distance)
+       {
+               int pos = _pos - distance - 1;
+               if (pos < 0)
+                       pos += _windowSize;
+               return _buffer[pos];
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/LZMA/Base.java b/lzma/Java/SevenZip/Compression/LZMA/Base.java
new file mode 100644 (file)
index 0000000..b4f2fb5
--- /dev/null
@@ -0,0 +1,88 @@
+// Base.java
+
+package SevenZip.Compression.LZMA;
+
+public class Base
+{
+       public static final int kNumRepDistances = 4;
+       public static final int kNumStates = 12;
+       
+       public static final int StateInit()
+       {
+               return 0;
+       }
+       
+       public static final int StateUpdateChar(int index)
+       {
+               if (index < 4) 
+                       return 0;
+               if (index < 10) 
+                       return index - 3;
+               return index - 6;
+       }
+       
+       public static final int StateUpdateMatch(int index)
+       {
+               return (index < 7 ? 7 : 10); 
+       }
+
+       public static final int StateUpdateRep(int index)
+       { 
+               return (index < 7 ? 8 : 11); 
+       }
+       
+       public static final int StateUpdateShortRep(int index)
+       { 
+               return (index < 7 ? 9 : 11); 
+       }
+
+       public static final boolean StateIsCharState(int index)
+       { 
+               return index < 7; 
+       }
+       
+       public static final int kNumPosSlotBits = 6;
+       public static final int kDicLogSizeMin = 0;
+       // public static final int kDicLogSizeMax = 28;
+       // public static final int kDistTableSizeMax = kDicLogSizeMax * 2;
+       
+       public static final int kNumLenToPosStatesBits = 2; // it's for speed optimization
+       public static final int kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
+       
+       public static final int kMatchMinLen = 2;
+       
+       public static final int GetLenToPosState(int len)
+       {
+               len -= kMatchMinLen;
+               if (len < kNumLenToPosStates)
+                       return len;
+               return (int)(kNumLenToPosStates - 1);
+       }
+       
+       public static final int kNumAlignBits = 4;
+       public static final int kAlignTableSize = 1 << kNumAlignBits;
+       public static final int kAlignMask = (kAlignTableSize - 1);
+       
+       public static final int kStartPosModelIndex = 4;
+       public static final int kEndPosModelIndex = 14;
+       public static final int kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
+       
+       public static final  int kNumFullDistances = 1 << (kEndPosModelIndex / 2);
+       
+       public static final  int kNumLitPosStatesBitsEncodingMax = 4;
+       public static final  int kNumLitContextBitsMax = 8;
+       
+       public static final  int kNumPosStatesBitsMax = 4;
+       public static final  int kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
+       public static final  int kNumPosStatesBitsEncodingMax = 4;
+       public static final  int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
+       
+       public static final  int kNumLowLenBits = 3;
+       public static final  int kNumMidLenBits = 3;
+       public static final  int kNumHighLenBits = 8;
+       public static final  int kNumLowLenSymbols = 1 << kNumLowLenBits;
+       public static final  int kNumMidLenSymbols = 1 << kNumMidLenBits;
+       public static final  int kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
+                       (1 << kNumHighLenBits);
+       public static final  int kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
+}
diff --git a/lzma/Java/SevenZip/Compression/LZMA/Decoder.java b/lzma/Java/SevenZip/Compression/LZMA/Decoder.java
new file mode 100644 (file)
index 0000000..16ee249
--- /dev/null
@@ -0,0 +1,329 @@
+package SevenZip.Compression.LZMA;
+
+import SevenZip.Compression.RangeCoder.BitTreeDecoder;
+import SevenZip.Compression.LZMA.Base;
+import SevenZip.Compression.LZ.OutWindow;
+import java.io.IOException;
+
+public class Decoder
+{
+       class LenDecoder
+       {
+               short[] m_Choice = new short[2];
+               BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
+               BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
+               BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
+               int m_NumPosStates = 0;
+               
+               public void Create(int numPosStates)
+               {
+                       for (; m_NumPosStates < numPosStates; m_NumPosStates++)
+                       {
+                               m_LowCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumLowLenBits);
+                               m_MidCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumMidLenBits);
+                       }
+               }
+               
+               public void Init()
+               {
+                       SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Choice);
+                       for (int posState = 0; posState < m_NumPosStates; posState++)
+                       {
+                               m_LowCoder[posState].Init();
+                               m_MidCoder[posState].Init();
+                       }
+                       m_HighCoder.Init();
+               }
+               
+               public int Decode(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, int posState) throws IOException
+               {
+                       if (rangeDecoder.DecodeBit(m_Choice, 0) == 0)
+                               return m_LowCoder[posState].Decode(rangeDecoder);
+                       int symbol = Base.kNumLowLenSymbols;
+                       if (rangeDecoder.DecodeBit(m_Choice, 1) == 0)
+                               symbol += m_MidCoder[posState].Decode(rangeDecoder);
+                       else
+                               symbol += Base.kNumMidLenSymbols + m_HighCoder.Decode(rangeDecoder);
+                       return symbol;
+               }
+       }
+       
+       class LiteralDecoder
+       {
+               class Decoder2
+               {
+                       short[] m_Decoders = new short[0x300];
+                       
+                       public void Init()
+                       {
+                               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Decoders);
+                       }
+                       
+                       public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder) throws IOException
+                       {
+                               int symbol = 1;
+                               do
+                                       symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);
+                               while (symbol < 0x100);
+                               return (byte)symbol;
+                       }
+                       
+                       public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, byte matchByte) throws IOException
+                       {
+                               int symbol = 1;
+                               do
+                               {
+                                       int matchBit = (matchByte >> 7) & 1;
+                                       matchByte <<= 1;
+                                       int bit = rangeDecoder.DecodeBit(m_Decoders, ((1 + matchBit) << 8) + symbol);
+                                       symbol = (symbol << 1) | bit;
+                                       if (matchBit != bit)
+                                       {
+                                               while (symbol < 0x100)
+                                                       symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);
+                                               break;
+                                       }
+                               }
+                               while (symbol < 0x100);
+                               return (byte)symbol;
+                       }
+               }
+               
+               Decoder2[] m_Coders;
+               int m_NumPrevBits;
+               int m_NumPosBits;
+               int m_PosMask;
+               
+               public void Create(int numPosBits, int numPrevBits)
+               {
+                       if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
+                               return;
+                       m_NumPosBits = numPosBits;
+                       m_PosMask = (1 << numPosBits) - 1;
+                       m_NumPrevBits = numPrevBits;
+                       int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
+                       m_Coders = new Decoder2[numStates];
+                       for (int i = 0; i < numStates; i++)
+                               m_Coders[i] = new Decoder2();
+               }
+               
+               public void Init()
+               {
+                       int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
+                       for (int i = 0; i < numStates; i++)
+                               m_Coders[i].Init();
+               }
+               
+               Decoder2 GetDecoder(int pos, byte prevByte)
+               {
+                       return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))];
+               }
+       }
+       
+       OutWindow m_OutWindow = new OutWindow();
+       SevenZip.Compression.RangeCoder.Decoder m_RangeDecoder = new SevenZip.Compression.RangeCoder.Decoder();
+       
+       short[] m_IsMatchDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
+       short[] m_IsRepDecoders = new short[Base.kNumStates];
+       short[] m_IsRepG0Decoders = new short[Base.kNumStates];
+       short[] m_IsRepG1Decoders = new short[Base.kNumStates];
+       short[] m_IsRepG2Decoders = new short[Base.kNumStates];
+       short[] m_IsRep0LongDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
+       
+       BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
+       short[] m_PosDecoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex];
+       
+       BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
+       
+       LenDecoder m_LenDecoder = new LenDecoder();
+       LenDecoder m_RepLenDecoder = new LenDecoder();
+       
+       LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
+       
+       int m_DictionarySize = -1;
+       int m_DictionarySizeCheck =  -1;
+       
+       int m_PosStateMask;
+       
+       public Decoder()
+       {
+               for (int i = 0; i < Base.kNumLenToPosStates; i++)
+                       m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
+       }
+       
+       boolean SetDictionarySize(int dictionarySize)
+       {
+               if (dictionarySize < 0)
+                       return false;
+               if (m_DictionarySize != dictionarySize)
+               {
+                       m_DictionarySize = dictionarySize;
+                       m_DictionarySizeCheck = Math.max(m_DictionarySize, 1);
+                       m_OutWindow.Create(Math.max(m_DictionarySizeCheck, (1 << 12)));
+               }
+               return true;
+       }
+       
+       boolean SetLcLpPb(int lc, int lp, int pb)
+       {
+               if (lc > Base.kNumLitContextBitsMax || lp > 4 || pb > Base.kNumPosStatesBitsMax)
+                       return false;
+               m_LiteralDecoder.Create(lp, lc);
+               int numPosStates = 1 << pb;
+               m_LenDecoder.Create(numPosStates);
+               m_RepLenDecoder.Create(numPosStates);
+               m_PosStateMask = numPosStates - 1;
+               return true;
+       }
+       
+       void Init() throws IOException
+       {
+               m_OutWindow.Init(false);
+               
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsMatchDecoders);
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRep0LongDecoders);
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepDecoders);
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG0Decoders);
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG1Decoders);
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG2Decoders);
+               SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_PosDecoders);
+               
+               m_LiteralDecoder.Init();
+               int i;
+               for (i = 0; i < Base.kNumLenToPosStates; i++)
+                       m_PosSlotDecoder[i].Init();
+               m_LenDecoder.Init();
+               m_RepLenDecoder.Init();
+               m_PosAlignDecoder.Init();
+               m_RangeDecoder.Init();
+       }
+       
+       public boolean Code(java.io.InputStream inStream, java.io.OutputStream outStream,
+                       long outSize) throws IOException
+       {
+               m_RangeDecoder.SetStream(inStream);
+               m_OutWindow.SetStream(outStream);
+               Init();
+               
+               int state = Base.StateInit();
+               int rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
+               
+               long nowPos64 = 0;
+               byte prevByte = 0;
+               while (outSize < 0 || nowPos64 < outSize)
+               {
+                       int posState = (int)nowPos64 & m_PosStateMask;
+                       if (m_RangeDecoder.DecodeBit(m_IsMatchDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)
+                       {
+                               LiteralDecoder.Decoder2 decoder2 = m_LiteralDecoder.GetDecoder((int)nowPos64, prevByte);
+                               if (!Base.StateIsCharState(state))
+                                       prevByte = decoder2.DecodeWithMatchByte(m_RangeDecoder, m_OutWindow.GetByte(rep0));
+                               else
+                                       prevByte = decoder2.DecodeNormal(m_RangeDecoder);
+                               m_OutWindow.PutByte(prevByte);
+                               state = Base.StateUpdateChar(state);
+                               nowPos64++;
+                       }
+                       else
+                       {
+                               int len;
+                               if (m_RangeDecoder.DecodeBit(m_IsRepDecoders, state) == 1)
+                               {
+                                       len = 0;
+                                       if (m_RangeDecoder.DecodeBit(m_IsRepG0Decoders, state) == 0)
+                                       {
+                                               if (m_RangeDecoder.DecodeBit(m_IsRep0LongDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)
+                                               {
+                                                       state = Base.StateUpdateShortRep(state);
+                                                       len = 1;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               int distance;
+                                               if (m_RangeDecoder.DecodeBit(m_IsRepG1Decoders, state) == 0)
+                                                       distance = rep1;
+                                               else
+                                               {
+                                                       if (m_RangeDecoder.DecodeBit(m_IsRepG2Decoders, state) == 0)
+                                                               distance = rep2;
+                                                       else
+                                                       {
+                                                               distance = rep3;
+                                                               rep3 = rep2;
+                                                       }
+                                                       rep2 = rep1;
+                                               }
+                                               rep1 = rep0;
+                                               rep0 = distance;
+                                       }
+                                       if (len == 0)
+                                       {
+                                               len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
+                                               state = Base.StateUpdateRep(state);
+                                       }
+                               }
+                               else
+                               {
+                                       rep3 = rep2;
+                                       rep2 = rep1;
+                                       rep1 = rep0;
+                                       len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
+                                       state = Base.StateUpdateMatch(state);
+                                       int posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
+                                       if (posSlot >= Base.kStartPosModelIndex)
+                                       {
+                                               int numDirectBits = (posSlot >> 1) - 1;
+                                               rep0 = ((2 | (posSlot & 1)) << numDirectBits);
+                                               if (posSlot < Base.kEndPosModelIndex)
+                                                       rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
+                                                                       rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
+                                               else
+                                               {
+                                                       rep0 += (m_RangeDecoder.DecodeDirectBits(
+                                                                       numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
+                                                       rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
+                                                       if (rep0 < 0)
+                                                       {
+                                                               if (rep0 == -1)
+                                                                       break;
+                                                               return false;
+                                                       }
+                                               }
+                                       }
+                                       else
+                                               rep0 = posSlot;
+                               }
+                               if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck)
+                               {
+                                       // m_OutWindow.Flush();
+                                       return false;
+                               }
+                               m_OutWindow.CopyBlock(rep0, len);
+                               nowPos64 += len;
+                               prevByte = m_OutWindow.GetByte(0);
+                       }
+               }
+               m_OutWindow.Flush();
+               m_OutWindow.ReleaseStream();
+               m_RangeDecoder.ReleaseStream();
+               return true;
+       }
+       
+       public boolean SetDecoderProperties(byte[] properties)
+       {
+               if (properties.length < 5)
+                       return false;
+               int val = properties[0] & 0xFF;
+               int lc = val % 9;
+               int remainder = val / 9;
+               int lp = remainder % 5;
+               int pb = remainder / 5;
+               int dictionarySize = 0;
+               for (int i = 0; i < 4; i++)
+                       dictionarySize += ((int)(properties[1 + i]) & 0xFF) << (i * 8);
+               if (!SetLcLpPb(lc, lp, pb))
+                       return false;
+               return SetDictionarySize(dictionarySize);
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/LZMA/Encoder.java b/lzma/Java/SevenZip/Compression/LZMA/Encoder.java
new file mode 100644 (file)
index 0000000..71fd6e5
--- /dev/null
@@ -0,0 +1,1416 @@
+package SevenZip.Compression.LZMA;
+
+import SevenZip.Compression.RangeCoder.BitTreeEncoder;
+import SevenZip.Compression.LZMA.Base;
+import SevenZip.Compression.LZ.BinTree;
+import SevenZip.ICodeProgress;
+import java.io.IOException;
+
+public class Encoder
+{
+       public static final int EMatchFinderTypeBT2 = 0;
+       public static final int EMatchFinderTypeBT4 = 1;
+
+
+
+
+       static final int kIfinityPrice = 0xFFFFFFF;
+
+       static byte[] g_FastPos = new byte[1 << 11];
+
+       static
+       {
+               int kFastSlots = 22;
+               int c = 2;
+               g_FastPos[0] = 0;
+               g_FastPos[1] = 1;
+               for (int slotFast = 2; slotFast < kFastSlots; slotFast++)
+               {
+                       int k = (1 << ((slotFast >> 1) - 1));
+                       for (int j = 0; j < k; j++, c++)
+                               g_FastPos[c] = (byte)slotFast;
+               }
+       }
+
+       static int GetPosSlot(int pos)
+       {
+               if (pos < (1 << 11))
+                       return g_FastPos[pos];
+               if (pos < (1 << 21))
+                       return (g_FastPos[pos >> 10] + 20);
+               return (g_FastPos[pos >> 20] + 40);
+       }
+
+       static int GetPosSlot2(int pos)
+       {
+               if (pos < (1 << 17))
+                       return (g_FastPos[pos >> 6] + 12);
+               if (pos < (1 << 27))
+                       return (g_FastPos[pos >> 16] + 32);
+               return (g_FastPos[pos >> 26] + 52);
+       }
+
+       int _state = Base.StateInit();
+       byte _previousByte;
+       int[] _repDistances = new int[Base.kNumRepDistances];
+
+       void BaseInit()
+       {
+               _state = Base.StateInit();
+               _previousByte = 0;
+               for (int i = 0; i < Base.kNumRepDistances; i++)
+                       _repDistances[i] = 0;
+       }
+
+       static final int kDefaultDictionaryLogSize = 22;
+       static final int kNumFastBytesDefault = 0x20;
+
+       class LiteralEncoder
+       {
+               class Encoder2
+               {
+                       short[] m_Encoders = new short[0x300];
+
+                       public void Init() { SevenZip.Compression.RangeCoder.Encoder.InitBitModels(m_Encoders); }
+
+
+
+                       public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol) throws IOException
+                       {
+                               int context = 1;
+                               for (int i = 7; i >= 0; i--)
+                               {
+                                       int bit = ((symbol >> i) & 1);
+                                       rangeEncoder.Encode(m_Encoders, context, bit);
+                                       context = (context << 1) | bit;
+                               }
+                       }
+
+                       public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException
+                       {
+                               int context = 1;
+                               boolean same = true;
+                               for (int i = 7; i >= 0; i--)
+                               {
+                                       int bit = ((symbol >> i) & 1);
+                                       int state = context;
+                                       if (same)
+                                       {
+                                               int matchBit = ((matchByte >> i) & 1);
+                                               state += ((1 + matchBit) << 8);
+                                               same = (matchBit == bit);
+                                       }
+                                       rangeEncoder.Encode(m_Encoders, state, bit);
+                                       context = (context << 1) | bit;
+                               }
+                       }
+
+                       public int GetPrice(boolean matchMode, byte matchByte, byte symbol)
+                       {
+                               int price = 0;
+                               int context = 1;
+                               int i = 7;
+                               if (matchMode)
+                               {
+                                       for (; i >= 0; i--)
+                                       {
+                                               int matchBit = (matchByte >> i) & 1;
+                                               int bit = (symbol >> i) & 1;
+                                               price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8) + context], bit);
+                                               context = (context << 1) | bit;
+                                               if (matchBit != bit)
+                                               {
+                                                       i--;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               for (; i >= 0; i--)
+                               {
+                                       int bit = (symbol >> i) & 1;
+                                       price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[context], bit);
+                                       context = (context << 1) | bit;
+                               }
+                               return price;
+                       }
+               }
+
+               Encoder2[] m_Coders;
+               int m_NumPrevBits;
+               int m_NumPosBits;
+               int m_PosMask;
+
+               public void Create(int numPosBits, int numPrevBits)
+               {
+                       if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
+                               return;
+                       m_NumPosBits = numPosBits;
+                       m_PosMask = (1 << numPosBits) - 1;
+                       m_NumPrevBits = numPrevBits;
+                       int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
+                       m_Coders = new Encoder2[numStates];
+                       for (int i = 0; i < numStates; i++)
+                               m_Coders[i] = new Encoder2();
+               }
+
+               public void Init()
+               {
+                       int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
+                       for (int i = 0; i < numStates; i++)
+                               m_Coders[i].Init();
+               }
+
+               public Encoder2 GetSubCoder(int pos, byte prevByte)
+               { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; }
+       }
+
+       class LenEncoder
+       {
+               short[] _choice = new short[2];
+               BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
+               BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
+               BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);
+
+
+               public LenEncoder()
+               {
+                       for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
+                       {
+                               _lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);
+                               _midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);
+                       }
+               }
+
+               public void Init(int numPosStates)
+               {
+                       SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_choice);
+
+                       for (int posState = 0; posState < numPosStates; posState++)
+                       {
+                               _lowCoder[posState].Init();
+                               _midCoder[posState].Init();
+                       }
+                       _highCoder.Init();
+               }
+
+               public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
+               {
+                       if (symbol < Base.kNumLowLenSymbols)
+                       {
+                               rangeEncoder.Encode(_choice, 0, 0);
+                               _lowCoder[posState].Encode(rangeEncoder, symbol);
+                       }
+                       else
+                       {
+                               symbol -= Base.kNumLowLenSymbols;
+                               rangeEncoder.Encode(_choice, 0, 1);
+                               if (symbol < Base.kNumMidLenSymbols)
+                               {
+                                       rangeEncoder.Encode(_choice, 1, 0);
+                                       _midCoder[posState].Encode(rangeEncoder, symbol);
+                               }
+                               else
+                               {
+                                       rangeEncoder.Encode(_choice, 1, 1);
+                                       _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
+                               }
+                       }
+               }
+
+               public void SetPrices(int posState, int numSymbols, int[] prices, int st)
+               {
+                       int a0 = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[0]);
+                       int a1 = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[0]);
+                       int b0 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[1]);
+                       int b1 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[1]);
+                       int i = 0;
+                       for (i = 0; i < Base.kNumLowLenSymbols; i++)
+                       {
+                               if (i >= numSymbols)
+                                       return;
+                               prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
+                       }
+                       for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
+                       {
+                               if (i >= numSymbols)
+                                       return;
+                               prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
+                       }
+                       for (; i < numSymbols; i++)
+                               prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
+               }
+       };
+
+       public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
+
+       class LenPriceTableEncoder extends LenEncoder
+       {
+               int[] _prices = new int[Base.kNumLenSymbols<<Base.kNumPosStatesBitsEncodingMax];
+               int _tableSize;
+               int[] _counters = new int[Base.kNumPosStatesEncodingMax];
+
+               public void SetTableSize(int tableSize) { _tableSize = tableSize; }
+
+               public int GetPrice(int symbol, int posState)
+               {
+                       return _prices[posState * Base.kNumLenSymbols + symbol];
+               }
+
+               void UpdateTable(int posState)
+               {
+                       SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
+                       _counters[posState] = _tableSize;
+               }
+
+               public void UpdateTables(int numPosStates)
+               {
+                       for (int posState = 0; posState < numPosStates; posState++)
+                               UpdateTable(posState);
+               }
+
+               public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
+               {
+                       super.Encode(rangeEncoder, symbol, posState);
+                       if (--_counters[posState] == 0)
+                               UpdateTable(posState);
+               }
+       }
+
+       static final int kNumOpts = 1 << 12;
+       class Optimal
+       {
+               public int State;
+
+               public boolean Prev1IsChar;
+               public boolean Prev2;
+
+               public int PosPrev2;
+               public int BackPrev2;
+
+               public int Price;
+               public int PosPrev;
+               public int BackPrev;
+
+               public int Backs0;
+               public int Backs1;
+               public int Backs2;
+               public int Backs3;
+
+               public void MakeAsChar() { BackPrev = -1; Prev1IsChar = false; }
+               public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
+               public boolean IsShortRep() { return (BackPrev == 0); }
+       };
+       Optimal[] _optimum = new Optimal[kNumOpts];
+       SevenZip.Compression.LZ.BinTree _matchFinder = null;
+       SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();
+
+       short[] _isMatch = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
+       short[] _isRep = new short[Base.kNumStates];
+       short[] _isRepG0 = new short[Base.kNumStates];
+       short[] _isRepG1 = new short[Base.kNumStates];
+       short[] _isRepG2 = new short[Base.kNumStates];
+       short[] _isRep0Long = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
+
+       BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits
+
+       short[] _posEncoders = new short[Base.kNumFullDistances-Base.kEndPosModelIndex];
+       BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);
+
+       LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
+       LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
+
+       LiteralEncoder _literalEncoder = new LiteralEncoder();
+
+       int[] _matchDistances = new int[Base.kMatchMaxLen*2+2];
+
+       int _numFastBytes = kNumFastBytesDefault;
+       int _longestMatchLength;
+       int _numDistancePairs;
+
+       int _additionalOffset;
+
+       int _optimumEndIndex;
+       int _optimumCurrentIndex;
+
+       boolean _longestMatchWasFound;
+
+       int[] _posSlotPrices = new int[1<<(Base.kNumPosSlotBits+Base.kNumLenToPosStatesBits)];
+       int[] _distancesPrices = new int[Base.kNumFullDistances<<Base.kNumLenToPosStatesBits];
+       int[] _alignPrices = new int[Base.kAlignTableSize];
+       int _alignPriceCount;
+
+       int _distTableSize = (kDefaultDictionaryLogSize * 2);
+
+       int _posStateBits = 2;
+       int _posStateMask = (4 - 1);
+       int _numLiteralPosStateBits = 0;
+       int _numLiteralContextBits = 3;
+
+       int _dictionarySize = (1 << kDefaultDictionaryLogSize);
+       int _dictionarySizePrev = -1;
+       int _numFastBytesPrev = -1;
+
+       long nowPos64;
+       boolean _finished;
+       java.io.InputStream _inStream;
+
+       int _matchFinderType = EMatchFinderTypeBT4;
+       boolean _writeEndMark = false;
+
+       boolean _needReleaseMFStream = false;
+
+       void Create()
+       {
+               if (_matchFinder == null)
+               {
+                       SevenZip.Compression.LZ.BinTree bt = new SevenZip.Compression.LZ.BinTree();
+                       int numHashBytes = 4;
+                       if (_matchFinderType == EMatchFinderTypeBT2)
+                               numHashBytes = 2;
+                       bt.SetType(numHashBytes);
+                       _matchFinder = bt;
+               }
+               _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
+
+               if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
+                       return;
+               _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
+               _dictionarySizePrev = _dictionarySize;
+               _numFastBytesPrev = _numFastBytes;
+       }
+
+       public Encoder()
+       {
+               for (int i = 0; i < kNumOpts; i++)
+                       _optimum[i] = new Optimal();
+               for (int i = 0; i < Base.kNumLenToPosStates; i++)
+                       _posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits);
+       }
+
+       void SetWriteEndMarkerMode(boolean writeEndMarker)
+       {
+               _writeEndMark = writeEndMarker;
+       }
+
+       void Init()
+       {
+               BaseInit();
+               _rangeEncoder.Init();
+
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isMatch);
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep0Long);
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep);
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG0);
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG1);
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG2);
+               SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_posEncoders);
+
+
+
+
+
+
+
+               _literalEncoder.Init();
+               for (int i = 0; i < Base.kNumLenToPosStates; i++)
+                       _posSlotEncoder[i].Init();
+
+
+
+               _lenEncoder.Init(1 << _posStateBits);
+               _repMatchLenEncoder.Init(1 << _posStateBits);
+
+               _posAlignEncoder.Init();
+
+               _longestMatchWasFound = false;
+               _optimumEndIndex = 0;
+               _optimumCurrentIndex = 0;
+               _additionalOffset = 0;
+       }
+
+       int ReadMatchDistances() throws java.io.IOException
+       {
+               int lenRes = 0;
+               _numDistancePairs = _matchFinder.GetMatches(_matchDistances);
+               if (_numDistancePairs > 0)
+               {
+                       lenRes = _matchDistances[_numDistancePairs - 2];
+                       if (lenRes == _numFastBytes)
+                               lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[_numDistancePairs - 1],
+                                       Base.kMatchMaxLen - lenRes);
+               }
+               _additionalOffset++;
+               return lenRes;
+       }
+
+       void MovePos(int num) throws java.io.IOException
+       {
+               if (num > 0)
+               {
+                       _matchFinder.Skip(num);
+                       _additionalOffset += num;
+               }
+       }
+
+       int GetRepLen1Price(int state, int posState)
+       {
+               return SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]) +
+                               SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
+       }
+
+       int GetPureRepPrice(int repIndex, int state, int posState)
+       {
+               int price;
+               if (repIndex == 0)
+               {
+                       price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]);
+                       price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
+               }
+               else
+               {
+                       price = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG0[state]);
+                       if (repIndex == 1)
+                               price += SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG1[state]);
+                       else
+                       {
+                               price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG1[state]);
+                               price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);
+                       }
+               }
+               return price;
+       }
+
+       int GetRepPrice(int repIndex, int len, int state, int posState)
+       {
+               int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
+               return price + GetPureRepPrice(repIndex, state, posState);
+       }
+
+       int GetPosLenPrice(int pos, int len, int posState)
+       {
+               int price;
+               int lenToPosState = Base.GetLenToPosState(len);
+               if (pos < Base.kNumFullDistances)
+                       price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
+               else
+                       price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
+                               _alignPrices[pos & Base.kAlignMask];
+               return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
+       }
+
+       int Backward(int cur)
+       {
+               _optimumEndIndex = cur;
+               int posMem = _optimum[cur].PosPrev;
+               int backMem = _optimum[cur].BackPrev;
+               do
+               {
+                       if (_optimum[cur].Prev1IsChar)
+                       {
+                               _optimum[posMem].MakeAsChar();
+                               _optimum[posMem].PosPrev = posMem - 1;
+                               if (_optimum[cur].Prev2)
+                               {
+                                       _optimum[posMem - 1].Prev1IsChar = false;
+                                       _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
+                                       _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
+                               }
+                       }
+                       int posPrev = posMem;
+                       int backCur = backMem;
+
+                       backMem = _optimum[posPrev].BackPrev;
+                       posMem = _optimum[posPrev].PosPrev;
+
+                       _optimum[posPrev].BackPrev = backCur;
+                       _optimum[posPrev].PosPrev = cur;
+                       cur = posPrev;
+               }
+               while (cur > 0);
+               backRes = _optimum[0].BackPrev;
+               _optimumCurrentIndex = _optimum[0].PosPrev;
+               return _optimumCurrentIndex;
+       }
+
+       int[] reps = new int[Base.kNumRepDistances];
+       int[] repLens = new int[Base.kNumRepDistances];
+       int backRes;
+
+       int GetOptimum(int position) throws IOException
+       {
+               if (_optimumEndIndex != _optimumCurrentIndex)
+               {
+                       int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
+                       backRes = _optimum[_optimumCurrentIndex].BackPrev;
+                       _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
+                       return lenRes;
+               }
+               _optimumCurrentIndex = _optimumEndIndex = 0;
+
+               int lenMain, numDistancePairs;
+               if (!_longestMatchWasFound)
+               {
+                       lenMain = ReadMatchDistances();
+               }
+               else
+               {
+                       lenMain = _longestMatchLength;
+                       _longestMatchWasFound = false;
+               }
+               numDistancePairs = _numDistancePairs;
+
+               int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
+               if (numAvailableBytes < 2)
+               {
+                       backRes = -1;
+                       return 1;
+               }
+               if (numAvailableBytes > Base.kMatchMaxLen)
+                       numAvailableBytes = Base.kMatchMaxLen;
+
+               int repMaxIndex = 0;
+               int i;
+               for (i = 0; i < Base.kNumRepDistances; i++)
+               {
+                       reps[i] = _repDistances[i];
+                       repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
+                       if (repLens[i] > repLens[repMaxIndex])
+                               repMaxIndex = i;
+               }
+               if (repLens[repMaxIndex] >= _numFastBytes)
+               {
+                       backRes = repMaxIndex;
+                       int lenRes = repLens[repMaxIndex];
+                       MovePos(lenRes - 1);
+                       return lenRes;
+               }
+
+               if (lenMain >= _numFastBytes)
+               {
+                       backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
+                       MovePos(lenMain - 1);
+                       return lenMain;
+               }
+
+               byte currentByte = _matchFinder.GetIndexByte(0 - 1);
+               byte matchByte = _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1);
+
+               if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
+               {
+                       backRes = -1;
+                       return 1;
+               }
+
+               _optimum[0].State = _state;
+
+               int posState = (position & _posStateMask);
+
+               _optimum[1].Price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) +
+                               _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);
+               _optimum[1].MakeAsChar();
+
+               int matchPrice = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);
+               int repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[_state]);
+
+               if (matchByte == currentByte)
+               {
+                       int shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
+                       if (shortRepPrice < _optimum[1].Price)
+                       {
+                               _optimum[1].Price = shortRepPrice;
+                               _optimum[1].MakeAsShortRep();
+                       }
+               }
+
+               int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
+
+               if (lenEnd < 2)
+               {
+                       backRes = _optimum[1].BackPrev;
+                       return 1;
+               }
+
+               _optimum[1].PosPrev = 0;
+
+               _optimum[0].Backs0 = reps[0];
+               _optimum[0].Backs1 = reps[1];
+               _optimum[0].Backs2 = reps[2];
+               _optimum[0].Backs3 = reps[3];
+
+               int len = lenEnd;
+               do
+                       _optimum[len--].Price = kIfinityPrice;
+               while (len >= 2);
+
+               for (i = 0; i < Base.kNumRepDistances; i++)
+               {
+                       int repLen = repLens[i];
+                       if (repLen < 2)
+                               continue;
+                       int price = repMatchPrice + GetPureRepPrice(i, _state, posState);
+                       do
+                       {
+                               int curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
+                               Optimal optimum = _optimum[repLen];
+                               if (curAndLenPrice < optimum.Price)
+                               {
+                                       optimum.Price = curAndLenPrice;
+                                       optimum.PosPrev = 0;
+                                       optimum.BackPrev = i;
+                                       optimum.Prev1IsChar = false;
+                               }
+                       }
+                       while (--repLen >= 2);
+               }
+
+               int normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[_state]);
+
+               len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+               if (len <= lenMain)
+               {
+                       int offs = 0;
+                       while (len > _matchDistances[offs])
+                               offs += 2;
+                       for (; ; len++)
+                       {
+                               int distance = _matchDistances[offs + 1];
+                               int curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
+                               Optimal optimum = _optimum[len];
+                               if (curAndLenPrice < optimum.Price)
+                               {
+                                       optimum.Price = curAndLenPrice;
+                                       optimum.PosPrev = 0;
+                                       optimum.BackPrev = distance + Base.kNumRepDistances;
+                                       optimum.Prev1IsChar = false;
+                               }
+                               if (len == _matchDistances[offs])
+                               {
+                                       offs += 2;
+                                       if (offs == numDistancePairs)
+                                               break;
+                               }
+                       }
+               }
+
+               int cur = 0;
+
+               while (true)
+               {
+                       cur++;
+                       if (cur == lenEnd)
+                               return Backward(cur);
+                       int newLen = ReadMatchDistances();
+                       numDistancePairs = _numDistancePairs;
+                       if (newLen >= _numFastBytes)
+                       {
+
+                               _longestMatchLength = newLen;
+                               _longestMatchWasFound = true;
+                               return Backward(cur);
+                       }
+                       position++;
+                       int posPrev = _optimum[cur].PosPrev;
+                       int state;
+                       if (_optimum[cur].Prev1IsChar)
+                       {
+                               posPrev--;
+                               if (_optimum[cur].Prev2)
+                               {
+                                       state = _optimum[_optimum[cur].PosPrev2].State;
+                                       if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
+                                               state = Base.StateUpdateRep(state);
+                                       else
+                                               state = Base.StateUpdateMatch(state);
+                               }
+                               else
+                                       state = _optimum[posPrev].State;
+                               state = Base.StateUpdateChar(state);
+                       }
+                       else
+                               state = _optimum[posPrev].State;
+                       if (posPrev == cur - 1)
+                       {
+                               if (_optimum[cur].IsShortRep())
+                                       state = Base.StateUpdateShortRep(state);
+                               else
+                                       state = Base.StateUpdateChar(state);
+                       }
+                       else
+                       {
+                               int pos;
+                               if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
+                               {
+                                       posPrev = _optimum[cur].PosPrev2;
+                                       pos = _optimum[cur].BackPrev2;
+                                       state = Base.StateUpdateRep(state);
+                               }
+                               else
+                               {
+                                       pos = _optimum[cur].BackPrev;
+                                       if (pos < Base.kNumRepDistances)
+                                               state = Base.StateUpdateRep(state);
+                                       else
+                                               state = Base.StateUpdateMatch(state);
+                               }
+                               Optimal opt = _optimum[posPrev];
+                               if (pos < Base.kNumRepDistances)
+                               {
+                                       if (pos == 0)
+                                       {
+                                               reps[0] = opt.Backs0;
+                                               reps[1] = opt.Backs1;
+                                               reps[2] = opt.Backs2;
+                                               reps[3] = opt.Backs3;
+                                       }
+                                       else if (pos == 1)
+                                       {
+                                               reps[0] = opt.Backs1;
+                                               reps[1] = opt.Backs0;
+                                               reps[2] = opt.Backs2;
+                                               reps[3] = opt.Backs3;
+                                       }
+                                       else if (pos == 2)
+                                       {
+                                               reps[0] = opt.Backs2;
+                                               reps[1] = opt.Backs0;
+                                               reps[2] = opt.Backs1;
+                                               reps[3] = opt.Backs3;
+                                       }
+                                       else
+                                       {
+                                               reps[0] = opt.Backs3;
+                                               reps[1] = opt.Backs0;
+                                               reps[2] = opt.Backs1;
+                                               reps[3] = opt.Backs2;
+                                       }
+                               }
+                               else
+                               {
+                                       reps[0] = (pos - Base.kNumRepDistances);
+                                       reps[1] = opt.Backs0;
+                                       reps[2] = opt.Backs1;
+                                       reps[3] = opt.Backs2;
+                               }
+                       }
+                       _optimum[cur].State = state;
+                       _optimum[cur].Backs0 = reps[0];
+                       _optimum[cur].Backs1 = reps[1];
+                       _optimum[cur].Backs2 = reps[2];
+                       _optimum[cur].Backs3 = reps[3];
+                       int curPrice = _optimum[cur].Price;
+
+                       currentByte = _matchFinder.GetIndexByte(0 - 1);
+                       matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);
+
+                       posState = (position & _posStateMask);
+
+                       int curAnd1Price = curPrice +
+                               SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) +
+                               _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
+                               GetPrice(!Base.StateIsCharState(state), matchByte, currentByte);
+
+                       Optimal nextOptimum = _optimum[cur + 1];
+
+                       boolean nextIsChar = false;
+                       if (curAnd1Price < nextOptimum.Price)
+                       {
+                               nextOptimum.Price = curAnd1Price;
+                               nextOptimum.PosPrev = cur;
+                               nextOptimum.MakeAsChar();
+                               nextIsChar = true;
+                       }
+
+                       matchPrice = curPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]);
+                       repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state]);
+
+                       if (matchByte == currentByte &&
+                               !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
+                       {
+                               int shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
+                               if (shortRepPrice <= nextOptimum.Price)
+                               {
+                                       nextOptimum.Price = shortRepPrice;
+                                       nextOptimum.PosPrev = cur;
+                                       nextOptimum.MakeAsShortRep();
+                                       nextIsChar = true;
+                               }
+                       }
+
+                       int numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
+                       numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull);
+                       numAvailableBytes = numAvailableBytesFull;
+
+                       if (numAvailableBytes < 2)
+                               continue;
+                       if (numAvailableBytes > _numFastBytes)
+                               numAvailableBytes = _numFastBytes;
+                       if (!nextIsChar && matchByte != currentByte)
+                       {
+                               // try Literal + rep0
+                               int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);
+                               int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
+                               if (lenTest2 >= 2)
+                               {
+                                       int state2 = Base.StateUpdateChar(state);
+
+                                       int posStateNext = (position + 1) & _posStateMask;
+                                       int nextRepMatchPrice = curAnd1Price +
+                                               SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
+                                               SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
+                                       {
+                                               int offset = cur + 1 + lenTest2;
+                                               while (lenEnd < offset)
+                                                       _optimum[++lenEnd].Price = kIfinityPrice;
+                                               int curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+                                                               0, lenTest2, state2, posStateNext);
+                                               Optimal optimum = _optimum[offset];
+                                               if (curAndLenPrice < optimum.Price)
+                                               {
+                                                       optimum.Price = curAndLenPrice;
+                                                       optimum.PosPrev = cur + 1;
+                                                       optimum.BackPrev = 0;
+                                                       optimum.Prev1IsChar = true;
+                                                       optimum.Prev2 = false;
+                                               }
+                                       }
+                               }
+                       }
+
+                       int startLen = 2; // speed optimization 
+
+                       for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
+                       {
+                               int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
+                               if (lenTest < 2)
+                                       continue;
+                               int lenTestTemp = lenTest;
+                               do
+                               {
+                                       while (lenEnd < cur + lenTest)
+                                               _optimum[++lenEnd].Price = kIfinityPrice;
+                                       int curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
+                                       Optimal optimum = _optimum[cur + lenTest];
+                                       if (curAndLenPrice < optimum.Price)
+                                       {
+                                               optimum.Price = curAndLenPrice;
+                                               optimum.PosPrev = cur;
+                                               optimum.BackPrev = repIndex;
+                                               optimum.Prev1IsChar = false;
+                                       }
+                               }
+                               while (--lenTest >= 2);
+                               lenTest = lenTestTemp;
+
+                               if (repIndex == 0)
+                                       startLen = lenTest + 1;
+
+                               // if (_maxMode)
+                               if (lenTest < numAvailableBytesFull)
+                               {
+                                       int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
+                                       int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);
+                                       if (lenTest2 >= 2)
+                                       {
+                                               int state2 = Base.StateUpdateRep(state);
+
+                                               int posStateNext = (position + lenTest) & _posStateMask;
+                                               int curAndLenCharPrice =
+                                                               repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
+                                                               SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
+                                                               _literalEncoder.GetSubCoder(position + lenTest,
+                                                               _matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,
+                                                               _matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)),
+                                                               _matchFinder.GetIndexByte(lenTest - 1));
+                                               state2 = Base.StateUpdateChar(state2);
+                                               posStateNext = (position + lenTest + 1) & _posStateMask;
+                                               int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
+                                               int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
+
+                                               // for(; lenTest2 >= 2; lenTest2--)
+                                               {
+                                                       int offset = lenTest + 1 + lenTest2;
+                                                       while (lenEnd < cur + offset)
+                                                               _optimum[++lenEnd].Price = kIfinityPrice;
+                                                       int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
+                                                       Optimal optimum = _optimum[cur + offset];
+                                                       if (curAndLenPrice < optimum.Price)
+                                                       {
+                                                               optimum.Price = curAndLenPrice;
+                                                               optimum.PosPrev = cur + lenTest + 1;
+                                                               optimum.BackPrev = 0;
+                                                               optimum.Prev1IsChar = true;
+                                                               optimum.Prev2 = true;
+                                                               optimum.PosPrev2 = cur;
+                                                               optimum.BackPrev2 = repIndex;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (newLen > numAvailableBytes)
+                       {
+                               newLen = numAvailableBytes;
+                               for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
+                               _matchDistances[numDistancePairs] = newLen;
+                               numDistancePairs += 2;
+                       }
+                       if (newLen >= startLen)
+                       {
+                               normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[state]);
+                               while (lenEnd < cur + newLen)
+                                       _optimum[++lenEnd].Price = kIfinityPrice;
+
+                               int offs = 0;
+                               while (startLen > _matchDistances[offs])
+                                       offs += 2;
+
+                               for (int lenTest = startLen; ; lenTest++)
+                               {
+                                       int curBack = _matchDistances[offs + 1];
+                                       int curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
+                                       Optimal optimum = _optimum[cur + lenTest];
+                                       if (curAndLenPrice < optimum.Price)
+                                       {
+                                               optimum.Price = curAndLenPrice;
+                                               optimum.PosPrev = cur;
+                                               optimum.BackPrev = curBack + Base.kNumRepDistances;
+                                               optimum.Prev1IsChar = false;
+                                       }
+
+                                       if (lenTest == _matchDistances[offs])
+                                       {
+                                               if (lenTest < numAvailableBytesFull)
+                                               {
+                                                       int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
+                                                       int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);
+                                                       if (lenTest2 >= 2)
+                                                       {
+                                                               int state2 = Base.StateUpdateMatch(state);
+
+                                                               int posStateNext = (position + lenTest) & _posStateMask;
+                                                               int curAndLenCharPrice = curAndLenPrice +
+                                                                       SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
+                                                                       _literalEncoder.GetSubCoder(position + lenTest,
+                                                                       _matchFinder.GetIndexByte(lenTest - 1 - 1)).
+                                                                       GetPrice(true,
+                                                                       _matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),
+                                                                       _matchFinder.GetIndexByte(lenTest - 1));
+                                                               state2 = Base.StateUpdateChar(state2);
+                                                               posStateNext = (position + lenTest + 1) & _posStateMask;
+                                                               int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
+                                                               int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
+
+                                                               int offset = lenTest + 1 + lenTest2;
+                                                               while (lenEnd < cur + offset)
+                                                                       _optimum[++lenEnd].Price = kIfinityPrice;
+                                                               curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
+                                                               optimum = _optimum[cur + offset];
+                                                               if (curAndLenPrice < optimum.Price)
+                                                               {
+                                                                       optimum.Price = curAndLenPrice;
+                                                                       optimum.PosPrev = cur + lenTest + 1;
+                                                                       optimum.BackPrev = 0;
+                                                                       optimum.Prev1IsChar = true;
+                                                                       optimum.Prev2 = true;
+                                                                       optimum.PosPrev2 = cur;
+                                                                       optimum.BackPrev2 = curBack + Base.kNumRepDistances;
+                                                               }
+                                                       }
+                                               }
+                                               offs += 2;
+                                               if (offs == numDistancePairs)
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       boolean ChangePair(int smallDist, int bigDist)
+       {
+               int kDif = 7;
+               return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));
+       }
+
+       void WriteEndMarker(int posState) throws IOException
+       {
+               if (!_writeEndMark)
+                       return;
+
+               _rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);
+               _rangeEncoder.Encode(_isRep, _state, 0);
+               _state = Base.StateUpdateMatch(_state);
+               int len = Base.kMatchMinLen;
+               _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
+               int posSlot = (1 << Base.kNumPosSlotBits) - 1;
+               int lenToPosState = Base.GetLenToPosState(len);
+               _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
+               int footerBits = 30;
+               int posReduced = (1 << footerBits) - 1;
+               _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
+               _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
+       }
+
+       void Flush(int nowPos) throws IOException
+       {
+               ReleaseMFStream();
+               WriteEndMarker(nowPos & _posStateMask);
+               _rangeEncoder.FlushData();
+               _rangeEncoder.FlushStream();
+       }
+
+       public void CodeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException
+       {
+               inSize[0] = 0;
+               outSize[0] = 0;
+               finished[0] = true;
+
+               if (_inStream != null)
+               {
+                       _matchFinder.SetStream(_inStream);
+                       _matchFinder.Init();
+                       _needReleaseMFStream = true;
+                       _inStream = null;
+               }
+
+               if (_finished)
+                       return;
+               _finished = true;
+
+
+               long progressPosValuePrev = nowPos64;
+               if (nowPos64 == 0)
+               {
+                       if (_matchFinder.GetNumAvailableBytes() == 0)
+                       {
+                               Flush((int)nowPos64);
+                               return;
+                       }
+
+                       ReadMatchDistances();
+                       int posState = (int)(nowPos64) & _posStateMask;
+                       _rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);
+                       _state = Base.StateUpdateChar(_state);
+                       byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);
+                       _literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
+                       _previousByte = curByte;
+                       _additionalOffset--;
+                       nowPos64++;
+               }
+               if (_matchFinder.GetNumAvailableBytes() == 0)
+               {
+                       Flush((int)nowPos64);
+                       return;
+               }
+               while (true)
+               {
+
+                       int len = GetOptimum((int)nowPos64);
+                       int pos = backRes;
+                       int posState = ((int)nowPos64) & _posStateMask;
+                       int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;
+                       if (len == 1 && pos == -1)
+                       {
+                               _rangeEncoder.Encode(_isMatch, complexState, 0);
+                               byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
+                               LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);
+                               if (!Base.StateIsCharState(_state))
+                               {
+                                       byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
+                                       subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
+                               }
+                               else
+                                       subCoder.Encode(_rangeEncoder, curByte);
+                               _previousByte = curByte;
+                               _state = Base.StateUpdateChar(_state);
+                       }
+                       else
+                       {
+                               _rangeEncoder.Encode(_isMatch, complexState, 1);
+                               if (pos < Base.kNumRepDistances)
+                               {
+                                       _rangeEncoder.Encode(_isRep, _state, 1);
+                                       if (pos == 0)
+                                       {
+                                               _rangeEncoder.Encode(_isRepG0, _state, 0);
+                                               if (len == 1)
+                                                       _rangeEncoder.Encode(_isRep0Long, complexState, 0);
+                                               else
+                                                       _rangeEncoder.Encode(_isRep0Long, complexState, 1);
+                                       }
+                                       else
+                                       {
+                                               _rangeEncoder.Encode(_isRepG0, _state, 1);
+                                               if (pos == 1)
+                                                       _rangeEncoder.Encode(_isRepG1, _state, 0);
+                                               else
+                                               {
+                                                       _rangeEncoder.Encode(_isRepG1, _state, 1);
+                                                       _rangeEncoder.Encode(_isRepG2, _state, pos - 2);
+                                               }
+                                       }
+                                       if (len == 1)
+                                               _state = Base.StateUpdateShortRep(_state);
+                                       else
+                                       {
+                                               _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
+                                               _state = Base.StateUpdateRep(_state);
+                                       }
+                                       int distance = _repDistances[pos];
+                                       if (pos != 0)
+                                       {
+                                               for (int i = pos; i >= 1; i--)
+                                                       _repDistances[i] = _repDistances[i - 1];
+                                               _repDistances[0] = distance;
+                                       }
+                               }
+                               else
+                               {
+                                       _rangeEncoder.Encode(_isRep, _state, 0);
+                                       _state = Base.StateUpdateMatch(_state);
+                                       _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
+                                       pos -= Base.kNumRepDistances;
+                                       int posSlot = GetPosSlot(pos);
+                                       int lenToPosState = Base.GetLenToPosState(len);
+                                       _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
+
+                                       if (posSlot >= Base.kStartPosModelIndex)
+                                       {
+                                               int footerBits = (int)((posSlot >> 1) - 1);
+                                               int baseVal = ((2 | (posSlot & 1)) << footerBits);
+                                               int posReduced = pos - baseVal;
+
+                                               if (posSlot < Base.kEndPosModelIndex)
+                                                       BitTreeEncoder.ReverseEncode(_posEncoders,
+                                                                       baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
+                                               else
+                                               {
+                                                       _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
+                                                       _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
+                                                       _alignPriceCount++;
+                                               }
+                                       }
+                                       int distance = pos;
+                                       for (int i = Base.kNumRepDistances - 1; i >= 1; i--)
+                                               _repDistances[i] = _repDistances[i - 1];
+                                       _repDistances[0] = distance;
+                                       _matchPriceCount++;
+                               }
+                               _previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);
+                       }
+                       _additionalOffset -= len;
+                       nowPos64 += len;
+                       if (_additionalOffset == 0)
+                       {
+                               // if (!_fastMode)
+                               if (_matchPriceCount >= (1 << 7))
+                                       FillDistancesPrices();
+                               if (_alignPriceCount >= Base.kAlignTableSize)
+                                       FillAlignPrices();
+                               inSize[0] = nowPos64;
+                               outSize[0] = _rangeEncoder.GetProcessedSizeAdd();
+                               if (_matchFinder.GetNumAvailableBytes() == 0)
+                               {
+                                       Flush((int)nowPos64);
+                                       return;
+                               }
+
+                               if (nowPos64 - progressPosValuePrev >= (1 << 12))
+                               {
+                                       _finished = false;
+                                       finished[0] = false;
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       void ReleaseMFStream()
+       {
+               if (_matchFinder != null && _needReleaseMFStream)
+               {
+                       _matchFinder.ReleaseStream();
+                       _needReleaseMFStream = false;
+               }
+       }
+
+       void SetOutStream(java.io.OutputStream outStream)
+       { _rangeEncoder.SetStream(outStream); }
+       void ReleaseOutStream()
+       { _rangeEncoder.ReleaseStream(); }
+
+       void ReleaseStreams()
+       {
+               ReleaseMFStream();
+               ReleaseOutStream();
+       }
+
+       void SetStreams(java.io.InputStream inStream, java.io.OutputStream outStream,
+                       long inSize, long outSize)
+       {
+               _inStream = inStream;
+               _finished = false;
+               Create();
+               SetOutStream(outStream);
+               Init();
+
+               // if (!_fastMode)
+               {
+                       FillDistancesPrices();
+                       FillAlignPrices();
+               }
+
+               _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
+               _lenEncoder.UpdateTables(1 << _posStateBits);
+               _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
+               _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
+
+               nowPos64 = 0;
+       }
+
+       long[] processedInSize = new long[1]; long[] processedOutSize = new long[1]; boolean[] finished = new boolean[1];
+       public void Code(java.io.InputStream inStream, java.io.OutputStream outStream,
+                       long inSize, long outSize, ICodeProgress progress) throws IOException
+       {
+               _needReleaseMFStream = false;
+               try
+               {
+                       SetStreams(inStream, outStream, inSize, outSize);
+                       while (true)
+                       {
+
+
+
+                               CodeOneBlock(processedInSize, processedOutSize, finished);
+                               if (finished[0])
+                                       return;
+                               if (progress != null)
+                               {
+                                       progress.SetProgress(processedInSize[0], processedOutSize[0]);
+                               }
+                       }
+               }
+               finally
+               {
+                       ReleaseStreams();
+               }
+       }
+
+       public static final int kPropSize = 5;
+       byte[] properties = new byte[kPropSize];
+
+       public void WriteCoderProperties(java.io.OutputStream outStream) throws IOException
+       {
+               properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
+               for (int i = 0; i < 4; i++)
+                       properties[1 + i] = (byte)(_dictionarySize >> (8 * i));
+               outStream.write(properties, 0, kPropSize);
+       }
+
+       int[] tempPrices = new int[Base.kNumFullDistances];
+       int _matchPriceCount;
+
+       void FillDistancesPrices()
+       {
+               for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
+               {
+                       int posSlot = GetPosSlot(i);
+                       int footerBits = (int)((posSlot >> 1) - 1);
+                       int baseVal = ((2 | (posSlot & 1)) << footerBits);
+                       tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
+                               baseVal - posSlot - 1, footerBits, i - baseVal);
+               }
+
+               for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
+               {
+                       int posSlot;
+                       BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
+
+                       int st = (lenToPosState << Base.kNumPosSlotBits);
+                       for (posSlot = 0; posSlot < _distTableSize; posSlot++)
+                               _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
+                       for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
+                               _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << SevenZip.Compression.RangeCoder.Encoder.kNumBitPriceShiftBits);
+
+                       int st2 = lenToPosState * Base.kNumFullDistances;
+                       int i;
+                       for (i = 0; i < Base.kStartPosModelIndex; i++)
+                               _distancesPrices[st2 + i] = _posSlotPrices[st + i];
+                       for (; i < Base.kNumFullDistances; i++)
+                               _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
+               }
+               _matchPriceCount = 0;
+       }
+
+       void FillAlignPrices()
+       {
+               for (int i = 0; i < Base.kAlignTableSize; i++)
+                       _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
+               _alignPriceCount = 0;
+       }
+
+
+       public boolean SetAlgorithm(int algorithm)
+       {
+               /*
+               _fastMode = (algorithm == 0);
+               _maxMode = (algorithm >= 2);
+               */
+               return true;
+       }
+
+       public boolean SetDictionarySize(int dictionarySize)
+       {
+               int kDicLogSizeMaxCompress = 29;
+               if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress))
+                       return false;
+               _dictionarySize = dictionarySize;
+               int dicLogSize;
+               for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) ;
+               _distTableSize = dicLogSize * 2;
+               return true;
+       }
+
+       public boolean SeNumFastBytes(int numFastBytes)
+       {
+               if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
+                       return false;
+               _numFastBytes = numFastBytes;
+               return true;
+       }
+
+       public boolean SetMatchFinder(int matchFinderIndex)
+       {
+               if (matchFinderIndex < 0 || matchFinderIndex > 2)
+                       return false;
+               int matchFinderIndexPrev = _matchFinderType;
+               _matchFinderType = matchFinderIndex;
+               if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
+               {
+                       _dictionarySizePrev = -1;
+                       _matchFinder = null;
+               }
+               return true;
+       }
+
+       public boolean SetLcLpPb(int lc, int lp, int pb)
+       {
+               if (
+                               lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax ||
+                               lc < 0 || lc > Base.kNumLitContextBitsMax ||
+                               pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax)
+                       return false;
+               _numLiteralPosStateBits = lp;
+               _numLiteralContextBits = lc;
+               _posStateBits = pb;
+               _posStateMask = ((1) << _posStateBits) - 1;
+               return true;
+       }
+
+       public void SetEndMarkerMode(boolean endMarkerMode)
+       {
+               _writeEndMark = endMarkerMode;
+       }
+}
+
diff --git a/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
new file mode 100644 (file)
index 0000000..7698581
--- /dev/null
@@ -0,0 +1,55 @@
+package SevenZip.Compression.RangeCoder;
+
+public class BitTreeDecoder
+{
+       short[] Models;
+       int NumBitLevels;
+       
+       public BitTreeDecoder(int numBitLevels)
+       {
+               NumBitLevels = numBitLevels;
+               Models = new short[1 << numBitLevels];
+       }
+       
+       public void Init()
+       {
+               Decoder.InitBitModels(Models);
+       }
+       
+       public int Decode(Decoder rangeDecoder) throws java.io.IOException
+       {
+               int m = 1;
+               for (int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--)
+                       m = (m << 1) + rangeDecoder.DecodeBit(Models, m);
+               return m - (1 << NumBitLevels);
+       }
+       
+       public int ReverseDecode(Decoder rangeDecoder) throws java.io.IOException
+       {
+               int m = 1;
+               int symbol = 0;
+               for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+               {
+                       int bit = rangeDecoder.DecodeBit(Models, m);
+                       m <<= 1;
+                       m += bit;
+                       symbol |= (bit << bitIndex);
+               }
+               return symbol;
+       }
+       
+       public static int ReverseDecode(short[] Models, int startIndex,
+                       Decoder rangeDecoder, int NumBitLevels) throws java.io.IOException
+       {
+               int m = 1;
+               int symbol = 0;
+               for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+               {
+                       int bit = rangeDecoder.DecodeBit(Models, startIndex + m);
+                       m <<= 1;
+                       m += bit;
+                       symbol |= (bit << bitIndex);
+               }
+               return symbol;
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
new file mode 100644 (file)
index 0000000..f9e97db
--- /dev/null
@@ -0,0 +1,99 @@
+package SevenZip.Compression.RangeCoder;
+import java.io.IOException;
+
+public class BitTreeEncoder
+{
+       short[] Models;
+       int NumBitLevels;
+       
+       public BitTreeEncoder(int numBitLevels)
+       {
+               NumBitLevels = numBitLevels;
+               Models = new short[1 << numBitLevels];
+       }
+       
+       public void Init()
+       {
+               Decoder.InitBitModels(Models);
+       }
+       
+       public void Encode(Encoder rangeEncoder, int symbol) throws IOException
+       {
+               int m = 1;
+               for (int bitIndex = NumBitLevels; bitIndex != 0; )
+               {
+                       bitIndex--;
+                       int bit = (symbol >>> bitIndex) & 1;
+                       rangeEncoder.Encode(Models, m, bit);
+                       m = (m << 1) | bit;
+               }
+       }
+       
+       public void ReverseEncode(Encoder rangeEncoder, int symbol) throws IOException
+       {
+               int m = 1;
+               for (int  i = 0; i < NumBitLevels; i++)
+               {
+                       int bit = symbol & 1;
+                       rangeEncoder.Encode(Models, m, bit);
+                       m = (m << 1) | bit;
+                       symbol >>= 1;
+               }
+       }
+       
+       public int GetPrice(int symbol)
+       {
+               int price = 0;
+               int m = 1;
+               for (int bitIndex = NumBitLevels; bitIndex != 0; )
+               {
+                       bitIndex--;
+                       int bit = (symbol >>> bitIndex) & 1;
+                       price += Encoder.GetPrice(Models[m], bit);
+                       m = (m << 1) + bit;
+               }
+               return price;
+       }
+       
+       public int ReverseGetPrice(int symbol)
+       {
+               int price = 0;
+               int m = 1;
+               for (int i = NumBitLevels; i != 0; i--)
+               {
+                       int bit = symbol & 1;
+                       symbol >>>= 1;
+                       price += Encoder.GetPrice(Models[m], bit);
+                       m = (m << 1) | bit;
+               }
+               return price;
+       }
+       
+       public static int ReverseGetPrice(short[] Models, int startIndex,
+                       int NumBitLevels, int symbol)
+       {
+               int price = 0;
+               int m = 1;
+               for (int i = NumBitLevels; i != 0; i--)
+               {
+                       int bit = symbol & 1;
+                       symbol >>>= 1;
+                       price += Encoder.GetPrice(Models[startIndex + m], bit);
+                       m = (m << 1) | bit;
+               }
+               return price;
+       }
+       
+       public static void ReverseEncode(short[] Models, int startIndex,
+                       Encoder rangeEncoder, int NumBitLevels, int symbol) throws IOException
+       {
+               int m = 1;
+               for (int i = 0; i < NumBitLevels; i++)
+               {
+                       int bit = symbol & 1;
+                       rangeEncoder.Encode(Models, startIndex + m, bit);
+                       m = (m << 1) | bit;
+                       symbol >>= 1;
+               }
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/RangeCoder/Decoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/Decoder.java
new file mode 100644 (file)
index 0000000..85b3150
--- /dev/null
@@ -0,0 +1,88 @@
+package SevenZip.Compression.RangeCoder;
+import java.io.IOException;
+
+public class Decoder
+{
+       static final int kTopMask = ~((1 << 24) - 1);
+       
+       static final int kNumBitModelTotalBits = 11;
+       static final int kBitModelTotal = (1 << kNumBitModelTotalBits);
+       static final int kNumMoveBits = 5;
+       
+       int Range;
+       int Code;
+
+       java.io.InputStream Stream;
+       
+       public final void SetStream(java.io.InputStream stream)
+       { 
+               Stream = stream; 
+       }
+       
+       public final void ReleaseStream()
+       { 
+               Stream = null; 
+       }
+       
+       public final void Init() throws IOException
+       {
+               Code = 0;
+               Range = -1;
+               for (int i = 0; i < 5; i++)
+                       Code = (Code << 8) | Stream.read();
+       }
+       
+       public final int DecodeDirectBits(int numTotalBits) throws IOException
+       {
+               int result = 0;
+               for (int i = numTotalBits; i != 0; i--)
+               {
+                       Range >>>= 1;
+                       int t = ((Code - Range) >>> 31);
+                       Code -= Range & (t - 1);
+                       result = (result << 1) | (1 - t);
+                       
+                       if ((Range & kTopMask) == 0)
+                       {
+                               Code = (Code << 8) | Stream.read();
+                               Range <<= 8;
+                       }
+               }
+               return result;
+       }
+       
+       public int DecodeBit(short []probs, int index) throws IOException
+       {
+               int prob = probs[index];
+               int newBound = (Range >>> kNumBitModelTotalBits) * prob;
+               if ((Code ^ 0x80000000) < (newBound ^ 0x80000000))
+               {
+                       Range = newBound;
+                       probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));
+                       if ((Range & kTopMask) == 0)
+                       {
+                               Code = (Code << 8) | Stream.read();
+                               Range <<= 8;
+                       }
+                       return 0;
+               }
+               else
+               {
+                       Range -= newBound;
+                       Code -= newBound;
+                       probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));
+                       if ((Range & kTopMask) == 0)
+                       {
+                               Code = (Code << 8) | Stream.read();
+                               Range <<= 8;
+                       }
+                       return 1;
+               }
+       }
+       
+       public static void InitBitModels(short []probs)
+       {
+               for (int i = 0; i < probs.length; i++)
+                       probs[i] = (kBitModelTotal >>> 1);
+       }
+}
diff --git a/lzma/Java/SevenZip/Compression/RangeCoder/Encoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/Encoder.java
new file mode 100644 (file)
index 0000000..d21b983
--- /dev/null
@@ -0,0 +1,151 @@
+package SevenZip.Compression.RangeCoder;
+import java.io.IOException;
+
+public class Encoder
+{
+       static final int kTopMask = ~((1 << 24) - 1);
+       
+       static final int kNumBitModelTotalBits = 11;
+       static final int kBitModelTotal = (1 << kNumBitModelTotalBits);
+       static final int kNumMoveBits = 5;
+       
+       java.io.OutputStream Stream;
+
+       long Low;
+       int Range;
+       int _cacheSize;
+       int _cache;
+       
+       long _position;
+       
+       public void SetStream(java.io.OutputStream stream)
+       {
+               Stream = stream;
+       }
+       
+       public void ReleaseStream()
+       {
+               Stream = null;
+       }
+       
+       public void Init()
+       {
+               _position = 0;
+               Low = 0;
+               Range = -1;
+               _cacheSize = 1;
+               _cache = 0;
+       }
+       
+       public void FlushData() throws IOException
+       {
+               for (int i = 0; i < 5; i++)
+                       ShiftLow();
+       }
+       
+       public void FlushStream() throws IOException
+       {
+               Stream.flush();
+       }
+       
+       public void ShiftLow() throws IOException
+       {
+               int LowHi = (int)(Low >>> 32);
+               if (LowHi != 0 || Low < 0xFF000000L)
+               {
+                       _position += _cacheSize;
+                       int temp = _cache;
+                       do
+                       {
+                               Stream.write(temp + LowHi);
+                               temp = 0xFF;
+                       }
+                       while(--_cacheSize != 0);
+                       _cache = (((int)Low) >>> 24);
+               }
+               _cacheSize++;
+               Low = (Low & 0xFFFFFF) << 8;
+       }
+       
+       public void EncodeDirectBits(int v, int numTotalBits) throws IOException
+       {
+               for (int i = numTotalBits - 1; i >= 0; i--)
+               {
+                       Range >>>= 1;
+                       if (((v >>> i) & 1) == 1)
+                               Low += Range;
+                       if ((Range & Encoder.kTopMask) == 0)
+                       {
+                               Range <<= 8;
+                               ShiftLow();
+                       }
+               }
+       }
+       
+       
+       public long GetProcessedSizeAdd()
+       {
+               return _cacheSize + _position + 4;
+       }
+       
+       
+       
+       static final int kNumMoveReducingBits = 2;
+       public static final int kNumBitPriceShiftBits = 6;
+       
+       public static void InitBitModels(short []probs)
+       {
+               for (int i = 0; i < probs.length; i++)
+                       probs[i] = (kBitModelTotal >>> 1);
+       }
+       
+       public void Encode(short []probs, int index, int symbol) throws IOException
+       {
+               int prob = probs[index];
+               int newBound = (Range >>> kNumBitModelTotalBits) * prob;
+               if (symbol == 0)
+               {
+                       Range = newBound;
+                       probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));
+               }
+               else
+               {
+                       Low += (newBound & 0xFFFFFFFFL);
+                       Range -= newBound;
+                       probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));
+               }
+               if ((Range & kTopMask) == 0)
+               {
+                       Range <<= 8;
+                       ShiftLow();
+               }
+       }
+       
+       private static int[] ProbPrices = new int[kBitModelTotal >>> kNumMoveReducingBits];
+       
+       static
+       {
+               int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
+               for (int i = kNumBits - 1; i >= 0; i--)
+               {
+                       int start = 1 << (kNumBits - i - 1);
+                       int end = 1 << (kNumBits - i);
+                       for (int j = start; j < end; j++)
+                               ProbPrices[j] = (i << kNumBitPriceShiftBits) +
+                                               (((end - j) << kNumBitPriceShiftBits) >>> (kNumBits - i - 1));
+               }
+       }
+       
+       static public int GetPrice(int Prob, int symbol)
+       {
+               return ProbPrices[(((Prob - symbol) ^ ((-symbol))) & (kBitModelTotal - 1)) >>> kNumMoveReducingBits];
+       }
+       static public int GetPrice0(int Prob)
+       { 
+               return ProbPrices[Prob >>> kNumMoveReducingBits]; 
+       }
+       static public int GetPrice1(int Prob)
+       { 
+               return ProbPrices[(kBitModelTotal - Prob) >>> kNumMoveReducingBits]; 
+       }
+}
diff --git a/lzma/Java/SevenZip/ICodeProgress.java b/lzma/Java/SevenZip/ICodeProgress.java
new file mode 100644 (file)
index 0000000..4cb8d1b
--- /dev/null
@@ -0,0 +1,6 @@
+package SevenZip;
+
+public interface ICodeProgress
+{
+       public void SetProgress(long inSize, long outSize);
+}
diff --git a/lzma/Java/SevenZip/LzmaAlone.java b/lzma/Java/SevenZip/LzmaAlone.java
new file mode 100644 (file)
index 0000000..79c2b00
--- /dev/null
@@ -0,0 +1,253 @@
+package SevenZip;
+
+public class LzmaAlone
+{
+       static public class CommandLine
+       {
+               public static final int kEncode = 0;
+               public static final int kDecode = 1;
+               public static final int kBenchmak = 2;
+               
+               public int Command = -1;
+               public int NumBenchmarkPasses = 10;
+               
+               public int DictionarySize = 1 << 23;
+               public boolean DictionarySizeIsDefined = false;
+               
+               public int Lc = 3;
+               public int Lp = 0;
+               public int Pb = 2;
+               
+               public int Fb = 128;
+               public boolean FbIsDefined = false;
+               
+               public boolean Eos = false;
+               
+               public int Algorithm = 2;
+               public int MatchFinder = 1;
+               
+               public String InFile;
+               public String OutFile;
+               
+               boolean ParseSwitch(String s)
+               {
+                       if (s.startsWith("d"))
+                       {
+                               DictionarySize = 1 << Integer.parseInt(s.substring(1));
+                               DictionarySizeIsDefined = true;
+                       }
+                       else if (s.startsWith("fb"))
+                       {
+                               Fb = Integer.parseInt(s.substring(2));
+                               FbIsDefined = true;
+                       }
+                       else if (s.startsWith("a"))
+                               Algorithm = Integer.parseInt(s.substring(1));
+                       else if (s.startsWith("lc"))
+                               Lc = Integer.parseInt(s.substring(2));
+                       else if (s.startsWith("lp"))
+                               Lp = Integer.parseInt(s.substring(2));
+                       else if (s.startsWith("pb"))
+                               Pb = Integer.parseInt(s.substring(2));
+                       else if (s.startsWith("eos"))
+                               Eos = true;
+                       else if (s.startsWith("mf"))
+                       {
+                               String mfs = s.substring(2);
+                               if (mfs.equals("bt2"))
+                                       MatchFinder = 0;
+                               else if (mfs.equals("bt4"))
+                                       MatchFinder = 1;
+                               else if (mfs.equals("bt4b"))
+                                       MatchFinder = 2;
+                               else
+                                       return false;
+                       }
+                       else
+                               return false;
+                       return true;
+               }
+               
+               public boolean Parse(String[] args) throws Exception
+               {
+                       int pos = 0;
+                       boolean switchMode = true;
+                       for (int i = 0; i < args.length; i++)
+                       {
+                               String s = args[i];
+                               if (s.length() == 0)
+                                       return false;
+                               if (switchMode)
+                               {
+                                       if (s.compareTo("--") == 0)
+                                       {
+                                               switchMode = false;
+                                               continue;
+                                       }
+                                       if (s.charAt(0) == '-')
+                                       {
+                                               String sw = s.substring(1).toLowerCase();
+                                               if (sw.length() == 0)
+                                                       return false;
+                                               try
+                                               {
+                                                       if (!ParseSwitch(sw))
+                                                               return false;
+                                               }
+                                               catch (NumberFormatException e)
+                                               {
+                                                       return false;
+                                               }
+                                               continue;
+                                       }
+                               }
+                               if (pos == 0)
+                               {
+                                       if (s.equalsIgnoreCase("e"))
+                                               Command = kEncode;
+                                       else if (s.equalsIgnoreCase("d"))
+                                               Command = kDecode;
+                                       else if (s.equalsIgnoreCase("b"))
+                                               Command = kBenchmak;
+                                       else
+                                               return false;
+                               }
+                               else if(pos == 1)
+                               {
+                                       if (Command == kBenchmak)
+                                       {
+                                               try
+                                               {
+                                                       NumBenchmarkPasses = Integer.parseInt(s);
+                                                       if (NumBenchmarkPasses < 1)
+                                                               return false;
+                                               }
+                                               catch (NumberFormatException e)
+                                               {
+                                                       return false;
+                                               }
+                                       }
+                                       else
+                                               InFile = s;
+                               }
+                               else if(pos == 2)
+                                       OutFile = s;
+                               else
+                                       return false;
+                               pos++;
+                               continue;
+                       }
+                       return true;
+               }
+       }
+       
+       
+       static void PrintHelp()
+       {
+               System.out.println(
+                               "\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +
+                               "  e: encode file\n" +
+                               "  d: decode file\n" +
+                               "  b: Benchmark\n" +
+                               "<Switches>\n" +
+                               // "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +
+                               "  -d{N}:  set dictionary - [0,28], default: 23 (8MB)\n" +
+                               "  -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
+                               "  -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
+                               "  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
+                               "  -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
+                               "  -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
+                               "  -eos:   write End Of Stream marker\n"
+                               );
+       }
+       
+       public static void main(String[] args) throws Exception
+       {
+               System.out.println("\nLZMA (Java) 4.42 Copyright (c) 1999-2006 Igor Pavlov  2006-05-15\n");
+               
+               if (args.length < 1)
+               {
+                       PrintHelp();
+                       return;
+               }
+               
+               CommandLine params = new CommandLine();
+               if (!params.Parse(args))
+               {
+                       System.out.println("\nIncorrect command");
+                       return;
+               }
+               
+               if (params.Command == CommandLine.kBenchmak)
+               {
+                       int dictionary = (1 << 21);
+                       if (params.DictionarySizeIsDefined)
+                               dictionary = params.DictionarySize;
+                       if (params.MatchFinder > 1)
+                               throw new Exception("Unsupported match finder");
+                       SevenZip.LzmaBench.LzmaBenchmark(params.NumBenchmarkPasses, dictionary);
+               }
+               else if (params.Command == CommandLine.kEncode || params.Command == CommandLine.kDecode)
+               {
+                       java.io.File inFile = new java.io.File(params.InFile);
+                       java.io.File outFile = new java.io.File(params.OutFile);
+                       
+                       java.io.BufferedInputStream inStream  = new java.io.BufferedInputStream(new java.io.FileInputStream(inFile));
+                       java.io.BufferedOutputStream outStream = new java.io.BufferedOutputStream(new java.io.FileOutputStream(outFile));
+                       
+                       boolean eos = false;
+                       if (params.Eos)
+                               eos = true;
+                       if (params.Command == CommandLine.kEncode)
+                       {
+                               SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
+                               if (!encoder.SetAlgorithm(params.Algorithm))
+                                       throw new Exception("Incorrect compression mode");
+                               if (!encoder.SetDictionarySize(params.DictionarySize))
+                                       throw new Exception("Incorrect dictionary size");
+                               if (!encoder.SeNumFastBytes(params.Fb))
+                                       throw new Exception("Incorrect -fb value");
+                               if (!encoder.SetMatchFinder(params.MatchFinder))
+                                       throw new Exception("Incorrect -mf value");
+                               if (!encoder.SetLcLpPb(params.Lc, params.Lp, params.Pb))
+                                       throw new Exception("Incorrect -lc or -lp or -pb value");
+                               encoder.SetEndMarkerMode(eos);
+                               encoder.WriteCoderProperties(outStream);
+                               long fileSize;
+                               if (eos)
+                                       fileSize = -1;
+                               else
+                                       fileSize = inFile.length();
+                               for (int i = 0; i < 8; i++)
+                                       outStream.write((int)(fileSize >>> (8 * i)) & 0xFF);
+                               encoder.Code(inStream, outStream, -1, -1, null);
+                       }
+                       else
+                       {
+                               int propertiesSize = 5;
+                               byte[] properties = new byte[propertiesSize];
+                               if (inStream.read(properties, 0, propertiesSize) != propertiesSize)
+                                       throw new Exception("input .lzma file is too short");
+                               SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
+                               if (!decoder.SetDecoderProperties(properties))
+                                       throw new Exception("Incorrect stream properties");
+                               long outSize = 0;
+                               for (int i = 0; i < 8; i++)
+                               {
+                                       int v = inStream.read();
+                                       if (v < 0)
+                                               throw new Exception("Can't read stream size");
+                                       outSize |= ((long)v) << (8 * i);
+                               }
+                               if (!decoder.Code(inStream, outStream, outSize))
+                                       throw new Exception("Error in data stream");
+                       }
+                       outStream.flush();
+                       outStream.close();
+                       inStream.close();
+               }
+               else
+                       throw new Exception("Incorrect command");
+               return;
+       }
+}
diff --git a/lzma/Java/SevenZip/LzmaBench.java b/lzma/Java/SevenZip/LzmaBench.java
new file mode 100644 (file)
index 0000000..397e7af
--- /dev/null
@@ -0,0 +1,392 @@
+package SevenZip;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+public class LzmaBench
+{
+       static final int kAdditionalSize = (1 << 21);
+       static final int kCompressedAdditionalSize = (1 << 10);
+       
+       static class CRandomGenerator
+       {
+               int A1;
+               int A2;
+               public CRandomGenerator() { Init(); }
+               public void Init() { A1 = 362436069; A2 = 521288629; }
+               public int GetRnd()
+               {
+                       return
+                               ((A1 = 36969 * (A1 & 0xffff) + (A1 >>> 16)) << 16) ^
+                               ((A2 = 18000 * (A2 & 0xffff) + (A2 >>> 16)));
+               }
+       };
+       
+       static class CBitRandomGenerator
+       {
+               CRandomGenerator RG = new CRandomGenerator();
+               int Value;
+               int NumBits;
+               public void Init()
+               {
+                       Value = 0;
+                       NumBits = 0;
+               }
+               public int GetRnd(int numBits)
+               {
+                       int result;
+                       if (NumBits > numBits)
+                       {
+                               result = Value & ((1 << numBits) - 1);
+                               Value >>>= numBits;
+                               NumBits -= numBits;
+                               return result;
+                       }
+                       numBits -= NumBits;
+                       result = (Value << numBits);
+                       Value = RG.GetRnd();
+                       result |= Value & (((int)1 << numBits) - 1);
+                       Value >>>= numBits;
+                       NumBits = 32 - numBits;
+                       return result;
+               }
+       };
+       
+       static class CBenchRandomGenerator
+       {
+               CBitRandomGenerator RG = new CBitRandomGenerator();
+               int Pos;
+               int Rep0;
+
+               public int BufferSize;
+               public byte[] Buffer = null;
+
+               public CBenchRandomGenerator() { }
+               public void Set(int bufferSize)
+               {
+                       Buffer = new byte[bufferSize];
+                       Pos = 0;
+                       BufferSize = bufferSize;
+               }
+               int GetRndBit() { return RG.GetRnd(1); }
+               int GetLogRandBits(int numBits)
+               {
+                       int len = RG.GetRnd(numBits);
+                       return RG.GetRnd((int)len);
+               }
+               int GetOffset()
+               {
+                       if (GetRndBit() == 0)
+                               return GetLogRandBits(4);
+                       return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
+               }
+               int GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
+               int GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
+               public void Generate()
+               {
+                       RG.Init();
+                       Rep0 = 1;
+                       while (Pos < BufferSize)
+                       {
+                               if (GetRndBit() == 0 || Pos < 1)
+                                       Buffer[Pos++] = (byte)(RG.GetRnd(8));
+                               else
+                               {
+                                       int len;
+                                       if (RG.GetRnd(3) == 0)
+                                               len = 1 + GetLen1();
+                                       else
+                                       {
+                                               do
+                                                       Rep0 = GetOffset();
+                                               while (Rep0 >= Pos);
+                                               Rep0++;
+                                               len = 2 + GetLen2();
+                                       }
+                                       for (int i = 0; i < len && Pos < BufferSize; i++, Pos++)
+                                               Buffer[Pos] = Buffer[Pos - Rep0];
+                               }
+                       }
+               }
+       };
+       
+       static class CrcOutStream extends java.io.OutputStream
+       {
+               public CRC CRC = new CRC();
+               
+               public void Init()
+               { 
+                       CRC.Init(); 
+               }
+               public int GetDigest()
+               { 
+                       return CRC.GetDigest(); 
+               }
+               public void write(byte[] b)
+               {
+                       CRC.Update(b);
+               }
+               public void write(byte[] b, int off, int len)
+               {
+                       CRC.Update(b, off, len);
+               }
+               public void write(int b)
+               {
+                       CRC.UpdateByte(b);
+               }
+       };
+
+       static class MyOutputStream extends java.io.OutputStream
+       {
+               byte[] _buffer;
+               int _size;
+               int _pos;
+               
+               public MyOutputStream(byte[] buffer)
+               {
+                       _buffer = buffer;
+                       _size = _buffer.length;
+               }
+               
+               public void reset()
+               { 
+                       _pos = 0; 
+               }
+               
+               public void write(int b) throws IOException
+               {
+                       if (_pos >= _size)
+                               throw new IOException("Error");
+                       _buffer[_pos++] = (byte)b;
+               }
+               
+               public int size()
+               {
+                       return _pos;
+               }
+       };
+
+       static class MyInputStream extends java.io.InputStream
+       {
+               byte[] _buffer;
+               int _size;
+               int _pos;
+               
+               public MyInputStream(byte[] buffer, int size)
+               {
+                       _buffer = buffer;
+                       _size = size;
+               }
+               
+               public void reset()
+               { 
+                       _pos = 0; 
+               }
+               
+               public int read()
+               {
+                       if (_pos >= _size)
+                               return -1;
+                       return _buffer[_pos++] & 0xFF;
+               }
+       };
+       
+       static class CProgressInfo implements ICodeProgress
+       {
+               public long ApprovedStart;
+               public long InSize;
+               public long Time;
+               public void Init()
+               { InSize = 0; }
+               public void SetProgress(long inSize, long outSize)
+               {
+                       if (inSize >= ApprovedStart && InSize == 0)
+                       {
+                               Time = System.currentTimeMillis();
+                               InSize = inSize;
+                       }
+               }
+       }
+       static final int kSubBits = 8;
+       
+       static int GetLogSize(int size)
+       {
+               for (int i = kSubBits; i < 32; i++)
+                       for (int j = 0; j < (1 << kSubBits); j++)
+                               if (size <= ((1) << i) + (j << (i - kSubBits)))
+                                       return (i << kSubBits) + j;
+               return (32 << kSubBits);
+       }
+       
+       static long MyMultDiv64(long value, long elapsedTime)
+       {
+               long freq = 1000; // ms
+               long elTime = elapsedTime;
+               while (freq > 1000000)
+               {
+                       freq >>>= 1;
+                       elTime >>>= 1;
+               }
+               if (elTime == 0)
+                       elTime = 1;
+               return value * freq / elTime;
+       }
+       
+       static long GetCompressRating(int dictionarySize, long elapsedTime, long size)
+       {
+               long t = GetLogSize(dictionarySize) - (18 << kSubBits);
+               long numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
+               long numCommands = (long)(size) * numCommandsForOne;
+               return MyMultDiv64(numCommands, elapsedTime);
+       }
+       
+       static long GetDecompressRating(long elapsedTime, long outSize, long inSize)
+       {
+               long numCommands = inSize * 220 + outSize * 20;
+               return MyMultDiv64(numCommands, elapsedTime);
+       }
+       
+       static long GetTotalRating(
+                       int dictionarySize,
+                       long elapsedTimeEn, long sizeEn,
+                       long elapsedTimeDe,
+                       long inSizeDe, long outSizeDe)
+       {
+               return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
+                               GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
+       }
+       
+       static void PrintValue(long v)
+       {
+               String s = "";
+               s += v;
+               for (int i = 0; i + s.length() < 6; i++)
+                       System.out.print(" ");
+               System.out.print(s);
+       }
+       
+       static void PrintRating(long rating)
+       {
+               PrintValue(rating / 1000000);
+               System.out.print(" MIPS");
+       }
+       
+       static void PrintResults(
+                       int dictionarySize,
+                       long elapsedTime,
+                       long size,
+                       boolean decompressMode, long secondSize)
+       {
+               long speed = MyMultDiv64(size, elapsedTime);
+               PrintValue(speed / 1024);
+               System.out.print(" KB/s  ");
+               long rating;
+               if (decompressMode)
+                       rating = GetDecompressRating(elapsedTime, size, secondSize);
+               else
+                       rating = GetCompressRating(dictionarySize, elapsedTime, size);
+               PrintRating(rating);
+       }
+       
+       static public int LzmaBenchmark(int numIterations, int dictionarySize) throws Exception
+       {
+               if (numIterations <= 0)
+                       return 0;
+               if (dictionarySize < (1 << 18))
+               {
+                       System.out.println("\nError: dictionary size for benchmark must be >= 18 (256 KB)");
+                       return 1;
+               }
+               System.out.print("\n       Compressing                Decompressing\n\n");
+               
+               SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
+               SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
+               
+               if (!encoder.SetDictionarySize(dictionarySize))
+                       throw new Exception("Incorrect dictionary size");
+               
+               int kBufferSize = dictionarySize + kAdditionalSize;
+               int kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+               
+               ByteArrayOutputStream propStream = new ByteArrayOutputStream();
+               encoder.WriteCoderProperties(propStream);
+               byte[] propArray = propStream.toByteArray();
+               decoder.SetDecoderProperties(propArray);
+               
+               CBenchRandomGenerator rg = new CBenchRandomGenerator();
+
+               rg.Set(kBufferSize);
+               rg.Generate();
+               CRC crc = new CRC();
+               crc.Init();
+               crc.Update(rg.Buffer, 0, rg.BufferSize);
+               
+               CProgressInfo progressInfo = new CProgressInfo();
+               progressInfo.ApprovedStart = dictionarySize;
+               
+               long totalBenchSize = 0;
+               long totalEncodeTime = 0;
+               long totalDecodeTime = 0;
+               long totalCompressedSize = 0;
+               
+               MyInputStream inStream = new MyInputStream(rg.Buffer, rg.BufferSize);
+
+               byte[] compressedBuffer = new byte[kCompressedBufferSize];
+               MyOutputStream compressedStream = new MyOutputStream(compressedBuffer);
+               CrcOutStream crcOutStream = new CrcOutStream();
+               MyInputStream inputCompressedStream = null;
+               int compressedSize = 0;
+               for (int i = 0; i < numIterations; i++)
+               {
+                       progressInfo.Init();
+                       inStream.reset();
+                       compressedStream.reset();
+                       encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
+                       long encodeTime = System.currentTimeMillis() - progressInfo.Time;
+                       
+                       if (i == 0)
+                       {
+                               compressedSize = compressedStream.size();
+                               inputCompressedStream = new MyInputStream(compressedBuffer, compressedSize);
+                       }
+                       else if (compressedSize != compressedStream.size())
+                               throw (new Exception("Encoding error"));
+                               
+                       if (progressInfo.InSize == 0)
+                               throw (new Exception("Internal ERROR 1282"));
+
+                       long decodeTime = 0;
+                       for (int j = 0; j < 2; j++)
+                       {
+                               inputCompressedStream.reset();
+                               crcOutStream.Init();
+                               
+                               long outSize = kBufferSize;
+                               long startTime = System.currentTimeMillis();
+                               if (!decoder.Code(inputCompressedStream, crcOutStream, outSize))
+                                       throw (new Exception("Decoding Error"));;
+                               decodeTime = System.currentTimeMillis() - startTime;
+                               if (crcOutStream.GetDigest() != crc.GetDigest())
+                                       throw (new Exception("CRC Error"));
+                       }
+                       long benchSize = kBufferSize - (long)progressInfo.InSize;
+                       PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
+                       System.out.print("     ");
+                       PrintResults(dictionarySize, decodeTime, kBufferSize, true, compressedSize);
+                       System.out.println();
+                       
+                       totalBenchSize += benchSize;
+                       totalEncodeTime += encodeTime;
+                       totalDecodeTime += decodeTime;
+                       totalCompressedSize += compressedSize;
+               }
+               System.out.println("---------------------------------------------------");
+               PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
+               System.out.print("     ");
+               PrintResults(dictionarySize, totalDecodeTime,
+                               kBufferSize * (long)numIterations, true, totalCompressedSize);
+               System.out.println("    Average");
+               return 0;
+       }
+}
diff --git a/lzma/LGPL.txt b/lzma/LGPL.txt
new file mode 100644 (file)
index 0000000..4c38901
--- /dev/null
@@ -0,0 +1,504 @@
+      GNU LESSER GENERAL PUBLIC LICENSE
+           Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+          Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+      GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+          NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+         END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/lzma/Methods.txt b/lzma/Methods.txt
new file mode 100644 (file)
index 0000000..e615669
--- /dev/null
@@ -0,0 +1,141 @@
+7-Zip method IDs (4.56)
+-----------------------
+
+Each compression or crypto method in 7z has unique binary value (ID).
+The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
+
+If you want to add some new ID, you have two ways:
+1) Write request for allocating IDs to 7-zip developers.
+2) Generate 8-bytes ID:
+
+    7F ZZ ZZ ZZ ZZ ZZ MM MM 
+
+    7F              - Prefix for random IDs (1 byte)
+    ZZ ZZ ZZ ZZ ZZ  - Developer ID (5 bytes). Use real random bytes. 
+                      
+    MM MM           - Method ID (2 bytes)
+
+    You can notify 7-Zip developers about your Developer ID / Method ID.
+
+    Note: Use new ID only if old codec can not decode data encoded with new version.
+
+
+List of defined IDs
+-------------------
+      
+00 - Copy
+01 - Reserved
+02 - Common
+   03 Swap
+      - 2 Swap2
+      - 4 Swap4
+   04 Delta (subject to change)
+
+03 - 7z
+   01 - LZMA
+      01 - Version
+  
+   03 - Branch
+      01 - x86
+         03  - BCJ
+         1B  - BCJ2
+      02 - PPC
+         05 - BC_PPC_B (Big Endian)
+      03 - Alpha
+         01 - BC_Alpha
+      04 - IA64
+         01 - BC_IA64
+      05 - ARM
+         01 - BC_ARM
+      06 - M68
+         05 - BC_M68_B (Big Endian)
+      07 - ARM Thumb
+         01 - BC_ARMThumb
+      08 - SPARC
+         05 - BC_SPARC
+
+   04 - PPMD
+      01 - Version
+
+   7F -
+      01 - experimental methods.
+
+   80 - reserved for independent developers
+
+   E0 - Random IDs
+
+04 - Misc
+   00 - Reserved
+   01 - Zip
+      00 - Copy (not used). Use {00} instead
+      01 - Shrink
+      06 - Implode
+      08 - Deflate
+      09 - Deflate64
+      12 - BZip2 (not used). Use {04 02 02} instead
+   02 - BZip
+      02 - BZip2
+   03 - Rar
+      01 - Rar15
+      02 - Rar20
+      03 - Rar29
+   04 - Arj
+      01 - Arj (1,2,3)
+      02 - Arj 4
+   05 - Z
+   06 - Lzh
+   07 - Reserved for 7z
+   08 - Cab
+   09 - NSIS
+      01 - DeflateNSIS
+      02 - BZip2NSIS
+
+
+06 - Crypto 
+   00 - 
+   01 - AES
+      0x - AES-128
+      4x - AES-192
+      8x - AES-256
+      Cx - AES
+
+      x0 - ECB
+      x1 - CBC
+      x2 - CFB
+      x3 - OFB
+
+   07 - Reserved
+   0F - Reserved
+
+   F0 - Misc Ciphers (Real Ciphers without hashing algo)
+
+   F1 - Misc Ciphers (Combine)
+      01 - Zip
+         01 - Main Zip crypto algo
+      03 - RAR
+         02 - 
+         03 - Rar29 AES-128 + (modified SHA-1)
+      07 - 7z
+         01 - AES-256 + SHA-256
+
+07 - Hash (subject to change)
+   00 - 
+   01 - CRC
+   02 - SHA-1
+   03 - SHA-256
+   04 - SHA-384
+   05 - SHA-512
+
+   F0 - Misc Hash
+
+   F1 - Misc
+      03 - RAR
+         03 - Rar29 Password Hashing (modified SHA1)
+      07 - 7z 
+         01 - SHA-256 Password Hashing
+    
+   
+
+
+---
+End of document
diff --git a/lzma/history.txt b/lzma/history.txt
new file mode 100644 (file)
index 0000000..8db5c10
--- /dev/null
@@ -0,0 +1,198 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+  4.57           2007-12-12
+  -------------------------
+    - Speed optimizations in Ñ++ LZMA Decoder. 
+    - Small changes for more compatibility with some C/C++ compilers.
+
+  
+  4.49 beta      2007-07-05
+  -------------------------
+    - .7z ANSI-C Decoder:
+         - now it supports BCJ and BCJ2 filters
+         - now it supports files larger than 4 GB.
+         - now it supports "Last Write Time" field for files.
+    - C++ code for .7z archives compressing/decompressing from 7-zip 
+      was included to LZMA SDK.
+      
+
+  4.43           2006-06-04
+  -------------------------
+    - Small changes for more compatibility with some C/C++ compilers.
+      
+
+  4.42           2006-05-15
+  -------------------------
+    - Small changes in .h files in ANSI-C version.
+      
+
+  4.39 beta      2006-04-14
+  -------------------------
+    - Bug in versions 4.33b:4.38b was fixed:
+      C++ version of LZMA encoder could not correctly compress 
+      files larger than 2 GB with HC4 match finder (-mfhc4).
+      
+
+  4.37 beta      2005-04-06
+  -------------------------
+    - Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined. 
+
+  
+  4.35 beta      2005-03-02
+  -------------------------
+    - Bug was fixed in C++ version of LZMA Decoder:
+       If encoded stream was corrupted, decoder could access memory 
+       outside of allocated range.
+
+  
+  4.34 beta      2006-02-27
+  -------------------------
+    - Compressing speed and memory requirements for compressing were increased
+    - LZMA now can use only these match finders: HC4, BT2, BT3, BT4
+
+  
+  4.32           2005-12-09
+  -------------------------
+    - Java version of LZMA SDK was included
+
+
+  4.30           2005-11-20
+  -------------------------
+    - Compression ratio was improved in -a2 mode
+    - Speed optimizations for compressing in -a2 mode
+    - -fb switch now supports values up to 273
+    - Bug in 7z_C (7zIn.c) was fixed:
+      It used Alloc/Free functions from different memory pools.
+      So if program used two memory pools, it worked incorrectly.
+    - 7z_C: .7z format supporting was improved
+    - LZMA# SDK (C#.NET version) was included
+
+
+  4.27 (Updated) 2005-09-21
+  -------------------------
+   - Some GUIDs/interfaces in C++ were changed.
+     IStream.h:
+       ISequentialInStream::Read now works as old ReadPart
+       ISequentialOutStream::Write now works as old WritePart
+
+  
+  4.27           2005-08-07
+  -------------------------
+    - Bug in LzmaDecodeSize.c was fixed:
+       if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
+       decompressing worked incorrectly.
+
+
+  4.26           2005-08-05
+  -------------------------
+    - Fixes in 7z_C code and LzmaTest.c:
+      previous versions could work incorrectly,
+      if malloc(0) returns 0
+
+
+  4.23           2005-06-29
+  -------------------------
+    - Small fixes in C++ code
+
+
+  4.22           2005-06-10
+  -------------------------
+    - Small fixes
+
+
+  4.21           2005-06-08
+  -------------------------
+    - Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
+    - New additional version of ANSI-C LZMA Decoder with zlib-like interface:
+        - LzmaStateDecode.h
+        - LzmaStateDecode.c
+        - LzmaStateTest.c
+    - ANSI-C LZMA Decoder now can decompress files larger than 4 GB
+
+  
+  4.17           2005-04-18
+  -------------------------
+    - New example for RAM->RAM compressing/decompressing: 
+      LZMA + BCJ (filter for x86 code):
+        - LzmaRam.h
+        - LzmaRam.cpp
+        - LzmaRamDecode.h
+        - LzmaRamDecode.c
+        - -f86 switch for lzma.exe
+
+  
+  4.16           2005-03-29
+  -------------------------
+    - Bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder): 
+       If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
+       decoder could access memory outside of allocated range.
+    - Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
+      Old version of LZMA Decoder now is in file LzmaDecodeSize.c. 
+      LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
+    - Small speed optimization in LZMA C++ code
+    - filter for SPARC's code was added
+    - Simplified version of .7z ANSI-C Decoder was included
+
+
+  4.06           2004-09-05
+  -------------------------
+    - Bug in v4.05 was fixed:
+        LZMA-Encoder didn't release output stream in some cases.
+
+
+  4.05           2004-08-25
+  -------------------------
+    - Source code of filters for x86, IA-64, ARM, ARM-Thumb 
+      and PowerPC code was included to SDK
+    - Some internal minor changes
+
+
+  4.04           2004-07-28
+  -------------------------
+    - More compatibility with some C++ compilers
+
+
+  4.03           2004-06-18
+  -------------------------
+    - "Benchmark" command was added. It measures compressing 
+      and decompressing speed and shows rating values. 
+      Also it checks hardware errors.
+
+
+  4.02           2004-06-10
+  -------------------------
+    - C++ LZMA Encoder/Decoder code now is more portable
+      and it can be compiled by GCC on Linux.
+
+
+  4.01           2004-02-15
+  -------------------------
+    - Some detection of data corruption was enabled.
+        LzmaDecode.c / RangeDecoderReadByte
+        .....
+        {
+          rd->ExtraBytes = 1;
+          return 0xFF;
+        }
+
+
+  4.00           2004-02-13
+  -------------------------
+    - Original version of LZMA SDK
+
+
+
+HISTORY of the LZMA
+-------------------
+  2001-2007:  Improvements to LZMA compressing/decompressing code, 
+              keeping compatibility with original LZMA format
+  1996-2001:  Development of LZMA compression format
+
+  Some milestones:
+
+  2001-08-30: LZMA compression was added to 7-Zip
+  1999-01-02: First version of 7-Zip was released
+  
+
+End of document
diff --git a/lzma/lzma.exe b/lzma/lzma.exe
new file mode 100755 (executable)
index 0000000..7239470
Binary files /dev/null and b/lzma/lzma.exe differ
diff --git a/lzma/lzma.txt b/lzma/lzma.txt
new file mode 100644 (file)
index 0000000..8169553
--- /dev/null
@@ -0,0 +1,663 @@
+LZMA SDK 4.57
+-------------
+
+LZMA SDK   Copyright (C) 1999-2007 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.
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+  - C++ source code of LZMA compressing and decompressing
+  - ANSI-C compatible source code for LZMA decompressing
+  - C# source code for LZMA compressing and decompressing
+  - Java source code for LZMA compressing and decompressing
+  - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+ANSI-C LZMA decompression code was ported from original C++ sources to C.
+Also it was simplified and optimized for code size. 
+But it is fully compatible with LZMA from 7-Zip.
+
+
+UNIX/Linux version 
+------------------
+To compile C++ version of file->file LZMA, go to directory
+C/7zip/Compress/LZMA_Alone 
+and type "make" or "make clean all" to recompile all.
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, change string in makefile
+LIB = -lm
+to string  
+LIB = -lm -static
+
+
+Files
+---------------------
+C        - C source code
+CPP      - CPP source code
+CS       - C# source code
+Java     - Java source code
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt  - 7z ANSI-C Decoder description (this file)
+methods.txt  - Compression method IDs for .7z
+LGPL.txt - GNU Lesser General Public License
+CPL.html - Common Public License
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C  - C files
+    Compress - files related to compression/decompression
+      Lz     - files related to LZ (Lempel-Ziv) compression algorithm
+      Lzma   - ANSI-C compatible LZMA decompressor
+
+        LzmaDecode.h  - interface for LZMA decoding on ANSI-C
+        LzmaDecode.c      - LZMA decoding on ANSI-C (new fastest version)
+        LzmaDecodeSize.c  - LZMA decoding on ANSI-C (old size-optimized version)
+        LzmaTest.c        - test application that decodes LZMA encoded file
+        LzmaTypes.h       - basic types for LZMA Decoder
+        LzmaStateDecode.h - interface for LZMA decoding (State version)
+        LzmaStateDecode.c - LZMA decoding on ANSI-C (State version)
+        LzmaStateTest.c   - test application (State version)
+
+      Branch       - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+
+    Archive - files related to archiving
+      7z_C     - 7z ANSI-C Decoder
+
+
+CPP -- CPP files
+
+  Common  - common files for C++ projects
+  Windows - common files for Windows related code
+  7zip    - files related to 7-Zip Project
+
+    Common   - common files for 7-Zip
+
+    Compress - files related to compression/decompression
+
+      LZ     - files related to LZ (Lempel-Ziv) compression algorithm
+
+      Copy         - Copy coder
+      RangeCoder   - Range Coder (special code of compression/decompression)
+      LZMA         - LZMA compression/decompression on C++
+      LZMA_Alone   - file->file LZMA compression/decompression
+
+      Branch       - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+
+    Archive - files related to archiving
+
+      Common   - common files for archive handling
+      7z       - 7z C++ Encoder/Decoder
+
+    Bundles    - Modules that are bundles of other modules
+  
+      Alone7z           - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
+      Format7zR         - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+      Format7zExtractR  - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+
+    UI        - User Interface files
+         
+      Client7z - Test application for 7za.dll,  7zr.dll, 7zxr.dll
+      Common   - Common UI files
+      Console  - Code for console archiver
+
+
+
+CS - C# files
+  7zip
+    Common   - some common files for 7-Zip
+    Compress - files related to compression/decompression
+      LZ     - files related to LZ (Lempel-Ziv) compression algorithm
+      LZMA         - LZMA compression/decompression
+      LzmaAlone    - file->file LZMA compression/decompression
+      RangeCoder   - Range Coder (special code of compression/decompression)
+
+Java  - Java files
+  SevenZip
+    Compression    - files related to compression/decompression
+      LZ           - files related to LZ (Lempel-Ziv) compression algorithm
+      LZMA         - LZMA compression/decompression
+      RangeCoder   - Range Coder (special code of compression/decompression)
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+
+You can find ANSI-C LZMA decompressing code at folder 
+  C/7zip/Compress/Lzma
+7-Zip doesn't use that ANSI-C LZMA code and that code was developed 
+specially for this SDK. And files from C/7zip/Compress/Lzma do not need 
+files from other directories of SDK for compiling.
+
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+  http://sourceforge.net/projects/sevenzip/
+
+
+LZMA features
+-------------
+  - Variable dictionary size (up to 1 GB)
+  - Estimated compressing speed: about 1 MB/s on 1 GHz CPU
+  - Estimated decompressing speed: 
+      - 8-12 MB/s on 1 GHz Intel Pentium 3 or AMD Athlon
+      - 500-1000 KB/s on 100 MHz ARM, MIPS, PowerPC or other simple RISC
+  - Small memory requirements for decompressing (8-32 KB + DictionarySize)
+  - Small code size for decompressing: 2-8 KB (depending from 
+    speed optimizations) 
+
+LZMA decoder uses only integer operations and can be 
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect to speed of LZMA decompression:
+  1) 32*16 bit integer multiply
+  2) Misspredicted branches (penalty mostly depends from pipeline length)
+  3) 32-bit shift and arithmetic operations
+
+Speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache, 
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage:  LZMA <e|d> inputFile outputFile [<switches>...]
+
+  e: encode file
+
+  d: decode file
+
+  b: Benchmark. There are two tests: compressing and decompressing 
+     with LZMA method. Benchmark shows rating in MIPS (million 
+     instructions per second). Rating value is calculated from 
+     measured speed and it is normalized with AMD Athlon 64 X2 CPU
+     results. Also Benchmark checks possible hardware errors (RAM 
+     errors in most cases). Benchmark uses these settings:
+     (-a1, -d21, -fb32, -mfbt4). You can change only -d. Also you 
+     can change number of iterations. Example for 30 iterations:
+       LZMA b 30
+     Default number of iterations is 10.
+
+<Switches>
+  
+
+  -a{N}:  set compression mode 0 = fast, 1 = normal
+          default: 1 (normal)
+
+  d{N}:   Sets Dictionary size - [0, 30], default: 23 (8MB)
+          The maximum value for dictionary size is 1 GB = 2^30 bytes.
+          Dictionary size is calculated as DictionarySize = 2^N bytes. 
+          For decompressing file compressed by LZMA method with dictionary 
+          size D = 2^N you need about D bytes of memory (RAM).
+
+  -fb{N}: set number of fast bytes - [5, 273], default: 128
+          Usually big number gives a little bit better compression ratio 
+          and slower compression process.
+
+  -lc{N}: set number of literal context bits - [0, 8], default: 3
+          Sometimes lc=4 gives gain for big files.
+
+  -lp{N}: set number of literal pos bits - [0, 4], default: 0
+          lp switch is intended for periodical data when period is 
+          equal 2^N. For example, for 32-bit (4 bytes) 
+          periodical data you can use lp=2. Often it's better to set lc0, 
+          if you change lp switch.
+
+  -pb{N}: set number of pos bits - [0, 4], default: 2
+          pb switch is intended for periodical data 
+          when period is equal 2^N.
+
+  -mf{MF_ID}: set Match Finder. Default: bt4. 
+              Algorithms from hc* group doesn't provide good compression 
+              ratio, but they often works pretty fast in combination with 
+              fast mode (-a0).
+
+              Memory requirements depend from dictionary size 
+              (parameter "d" in table below). 
+
+               MF_ID     Memory                   Description
+
+                bt2    d *  9.5 + 4MB  Binary Tree with 2 bytes hashing.
+                bt3    d * 11.5 + 4MB  Binary Tree with 3 bytes hashing.
+                bt4    d * 11.5 + 4MB  Binary Tree with 4 bytes hashing.
+                hc4    d *  7.5 + 4MB  Hash Chain with 4 bytes hashing.
+
+  -eos:   write End Of Stream marker. By default LZMA doesn't write 
+          eos marker, since LZMA decoder knows uncompressed size 
+          stored in .lzma file header.
+
+  -si:    Read data from stdin (it will write End Of Stream marker).
+  -so:    Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0 
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)  
+and 0 literal context bits. -lc0 allows to reduce memory requirements 
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable 
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase compression ratio for LZMA compressing it's desirable 
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is 
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Using Filters
+-------------
+You can increase compression ratio for some data types, using
+special filters before compressing. For example, it's possible to 
+increase compression ratio on 5-10% for code for those CPU ISAs: 
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C/C++ source code of such filters in folder "7zip/Compress/Branch"
+
+You can check compression ratio gain of these filters with such 
+7-Zip commands (example for ARM code):
+No filter:
+  7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+  7z a a2.7z a.bin -m0=bc_arm -m1=lzma        
+
+With filter for big-endian ARM code (using additional Swap4 filter):
+  7z a a3.7z a.bin -m0=swap4 -m1=bc_arm -m2=lzma
+
+It works in such manner:
+Compressing    = Filter_encoding + LZMA_encoding
+Decompressing  = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding, 
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions 
+from relative offsets to absolute addresses, so such data becomes more 
+compressible. Source code of these CALL filters is pretty simple
+(about 20 lines of C++), so you can convert it from C++ version yourself.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+  0     1   Special LZMA properties for compressed data
+  1     4   Dictionary size (little endian)
+  5     8   Uncompressed size (little endian). -1 means unknown size
+ 13         Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+To compile ANSI-C LZMA Decoder you can use one of the following files sets:
+1) LzmaDecode.h + LzmaDecode.c + LzmaTest.c  (fastest version)
+2) LzmaDecode.h + LzmaDecodeSize.c + LzmaTest.c  (old size-optimized version)
+3) LzmaStateDecode.h + LzmaStateDecode.c + LzmaStateTest.c  (zlib-like interface)
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+LZMA decoder doesn't allocate memory itself, so you must 
+allocate memory and send it to LZMA.
+
+Stack usage of LZMA decoding function for local variables is not 
+larger than 200 bytes.
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 5 interfaces:
+1) Single-call Decompressing
+2) Single-call Decompressing with input stream callback
+3) Multi-call Decompressing with output buffer
+4) Multi-call Decompressing with input callback and output buffer
+5) Multi-call State Decompressing (zlib-like interface)
+
+Variant-5 is similar to Variant-4, but Variant-5 doesn't use callback functions.
+
+Decompressing steps
+-------------------
+
+1) read LZMA properties (5 bytes):
+   unsigned char properties[LZMA_PROPERTIES_SIZE];
+
+2) read uncompressed size (8 bytes, little-endian)
+
+3) Decode properties:
+
+  CLzmaDecoderState state;  /* it's 24-140 bytes structure, if int is 32-bit */
+
+  if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+    return PrintError(rs, "Incorrect stream properties");
+
+4) Allocate memory block for internal Structures:
+
+  state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+  if (state.Probs == 0)
+    return PrintError(rs, kCantAllocateMessage);
+
+  LZMA decoder uses array of CProb variables as internal structure.
+  By default, CProb is unsigned_short. But you can define _LZMA_PROB32 to make 
+  it unsigned_int. It can increase speed on some 32-bit CPUs, but memory 
+  usage will be doubled in that case.
+
+
+5) Main Decompressing
+
+You must use one of the following interfaces:
+
+5.1 Single-call Decompressing
+-----------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: no defines
+Memory Requirements:
+  - Input buffer: compressed size
+  - Output buffer: uncompressed size
+  - LZMA Internal Structures (~16 KB for default settings) 
+
+Interface:
+  int res = LzmaDecode(&state, 
+      inStream, compressedSize, &inProcessed,
+      outStream, outSize, &outProcessed);
+
+
+5.2 Single-call Decompressing with input stream callback
+--------------------------------------------------------
+When to use: File->RAM or Flash->RAM decompressing.
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: _LZMA_IN_CB
+Memory Requirements:
+  - Buffer for input stream: any size (for example, 16 KB)
+  - Output buffer: uncompressed size
+  - LZMA Internal Structures (~16 KB for default settings) 
+
+Interface:
+  typedef struct _CBuffer
+  {
+    ILzmaInCallback InCallback;
+    FILE *File;
+    unsigned char Buffer[kInBufferSize];
+  } CBuffer;
+
+  int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size)
+  {
+    CBuffer *bo = (CBuffer *)object;
+    *buffer = bo->Buffer;
+    *size = MyReadFile(bo->File, bo->Buffer, kInBufferSize);
+    return LZMA_RESULT_OK;
+  }
+
+  CBuffer g_InBuffer;
+
+  g_InBuffer.File = inFile;
+  g_InBuffer.InCallback.Read = LzmaReadCompressed;
+  int res = LzmaDecode(&state, 
+      &g_InBuffer.InCallback,
+      outStream, outSize, &outProcessed);
+
+
+5.3 Multi-call decompressing with output buffer
+-----------------------------------------------
+When to use: RAM->File decompressing 
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: _LZMA_OUT_READ
+Memory Requirements:
+ - Input buffer: compressed size
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures (~16 KB for default settings) 
+ - LZMA dictionary (dictionary size is encoded in stream properties)
+Interface:
+
+  state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+
+  LzmaDecoderInit(&state);
+  do
+  {
+    LzmaDecode(&state,
+      inBuffer, inAvail, &inProcessed,
+      g_OutBuffer, outAvail, &outProcessed);
+    inAvail -= inProcessed;
+    inBuffer += inProcessed;
+  }
+  while you need more bytes
+
+  see LzmaTest.c for more details.
+
+
+5.4 Multi-call decompressing with input callback and output buffer
+------------------------------------------------------------------
+When to use: File->File decompressing 
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: _LZMA_IN_CB, _LZMA_OUT_READ
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures (~16 KB for default settings) 
+ - LZMA dictionary (dictionary size is encoded in stream properties)
+Interface:
+
+  state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+  LzmaDecoderInit(&state);
+  do
+  {
+    LzmaDecode(&state,
+      &bo.InCallback,
+      g_OutBuffer, outAvail, &outProcessed);
+  }
+  while you need more bytes
+
+  see LzmaTest.c for more details:
+
+
+5.5 Multi-call State Decompressing (zlib-like interface)
+------------------------------------------------------------------
+When to use: file->file decompressing 
+Compile files: LzmaStateDecode.h, LzmaStateDecode.c
+Compile defines:
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures (~16 KB for default settings) 
+ - LZMA dictionary (dictionary size is encoded in stream properties)
+Interface:
+
+  state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+
+  
+  LzmaDecoderInit(&state);
+  do
+  {
+    res = LzmaDecode(&state,
+      inBuffer, inAvail, &inProcessed,
+      g_OutBuffer, outAvail, &outProcessed,
+      finishDecoding);
+    inAvail -= inProcessed;
+    inBuffer += inProcessed;
+  }
+  while you need more bytes
+
+  see LzmaStateTest.c for more details:
+
+
+6) Free all allocated blocks
+
+
+Note
+----
+LzmaDecodeSize.c is size-optimized version of LzmaDecode.c.
+But compiled code of LzmaDecodeSize.c can be larger than 
+compiled code of LzmaDecode.c. So it's better to use 
+LzmaDecode.c in most cases.
+
+
+EXIT codes
+-----------
+
+LZMA decoder can return one of the following codes:
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+If you use callback function for input data and you return some 
+error code, LZMA Decoder also returns that code.
+
+
+
+LZMA Defines
+------------
+
+_LZMA_IN_CB    - Use callback for input data
+
+_LZMA_OUT_READ - Use read function for output data
+
+_LZMA_LOC_OPT  - Enable local speed optimizations inside code.
+                 _LZMA_LOC_OPT is only for LzmaDecodeSize.c (size-optimized version).
+                 _LZMA_LOC_OPT doesn't affect LzmaDecode.c (speed-optimized version)
+                 and LzmaStateDecode.c
+
+_LZMA_PROB32   - It can increase speed on some 32-bit CPUs, 
+                 but memory usage will be doubled in that case
+
+_LZMA_UINT32_IS_ULONG  - Define it if int is 16-bit on your compiler
+                         and long is 32-bit.
+
+_LZMA_SYSTEM_SIZE_T  - Define it if you want to use system's size_t.
+                       You can use it to enable 64-bit sizes supporting
+
+
+
+C++ LZMA Encoder/Decoder 
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it, 
+you can study basics of COM/OLE.
+
+By default, LZMA Encoder contains all Match Finders.
+But for compressing it's enough to have just one of them.
+So for reducing size of compressing code you can define:
+  #define COMPRESS_MF_BT
+  #define COMPRESS_MF_BT4
+and it will use only bt4 match finder.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/support.html
diff --git a/makeos2.cmd b/makeos2.cmd
new file mode 100644 (file)
index 0000000..b1fb4c0
--- /dev/null
@@ -0,0 +1,181 @@
+@echo off
+rem this is a simple batch file to build PhysicsFS on OS/2. You need to have
+rem  the Innotek libc and GCC (or "kLIBC") installed for this to work:
+rem
+rem     http://svn.netlabs.org/libc
+rem
+rem This script (and, indeed, our OS/2 support) could use some tweaking.
+rem  Patches go to icculus@icculus.org ...
+
+set PHYSFSLANG=PHYSFS_LANG_ENGLISH
+set DEBUGFLAGS=-D_NDEBUG -O2 -s
+rem set CFLAGS=%DEBUGFLAGS% -Wall -Werror -Zomf -Zmt -Zmtd -I. -Izlib123 -c -D__ST_MT_ERRNO__ -DOS2 -DZ_PREFIX -DPHYSFS_SUPPORTS_ZIP -DPHYSFS_SUPPORTS_7Z -DPHYSFS_SUPPORTS_GRP -DPHYSFS_SUPPORTS_WAD -DPHYSFS_SUPPORTS_QPAK -DPHYSFS_SUPPORTS_HOG -DPHYSFS_SUPPORTS_MVL -DPHYSFS_LANG=%PHYSFSLANG% -DHAVE_ASSERT_H
+set CFLAGS=%DEBUGFLAGS% -Wall -Werror -Zomf -I. -Iz -c -D__ST_MT_ERRNO__ -DOS2 -DZ_PREFIX -DPHYSFS_SUPPORTS_ZIP -DPHYSFS_SUPPORTS_7Z -DPHYSFS_SUPPORTS_GRP -DPHYSFS_SUPPORTS_WAD -DPHYSFS_SUPPORTS_QPAK -DPHYSFS_SUPPORTS_HOG -DPHYSFS_SUPPORTS_MVL -DHAVE_ASSERT_H
+
+rem goto :dolinking
+
+@echo cleaning up any previous build...
+@mkdir bin 2>NUL
+@erase /N bin\*.* 2>NUL
+
+@echo Building export definitions...
+@echo ;don't edit this directly! It is rewritten by makeos2.cmd! > bin\test_physfs.def
+@echo NAME TESTPHYSFS WINDOWCOMPAT >> bin\test_physfs.def
+@echo DESCRIPTION 'PhysicsFS: http://icculus.org/physfs/' >> bin\test_physfs.def
+@echo STACKSIZE 0x10000 >> bin\test_physfs.def
+@echo BASE=0x10000 >> bin\test_physfs.def
+@echo PROTMODE >> bin\test_physfs.def
+
+@echo ;don't edit this directly! It is rewritten by makeos2.cmd! > bin\physfs.def
+@echo LIBRARY 'physfs' INITINSTANCE TERMINSTANCE >> bin\physfs.def
+@echo STACKSIZE 0x10000 >> bin\physfs.def
+@echo CODE LOADONCALL >> bin\physfs.def
+@echo DATA LOADONCALL NONSHARED MULTIPLE >> bin\physfs.def
+@echo DESCRIPTION 'PhysicsFS: http://icculus.org/physfs/' >> bin\physfs.def
+@echo EXPORTS >> bin\physfs.def
+@echo "_PHYSFS_getLinkedVersion" >> bin\physfs.def
+@echo "_PHYSFS_init" >> bin\physfs.def
+@echo "_PHYSFS_deinit" >> bin\physfs.def
+@echo "_PHYSFS_isInit" >> bin\physfs.def
+@echo "_PHYSFS_supportedArchiveTypes" >> bin\physfs.def
+@echo "_PHYSFS_freeList" >> bin\physfs.def
+@echo "_PHYSFS_getLastError" >> bin\physfs.def
+@echo "_PHYSFS_getDirSeparator" >> bin\physfs.def
+@echo "_PHYSFS_permitSymbolicLinks" >> bin\physfs.def
+@echo "_PHYSFS_symbolicLinksPermitted" >> bin\physfs.def
+@echo "_PHYSFS_getCdRomDirs" >> bin\physfs.def
+@echo "_PHYSFS_getBaseDir" >> bin\physfs.def
+@echo "_PHYSFS_getUserDir" >> bin\physfs.def
+@echo "_PHYSFS_getWriteDir" >> bin\physfs.def
+@echo "_PHYSFS_setWriteDir" >> bin\physfs.def
+@echo "_PHYSFS_addToSearchPath" >> bin\physfs.def
+@echo "_PHYSFS_removeFromSearchPath" >> bin\physfs.def
+@echo "_PHYSFS_getSearchPath" >> bin\physfs.def
+@echo "_PHYSFS_setSaneConfig" >> bin\physfs.def
+@echo "_PHYSFS_mkdir" >> bin\physfs.def
+@echo "_PHYSFS_delete" >> bin\physfs.def
+@echo "_PHYSFS_getRealDir" >> bin\physfs.def
+@echo "_PHYSFS_enumerateFiles" >> bin\physfs.def
+@echo "_PHYSFS_exists" >> bin\physfs.def
+@echo "_PHYSFS_isDirectory" >> bin\physfs.def
+@echo "_PHYSFS_isSymbolicLink" >> bin\physfs.def
+@echo "_PHYSFS_openWrite" >> bin\physfs.def
+@echo "_PHYSFS_openAppend" >> bin\physfs.def
+@echo "_PHYSFS_openRead" >> bin\physfs.def
+@echo "_PHYSFS_close" >> bin\physfs.def
+@echo "_PHYSFS_read" >> bin\physfs.def
+@echo "_PHYSFS_write" >> bin\physfs.def
+@echo "_PHYSFS_eof" >> bin\physfs.def
+@echo "_PHYSFS_tell" >> bin\physfs.def
+@echo "_PHYSFS_seek" >> bin\physfs.def
+@echo "_PHYSFS_fileLength" >> bin\physfs.def
+@echo "_PHYSFS_swapSLE16" >> bin\physfs.def
+@echo "_PHYSFS_swapULE16" >> bin\physfs.def
+@echo "_PHYSFS_swapSLE32" >> bin\physfs.def
+@echo "_PHYSFS_swapULE32" >> bin\physfs.def
+@echo "_PHYSFS_swapSLE64" >> bin\physfs.def
+@echo "_PHYSFS_swapULE64" >> bin\physfs.def
+@echo "_PHYSFS_swapSBE16" >> bin\physfs.def
+@echo "_PHYSFS_swapUBE16" >> bin\physfs.def
+@echo "_PHYSFS_swapSBE32" >> bin\physfs.def
+@echo "_PHYSFS_swapUBE32" >> bin\physfs.def
+@echo "_PHYSFS_swapSBE64" >> bin\physfs.def
+@echo "_PHYSFS_swapUBE64" >> bin\physfs.def
+@echo "_PHYSFS_getLastModTime" >> bin\physfs.def
+@echo "_PHYSFS_readSLE16" >> bin\physfs.def
+@echo "_PHYSFS_readULE16" >> bin\physfs.def
+@echo "_PHYSFS_readSLE32" >> bin\physfs.def
+@echo "_PHYSFS_readULE32" >> bin\physfs.def
+@echo "_PHYSFS_readSLE64" >> bin\physfs.def
+@echo "_PHYSFS_readULE64" >> bin\physfs.def
+@echo "_PHYSFS_readSBE16" >> bin\physfs.def
+@echo "_PHYSFS_readUBE16" >> bin\physfs.def
+@echo "_PHYSFS_readSBE32" >> bin\physfs.def
+@echo "_PHYSFS_readUBE32" >> bin\physfs.def
+@echo "_PHYSFS_readSBE64" >> bin\physfs.def
+@echo "_PHYSFS_readUBE64" >> bin\physfs.def
+@echo "_PHYSFS_writeSLE16" >> bin\physfs.def
+@echo "_PHYSFS_writeULE16" >> bin\physfs.def
+@echo "_PHYSFS_writeSLE32" >> bin\physfs.def
+@echo "_PHYSFS_writeULE32" >> bin\physfs.def
+@echo "_PHYSFS_writeSLE64" >> bin\physfs.def
+@echo "_PHYSFS_writeULE64" >> bin\physfs.def
+@echo "_PHYSFS_writeSBE16" >> bin\physfs.def
+@echo "_PHYSFS_writeUBE16" >> bin\physfs.def
+@echo "_PHYSFS_writeSBE32" >> bin\physfs.def
+@echo "_PHYSFS_writeUBE32" >> bin\physfs.def
+@echo "_PHYSFS_writeSBE64" >> bin\physfs.def
+@echo "_PHYSFS_writeUBE64" >> bin\physfs.def
+@echo "_PHYSFS_setBuffer" >> bin\physfs.def
+@echo "_PHYSFS_flush" >> bin\physfs.def
+@echo "_PHYSFS_mount" >> bin\physfs.def
+@echo "_PHYSFS_getMountPoint" >> bin\physfs.def
+@echo "_PHYSFS_setAllocator" >> bin\physfs.def
+@echo "_PHYSFS_getCdRomDirsCallback" >> bin\physfs.def
+@echo "_PHYSFS_getSearchPathCallback" >> bin\physfs.def
+@echo "_PHYSFS_enumerateFilesCallback" >> bin\physfs.def
+@echo "_PHYSFS_utf8ToUcs2" >> bin\physfs.def
+@echo "_PHYSFS_utf8FromUcs2" >> bin\physfs.def
+@echo "_PHYSFS_utf8ToUcs4" >> bin\physfs.def
+@echo "_PHYSFS_utf8FromUcs4" >> bin\physfs.def
+@echo "_PHYSFS_utf8FromLatin1" >> bin\physfs.def
+
+@echo Building export library...
+emximp -o bin/physfs.lib bin/physfs.def
+emximp -o bin/physfs.a bin/physfs.def
+
+@echo Compiling PhysicsFS library...
+@echo on
+gcc %CFLAGS% -o bin/physfs.obj physfs.c
+gcc %CFLAGS% -o bin/physfs_byteorder.obj physfs_byteorder.c
+gcc %CFLAGS% -o bin/physfs_unicode.obj physfs_unicode.c
+gcc %CFLAGS% -o bin/os2.obj platform/os2.c
+gcc %CFLAGS% -o bin/dir.obj archivers/dir.c
+gcc %CFLAGS% -o bin/grp.obj archivers/grp.c
+gcc %CFLAGS% -o bin/wad.obj archivers/wad.c
+gcc %CFLAGS% -o bin/lzma.obj archivers/lzma.c
+gcc %CFLAGS% -o bin/zip.obj archivers/zip.c
+gcc %CFLAGS% -o bin/qpak.obj archivers/qpak.c
+gcc %CFLAGS% -o bin/hog.obj archivers/hog.c
+gcc %CFLAGS% -o bin/mvl.obj archivers/mvl.c
+gcc %CFLAGS% -o bin/adler32.obj zlib123/adler32.c
+gcc %CFLAGS% -o bin/compress.obj zlib123/compress.c
+gcc %CFLAGS% -o bin/crc32.obj zlib123/crc32.c
+gcc %CFLAGS% -o bin/deflate.obj zlib123/deflate.c
+gcc %CFLAGS% -o bin/gzio.obj zlib123/gzio.c
+gcc %CFLAGS% -o bin/infback.obj zlib123/infback.c
+gcc %CFLAGS% -o bin/inffast.obj zlib123/inffast.c
+gcc %CFLAGS% -o bin/inflate.obj zlib123/inflate.c
+gcc %CFLAGS% -o bin/inftrees.obj zlib123/inftrees.c
+gcc %CFLAGS% -o bin/trees.obj zlib123/trees.c
+gcc %CFLAGS% -o bin/uncompr.obj zlib123/uncompr.c
+gcc %CFLAGS% -o bin/zutil.obj zlib123/zutil.c
+gcc %CFLAGS% -o bin/7zBuffer.obj lzma/7zBuffer.c
+gcc %CFLAGS% -o bin/7zCrc.obj lzma/7zCrc.c
+gcc %CFLAGS% -o bin/7zDecode.obj lzma/7zDecode.c
+gcc %CFLAGS% -o bin/7zExtract.obj lzma/7zExtract.c
+gcc %CFLAGS% -o bin/7zHeader.obj lzma/7zHeader.c
+gcc %CFLAGS% -o bin/7zIn.obj lzma/7zIn.c
+gcc %CFLAGS% -o bin/7zItem.obj lzma/7zItem.c
+gcc %CFLAGS% -o bin/7zMethodID.obj lzma/7zMethodID.c
+gcc %CFLAGS% -o bin/LzmaDecode.obj lzma/LzmaDecode.c
+gcc %CFLAGS% -o bin/LzmaStateDecode.obj lzma/LzmaStateDecode.c
+@echo off
+
+:dolinking
+@echo Linking PhysicsFS library...
+gcc %DEBUGFLAGS% -Zdll -Zcrtdll -Zomf -o bin/physfs.dll bin/*.obj bin/physfs.def
+
+rem goto :builddone
+
+@echo Compiling test program...
+gcc %CFLAGS% -o bin/test_physfs.obj test/test_physfs.c
+@echo Linking test program...
+gcc %DEBUGFLAGS% -Zomf -Zcrtdll -o bin/test_physfs.exe bin/test_physfs.obj bin/physfs.lib bin/test_physfs.def
+
+:builddone
+
+@echo "All done!"
+
+rem end of makeos2.cmd ...
+
diff --git a/physfs.c b/physfs.c
new file mode 100644 (file)
index 0000000..a042603
--- /dev/null
+++ b/physfs.c
@@ -0,0 +1,2221 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+typedef struct __PHYSFS_DIRHANDLE__
+{
+    void *opaque;  /* Instance data unique to the archiver. */
+    char *dirName;  /* Path to archive in platform-dependent notation. */
+    char *mountPoint; /* Mountpoint in virtual file tree. */
+    const PHYSFS_Archiver *funcs;  /* Ptr to archiver info for this handle. */
+    struct __PHYSFS_DIRHANDLE__ *next;  /* linked list stuff. */
+} DirHandle;
+
+
+typedef struct __PHYSFS_FILEHANDLE__
+{
+    void *opaque;  /* Instance data unique to the archiver for this file. */
+    PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
+    const DirHandle *dirHandle;  /* Archiver instance that created this */
+    const PHYSFS_Archiver *funcs;  /* Ptr to archiver info for this handle. */
+    PHYSFS_uint8 *buffer;  /* Buffer, if set (NULL otherwise). Don't touch! */
+    PHYSFS_uint32 bufsize;  /* Bufsize, if set (0 otherwise). Don't touch! */
+    PHYSFS_uint32 buffill;  /* Buffer fill size. Don't touch! */
+    PHYSFS_uint32 bufpos;  /* Buffer position. Don't touch! */
+    struct __PHYSFS_FILEHANDLE__ *next;  /* linked list stuff. */
+} FileHandle;
+
+
+typedef struct __PHYSFS_ERRMSGTYPE__
+{
+    PHYSFS_uint64 tid;
+    int errorAvailable;
+    char errorString[80];
+    struct __PHYSFS_ERRMSGTYPE__ *next;
+} ErrMsg;
+
+
+/* The various i/o drivers...some of these may not be compiled in. */
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_ZIP;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_ZIP;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_LZMA;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_LZMA;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_GRP;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_GRP;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_QPAK;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_QPAK;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_HOG;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_HOG;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_MVL;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_MVL;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_WAD;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_WAD;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_DIR;
+
+
+static const PHYSFS_ArchiveInfo *supported_types[] =
+{
+#if (defined PHYSFS_SUPPORTS_ZIP)
+    &__PHYSFS_ArchiveInfo_ZIP,
+#endif
+#if (defined PHYSFS_SUPPORTS_7Z)
+    &__PHYSFS_ArchiveInfo_LZMA,
+#endif
+#if (defined PHYSFS_SUPPORTS_GRP)
+    &__PHYSFS_ArchiveInfo_GRP,
+#endif
+#if (defined PHYSFS_SUPPORTS_QPAK)
+    &__PHYSFS_ArchiveInfo_QPAK,
+#endif
+#if (defined PHYSFS_SUPPORTS_HOG)
+    &__PHYSFS_ArchiveInfo_HOG,
+#endif
+#if (defined PHYSFS_SUPPORTS_MVL)
+    &__PHYSFS_ArchiveInfo_MVL,
+#endif
+#if (defined PHYSFS_SUPPORTS_WAD)
+    &__PHYSFS_ArchiveInfo_WAD,
+#endif
+    NULL
+};
+
+static const PHYSFS_Archiver *archivers[] =
+{
+    &__PHYSFS_Archiver_DIR,
+#if (defined PHYSFS_SUPPORTS_ZIP)
+    &__PHYSFS_Archiver_ZIP,
+#endif
+#if (defined PHYSFS_SUPPORTS_7Z)
+    &__PHYSFS_Archiver_LZMA,
+#endif
+#if (defined PHYSFS_SUPPORTS_GRP)
+    &__PHYSFS_Archiver_GRP,
+#endif
+#if (defined PHYSFS_SUPPORTS_QPAK)
+    &__PHYSFS_Archiver_QPAK,
+#endif
+#if (defined PHYSFS_SUPPORTS_HOG)
+    &__PHYSFS_Archiver_HOG,
+#endif
+#if (defined PHYSFS_SUPPORTS_MVL)
+    &__PHYSFS_Archiver_MVL,
+#endif
+#if (defined PHYSFS_SUPPORTS_WAD)
+    &__PHYSFS_Archiver_WAD,
+#endif
+    NULL
+};
+
+
+
+/* General PhysicsFS state ... */
+static int initialized = 0;
+static ErrMsg *errorMessages = NULL;
+static DirHandle *searchPath = NULL;
+static DirHandle *writeDir = NULL;
+static FileHandle *openWriteList = NULL;
+static FileHandle *openReadList = NULL;
+static char *baseDir = NULL;
+static char *userDir = NULL;
+static int allowSymLinks = 0;
+
+/* mutexes ... */
+static void *errorLock = NULL;     /* protects error message list.        */
+static void *stateLock = NULL;     /* protects other PhysFS static state. */
+
+/* allocator ... */
+static int externalAllocator = 0;
+PHYSFS_Allocator allocator;
+
+
+/* functions ... */
+
+typedef struct
+{
+    char **list;
+    PHYSFS_uint32 size;
+    const char *errorstr;
+} EnumStringListCallbackData;
+
+static void enumStringListCallback(void *data, const char *str)
+{
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    if (pecd->errorstr)
+        return;
+
+    ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = (char *) allocator.Malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+    {
+        pecd->errorstr = ERR_OUT_OF_MEMORY;
+        pecd->list[pecd->size] = NULL;
+        PHYSFS_freeList(pecd->list);
+        return;
+    } /* if */
+
+    strcpy(newstr, str);
+    pecd->list[pecd->size] = newstr;
+    pecd->size++;
+} /* enumStringListCallback */
+
+
+static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
+{
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) allocator.Malloc(sizeof (char *));
+    BAIL_IF_MACRO(ecd.list == NULL, ERR_OUT_OF_MEMORY, NULL);
+    func(enumStringListCallback, &ecd);
+    BAIL_IF_MACRO(ecd.errorstr != NULL, ecd.errorstr, NULL);
+    ecd.list[ecd.size] = NULL;
+    return(ecd.list);
+} /* doEnumStringList */
+
+
+static void __PHYSFS_bubble_sort(void *a, PHYSFS_uint32 lo, PHYSFS_uint32 hi,
+                         int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
+                         void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32))
+{
+    PHYSFS_uint32 i;
+    int sorted;
+
+    do
+    {
+        sorted = 1;
+        for (i = lo; i < hi; i++)
+        {
+            if (cmpfn(a, i, i + 1) > 0)
+            {
+                swapfn(a, i, i + 1);
+                sorted = 0;
+            } /* if */
+        } /* for */
+    } while (!sorted);
+} /* __PHYSFS_bubble_sort */
+
+
+static void __PHYSFS_quick_sort(void *a, PHYSFS_uint32 lo, PHYSFS_uint32 hi,
+                         int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
+                         void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32))
+{
+    PHYSFS_uint32 i;
+    PHYSFS_uint32 j;
+    PHYSFS_uint32 v;
+
+    if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD)
+        __PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn);
+    else
+    {
+        i = (hi + lo) / 2;
+
+        if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i);
+        if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi);
+        if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi);
+
+        j = hi - 1;
+        swapfn(a, i, j);
+        i = lo;
+        v = j;
+        while (1)
+        {
+            while(cmpfn(a, ++i, v) < 0) { /* do nothing */ }
+            while(cmpfn(a, --j, v) > 0) { /* do nothing */ }
+            if (j < i)
+                break;
+            swapfn(a, i, j);
+        } /* while */
+        if (i != (hi-1))
+            swapfn(a, i, hi-1);
+        __PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn);
+        __PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn);
+    } /* else */
+} /* __PHYSFS_quick_sort */
+
+
+void __PHYSFS_sort(void *entries, 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 = __PHYSFS_platformGetUserDir();
+    if (retval != NULL)
+    {
+        /* make sure it really exists and is normalized. */
+        char *ptr = __PHYSFS_platformRealPath(retval);
+        allocator.Free(retval);
+        retval = ptr;
+    } /* if */
+
+    if (retval == NULL)
+    {
+        const char *dirsep = PHYSFS_getDirSeparator();
+        const char *uname = __PHYSFS_platformGetUserName();
+        const char *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) || (!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);
+    BAIL_IF_MACRO(objSize == 0, NULL, 0);
+    BAIL_IF_MACRO(objCount == 0, NULL, 0);
+    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);
+    BAIL_IF_MACRO(objSize == 0, NULL, 0);
+    BAIL_IF_MACRO(objCount == 0, NULL, 0);
+    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/physfs.h b/physfs.h
new file mode 100644 (file)
index 0000000..23a8ddd
--- /dev/null
+++ b/physfs.h
@@ -0,0 +1,2395 @@
+/**
+ * \file physfs.h
+ *
+ * Main header file for PhysicsFS.
+ */
+
+/**
+ * \mainpage PhysicsFS
+ *
+ * The latest version of PhysicsFS can be found at:
+ *     http://icculus.org/physfs/
+ *
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * This API gives you access to a system file system in ways superior to the
+ *  stdio or system i/o calls. The brief benefits:
+ *
+ *   - It's portable.
+ *   - It's safe. No file access is permitted outside the specified dirs.
+ *   - It's flexible. Archives (.ZIP files) can be used transparently as
+ *      directory structures.
+ *
+ * This system is largely inspired by Quake 3's PK3 files and the related
+ *  fs_* cvars. If you've ever tinkered with these, then this API will be
+ *  familiar to you.
+ *
+ * With PhysicsFS, you have a single writing directory and multiple
+ *  directories (the "search path") for reading. You can think of this as a
+ *  filesystem within a filesystem. If (on Windows) you were to set the
+ *  writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls
+ *  could touch anything above this directory, including the "C:\MyGame" and
+ *  "C:\" directories. This prevents an application's internal scripting
+ *  language from piddling over c:\\config.sys, for example. If you'd rather
+ *  give PHYSFS full access to the system's REAL file system, set the writing
+ *  dir to "C:\", but that's generally A Bad Thing for several reasons.
+ *
+ * Drive letters are hidden in PhysicsFS once you set up your initial paths.
+ *  The search path creates a single, hierarchical directory structure.
+ *  Not only does this lend itself well to general abstraction with archives,
+ *  it also gives better support to operating systems like MacOS and Unix.
+ *  Generally speaking, you shouldn't ever hardcode a drive letter; not only
+ *  does this hurt portability to non-Microsoft OSes, but it limits your win32
+ *  users to a single drive, too. Use the PhysicsFS abstraction functions and
+ *  allow user-defined configuration options, too. When opening a file, you
+ *  specify it like it was on a Unix filesystem: if you want to write to
+ *  "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to
+ *  "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an
+ *  abstraction across all platforms. Specifying a file in this way is termed
+ *  "platform-independent notation" in this documentation. Specifying a
+ *  a filename in a form such as "C:\mydir\myfile" or
+ *  "MacOS hard drive:My Directory:My File" is termed "platform-dependent
+ *  notation". The only time you use platform-dependent notation is when
+ *  setting up your write directory and search path; after that, all file
+ *  access into those directories are done with platform-independent notation.
+ *
+ * All files opened for writing are opened in relation to the write directory,
+ *  which is the root of the writable filesystem. When opening a file for
+ *  reading, PhysicsFS goes through the search path. This is NOT the
+ *  same thing as the PATH environment variable. An application using
+ *  PhysicsFS specifies directories to be searched which may be actual
+ *  directories, or archive files that contain files and subdirectories of
+ *  their own. See the end of these docs for currently supported archive
+ *  formats.
+ *
+ * Once the search path is defined, you may open files for reading. If you've
+ *  got the following search path defined (to use a win32 example again):
+ *
+ *  - C:\\mygame
+ *  - C:\\mygame\\myuserfiles
+ *  - D:\\mygamescdromdatafiles
+ *  - C:\\mygame\\installeddatafiles.zip
+ *
+ * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory
+ *  separator, lack of drive letter, and lack of dir separator at the start of
+ *  the string; this is platform-independent notation) will check for
+ *  C:\\mygame\\textfiles\\myfile.txt, then
+ *  C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then
+ *  D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for
+ *  textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip.
+ *  Remember that most archive types and platform filesystems store their
+ *  filenames in a case-sensitive manner, so you should be careful to specify
+ *  it correctly.
+ *
+ * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir
+ *  elements. Not only are these meaningless on MacOS Classic and/or Unix,
+ *  they are a security hole. Also, symbolic links (which can be found in
+ *  some archive types and directly in the filesystem on Unix platforms) are
+ *  NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to
+ *  your own discretion, as following a symlink can allow for access outside
+ *  the write dir and search paths. For portability, there is no mechanism for
+ *  creating new symlinks in PhysicsFS.
+ *
+ * The write dir is not included in the search path unless you specifically
+ *  add it. While you CAN change the write dir as many times as you like,
+ *  you should probably set it once and stick to it. Remember that your
+ *  program will not have permission to write in every directory on Unix and
+ *  NT systems.
+ *
+ * All files are opened in binary mode; there is no endline conversion for
+ *  textfiles. Other than that, PhysicsFS has some convenience functions for
+ *  platform-independence. There is a function to tell you the current
+ *  platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS),
+ *  which is needed only to set up your search/write paths. There is a
+ *  function to tell you what CD-ROM drives contain accessible discs, and a
+ *  function to recommend a good search path, etc.
+ *
+ * A recommended order for the search path is the write dir, then the base dir,
+ *  then the cdrom dir, then any archives discovered. Quake 3 does something
+ *  like this, but moves the archives to the start of the search path. Build
+ *  Engine games, like Duke Nukem 3D and Blood, place the archives last, and
+ *  use the base dir for both searching and writing. There is a helper
+ *  function (PHYSFS_setSaneConfig()) that puts together a basic configuration
+ *  for you, based on a few parameters. Also see the comments on
+ *  PHYSFS_getBaseDir(), and PHYSFS_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 PHYSFS_File
+{
+    void *opaque;  /**< That's all you get. Don't touch. */
+} PHYSFS_File;
+
+
+/**
+ * \def PHYSFS_file
+ * \brief 1.0 API compatibility define.
+ *
+ * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards
+ *  compatibility with the 1.0 API, which had an inconsistent capitalization
+ *  convention in this case. New code should use PHYSFS_File, as this #define
+ *  may go away someday.
+ *
+ * \sa PHYSFS_File
+ */
+#define PHYSFS_file PHYSFS_File
+
+
+/**
+ * \struct PHYSFS_ArchiveInfo
+ * \brief Information on various PhysicsFS-supported archives.
+ *
+ * This structure gives you details on what sort of archives are supported
+ *  by this implementation of PhysicsFS. Archives tend to be things like
+ *  ZIP files and such.
+ *
+ * \warning Not all binaries are created equal! PhysicsFS can be built with
+ *          or without support for various archives. You can check with
+ *          PHYSFS_supportedArchiveTypes() to see if your archive type is
+ *          supported.
+ *
+ * \sa PHYSFS_supportedArchiveTypes
+ */
+typedef struct PHYSFS_ArchiveInfo
+{
+    const char *extension;   /**< Archive file extension: "ZIP", for example. */
+    const char *description; /**< Human-readable archive description. */
+    const char *author;      /**< Person who did support for this archive. */
+    const char *url;         /**< URL related to this archive */
+} PHYSFS_ArchiveInfo;
+
+
+/**
+ * \struct PHYSFS_Version
+ * \brief Information the version of PhysicsFS in use.
+ *
+ * Represents the library's version as three levels: major revision
+ *  (increments with massive changes, additions, and enhancements),
+ *  minor revision (increments with backwards-compatible changes to the
+ *  major revision), and patchlevel (increments with fixes to the minor
+ *  revision).
+ *
+ * \sa PHYSFS_VERSION
+ * \sa PHYSFS_getLinkedVersion
+ */
+typedef struct PHYSFS_Version
+{
+    PHYSFS_uint8 major; /**< major revision */
+    PHYSFS_uint8 minor; /**< minor revision */
+    PHYSFS_uint8 patch; /**< patchlevel */
+} PHYSFS_Version;
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+#define PHYSFS_VER_MAJOR 2
+#define PHYSFS_VER_MINOR 0
+#define PHYSFS_VER_PATCH 2
+#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 default API states are restored at this
+ *  point, with the exception of any custom allocator you might have
+ *  specified, which survives between initializations.
+ *
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is
+ *          undefined, and probably badly screwed up.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_isInit
+ */
+__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 of bytes to write to (handle).
+ *   \param objSize size in bytes of objects being written to (handle).
+ *   \param objCount number of (objSize) objects to write to (handle).
+ *  \return number of objects written. PHYSFS_getLastError() can shed light on
+ *           the reason this might be < (objCount). -1 if complete failure.
+ */
+__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 PHYSFS_Allocator
+{
+    int (*Init)(void);   /**< Initialize. Can be NULL. Zero on failure. */
+    void (*Deinit)(void);  /**< Deinitialize your allocator. Can be NULL. */
+    void *(*Malloc)(PHYSFS_uint64);  /**< Allocate like malloc(). */
+    void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */
+    void (*Free)(void *); /**< Free memory from Malloc or Realloc. */
+} PHYSFS_Allocator;
+
+
+/**
+ * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator)
+ * \brief Hook your own allocation routines into PhysicsFS.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * By default, PhysicsFS will use whatever is reasonable for a platform
+ *  to manage dynamic memory (usually ANSI C malloc/realloc/calloc/free, but
+ *  some platforms might use something else), but in some uncommon cases, the
+ *  app might want more control over the library's memory management. This
+ *  lets you redirect PhysicsFS to use your own allocation routines instead.
+ *  You can only call this function before PHYSFS_init(); if the library is
+ *  initialized, it'll reject your efforts to change the allocator mid-stream.
+ *  You may call this function after PHYSFS_deinit() if you are willing to
+ *  shut down the library and restart it with a new allocator; this is a safe
+ *  and supported operation. The allocator remains intact between deinit/init
+ *  calls. If you want to return to the platform's default allocator, pass a
+ *  NULL in here.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ *  safely ignore it altogether.
+ *
+ *    \param allocator Structure containing your allocator's entry points.
+ *   \return zero on failure, non-zero on success. This call only fails
+ *           when used between PHYSFS_init() and PHYSFS_deinit() calls.
+ */
+__EXPORT__ int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
+
+
+/**
+ * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * If this is a duplicate, the entry is not added again, even though the
+ *  function succeeds. You may not add the same archive to two different
+ *  mountpoints: duplicate checking is done against the archive and not the
+ *  mountpoint.
+ *
+ * When you mount an archive, it is added to a virtual file system...all files
+ *  in all of the archives are interpolated into a single hierachical file
+ *  tree. Two archives mounted at the same place (or an archive with files
+ *  overlapping another mountpoint) may have overlapping files: in such a case,
+ *  the file earliest in the search path is selected, and the other files are
+ *  inaccessible to the application. This allows archives to be used to
+ *  override previous revisions; you can use the mounting mechanism to place
+ *  archives at a specific point in the file tree and prevent overlap; this
+ *  is useful for downloadable mods that might trample over application data
+ *  or each other, for example.
+ *
+ * The mountpoint does not need to exist prior to mounting, which is different
+ *  than those familiar with the Unix concept of "mounting" may not expect.
+ *  As well, more than one archive can be mounted to the same mountpoint, or
+ *  mountpoints and archive contents can overlap...the interpolation mechanism
+ *  still functions as usual.
+ *
+ *   \param newDir directory or archive to add to the path, in
+ *                   platform-dependent notation.
+ *   \param mountPoint Location in the interpolated tree that this archive
+ *                     will be "mounted", in platform-independent notation.
+ *                     NULL or "" is equivalent to "/".
+ *   \param appendToPath nonzero to append to search path, zero to prepend.
+ *  \return nonzero if added to path, zero on failure (bogus archive, dir
+ *                   missing, etc). Specifics of the error can be
+ *                   gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+__EXPORT__ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath);
+
+/**
+ * \fn int PHYSFS_getMountPoint(const char *dir)
+ * \brief Determine a mounted archive's mountpoint.
+ *
+ * You give this function the name of an archive or dir you successfully
+ *  added to the search path, and it reports the location in the interpolated
+ *  tree where it is mounted. Files mounted with a NULL mountpoint or through
+ *  PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY
+ *  and valid until the archive is removed from the search path.
+ *
+ *   \param dir directory or archive previously added to the path, in
+ *              platform-dependent notation. This must match the string
+ *              used when adding, even if your string would also reference
+ *              the same file with a different string of characters.
+ *  \return READ-ONLY string of mount point if added to path, NULL on failure
+ *          (bogus archive, etc) Specifics of the error can be gleaned from
+ *          PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+__EXPORT__ const char *PHYSFS_getMountPoint(const char *dir);
+
+
+/**
+ * \typedef PHYSFS_StringCallback
+ * \brief Function signature for callbacks that report strings.
+ *
+ * These are used to report a list of strings to an original caller, one
+ *  string per callback. All strings are UTF-8 encoded. Functions should not
+ *  try to modify or free the string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ *  functions that would return lists that need to be cleaned up with
+ *  PHYSFS_freeList(). The callback means that the library doesn't need to
+ *  allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ *  necessarily so in the callback versions. Check the documentation on
+ *  specific APIs, but strings may not be sorted as you expect.
+ *
+ *    \param data User-defined data pointer, passed through from the API
+ *                that eventually called the callback.
+ *    \param str The string data about which the callback is meant to inform.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ * \sa PHYSFS_getSearchPathCallback
+ */
+typedef void (*PHYSFS_StringCallback)(void *data, const char *str);
+
+
+/**
+ * \typedef PHYSFS_EnumFilesCallback
+ * \brief Function signature for callbacks that enumerate files.
+ *
+ * These are used to report a list of directory entries to an original caller,
+ *  one file/dir/symlink per callback. All strings are UTF-8 encoded.
+ *  Functions should not try to modify or free any string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ *  functions that would return lists that need to be cleaned up with
+ *  PHYSFS_freeList(). The callback means that the library doesn't need to
+ *  allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ *  necessarily so in the callback versions. Check the documentation on
+ *  specific APIs, but strings may not be sorted as you expect.
+ *
+ *    \param data User-defined data pointer, passed through from the API
+ *                that eventually called the callback.
+ *    \param origdir A string containing the full path, in platform-independent
+ *                   notation, of the directory containing this file. In most
+ *                   cases, this is the directory on which you requested
+ *                   enumeration, passed in the callback for your convenience.
+ *    \param fname The filename that is being enumerated. It may not be in
+ *                 alphabetical order compared to other callbacks that have
+ *                 fired, and it will not contain the full path. You can
+ *                 recreate the fullpath with $origdir/$fname ... The file
+ *                 can be a subdirectory, a file, a symlink, etc.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir,
+                                         const char *fname);
+
+
+/**
+ * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate CD-ROM directories, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getCdRomDirs(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  detected disc:
+ *
+ * \code
+ *
+ * static void foundDisc(void *data, const char *cddir)
+ * {
+ *     printf("cdrom dir [%s] is available.\n", cddir);
+ * }
+ *
+ * // ...
+ * PHYSFS_getCdRomDirsCallback(foundDisc, NULL);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ *    \param c Callback function to notify about detected drives.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getCdRomDirs
+ */
+__EXPORT__ void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate the search path, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getSearchPath() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getSearchPath(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  element of the search path:
+ *
+ * \code
+ *
+ * static void printSearchPath(void *data, const char *pathItem)
+ * {
+ *     printf("[%s] is in the search path.\n", pathItem);
+ * }
+ *
+ * // ...
+ * PHYSFS_getSearchPathCallback(printSearchPath, NULL);
+ * \endcode
+ *
+ * Elements of the search path are reported in order search priority, so the
+ *  first archive/dir that would be examined when looking for a file is the
+ *  first element passed through the callback.
+ *
+ *    \param c Callback function to notify about search path elements.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getSearchPath
+ */
+__EXPORT__ void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d)
+ * \brief Get a file listing of a search path's directory, using an application-defined callback.
+ *
+ * Internally, PHYSFS_enumerateFiles() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  element of the search path:
+ *
+ * \code
+ *
+ * static void printDir(void *data, const char *origdir, const char *fname)
+ * {
+ *     printf(" * We've got [%s] in [%s].\n", fname, origdir);
+ * }
+ *
+ * // ...
+ * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL);
+ * \endcode
+ *
+ * Items sent to the callback are not guaranteed to be in any order whatsoever.
+ *  There is no sorting done at this level, and if you need that, you should
+ *  probably use PHYSFS_enumerateFiles() instead, which guarantees
+ *  alphabetical sorting. This form reports whatever is discovered in each
+ *  archive before moving on to the next. Even within one archive, we can't
+ *  guarantee what order it will discover data. <em>Any sorting you find in
+ *  these callbacks is just pure luck. Do not rely on it.</em>
+ *
+ *    \param dir Directory, in platform-independent notation, to enumerate.
+ *    \param c Callback function to notify about search path elements.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_EnumFilesCallback
+ * \sa PHYSFS_enumerateFiles
+ */
+__EXPORT__ void PHYSFS_enumerateFilesCallback(const char *dir,
+                                              PHYSFS_EnumFilesCallback c,
+                                              void *d);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-4 string to a UTF-8 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is the same size as the source buffer. UTF-8
+ *  never uses more than 32-bits per character, so while it may shrink a UCS-4
+ *  string, it will never expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UCS-4 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__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. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UTF-8 format.
+ *   \param dst Buffer to store converted UCS-4 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__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. If the buffer length is 0, this function does nothing.
+ *
+ * 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. If the buffer length is 0, this function does nothing.
+ *
+ * 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. If the buffer length is 0, this function does nothing.
+ *
+ * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1
+ *  can't express most Unicode codepoints. It's a legacy encoding; you should
+ *  be converting away from it at all times.
+ *
+ *   \param src Null-terminated source string in Latin1 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__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/physfs_byteorder.c b/physfs_byteorder.c
new file mode 100644 (file)
index 0000000..ee3688b
--- /dev/null
@@ -0,0 +1,312 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#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/physfs_casefolding.h b/physfs_casefolding.h
new file mode 100644 (file)
index 0000000..0e50f1e
--- /dev/null
@@ -0,0 +1,2013 @@
+/*
+ * This file is part of PhysicsFS (http://icculus.org/physfs/)
+ *
+ * This data generated by physfs/extras/makecasefoldhashtable.pl ...
+ * Do not manually edit this file!
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ */
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+static const CaseFoldMapping case_fold_000[] = {
+    { 0x0202, 0x0203, 0x0000, 0x0000 },
+    { 0x0404, 0x0454, 0x0000, 0x0000 },
+    { 0x1E1E, 0x1E1F, 0x0000, 0x0000 },
+    { 0x2C2C, 0x2C5C, 0x0000, 0x0000 },
+    { 0x10404, 0x1042C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_001[] = {
+    { 0x0100, 0x0101, 0x0000, 0x0000 },
+    { 0x0405, 0x0455, 0x0000, 0x0000 },
+    { 0x0504, 0x0505, 0x0000, 0x0000 },
+    { 0x2C2D, 0x2C5D, 0x0000, 0x0000 },
+    { 0x10405, 0x1042D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_002[] = {
+    { 0x0200, 0x0201, 0x0000, 0x0000 },
+    { 0x0406, 0x0456, 0x0000, 0x0000 },
+    { 0x1E1C, 0x1E1D, 0x0000, 0x0000 },
+    { 0x1F1D, 0x1F15, 0x0000, 0x0000 },
+    { 0x2C2E, 0x2C5E, 0x0000, 0x0000 },
+    { 0x10406, 0x1042E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_003[] = {
+    { 0x0102, 0x0103, 0x0000, 0x0000 },
+    { 0x0407, 0x0457, 0x0000, 0x0000 },
+    { 0x0506, 0x0507, 0x0000, 0x0000 },
+    { 0x1F1C, 0x1F14, 0x0000, 0x0000 },
+    { 0x10407, 0x1042F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_004[] = {
+    { 0x0206, 0x0207, 0x0000, 0x0000 },
+    { 0x0400, 0x0450, 0x0000, 0x0000 },
+    { 0x1E1A, 0x1E1B, 0x0000, 0x0000 },
+    { 0x1F1B, 0x1F13, 0x0000, 0x0000 },
+    { 0x2C28, 0x2C58, 0x0000, 0x0000 },
+    { 0x10400, 0x10428, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_005[] = {
+    { 0x0104, 0x0105, 0x0000, 0x0000 },
+    { 0x0401, 0x0451, 0x0000, 0x0000 },
+    { 0x0500, 0x0501, 0x0000, 0x0000 },
+    { 0x1F1A, 0x1F12, 0x0000, 0x0000 },
+    { 0x2C29, 0x2C59, 0x0000, 0x0000 },
+    { 0x10401, 0x10429, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_006[] = {
+    { 0x0204, 0x0205, 0x0000, 0x0000 },
+    { 0x0402, 0x0452, 0x0000, 0x0000 },
+    { 0x1E18, 0x1E19, 0x0000, 0x0000 },
+    { 0x1F19, 0x1F11, 0x0000, 0x0000 },
+    { 0x2C2A, 0x2C5A, 0x0000, 0x0000 },
+    { 0x10402, 0x1042A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_007[] = {
+    { 0x0106, 0x0107, 0x0000, 0x0000 },
+    { 0x0403, 0x0453, 0x0000, 0x0000 },
+    { 0x0502, 0x0503, 0x0000, 0x0000 },
+    { 0x1F18, 0x1F10, 0x0000, 0x0000 },
+    { 0x2126, 0x03C9, 0x0000, 0x0000 },
+    { 0x2C2B, 0x2C5B, 0x0000, 0x0000 },
+    { 0x10403, 0x1042B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_008[] = {
+    { 0x020A, 0x020B, 0x0000, 0x0000 },
+    { 0x040C, 0x045C, 0x0000, 0x0000 },
+    { 0x1E16, 0x1E17, 0x0000, 0x0000 },
+    { 0x2C24, 0x2C54, 0x0000, 0x0000 },
+    { 0x1040C, 0x10434, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_009[] = {
+    { 0x0108, 0x0109, 0x0000, 0x0000 },
+    { 0x040D, 0x045D, 0x0000, 0x0000 },
+    { 0x050C, 0x050D, 0x0000, 0x0000 },
+    { 0x2C25, 0x2C55, 0x0000, 0x0000 },
+    { 0x1040D, 0x10435, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_010[] = {
+    { 0x0208, 0x0209, 0x0000, 0x0000 },
+    { 0x040E, 0x045E, 0x0000, 0x0000 },
+    { 0x1E14, 0x1E15, 0x0000, 0x0000 },
+    { 0x212B, 0x00E5, 0x0000, 0x0000 },
+    { 0x2C26, 0x2C56, 0x0000, 0x0000 },
+    { 0x1040E, 0x10436, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_011[] = {
+    { 0x010A, 0x010B, 0x0000, 0x0000 },
+    { 0x040F, 0x045F, 0x0000, 0x0000 },
+    { 0x050E, 0x050F, 0x0000, 0x0000 },
+    { 0x212A, 0x006B, 0x0000, 0x0000 },
+    { 0x2C27, 0x2C57, 0x0000, 0x0000 },
+    { 0x1040F, 0x10437, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_012[] = {
+    { 0x020E, 0x020F, 0x0000, 0x0000 },
+    { 0x0408, 0x0458, 0x0000, 0x0000 },
+    { 0x1E12, 0x1E13, 0x0000, 0x0000 },
+    { 0x2C20, 0x2C50, 0x0000, 0x0000 },
+    { 0x10408, 0x10430, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_013[] = {
+    { 0x010C, 0x010D, 0x0000, 0x0000 },
+    { 0x0409, 0x0459, 0x0000, 0x0000 },
+    { 0x0508, 0x0509, 0x0000, 0x0000 },
+    { 0x2C21, 0x2C51, 0x0000, 0x0000 },
+    { 0x10409, 0x10431, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_014[] = {
+    { 0x020C, 0x020D, 0x0000, 0x0000 },
+    { 0x040A, 0x045A, 0x0000, 0x0000 },
+    { 0x1E10, 0x1E11, 0x0000, 0x0000 },
+    { 0x2C22, 0x2C52, 0x0000, 0x0000 },
+    { 0x1040A, 0x10432, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_015[] = {
+    { 0x010E, 0x010F, 0x0000, 0x0000 },
+    { 0x040B, 0x045B, 0x0000, 0x0000 },
+    { 0x050A, 0x050B, 0x0000, 0x0000 },
+    { 0x2C23, 0x2C53, 0x0000, 0x0000 },
+    { 0x1040B, 0x10433, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_016[] = {
+    { 0x0212, 0x0213, 0x0000, 0x0000 },
+    { 0x0414, 0x0434, 0x0000, 0x0000 },
+    { 0x1E0E, 0x1E0F, 0x0000, 0x0000 },
+    { 0x1F0F, 0x1F07, 0x0000, 0x0000 },
+    { 0x10414, 0x1043C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_017[] = {
+    { 0x0110, 0x0111, 0x0000, 0x0000 },
+    { 0x0415, 0x0435, 0x0000, 0x0000 },
+    { 0x1F0E, 0x1F06, 0x0000, 0x0000 },
+    { 0x10415, 0x1043D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_018[] = {
+    { 0x0210, 0x0211, 0x0000, 0x0000 },
+    { 0x0416, 0x0436, 0x0000, 0x0000 },
+    { 0x1E0C, 0x1E0D, 0x0000, 0x0000 },
+    { 0x1F0D, 0x1F05, 0x0000, 0x0000 },
+    { 0x10416, 0x1043E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_019[] = {
+    { 0x0112, 0x0113, 0x0000, 0x0000 },
+    { 0x0417, 0x0437, 0x0000, 0x0000 },
+    { 0x1F0C, 0x1F04, 0x0000, 0x0000 },
+    { 0x10417, 0x1043F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_020[] = {
+    { 0x0216, 0x0217, 0x0000, 0x0000 },
+    { 0x0410, 0x0430, 0x0000, 0x0000 },
+    { 0x1E0A, 0x1E0B, 0x0000, 0x0000 },
+    { 0x1F0B, 0x1F03, 0x0000, 0x0000 },
+    { 0x10410, 0x10438, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_021[] = {
+    { 0x0114, 0x0115, 0x0000, 0x0000 },
+    { 0x0411, 0x0431, 0x0000, 0x0000 },
+    { 0x1F0A, 0x1F02, 0x0000, 0x0000 },
+    { 0x10411, 0x10439, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_022[] = {
+    { 0x0214, 0x0215, 0x0000, 0x0000 },
+    { 0x0412, 0x0432, 0x0000, 0x0000 },
+    { 0x1E08, 0x1E09, 0x0000, 0x0000 },
+    { 0x1F09, 0x1F01, 0x0000, 0x0000 },
+    { 0x10412, 0x1043A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_023[] = {
+    { 0x0116, 0x0117, 0x0000, 0x0000 },
+    { 0x0413, 0x0433, 0x0000, 0x0000 },
+    { 0x1F08, 0x1F00, 0x0000, 0x0000 },
+    { 0x10413, 0x1043B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_024[] = {
+    { 0x021A, 0x021B, 0x0000, 0x0000 },
+    { 0x041C, 0x043C, 0x0000, 0x0000 },
+    { 0x1E06, 0x1E07, 0x0000, 0x0000 },
+    { 0x1041C, 0x10444, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_025[] = {
+    { 0x0118, 0x0119, 0x0000, 0x0000 },
+    { 0x041D, 0x043D, 0x0000, 0x0000 },
+    { 0x1041D, 0x10445, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_026[] = {
+    { 0x0218, 0x0219, 0x0000, 0x0000 },
+    { 0x041E, 0x043E, 0x0000, 0x0000 },
+    { 0x1E04, 0x1E05, 0x0000, 0x0000 },
+    { 0x1041E, 0x10446, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_027[] = {
+    { 0x011A, 0x011B, 0x0000, 0x0000 },
+    { 0x041F, 0x043F, 0x0000, 0x0000 },
+    { 0x1041F, 0x10447, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_028[] = {
+    { 0x021E, 0x021F, 0x0000, 0x0000 },
+    { 0x0418, 0x0438, 0x0000, 0x0000 },
+    { 0x1E02, 0x1E03, 0x0000, 0x0000 },
+    { 0x10418, 0x10440, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_029[] = {
+    { 0x011C, 0x011D, 0x0000, 0x0000 },
+    { 0x0419, 0x0439, 0x0000, 0x0000 },
+    { 0x10419, 0x10441, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_030[] = {
+    { 0x021C, 0x021D, 0x0000, 0x0000 },
+    { 0x041A, 0x043A, 0x0000, 0x0000 },
+    { 0x1E00, 0x1E01, 0x0000, 0x0000 },
+    { 0x1041A, 0x10442, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_031[] = {
+    { 0x011E, 0x011F, 0x0000, 0x0000 },
+    { 0x041B, 0x043B, 0x0000, 0x0000 },
+    { 0x1041B, 0x10443, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_032[] = {
+    { 0x0222, 0x0223, 0x0000, 0x0000 },
+    { 0x0424, 0x0444, 0x0000, 0x0000 },
+    { 0x1E3E, 0x1E3F, 0x0000, 0x0000 },
+    { 0x1F3F, 0x1F37, 0x0000, 0x0000 },
+    { 0x2C0C, 0x2C3C, 0x0000, 0x0000 },
+    { 0x10424, 0x1044C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_033[] = {
+    { 0x0120, 0x0121, 0x0000, 0x0000 },
+    { 0x0425, 0x0445, 0x0000, 0x0000 },
+    { 0x1F3E, 0x1F36, 0x0000, 0x0000 },
+    { 0x2C0D, 0x2C3D, 0x0000, 0x0000 },
+    { 0x10425, 0x1044D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_034[] = {
+    { 0x0220, 0x019E, 0x0000, 0x0000 },
+    { 0x0426, 0x0446, 0x0000, 0x0000 },
+    { 0x1E3C, 0x1E3D, 0x0000, 0x0000 },
+    { 0x1F3D, 0x1F35, 0x0000, 0x0000 },
+    { 0x2C0E, 0x2C3E, 0x0000, 0x0000 },
+    { 0x10426, 0x1044E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_035[] = {
+    { 0x0122, 0x0123, 0x0000, 0x0000 },
+    { 0x0427, 0x0447, 0x0000, 0x0000 },
+    { 0x1F3C, 0x1F34, 0x0000, 0x0000 },
+    { 0x2C0F, 0x2C3F, 0x0000, 0x0000 },
+    { 0x10427, 0x1044F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_036[] = {
+    { 0x0226, 0x0227, 0x0000, 0x0000 },
+    { 0x0420, 0x0440, 0x0000, 0x0000 },
+    { 0x1E3A, 0x1E3B, 0x0000, 0x0000 },
+    { 0x1F3B, 0x1F33, 0x0000, 0x0000 },
+    { 0x2C08, 0x2C38, 0x0000, 0x0000 },
+    { 0x10420, 0x10448, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_037[] = {
+    { 0x0124, 0x0125, 0x0000, 0x0000 },
+    { 0x0421, 0x0441, 0x0000, 0x0000 },
+    { 0x1F3A, 0x1F32, 0x0000, 0x0000 },
+    { 0x2C09, 0x2C39, 0x0000, 0x0000 },
+    { 0x10421, 0x10449, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_038[] = {
+    { 0x0224, 0x0225, 0x0000, 0x0000 },
+    { 0x0422, 0x0442, 0x0000, 0x0000 },
+    { 0x1E38, 0x1E39, 0x0000, 0x0000 },
+    { 0x1F39, 0x1F31, 0x0000, 0x0000 },
+    { 0x2C0A, 0x2C3A, 0x0000, 0x0000 },
+    { 0x10422, 0x1044A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_039[] = {
+    { 0x0126, 0x0127, 0x0000, 0x0000 },
+    { 0x0423, 0x0443, 0x0000, 0x0000 },
+    { 0x1F38, 0x1F30, 0x0000, 0x0000 },
+    { 0x2C0B, 0x2C3B, 0x0000, 0x0000 },
+    { 0x10423, 0x1044B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_040[] = {
+    { 0x022A, 0x022B, 0x0000, 0x0000 },
+    { 0x042C, 0x044C, 0x0000, 0x0000 },
+    { 0x1E36, 0x1E37, 0x0000, 0x0000 },
+    { 0x2C04, 0x2C34, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_041[] = {
+    { 0x0128, 0x0129, 0x0000, 0x0000 },
+    { 0x042D, 0x044D, 0x0000, 0x0000 },
+    { 0x2C05, 0x2C35, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_042[] = {
+    { 0x0228, 0x0229, 0x0000, 0x0000 },
+    { 0x042E, 0x044E, 0x0000, 0x0000 },
+    { 0x1E34, 0x1E35, 0x0000, 0x0000 },
+    { 0x2C06, 0x2C36, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_043[] = {
+    { 0x012A, 0x012B, 0x0000, 0x0000 },
+    { 0x042F, 0x044F, 0x0000, 0x0000 },
+    { 0x2C07, 0x2C37, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_044[] = {
+    { 0x022E, 0x022F, 0x0000, 0x0000 },
+    { 0x0428, 0x0448, 0x0000, 0x0000 },
+    { 0x1E32, 0x1E33, 0x0000, 0x0000 },
+    { 0x2C00, 0x2C30, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_045[] = {
+    { 0x012C, 0x012D, 0x0000, 0x0000 },
+    { 0x0429, 0x0449, 0x0000, 0x0000 },
+    { 0x2C01, 0x2C31, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_046[] = {
+    { 0x022C, 0x022D, 0x0000, 0x0000 },
+    { 0x042A, 0x044A, 0x0000, 0x0000 },
+    { 0x1E30, 0x1E31, 0x0000, 0x0000 },
+    { 0x2C02, 0x2C32, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_047[] = {
+    { 0x012E, 0x012F, 0x0000, 0x0000 },
+    { 0x042B, 0x044B, 0x0000, 0x0000 },
+    { 0x2C03, 0x2C33, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_048[] = {
+    { 0x0232, 0x0233, 0x0000, 0x0000 },
+    { 0x0535, 0x0565, 0x0000, 0x0000 },
+    { 0x1E2E, 0x1E2F, 0x0000, 0x0000 },
+    { 0x1F2F, 0x1F27, 0x0000, 0x0000 },
+    { 0x2C1C, 0x2C4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_049[] = {
+    { 0x0130, 0x0069, 0x0307, 0x0000 },
+    { 0x0534, 0x0564, 0x0000, 0x0000 },
+    { 0x1F2E, 0x1F26, 0x0000, 0x0000 },
+    { 0x2C1D, 0x2C4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_050[] = {
+    { 0x0230, 0x0231, 0x0000, 0x0000 },
+    { 0x0537, 0x0567, 0x0000, 0x0000 },
+    { 0x1E2C, 0x1E2D, 0x0000, 0x0000 },
+    { 0x1F2D, 0x1F25, 0x0000, 0x0000 },
+    { 0x2C1E, 0x2C4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_051[] = {
+    { 0x0132, 0x0133, 0x0000, 0x0000 },
+    { 0x0536, 0x0566, 0x0000, 0x0000 },
+    { 0x1F2C, 0x1F24, 0x0000, 0x0000 },
+    { 0x2C1F, 0x2C4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_052[] = {
+    { 0x0531, 0x0561, 0x0000, 0x0000 },
+    { 0x1E2A, 0x1E2B, 0x0000, 0x0000 },
+    { 0x1F2B, 0x1F23, 0x0000, 0x0000 },
+    { 0x2C18, 0x2C48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_053[] = {
+    { 0x0134, 0x0135, 0x0000, 0x0000 },
+    { 0x1F2A, 0x1F22, 0x0000, 0x0000 },
+    { 0x2C19, 0x2C49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_054[] = {
+    { 0x0533, 0x0563, 0x0000, 0x0000 },
+    { 0x1E28, 0x1E29, 0x0000, 0x0000 },
+    { 0x1F29, 0x1F21, 0x0000, 0x0000 },
+    { 0x2C1A, 0x2C4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_055[] = {
+    { 0x0136, 0x0137, 0x0000, 0x0000 },
+    { 0x0532, 0x0562, 0x0000, 0x0000 },
+    { 0x1F28, 0x1F20, 0x0000, 0x0000 },
+    { 0x2C1B, 0x2C4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_056[] = {
+    { 0x0139, 0x013A, 0x0000, 0x0000 },
+    { 0x053D, 0x056D, 0x0000, 0x0000 },
+    { 0x1E26, 0x1E27, 0x0000, 0x0000 },
+    { 0x2C14, 0x2C44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_057[] = {
+    { 0x023B, 0x023C, 0x0000, 0x0000 },
+    { 0x053C, 0x056C, 0x0000, 0x0000 },
+    { 0x2C15, 0x2C45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_058[] = {
+    { 0x013B, 0x013C, 0x0000, 0x0000 },
+    { 0x053F, 0x056F, 0x0000, 0x0000 },
+    { 0x1E24, 0x1E25, 0x0000, 0x0000 },
+    { 0x2C16, 0x2C46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_059[] = {
+    { 0x053E, 0x056E, 0x0000, 0x0000 },
+    { 0x2C17, 0x2C47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_060[] = {
+    { 0x013D, 0x013E, 0x0000, 0x0000 },
+    { 0x0539, 0x0569, 0x0000, 0x0000 },
+    { 0x1E22, 0x1E23, 0x0000, 0x0000 },
+    { 0x2C10, 0x2C40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_061[] = {
+    { 0x0538, 0x0568, 0x0000, 0x0000 },
+    { 0x2C11, 0x2C41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_062[] = {
+    { 0x013F, 0x0140, 0x0000, 0x0000 },
+    { 0x053B, 0x056B, 0x0000, 0x0000 },
+    { 0x1E20, 0x1E21, 0x0000, 0x0000 },
+    { 0x2C12, 0x2C42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_063[] = {
+    { 0x023D, 0x019A, 0x0000, 0x0000 },
+    { 0x053A, 0x056A, 0x0000, 0x0000 },
+    { 0x2C13, 0x2C43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_064[] = {
+    { 0x0141, 0x0142, 0x0000, 0x0000 },
+    { 0x0545, 0x0575, 0x0000, 0x0000 },
+    { 0x1E5E, 0x1E5F, 0x0000, 0x0000 },
+    { 0x1F5F, 0x1F57, 0x0000, 0x0000 },
+    { 0x2161, 0x2171, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_065[] = {
+    { 0x0041, 0x0061, 0x0000, 0x0000 },
+    { 0x0544, 0x0574, 0x0000, 0x0000 },
+    { 0x2160, 0x2170, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_066[] = {
+    { 0x0042, 0x0062, 0x0000, 0x0000 },
+    { 0x0143, 0x0144, 0x0000, 0x0000 },
+    { 0x0547, 0x0577, 0x0000, 0x0000 },
+    { 0x1E5C, 0x1E5D, 0x0000, 0x0000 },
+    { 0x1F5D, 0x1F55, 0x0000, 0x0000 },
+    { 0x2163, 0x2173, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_067[] = {
+    { 0x0043, 0x0063, 0x0000, 0x0000 },
+    { 0x0241, 0x0294, 0x0000, 0x0000 },
+    { 0x0546, 0x0576, 0x0000, 0x0000 },
+    { 0x2162, 0x2172, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_068[] = {
+    { 0x0044, 0x0064, 0x0000, 0x0000 },
+    { 0x0145, 0x0146, 0x0000, 0x0000 },
+    { 0x0541, 0x0571, 0x0000, 0x0000 },
+    { 0x1E5A, 0x1E5B, 0x0000, 0x0000 },
+    { 0x1F5B, 0x1F53, 0x0000, 0x0000 },
+    { 0x2165, 0x2175, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_069[] = {
+    { 0x0045, 0x0065, 0x0000, 0x0000 },
+    { 0x0540, 0x0570, 0x0000, 0x0000 },
+    { 0x2164, 0x2174, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_070[] = {
+    { 0x0046, 0x0066, 0x0000, 0x0000 },
+    { 0x0147, 0x0148, 0x0000, 0x0000 },
+    { 0x0345, 0x03B9, 0x0000, 0x0000 },
+    { 0x0543, 0x0573, 0x0000, 0x0000 },
+    { 0x1E58, 0x1E59, 0x0000, 0x0000 },
+    { 0x1F59, 0x1F51, 0x0000, 0x0000 },
+    { 0x2167, 0x2177, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_071[] = {
+    { 0x0047, 0x0067, 0x0000, 0x0000 },
+    { 0x0542, 0x0572, 0x0000, 0x0000 },
+    { 0x2166, 0x2176, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_072[] = {
+    { 0x0048, 0x0068, 0x0000, 0x0000 },
+    { 0x0149, 0x02BC, 0x006E, 0x0000 },
+    { 0x054D, 0x057D, 0x0000, 0x0000 },
+    { 0x1E56, 0x1E57, 0x0000, 0x0000 },
+    { 0x2169, 0x2179, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_073[] = {
+    { 0x0049, 0x0069, 0x0000, 0x0000 },
+    { 0x054C, 0x057C, 0x0000, 0x0000 },
+    { 0x1F56, 0x03C5, 0x0313, 0x0342 },
+    { 0x2168, 0x2178, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_074[] = {
+    { 0x004A, 0x006A, 0x0000, 0x0000 },
+    { 0x054F, 0x057F, 0x0000, 0x0000 },
+    { 0x1E54, 0x1E55, 0x0000, 0x0000 },
+    { 0x216B, 0x217B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_075[] = {
+    { 0x004B, 0x006B, 0x0000, 0x0000 },
+    { 0x014A, 0x014B, 0x0000, 0x0000 },
+    { 0x054E, 0x057E, 0x0000, 0x0000 },
+    { 0x1F54, 0x03C5, 0x0313, 0x0301 },
+    { 0x216A, 0x217A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_076[] = {
+    { 0x004C, 0x006C, 0x0000, 0x0000 },
+    { 0x0549, 0x0579, 0x0000, 0x0000 },
+    { 0x1E52, 0x1E53, 0x0000, 0x0000 },
+    { 0x216D, 0x217D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_077[] = {
+    { 0x004D, 0x006D, 0x0000, 0x0000 },
+    { 0x014C, 0x014D, 0x0000, 0x0000 },
+    { 0x0548, 0x0578, 0x0000, 0x0000 },
+    { 0x1F52, 0x03C5, 0x0313, 0x0300 },
+    { 0x216C, 0x217C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_078[] = {
+    { 0x004E, 0x006E, 0x0000, 0x0000 },
+    { 0x054B, 0x057B, 0x0000, 0x0000 },
+    { 0x1E50, 0x1E51, 0x0000, 0x0000 },
+    { 0x216F, 0x217F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_079[] = {
+    { 0x004F, 0x006F, 0x0000, 0x0000 },
+    { 0x014E, 0x014F, 0x0000, 0x0000 },
+    { 0x054A, 0x057A, 0x0000, 0x0000 },
+    { 0x1F50, 0x03C5, 0x0313, 0x0000 },
+    { 0x216E, 0x217E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_080[] = {
+    { 0x0050, 0x0070, 0x0000, 0x0000 },
+    { 0x0555, 0x0585, 0x0000, 0x0000 },
+    { 0x1E4E, 0x1E4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_081[] = {
+    { 0x0051, 0x0071, 0x0000, 0x0000 },
+    { 0x0150, 0x0151, 0x0000, 0x0000 },
+    { 0x0554, 0x0584, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_082[] = {
+    { 0x0052, 0x0072, 0x0000, 0x0000 },
+    { 0x1E4C, 0x1E4D, 0x0000, 0x0000 },
+    { 0x1F4D, 0x1F45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_083[] = {
+    { 0x0053, 0x0073, 0x0000, 0x0000 },
+    { 0x0152, 0x0153, 0x0000, 0x0000 },
+    { 0x0556, 0x0586, 0x0000, 0x0000 },
+    { 0x1F4C, 0x1F44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_084[] = {
+    { 0x0054, 0x0074, 0x0000, 0x0000 },
+    { 0x0551, 0x0581, 0x0000, 0x0000 },
+    { 0x1E4A, 0x1E4B, 0x0000, 0x0000 },
+    { 0x1F4B, 0x1F43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_085[] = {
+    { 0x0055, 0x0075, 0x0000, 0x0000 },
+    { 0x0154, 0x0155, 0x0000, 0x0000 },
+    { 0x0550, 0x0580, 0x0000, 0x0000 },
+    { 0x1F4A, 0x1F42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_086[] = {
+    { 0x0056, 0x0076, 0x0000, 0x0000 },
+    { 0x0553, 0x0583, 0x0000, 0x0000 },
+    { 0x1E48, 0x1E49, 0x0000, 0x0000 },
+    { 0x1F49, 0x1F41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_087[] = {
+    { 0x0057, 0x0077, 0x0000, 0x0000 },
+    { 0x0156, 0x0157, 0x0000, 0x0000 },
+    { 0x0552, 0x0582, 0x0000, 0x0000 },
+    { 0x1F48, 0x1F40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_088[] = {
+    { 0x0058, 0x0078, 0x0000, 0x0000 },
+    { 0x1E46, 0x1E47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_089[] = {
+    { 0x0059, 0x0079, 0x0000, 0x0000 },
+    { 0x0158, 0x0159, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_090[] = {
+    { 0x005A, 0x007A, 0x0000, 0x0000 },
+    { 0x1E44, 0x1E45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_091[] = {
+    { 0x015A, 0x015B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_092[] = {
+    { 0x1E42, 0x1E43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_093[] = {
+    { 0x015C, 0x015D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_094[] = {
+    { 0x1E40, 0x1E41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_095[] = {
+    { 0x015E, 0x015F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_096[] = {
+    { 0x0464, 0x0465, 0x0000, 0x0000 },
+    { 0x1E7E, 0x1E7F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_097[] = {
+    { 0x0160, 0x0161, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_098[] = {
+    { 0x0466, 0x0467, 0x0000, 0x0000 },
+    { 0x1E7C, 0x1E7D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_099[] = {
+    { 0x0162, 0x0163, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_100[] = {
+    { 0x0460, 0x0461, 0x0000, 0x0000 },
+    { 0x1E7A, 0x1E7B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_101[] = {
+    { 0x0164, 0x0165, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_102[] = {
+    { 0x0462, 0x0463, 0x0000, 0x0000 },
+    { 0x1E78, 0x1E79, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_103[] = {
+    { 0x0166, 0x0167, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_104[] = {
+    { 0x046C, 0x046D, 0x0000, 0x0000 },
+    { 0x1E76, 0x1E77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_105[] = {
+    { 0x0168, 0x0169, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_106[] = {
+    { 0x046E, 0x046F, 0x0000, 0x0000 },
+    { 0x1E74, 0x1E75, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_107[] = {
+    { 0x016A, 0x016B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_108[] = {
+    { 0x0468, 0x0469, 0x0000, 0x0000 },
+    { 0x1E72, 0x1E73, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_109[] = {
+    { 0x016C, 0x016D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_110[] = {
+    { 0x046A, 0x046B, 0x0000, 0x0000 },
+    { 0x1E70, 0x1E71, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_111[] = {
+    { 0x016E, 0x016F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_112[] = {
+    { 0x0474, 0x0475, 0x0000, 0x0000 },
+    { 0x1E6E, 0x1E6F, 0x0000, 0x0000 },
+    { 0x1F6F, 0x1F67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_113[] = {
+    { 0x0170, 0x0171, 0x0000, 0x0000 },
+    { 0x1F6E, 0x1F66, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_114[] = {
+    { 0x0476, 0x0477, 0x0000, 0x0000 },
+    { 0x1E6C, 0x1E6D, 0x0000, 0x0000 },
+    { 0x1F6D, 0x1F65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_115[] = {
+    { 0x0172, 0x0173, 0x0000, 0x0000 },
+    { 0x1F6C, 0x1F64, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_116[] = {
+    { 0x0470, 0x0471, 0x0000, 0x0000 },
+    { 0x1E6A, 0x1E6B, 0x0000, 0x0000 },
+    { 0x1F6B, 0x1F63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_117[] = {
+    { 0x0174, 0x0175, 0x0000, 0x0000 },
+    { 0x1F6A, 0x1F62, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_118[] = {
+    { 0x0472, 0x0473, 0x0000, 0x0000 },
+    { 0x1E68, 0x1E69, 0x0000, 0x0000 },
+    { 0x1F69, 0x1F61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_119[] = {
+    { 0x0176, 0x0177, 0x0000, 0x0000 },
+    { 0x1F68, 0x1F60, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_120[] = {
+    { 0x0179, 0x017A, 0x0000, 0x0000 },
+    { 0x047C, 0x047D, 0x0000, 0x0000 },
+    { 0x1E66, 0x1E67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_121[] = {
+    { 0x0178, 0x00FF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_122[] = {
+    { 0x017B, 0x017C, 0x0000, 0x0000 },
+    { 0x047E, 0x047F, 0x0000, 0x0000 },
+    { 0x1E64, 0x1E65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_124[] = {
+    { 0x017D, 0x017E, 0x0000, 0x0000 },
+    { 0x0478, 0x0479, 0x0000, 0x0000 },
+    { 0x1E62, 0x1E63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_126[] = {
+    { 0x017F, 0x0073, 0x0000, 0x0000 },
+    { 0x047A, 0x047B, 0x0000, 0x0000 },
+    { 0x1E60, 0x1E61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_128[] = {
+    { 0x0181, 0x0253, 0x0000, 0x0000 },
+    { 0x1F9F, 0x1F27, 0x03B9, 0x0000 },
+    { 0x2CAC, 0x2CAD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_129[] = {
+    { 0x1F9E, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_130[] = {
+    { 0x0587, 0x0565, 0x0582, 0x0000 },
+    { 0x1F9D, 0x1F25, 0x03B9, 0x0000 },
+    { 0x2CAE, 0x2CAF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_131[] = {
+    { 0x0182, 0x0183, 0x0000, 0x0000 },
+    { 0x1F9C, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_132[] = {
+    { 0x0480, 0x0481, 0x0000, 0x0000 },
+    { 0x1E9A, 0x0061, 0x02BE, 0x0000 },
+    { 0x1F9B, 0x1F23, 0x03B9, 0x0000 },
+    { 0x2CA8, 0x2CA9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_133[] = {
+    { 0x0184, 0x0185, 0x0000, 0x0000 },
+    { 0x0386, 0x03AC, 0x0000, 0x0000 },
+    { 0x1E9B, 0x1E61, 0x0000, 0x0000 },
+    { 0x1F9A, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_134[] = {
+    { 0x0187, 0x0188, 0x0000, 0x0000 },
+    { 0x1E98, 0x0077, 0x030A, 0x0000 },
+    { 0x1F99, 0x1F21, 0x03B9, 0x0000 },
+    { 0x2CAA, 0x2CAB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_135[] = {
+    { 0x0186, 0x0254, 0x0000, 0x0000 },
+    { 0x1E99, 0x0079, 0x030A, 0x0000 },
+    { 0x1F98, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_136[] = {
+    { 0x0189, 0x0256, 0x0000, 0x0000 },
+    { 0x048C, 0x048D, 0x0000, 0x0000 },
+    { 0x1E96, 0x0068, 0x0331, 0x0000 },
+    { 0x1F97, 0x1F27, 0x03B9, 0x0000 },
+    { 0x2CA4, 0x2CA5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_137[] = {
+    { 0x038A, 0x03AF, 0x0000, 0x0000 },
+    { 0x1E97, 0x0074, 0x0308, 0x0000 },
+    { 0x1F96, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_138[] = {
+    { 0x018B, 0x018C, 0x0000, 0x0000 },
+    { 0x0389, 0x03AE, 0x0000, 0x0000 },
+    { 0x048E, 0x048F, 0x0000, 0x0000 },
+    { 0x1E94, 0x1E95, 0x0000, 0x0000 },
+    { 0x1F95, 0x1F25, 0x03B9, 0x0000 },
+    { 0x2CA6, 0x2CA7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_139[] = {
+    { 0x018A, 0x0257, 0x0000, 0x0000 },
+    { 0x0388, 0x03AD, 0x0000, 0x0000 },
+    { 0x1F94, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_140[] = {
+    { 0x038F, 0x03CE, 0x0000, 0x0000 },
+    { 0x1E92, 0x1E93, 0x0000, 0x0000 },
+    { 0x1F93, 0x1F23, 0x03B9, 0x0000 },
+    { 0x2CA0, 0x2CA1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_141[] = {
+    { 0x038E, 0x03CD, 0x0000, 0x0000 },
+    { 0x1F92, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_142[] = {
+    { 0x018F, 0x0259, 0x0000, 0x0000 },
+    { 0x048A, 0x048B, 0x0000, 0x0000 },
+    { 0x1E90, 0x1E91, 0x0000, 0x0000 },
+    { 0x1F91, 0x1F21, 0x03B9, 0x0000 },
+    { 0x2CA2, 0x2CA3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_143[] = {
+    { 0x018E, 0x01DD, 0x0000, 0x0000 },
+    { 0x038C, 0x03CC, 0x0000, 0x0000 },
+    { 0x1F90, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_144[] = {
+    { 0x0191, 0x0192, 0x0000, 0x0000 },
+    { 0x0393, 0x03B3, 0x0000, 0x0000 },
+    { 0x0494, 0x0495, 0x0000, 0x0000 },
+    { 0x1E8E, 0x1E8F, 0x0000, 0x0000 },
+    { 0x1F8F, 0x1F07, 0x03B9, 0x0000 },
+    { 0x2CBC, 0x2CBD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_145[] = {
+    { 0x0190, 0x025B, 0x0000, 0x0000 },
+    { 0x0392, 0x03B2, 0x0000, 0x0000 },
+    { 0x1F8E, 0x1F06, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_146[] = {
+    { 0x0193, 0x0260, 0x0000, 0x0000 },
+    { 0x0391, 0x03B1, 0x0000, 0x0000 },
+    { 0x0496, 0x0497, 0x0000, 0x0000 },
+    { 0x1E8C, 0x1E8D, 0x0000, 0x0000 },
+    { 0x1F8D, 0x1F05, 0x03B9, 0x0000 },
+    { 0x24B6, 0x24D0, 0x0000, 0x0000 },
+    { 0x2CBE, 0x2CBF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_147[] = {
+    { 0x0390, 0x03B9, 0x0308, 0x0301 },
+    { 0x1F8C, 0x1F04, 0x03B9, 0x0000 },
+    { 0x24B7, 0x24D1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_148[] = {
+    { 0x0397, 0x03B7, 0x0000, 0x0000 },
+    { 0x0490, 0x0491, 0x0000, 0x0000 },
+    { 0x1E8A, 0x1E8B, 0x0000, 0x0000 },
+    { 0x1F8B, 0x1F03, 0x03B9, 0x0000 },
+    { 0x2CB8, 0x2CB9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_149[] = {
+    { 0x0194, 0x0263, 0x0000, 0x0000 },
+    { 0x0396, 0x03B6, 0x0000, 0x0000 },
+    { 0x1F8A, 0x1F02, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_150[] = {
+    { 0x0197, 0x0268, 0x0000, 0x0000 },
+    { 0x0395, 0x03B5, 0x0000, 0x0000 },
+    { 0x0492, 0x0493, 0x0000, 0x0000 },
+    { 0x1E88, 0x1E89, 0x0000, 0x0000 },
+    { 0x1F89, 0x1F01, 0x03B9, 0x0000 },
+    { 0x2CBA, 0x2CBB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_151[] = {
+    { 0x0196, 0x0269, 0x0000, 0x0000 },
+    { 0x0394, 0x03B4, 0x0000, 0x0000 },
+    { 0x1F88, 0x1F00, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_152[] = {
+    { 0x039B, 0x03BB, 0x0000, 0x0000 },
+    { 0x049C, 0x049D, 0x0000, 0x0000 },
+    { 0x1E86, 0x1E87, 0x0000, 0x0000 },
+    { 0x1F87, 0x1F07, 0x03B9, 0x0000 },
+    { 0x24BC, 0x24D6, 0x0000, 0x0000 },
+    { 0x2CB4, 0x2CB5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_153[] = {
+    { 0x0198, 0x0199, 0x0000, 0x0000 },
+    { 0x039A, 0x03BA, 0x0000, 0x0000 },
+    { 0x1F86, 0x1F06, 0x03B9, 0x0000 },
+    { 0x24BD, 0x24D7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_154[] = {
+    { 0x0399, 0x03B9, 0x0000, 0x0000 },
+    { 0x049E, 0x049F, 0x0000, 0x0000 },
+    { 0x1E84, 0x1E85, 0x0000, 0x0000 },
+    { 0x1F85, 0x1F05, 0x03B9, 0x0000 },
+    { 0x24BE, 0x24D8, 0x0000, 0x0000 },
+    { 0x2CB6, 0x2CB7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_155[] = {
+    { 0x0398, 0x03B8, 0x0000, 0x0000 },
+    { 0x1F84, 0x1F04, 0x03B9, 0x0000 },
+    { 0x24BF, 0x24D9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_156[] = {
+    { 0x019D, 0x0272, 0x0000, 0x0000 },
+    { 0x039F, 0x03BF, 0x0000, 0x0000 },
+    { 0x0498, 0x0499, 0x0000, 0x0000 },
+    { 0x1E82, 0x1E83, 0x0000, 0x0000 },
+    { 0x1F83, 0x1F03, 0x03B9, 0x0000 },
+    { 0x24B8, 0x24D2, 0x0000, 0x0000 },
+    { 0x2CB0, 0x2CB1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_157[] = {
+    { 0x019C, 0x026F, 0x0000, 0x0000 },
+    { 0x039E, 0x03BE, 0x0000, 0x0000 },
+    { 0x1F82, 0x1F02, 0x03B9, 0x0000 },
+    { 0x24B9, 0x24D3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_158[] = {
+    { 0x019F, 0x0275, 0x0000, 0x0000 },
+    { 0x039D, 0x03BD, 0x0000, 0x0000 },
+    { 0x049A, 0x049B, 0x0000, 0x0000 },
+    { 0x1E80, 0x1E81, 0x0000, 0x0000 },
+    { 0x1F81, 0x1F01, 0x03B9, 0x0000 },
+    { 0x24BA, 0x24D4, 0x0000, 0x0000 },
+    { 0x2CB2, 0x2CB3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_159[] = {
+    { 0x039C, 0x03BC, 0x0000, 0x0000 },
+    { 0x1F80, 0x1F00, 0x03B9, 0x0000 },
+    { 0x24BB, 0x24D5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_160[] = {
+    { 0x03A3, 0x03C3, 0x0000, 0x0000 },
+    { 0x04A4, 0x04A5, 0x0000, 0x0000 },
+    { 0x10B0, 0x2D10, 0x0000, 0x0000 },
+    { 0x1EBE, 0x1EBF, 0x0000, 0x0000 },
+    { 0x2C8C, 0x2C8D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_161[] = {
+    { 0x01A0, 0x01A1, 0x0000, 0x0000 },
+    { 0x10B1, 0x2D11, 0x0000, 0x0000 },
+    { 0x1FBE, 0x03B9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_162[] = {
+    { 0x03A1, 0x03C1, 0x0000, 0x0000 },
+    { 0x04A6, 0x04A7, 0x0000, 0x0000 },
+    { 0x10B2, 0x2D12, 0x0000, 0x0000 },
+    { 0x1EBC, 0x1EBD, 0x0000, 0x0000 },
+    { 0x2C8E, 0x2C8F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_163[] = {
+    { 0x01A2, 0x01A3, 0x0000, 0x0000 },
+    { 0x03A0, 0x03C0, 0x0000, 0x0000 },
+    { 0x10B3, 0x2D13, 0x0000, 0x0000 },
+    { 0x1FBC, 0x03B1, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_164[] = {
+    { 0x03A7, 0x03C7, 0x0000, 0x0000 },
+    { 0x04A0, 0x04A1, 0x0000, 0x0000 },
+    { 0x10B4, 0x2D14, 0x0000, 0x0000 },
+    { 0x1EBA, 0x1EBB, 0x0000, 0x0000 },
+    { 0x1FBB, 0x1F71, 0x0000, 0x0000 },
+    { 0x2C88, 0x2C89, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_165[] = {
+    { 0x01A4, 0x01A5, 0x0000, 0x0000 },
+    { 0x03A6, 0x03C6, 0x0000, 0x0000 },
+    { 0x10B5, 0x2D15, 0x0000, 0x0000 },
+    { 0x1FBA, 0x1F70, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_166[] = {
+    { 0x01A7, 0x01A8, 0x0000, 0x0000 },
+    { 0x03A5, 0x03C5, 0x0000, 0x0000 },
+    { 0x04A2, 0x04A3, 0x0000, 0x0000 },
+    { 0x10B6, 0x2D16, 0x0000, 0x0000 },
+    { 0x1EB8, 0x1EB9, 0x0000, 0x0000 },
+    { 0x1FB9, 0x1FB1, 0x0000, 0x0000 },
+    { 0x2C8A, 0x2C8B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_167[] = {
+    { 0x01A6, 0x0280, 0x0000, 0x0000 },
+    { 0x03A4, 0x03C4, 0x0000, 0x0000 },
+    { 0x10B7, 0x2D17, 0x0000, 0x0000 },
+    { 0x1FB8, 0x1FB0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_168[] = {
+    { 0x01A9, 0x0283, 0x0000, 0x0000 },
+    { 0x03AB, 0x03CB, 0x0000, 0x0000 },
+    { 0x04AC, 0x04AD, 0x0000, 0x0000 },
+    { 0x10B8, 0x2D18, 0x0000, 0x0000 },
+    { 0x1EB6, 0x1EB7, 0x0000, 0x0000 },
+    { 0x1FB7, 0x03B1, 0x0342, 0x03B9 },
+    { 0x2C84, 0x2C85, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_169[] = {
+    { 0x03AA, 0x03CA, 0x0000, 0x0000 },
+    { 0x10B9, 0x2D19, 0x0000, 0x0000 },
+    { 0x1FB6, 0x03B1, 0x0342, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_170[] = {
+    { 0x03A9, 0x03C9, 0x0000, 0x0000 },
+    { 0x04AE, 0x04AF, 0x0000, 0x0000 },
+    { 0x10BA, 0x2D1A, 0x0000, 0x0000 },
+    { 0x1EB4, 0x1EB5, 0x0000, 0x0000 },
+    { 0x2C86, 0x2C87, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_171[] = {
+    { 0x03A8, 0x03C8, 0x0000, 0x0000 },
+    { 0x10BB, 0x2D1B, 0x0000, 0x0000 },
+    { 0x1FB4, 0x03AC, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_172[] = {
+    { 0x04A8, 0x04A9, 0x0000, 0x0000 },
+    { 0x10BC, 0x2D1C, 0x0000, 0x0000 },
+    { 0x1EB2, 0x1EB3, 0x0000, 0x0000 },
+    { 0x1FB3, 0x03B1, 0x03B9, 0x0000 },
+    { 0x2C80, 0x2C81, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_173[] = {
+    { 0x01AC, 0x01AD, 0x0000, 0x0000 },
+    { 0x10BD, 0x2D1D, 0x0000, 0x0000 },
+    { 0x1FB2, 0x1F70, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_174[] = {
+    { 0x01AF, 0x01B0, 0x0000, 0x0000 },
+    { 0x04AA, 0x04AB, 0x0000, 0x0000 },
+    { 0x10BE, 0x2D1E, 0x0000, 0x0000 },
+    { 0x1EB0, 0x1EB1, 0x0000, 0x0000 },
+    { 0x2C82, 0x2C83, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_175[] = {
+    { 0x01AE, 0x0288, 0x0000, 0x0000 },
+    { 0x10BF, 0x2D1F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_176[] = {
+    { 0x01B1, 0x028A, 0x0000, 0x0000 },
+    { 0x04B4, 0x04B5, 0x0000, 0x0000 },
+    { 0x10A0, 0x2D00, 0x0000, 0x0000 },
+    { 0x1EAE, 0x1EAF, 0x0000, 0x0000 },
+    { 0x1FAF, 0x1F67, 0x03B9, 0x0000 },
+    { 0x2C9C, 0x2C9D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_177[] = {
+    { 0x10A1, 0x2D01, 0x0000, 0x0000 },
+    { 0x1FAE, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_178[] = {
+    { 0x01B3, 0x01B4, 0x0000, 0x0000 },
+    { 0x04B6, 0x04B7, 0x0000, 0x0000 },
+    { 0x10A2, 0x2D02, 0x0000, 0x0000 },
+    { 0x1EAC, 0x1EAD, 0x0000, 0x0000 },
+    { 0x1FAD, 0x1F65, 0x03B9, 0x0000 },
+    { 0x2C9E, 0x2C9F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_179[] = {
+    { 0x01B2, 0x028B, 0x0000, 0x0000 },
+    { 0x03B0, 0x03C5, 0x0308, 0x0301 },
+    { 0x10A3, 0x2D03, 0x0000, 0x0000 },
+    { 0x1FAC, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_180[] = {
+    { 0x01B5, 0x01B6, 0x0000, 0x0000 },
+    { 0x04B0, 0x04B1, 0x0000, 0x0000 },
+    { 0x10A4, 0x2D04, 0x0000, 0x0000 },
+    { 0x1EAA, 0x1EAB, 0x0000, 0x0000 },
+    { 0x1FAB, 0x1F63, 0x03B9, 0x0000 },
+    { 0x2C98, 0x2C99, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_181[] = {
+    { 0x00B5, 0x03BC, 0x0000, 0x0000 },
+    { 0x10A5, 0x2D05, 0x0000, 0x0000 },
+    { 0x1FAA, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_182[] = {
+    { 0x01B7, 0x0292, 0x0000, 0x0000 },
+    { 0x04B2, 0x04B3, 0x0000, 0x0000 },
+    { 0x10A6, 0x2D06, 0x0000, 0x0000 },
+    { 0x1EA8, 0x1EA9, 0x0000, 0x0000 },
+    { 0x1FA9, 0x1F61, 0x03B9, 0x0000 },
+    { 0x2C9A, 0x2C9B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_183[] = {
+    { 0x10A7, 0x2D07, 0x0000, 0x0000 },
+    { 0x1FA8, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_184[] = {
+    { 0x04BC, 0x04BD, 0x0000, 0x0000 },
+    { 0x10A8, 0x2D08, 0x0000, 0x0000 },
+    { 0x1EA6, 0x1EA7, 0x0000, 0x0000 },
+    { 0x1FA7, 0x1F67, 0x03B9, 0x0000 },
+    { 0x2C94, 0x2C95, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_185[] = {
+    { 0x01B8, 0x01B9, 0x0000, 0x0000 },
+    { 0x10A9, 0x2D09, 0x0000, 0x0000 },
+    { 0x1FA6, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_186[] = {
+    { 0x04BE, 0x04BF, 0x0000, 0x0000 },
+    { 0x10AA, 0x2D0A, 0x0000, 0x0000 },
+    { 0x1EA4, 0x1EA5, 0x0000, 0x0000 },
+    { 0x1FA5, 0x1F65, 0x03B9, 0x0000 },
+    { 0x2C96, 0x2C97, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_187[] = {
+    { 0x10AB, 0x2D0B, 0x0000, 0x0000 },
+    { 0x1FA4, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_188[] = {
+    { 0x04B8, 0x04B9, 0x0000, 0x0000 },
+    { 0x10AC, 0x2D0C, 0x0000, 0x0000 },
+    { 0x1EA2, 0x1EA3, 0x0000, 0x0000 },
+    { 0x1FA3, 0x1F63, 0x03B9, 0x0000 },
+    { 0x2C90, 0x2C91, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_189[] = {
+    { 0x01BC, 0x01BD, 0x0000, 0x0000 },
+    { 0x10AD, 0x2D0D, 0x0000, 0x0000 },
+    { 0x1FA2, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_190[] = {
+    { 0x04BA, 0x04BB, 0x0000, 0x0000 },
+    { 0x10AE, 0x2D0E, 0x0000, 0x0000 },
+    { 0x1EA0, 0x1EA1, 0x0000, 0x0000 },
+    { 0x1FA1, 0x1F61, 0x03B9, 0x0000 },
+    { 0x2C92, 0x2C93, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_191[] = {
+    { 0x10AF, 0x2D0F, 0x0000, 0x0000 },
+    { 0x1FA0, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_192[] = {
+    { 0x00C0, 0x00E0, 0x0000, 0x0000 },
+    { 0x1EDE, 0x1EDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_193[] = {
+    { 0x00C1, 0x00E1, 0x0000, 0x0000 },
+    { 0x03C2, 0x03C3, 0x0000, 0x0000 },
+    { 0x04C5, 0x04C6, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_194[] = {
+    { 0x00C2, 0x00E2, 0x0000, 0x0000 },
+    { 0x1EDC, 0x1EDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_195[] = {
+    { 0x00C3, 0x00E3, 0x0000, 0x0000 },
+    { 0x04C7, 0x04C8, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_196[] = {
+    { 0x00C4, 0x00E4, 0x0000, 0x0000 },
+    { 0x01C5, 0x01C6, 0x0000, 0x0000 },
+    { 0x1EDA, 0x1EDB, 0x0000, 0x0000 },
+    { 0x1FDB, 0x1F77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_197[] = {
+    { 0x00C5, 0x00E5, 0x0000, 0x0000 },
+    { 0x01C4, 0x01C6, 0x0000, 0x0000 },
+    { 0x04C1, 0x04C2, 0x0000, 0x0000 },
+    { 0x1FDA, 0x1F76, 0x0000, 0x0000 },
+    { 0xFF3A, 0xFF5A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_198[] = {
+    { 0x00C6, 0x00E6, 0x0000, 0x0000 },
+    { 0x01C7, 0x01C9, 0x0000, 0x0000 },
+    { 0x1ED8, 0x1ED9, 0x0000, 0x0000 },
+    { 0x1FD9, 0x1FD1, 0x0000, 0x0000 },
+    { 0xFF39, 0xFF59, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_199[] = {
+    { 0x00C7, 0x00E7, 0x0000, 0x0000 },
+    { 0x04C3, 0x04C4, 0x0000, 0x0000 },
+    { 0x1FD8, 0x1FD0, 0x0000, 0x0000 },
+    { 0xFF38, 0xFF58, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_200[] = {
+    { 0x00C8, 0x00E8, 0x0000, 0x0000 },
+    { 0x1ED6, 0x1ED7, 0x0000, 0x0000 },
+    { 0x1FD7, 0x03B9, 0x0308, 0x0342 },
+    { 0xFF37, 0xFF57, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_201[] = {
+    { 0x00C9, 0x00E9, 0x0000, 0x0000 },
+    { 0x01C8, 0x01C9, 0x0000, 0x0000 },
+    { 0x04CD, 0x04CE, 0x0000, 0x0000 },
+    { 0x1FD6, 0x03B9, 0x0342, 0x0000 },
+    { 0xFF36, 0xFF56, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_202[] = {
+    { 0x00CA, 0x00EA, 0x0000, 0x0000 },
+    { 0x01CB, 0x01CC, 0x0000, 0x0000 },
+    { 0x1ED4, 0x1ED5, 0x0000, 0x0000 },
+    { 0xFF35, 0xFF55, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_203[] = {
+    { 0x00CB, 0x00EB, 0x0000, 0x0000 },
+    { 0x01CA, 0x01CC, 0x0000, 0x0000 },
+    { 0xFF34, 0xFF54, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_204[] = {
+    { 0x00CC, 0x00EC, 0x0000, 0x0000 },
+    { 0x01CD, 0x01CE, 0x0000, 0x0000 },
+    { 0x1ED2, 0x1ED3, 0x0000, 0x0000 },
+    { 0x1FD3, 0x03B9, 0x0308, 0x0301 },
+    { 0x2CE0, 0x2CE1, 0x0000, 0x0000 },
+    { 0xFF33, 0xFF53, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_205[] = {
+    { 0x00CD, 0x00ED, 0x0000, 0x0000 },
+    { 0x04C9, 0x04CA, 0x0000, 0x0000 },
+    { 0x1FD2, 0x03B9, 0x0308, 0x0300 },
+    { 0xFF32, 0xFF52, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_206[] = {
+    { 0x00CE, 0x00EE, 0x0000, 0x0000 },
+    { 0x01CF, 0x01D0, 0x0000, 0x0000 },
+    { 0x1ED0, 0x1ED1, 0x0000, 0x0000 },
+    { 0x2CE2, 0x2CE3, 0x0000, 0x0000 },
+    { 0xFF31, 0xFF51, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_207[] = {
+    { 0x00CF, 0x00EF, 0x0000, 0x0000 },
+    { 0x04CB, 0x04CC, 0x0000, 0x0000 },
+    { 0xFF30, 0xFF50, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_208[] = {
+    { 0x00D0, 0x00F0, 0x0000, 0x0000 },
+    { 0x01D1, 0x01D2, 0x0000, 0x0000 },
+    { 0x04D4, 0x04D5, 0x0000, 0x0000 },
+    { 0x10C0, 0x2D20, 0x0000, 0x0000 },
+    { 0x1ECE, 0x1ECF, 0x0000, 0x0000 },
+    { 0xFF2F, 0xFF4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_209[] = {
+    { 0x00D1, 0x00F1, 0x0000, 0x0000 },
+    { 0x10C1, 0x2D21, 0x0000, 0x0000 },
+    { 0xFF2E, 0xFF4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_210[] = {
+    { 0x00D2, 0x00F2, 0x0000, 0x0000 },
+    { 0x01D3, 0x01D4, 0x0000, 0x0000 },
+    { 0x03D1, 0x03B8, 0x0000, 0x0000 },
+    { 0x04D6, 0x04D7, 0x0000, 0x0000 },
+    { 0x10C2, 0x2D22, 0x0000, 0x0000 },
+    { 0x1ECC, 0x1ECD, 0x0000, 0x0000 },
+    { 0xFF2D, 0xFF4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_211[] = {
+    { 0x00D3, 0x00F3, 0x0000, 0x0000 },
+    { 0x03D0, 0x03B2, 0x0000, 0x0000 },
+    { 0x10C3, 0x2D23, 0x0000, 0x0000 },
+    { 0x1FCC, 0x03B7, 0x03B9, 0x0000 },
+    { 0xFF2C, 0xFF4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_212[] = {
+    { 0x00D4, 0x00F4, 0x0000, 0x0000 },
+    { 0x01D5, 0x01D6, 0x0000, 0x0000 },
+    { 0x04D0, 0x04D1, 0x0000, 0x0000 },
+    { 0x10C4, 0x2D24, 0x0000, 0x0000 },
+    { 0x1ECA, 0x1ECB, 0x0000, 0x0000 },
+    { 0x1FCB, 0x1F75, 0x0000, 0x0000 },
+    { 0xFF2B, 0xFF4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_213[] = {
+    { 0x00D5, 0x00F5, 0x0000, 0x0000 },
+    { 0x03D6, 0x03C0, 0x0000, 0x0000 },
+    { 0x10C5, 0x2D25, 0x0000, 0x0000 },
+    { 0x1FCA, 0x1F74, 0x0000, 0x0000 },
+    { 0xFF2A, 0xFF4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_214[] = {
+    { 0x00D6, 0x00F6, 0x0000, 0x0000 },
+    { 0x01D7, 0x01D8, 0x0000, 0x0000 },
+    { 0x03D5, 0x03C6, 0x0000, 0x0000 },
+    { 0x04D2, 0x04D3, 0x0000, 0x0000 },
+    { 0x1EC8, 0x1EC9, 0x0000, 0x0000 },
+    { 0x1FC9, 0x1F73, 0x0000, 0x0000 },
+    { 0xFF29, 0xFF49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_215[] = {
+    { 0x1FC8, 0x1F72, 0x0000, 0x0000 },
+    { 0xFF28, 0xFF48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_216[] = {
+    { 0x00D8, 0x00F8, 0x0000, 0x0000 },
+    { 0x01D9, 0x01DA, 0x0000, 0x0000 },
+    { 0x04DC, 0x04DD, 0x0000, 0x0000 },
+    { 0x1EC6, 0x1EC7, 0x0000, 0x0000 },
+    { 0x1FC7, 0x03B7, 0x0342, 0x03B9 },
+    { 0xFF27, 0xFF47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_217[] = {
+    { 0x00D9, 0x00F9, 0x0000, 0x0000 },
+    { 0x03DA, 0x03DB, 0x0000, 0x0000 },
+    { 0x1FC6, 0x03B7, 0x0342, 0x0000 },
+    { 0xFF26, 0xFF46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_218[] = {
+    { 0x00DA, 0x00FA, 0x0000, 0x0000 },
+    { 0x01DB, 0x01DC, 0x0000, 0x0000 },
+    { 0x04DE, 0x04DF, 0x0000, 0x0000 },
+    { 0x1EC4, 0x1EC5, 0x0000, 0x0000 },
+    { 0xFF25, 0xFF45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_219[] = {
+    { 0x00DB, 0x00FB, 0x0000, 0x0000 },
+    { 0x03D8, 0x03D9, 0x0000, 0x0000 },
+    { 0x1FC4, 0x03AE, 0x03B9, 0x0000 },
+    { 0xFF24, 0xFF44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_220[] = {
+    { 0x00DC, 0x00FC, 0x0000, 0x0000 },
+    { 0x04D8, 0x04D9, 0x0000, 0x0000 },
+    { 0x1EC2, 0x1EC3, 0x0000, 0x0000 },
+    { 0x1FC3, 0x03B7, 0x03B9, 0x0000 },
+    { 0xFF23, 0xFF43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_221[] = {
+    { 0x00DD, 0x00FD, 0x0000, 0x0000 },
+    { 0x03DE, 0x03DF, 0x0000, 0x0000 },
+    { 0x1FC2, 0x1F74, 0x03B9, 0x0000 },
+    { 0xFF22, 0xFF42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_222[] = {
+    { 0x00DE, 0x00FE, 0x0000, 0x0000 },
+    { 0x04DA, 0x04DB, 0x0000, 0x0000 },
+    { 0x1EC0, 0x1EC1, 0x0000, 0x0000 },
+    { 0xFF21, 0xFF41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_223[] = {
+    { 0x00DF, 0x0073, 0x0073, 0x0000 },
+    { 0x01DE, 0x01DF, 0x0000, 0x0000 },
+    { 0x03DC, 0x03DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_224[] = {
+    { 0x04E4, 0x04E5, 0x0000, 0x0000 },
+    { 0x24C4, 0x24DE, 0x0000, 0x0000 },
+    { 0x2CCC, 0x2CCD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_225[] = {
+    { 0x01E0, 0x01E1, 0x0000, 0x0000 },
+    { 0x03E2, 0x03E3, 0x0000, 0x0000 },
+    { 0x24C5, 0x24DF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_226[] = {
+    { 0x04E6, 0x04E7, 0x0000, 0x0000 },
+    { 0x24C6, 0x24E0, 0x0000, 0x0000 },
+    { 0x2CCE, 0x2CCF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_227[] = {
+    { 0x01E2, 0x01E3, 0x0000, 0x0000 },
+    { 0x03E0, 0x03E1, 0x0000, 0x0000 },
+    { 0x1FFC, 0x03C9, 0x03B9, 0x0000 },
+    { 0x24C7, 0x24E1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_228[] = {
+    { 0x04E0, 0x04E1, 0x0000, 0x0000 },
+    { 0x1FFB, 0x1F7D, 0x0000, 0x0000 },
+    { 0x24C0, 0x24DA, 0x0000, 0x0000 },
+    { 0x2CC8, 0x2CC9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_229[] = {
+    { 0x01E4, 0x01E5, 0x0000, 0x0000 },
+    { 0x03E6, 0x03E7, 0x0000, 0x0000 },
+    { 0x1FFA, 0x1F7C, 0x0000, 0x0000 },
+    { 0x24C1, 0x24DB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_230[] = {
+    { 0x04E2, 0x04E3, 0x0000, 0x0000 },
+    { 0x1EF8, 0x1EF9, 0x0000, 0x0000 },
+    { 0x1FF9, 0x1F79, 0x0000, 0x0000 },
+    { 0x24C2, 0x24DC, 0x0000, 0x0000 },
+    { 0x2CCA, 0x2CCB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_231[] = {
+    { 0x01E6, 0x01E7, 0x0000, 0x0000 },
+    { 0x03E4, 0x03E5, 0x0000, 0x0000 },
+    { 0x1FF8, 0x1F78, 0x0000, 0x0000 },
+    { 0x24C3, 0x24DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_232[] = {
+    { 0x04EC, 0x04ED, 0x0000, 0x0000 },
+    { 0x1EF6, 0x1EF7, 0x0000, 0x0000 },
+    { 0x1FF7, 0x03C9, 0x0342, 0x03B9 },
+    { 0x24CC, 0x24E6, 0x0000, 0x0000 },
+    { 0x2CC4, 0x2CC5, 0x0000, 0x0000 },
+    { 0xFB13, 0x0574, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_233[] = {
+    { 0x01E8, 0x01E9, 0x0000, 0x0000 },
+    { 0x03EA, 0x03EB, 0x0000, 0x0000 },
+    { 0x1FF6, 0x03C9, 0x0342, 0x0000 },
+    { 0x24CD, 0x24E7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_234[] = {
+    { 0x04EE, 0x04EF, 0x0000, 0x0000 },
+    { 0x1EF4, 0x1EF5, 0x0000, 0x0000 },
+    { 0x24CE, 0x24E8, 0x0000, 0x0000 },
+    { 0x2CC6, 0x2CC7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_235[] = {
+    { 0x01EA, 0x01EB, 0x0000, 0x0000 },
+    { 0x03E8, 0x03E9, 0x0000, 0x0000 },
+    { 0x1FF4, 0x03CE, 0x03B9, 0x0000 },
+    { 0x24CF, 0x24E9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_236[] = {
+    { 0x04E8, 0x04E9, 0x0000, 0x0000 },
+    { 0x1EF2, 0x1EF3, 0x0000, 0x0000 },
+    { 0x1FF3, 0x03C9, 0x03B9, 0x0000 },
+    { 0x24C8, 0x24E2, 0x0000, 0x0000 },
+    { 0x2CC0, 0x2CC1, 0x0000, 0x0000 },
+    { 0xFB17, 0x0574, 0x056D, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_237[] = {
+    { 0x01EC, 0x01ED, 0x0000, 0x0000 },
+    { 0x03EE, 0x03EF, 0x0000, 0x0000 },
+    { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 },
+    { 0x24C9, 0x24E3, 0x0000, 0x0000 },
+    { 0xFB16, 0x057E, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_238[] = {
+    { 0x04EA, 0x04EB, 0x0000, 0x0000 },
+    { 0x1EF0, 0x1EF1, 0x0000, 0x0000 },
+    { 0x24CA, 0x24E4, 0x0000, 0x0000 },
+    { 0x2CC2, 0x2CC3, 0x0000, 0x0000 },
+    { 0xFB15, 0x0574, 0x056B, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_239[] = {
+    { 0x01EE, 0x01EF, 0x0000, 0x0000 },
+    { 0x03EC, 0x03ED, 0x0000, 0x0000 },
+    { 0x24CB, 0x24E5, 0x0000, 0x0000 },
+    { 0xFB14, 0x0574, 0x0565, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_240[] = {
+    { 0x01F1, 0x01F3, 0x0000, 0x0000 },
+    { 0x04F4, 0x04F5, 0x0000, 0x0000 },
+    { 0x1EEE, 0x1EEF, 0x0000, 0x0000 },
+    { 0x2CDC, 0x2CDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_241[] = {
+    { 0x01F0, 0x006A, 0x030C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_242[] = {
+    { 0x03F1, 0x03C1, 0x0000, 0x0000 },
+    { 0x04F6, 0x04F7, 0x0000, 0x0000 },
+    { 0x1EEC, 0x1EED, 0x0000, 0x0000 },
+    { 0x2CDE, 0x2CDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_243[] = {
+    { 0x01F2, 0x01F3, 0x0000, 0x0000 },
+    { 0x03F0, 0x03BA, 0x0000, 0x0000 },
+    { 0x1FEC, 0x1FE5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_244[] = {
+    { 0x03F7, 0x03F8, 0x0000, 0x0000 },
+    { 0x04F0, 0x04F1, 0x0000, 0x0000 },
+    { 0x1EEA, 0x1EEB, 0x0000, 0x0000 },
+    { 0x1FEB, 0x1F7B, 0x0000, 0x0000 },
+    { 0x2CD8, 0x2CD9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_245[] = {
+    { 0x01F4, 0x01F5, 0x0000, 0x0000 },
+    { 0x1FEA, 0x1F7A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_246[] = {
+    { 0x01F7, 0x01BF, 0x0000, 0x0000 },
+    { 0x03F5, 0x03B5, 0x0000, 0x0000 },
+    { 0x04F2, 0x04F3, 0x0000, 0x0000 },
+    { 0x1EE8, 0x1EE9, 0x0000, 0x0000 },
+    { 0x1FE9, 0x1FE1, 0x0000, 0x0000 },
+    { 0x2CDA, 0x2CDB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_247[] = {
+    { 0x01F6, 0x0195, 0x0000, 0x0000 },
+    { 0x03F4, 0x03B8, 0x0000, 0x0000 },
+    { 0x1FE8, 0x1FE0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_248[] = {
+    { 0x1EE6, 0x1EE7, 0x0000, 0x0000 },
+    { 0x1FE7, 0x03C5, 0x0308, 0x0342 },
+    { 0x2CD4, 0x2CD5, 0x0000, 0x0000 },
+    { 0xFB03, 0x0066, 0x0066, 0x0069 }
+};
+
+static const CaseFoldMapping case_fold_249[] = {
+    { 0x01F8, 0x01F9, 0x0000, 0x0000 },
+    { 0x03FA, 0x03FB, 0x0000, 0x0000 },
+    { 0x1FE6, 0x03C5, 0x0342, 0x0000 },
+    { 0xFB02, 0x0066, 0x006C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_250[] = {
+    { 0x03F9, 0x03F2, 0x0000, 0x0000 },
+    { 0x1EE4, 0x1EE5, 0x0000, 0x0000 },
+    { 0x2CD6, 0x2CD7, 0x0000, 0x0000 },
+    { 0xFB01, 0x0066, 0x0069, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_251[] = {
+    { 0x01FA, 0x01FB, 0x0000, 0x0000 },
+    { 0x1FE4, 0x03C1, 0x0313, 0x0000 },
+    { 0xFB00, 0x0066, 0x0066, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_252[] = {
+    { 0x04F8, 0x04F9, 0x0000, 0x0000 },
+    { 0x1EE2, 0x1EE3, 0x0000, 0x0000 },
+    { 0x1FE3, 0x03C5, 0x0308, 0x0301 },
+    { 0x2CD0, 0x2CD1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_253[] = {
+    { 0x01FC, 0x01FD, 0x0000, 0x0000 },
+    { 0x1FE2, 0x03C5, 0x0308, 0x0300 },
+    { 0xFB06, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_254[] = {
+    { 0x1EE0, 0x1EE1, 0x0000, 0x0000 },
+    { 0x2CD2, 0x2CD3, 0x0000, 0x0000 },
+    { 0xFB05, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_255[] = {
+    { 0x01FE, 0x01FF, 0x0000, 0x0000 },
+    { 0xFB04, 0x0066, 0x0066, 0x006C }
+};
+
+
+static const CaseFoldHashBucket case_fold_hash[256] = {
+    { __PHYSFS_ARRAYLEN(case_fold_000), case_fold_000 },
+    { __PHYSFS_ARRAYLEN(case_fold_001), case_fold_001 },
+    { __PHYSFS_ARRAYLEN(case_fold_002), case_fold_002 },
+    { __PHYSFS_ARRAYLEN(case_fold_003), case_fold_003 },
+    { __PHYSFS_ARRAYLEN(case_fold_004), case_fold_004 },
+    { __PHYSFS_ARRAYLEN(case_fold_005), case_fold_005 },
+    { __PHYSFS_ARRAYLEN(case_fold_006), case_fold_006 },
+    { __PHYSFS_ARRAYLEN(case_fold_007), case_fold_007 },
+    { __PHYSFS_ARRAYLEN(case_fold_008), case_fold_008 },
+    { __PHYSFS_ARRAYLEN(case_fold_009), case_fold_009 },
+    { __PHYSFS_ARRAYLEN(case_fold_010), case_fold_010 },
+    { __PHYSFS_ARRAYLEN(case_fold_011), case_fold_011 },
+    { __PHYSFS_ARRAYLEN(case_fold_012), case_fold_012 },
+    { __PHYSFS_ARRAYLEN(case_fold_013), case_fold_013 },
+    { __PHYSFS_ARRAYLEN(case_fold_014), case_fold_014 },
+    { __PHYSFS_ARRAYLEN(case_fold_015), case_fold_015 },
+    { __PHYSFS_ARRAYLEN(case_fold_016), case_fold_016 },
+    { __PHYSFS_ARRAYLEN(case_fold_017), case_fold_017 },
+    { __PHYSFS_ARRAYLEN(case_fold_018), case_fold_018 },
+    { __PHYSFS_ARRAYLEN(case_fold_019), case_fold_019 },
+    { __PHYSFS_ARRAYLEN(case_fold_020), case_fold_020 },
+    { __PHYSFS_ARRAYLEN(case_fold_021), case_fold_021 },
+    { __PHYSFS_ARRAYLEN(case_fold_022), case_fold_022 },
+    { __PHYSFS_ARRAYLEN(case_fold_023), case_fold_023 },
+    { __PHYSFS_ARRAYLEN(case_fold_024), case_fold_024 },
+    { __PHYSFS_ARRAYLEN(case_fold_025), case_fold_025 },
+    { __PHYSFS_ARRAYLEN(case_fold_026), case_fold_026 },
+    { __PHYSFS_ARRAYLEN(case_fold_027), case_fold_027 },
+    { __PHYSFS_ARRAYLEN(case_fold_028), case_fold_028 },
+    { __PHYSFS_ARRAYLEN(case_fold_029), case_fold_029 },
+    { __PHYSFS_ARRAYLEN(case_fold_030), case_fold_030 },
+    { __PHYSFS_ARRAYLEN(case_fold_031), case_fold_031 },
+    { __PHYSFS_ARRAYLEN(case_fold_032), case_fold_032 },
+    { __PHYSFS_ARRAYLEN(case_fold_033), case_fold_033 },
+    { __PHYSFS_ARRAYLEN(case_fold_034), case_fold_034 },
+    { __PHYSFS_ARRAYLEN(case_fold_035), case_fold_035 },
+    { __PHYSFS_ARRAYLEN(case_fold_036), case_fold_036 },
+    { __PHYSFS_ARRAYLEN(case_fold_037), case_fold_037 },
+    { __PHYSFS_ARRAYLEN(case_fold_038), case_fold_038 },
+    { __PHYSFS_ARRAYLEN(case_fold_039), case_fold_039 },
+    { __PHYSFS_ARRAYLEN(case_fold_040), case_fold_040 },
+    { __PHYSFS_ARRAYLEN(case_fold_041), case_fold_041 },
+    { __PHYSFS_ARRAYLEN(case_fold_042), case_fold_042 },
+    { __PHYSFS_ARRAYLEN(case_fold_043), case_fold_043 },
+    { __PHYSFS_ARRAYLEN(case_fold_044), case_fold_044 },
+    { __PHYSFS_ARRAYLEN(case_fold_045), case_fold_045 },
+    { __PHYSFS_ARRAYLEN(case_fold_046), case_fold_046 },
+    { __PHYSFS_ARRAYLEN(case_fold_047), case_fold_047 },
+    { __PHYSFS_ARRAYLEN(case_fold_048), case_fold_048 },
+    { __PHYSFS_ARRAYLEN(case_fold_049), case_fold_049 },
+    { __PHYSFS_ARRAYLEN(case_fold_050), case_fold_050 },
+    { __PHYSFS_ARRAYLEN(case_fold_051), case_fold_051 },
+    { __PHYSFS_ARRAYLEN(case_fold_052), case_fold_052 },
+    { __PHYSFS_ARRAYLEN(case_fold_053), case_fold_053 },
+    { __PHYSFS_ARRAYLEN(case_fold_054), case_fold_054 },
+    { __PHYSFS_ARRAYLEN(case_fold_055), case_fold_055 },
+    { __PHYSFS_ARRAYLEN(case_fold_056), case_fold_056 },
+    { __PHYSFS_ARRAYLEN(case_fold_057), case_fold_057 },
+    { __PHYSFS_ARRAYLEN(case_fold_058), case_fold_058 },
+    { __PHYSFS_ARRAYLEN(case_fold_059), case_fold_059 },
+    { __PHYSFS_ARRAYLEN(case_fold_060), case_fold_060 },
+    { __PHYSFS_ARRAYLEN(case_fold_061), case_fold_061 },
+    { __PHYSFS_ARRAYLEN(case_fold_062), case_fold_062 },
+    { __PHYSFS_ARRAYLEN(case_fold_063), case_fold_063 },
+    { __PHYSFS_ARRAYLEN(case_fold_064), case_fold_064 },
+    { __PHYSFS_ARRAYLEN(case_fold_065), case_fold_065 },
+    { __PHYSFS_ARRAYLEN(case_fold_066), case_fold_066 },
+    { __PHYSFS_ARRAYLEN(case_fold_067), case_fold_067 },
+    { __PHYSFS_ARRAYLEN(case_fold_068), case_fold_068 },
+    { __PHYSFS_ARRAYLEN(case_fold_069), case_fold_069 },
+    { __PHYSFS_ARRAYLEN(case_fold_070), case_fold_070 },
+    { __PHYSFS_ARRAYLEN(case_fold_071), case_fold_071 },
+    { __PHYSFS_ARRAYLEN(case_fold_072), case_fold_072 },
+    { __PHYSFS_ARRAYLEN(case_fold_073), case_fold_073 },
+    { __PHYSFS_ARRAYLEN(case_fold_074), case_fold_074 },
+    { __PHYSFS_ARRAYLEN(case_fold_075), case_fold_075 },
+    { __PHYSFS_ARRAYLEN(case_fold_076), case_fold_076 },
+    { __PHYSFS_ARRAYLEN(case_fold_077), case_fold_077 },
+    { __PHYSFS_ARRAYLEN(case_fold_078), case_fold_078 },
+    { __PHYSFS_ARRAYLEN(case_fold_079), case_fold_079 },
+    { __PHYSFS_ARRAYLEN(case_fold_080), case_fold_080 },
+    { __PHYSFS_ARRAYLEN(case_fold_081), case_fold_081 },
+    { __PHYSFS_ARRAYLEN(case_fold_082), case_fold_082 },
+    { __PHYSFS_ARRAYLEN(case_fold_083), case_fold_083 },
+    { __PHYSFS_ARRAYLEN(case_fold_084), case_fold_084 },
+    { __PHYSFS_ARRAYLEN(case_fold_085), case_fold_085 },
+    { __PHYSFS_ARRAYLEN(case_fold_086), case_fold_086 },
+    { __PHYSFS_ARRAYLEN(case_fold_087), case_fold_087 },
+    { __PHYSFS_ARRAYLEN(case_fold_088), case_fold_088 },
+    { __PHYSFS_ARRAYLEN(case_fold_089), case_fold_089 },
+    { __PHYSFS_ARRAYLEN(case_fold_090), case_fold_090 },
+    { __PHYSFS_ARRAYLEN(case_fold_091), case_fold_091 },
+    { __PHYSFS_ARRAYLEN(case_fold_092), case_fold_092 },
+    { __PHYSFS_ARRAYLEN(case_fold_093), case_fold_093 },
+    { __PHYSFS_ARRAYLEN(case_fold_094), case_fold_094 },
+    { __PHYSFS_ARRAYLEN(case_fold_095), case_fold_095 },
+    { __PHYSFS_ARRAYLEN(case_fold_096), case_fold_096 },
+    { __PHYSFS_ARRAYLEN(case_fold_097), case_fold_097 },
+    { __PHYSFS_ARRAYLEN(case_fold_098), case_fold_098 },
+    { __PHYSFS_ARRAYLEN(case_fold_099), case_fold_099 },
+    { __PHYSFS_ARRAYLEN(case_fold_100), case_fold_100 },
+    { __PHYSFS_ARRAYLEN(case_fold_101), case_fold_101 },
+    { __PHYSFS_ARRAYLEN(case_fold_102), case_fold_102 },
+    { __PHYSFS_ARRAYLEN(case_fold_103), case_fold_103 },
+    { __PHYSFS_ARRAYLEN(case_fold_104), case_fold_104 },
+    { __PHYSFS_ARRAYLEN(case_fold_105), case_fold_105 },
+    { __PHYSFS_ARRAYLEN(case_fold_106), case_fold_106 },
+    { __PHYSFS_ARRAYLEN(case_fold_107), case_fold_107 },
+    { __PHYSFS_ARRAYLEN(case_fold_108), case_fold_108 },
+    { __PHYSFS_ARRAYLEN(case_fold_109), case_fold_109 },
+    { __PHYSFS_ARRAYLEN(case_fold_110), case_fold_110 },
+    { __PHYSFS_ARRAYLEN(case_fold_111), case_fold_111 },
+    { __PHYSFS_ARRAYLEN(case_fold_112), case_fold_112 },
+    { __PHYSFS_ARRAYLEN(case_fold_113), case_fold_113 },
+    { __PHYSFS_ARRAYLEN(case_fold_114), case_fold_114 },
+    { __PHYSFS_ARRAYLEN(case_fold_115), case_fold_115 },
+    { __PHYSFS_ARRAYLEN(case_fold_116), case_fold_116 },
+    { __PHYSFS_ARRAYLEN(case_fold_117), case_fold_117 },
+    { __PHYSFS_ARRAYLEN(case_fold_118), case_fold_118 },
+    { __PHYSFS_ARRAYLEN(case_fold_119), case_fold_119 },
+    { __PHYSFS_ARRAYLEN(case_fold_120), case_fold_120 },
+    { __PHYSFS_ARRAYLEN(case_fold_121), case_fold_121 },
+    { __PHYSFS_ARRAYLEN(case_fold_122), case_fold_122 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_124), case_fold_124 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_126), case_fold_126 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_128), case_fold_128 },
+    { __PHYSFS_ARRAYLEN(case_fold_129), case_fold_129 },
+    { __PHYSFS_ARRAYLEN(case_fold_130), case_fold_130 },
+    { __PHYSFS_ARRAYLEN(case_fold_131), case_fold_131 },
+    { __PHYSFS_ARRAYLEN(case_fold_132), case_fold_132 },
+    { __PHYSFS_ARRAYLEN(case_fold_133), case_fold_133 },
+    { __PHYSFS_ARRAYLEN(case_fold_134), case_fold_134 },
+    { __PHYSFS_ARRAYLEN(case_fold_135), case_fold_135 },
+    { __PHYSFS_ARRAYLEN(case_fold_136), case_fold_136 },
+    { __PHYSFS_ARRAYLEN(case_fold_137), case_fold_137 },
+    { __PHYSFS_ARRAYLEN(case_fold_138), case_fold_138 },
+    { __PHYSFS_ARRAYLEN(case_fold_139), case_fold_139 },
+    { __PHYSFS_ARRAYLEN(case_fold_140), case_fold_140 },
+    { __PHYSFS_ARRAYLEN(case_fold_141), case_fold_141 },
+    { __PHYSFS_ARRAYLEN(case_fold_142), case_fold_142 },
+    { __PHYSFS_ARRAYLEN(case_fold_143), case_fold_143 },
+    { __PHYSFS_ARRAYLEN(case_fold_144), case_fold_144 },
+    { __PHYSFS_ARRAYLEN(case_fold_145), case_fold_145 },
+    { __PHYSFS_ARRAYLEN(case_fold_146), case_fold_146 },
+    { __PHYSFS_ARRAYLEN(case_fold_147), case_fold_147 },
+    { __PHYSFS_ARRAYLEN(case_fold_148), case_fold_148 },
+    { __PHYSFS_ARRAYLEN(case_fold_149), case_fold_149 },
+    { __PHYSFS_ARRAYLEN(case_fold_150), case_fold_150 },
+    { __PHYSFS_ARRAYLEN(case_fold_151), case_fold_151 },
+    { __PHYSFS_ARRAYLEN(case_fold_152), case_fold_152 },
+    { __PHYSFS_ARRAYLEN(case_fold_153), case_fold_153 },
+    { __PHYSFS_ARRAYLEN(case_fold_154), case_fold_154 },
+    { __PHYSFS_ARRAYLEN(case_fold_155), case_fold_155 },
+    { __PHYSFS_ARRAYLEN(case_fold_156), case_fold_156 },
+    { __PHYSFS_ARRAYLEN(case_fold_157), case_fold_157 },
+    { __PHYSFS_ARRAYLEN(case_fold_158), case_fold_158 },
+    { __PHYSFS_ARRAYLEN(case_fold_159), case_fold_159 },
+    { __PHYSFS_ARRAYLEN(case_fold_160), case_fold_160 },
+    { __PHYSFS_ARRAYLEN(case_fold_161), case_fold_161 },
+    { __PHYSFS_ARRAYLEN(case_fold_162), case_fold_162 },
+    { __PHYSFS_ARRAYLEN(case_fold_163), case_fold_163 },
+    { __PHYSFS_ARRAYLEN(case_fold_164), case_fold_164 },
+    { __PHYSFS_ARRAYLEN(case_fold_165), case_fold_165 },
+    { __PHYSFS_ARRAYLEN(case_fold_166), case_fold_166 },
+    { __PHYSFS_ARRAYLEN(case_fold_167), case_fold_167 },
+    { __PHYSFS_ARRAYLEN(case_fold_168), case_fold_168 },
+    { __PHYSFS_ARRAYLEN(case_fold_169), case_fold_169 },
+    { __PHYSFS_ARRAYLEN(case_fold_170), case_fold_170 },
+    { __PHYSFS_ARRAYLEN(case_fold_171), case_fold_171 },
+    { __PHYSFS_ARRAYLEN(case_fold_172), case_fold_172 },
+    { __PHYSFS_ARRAYLEN(case_fold_173), case_fold_173 },
+    { __PHYSFS_ARRAYLEN(case_fold_174), case_fold_174 },
+    { __PHYSFS_ARRAYLEN(case_fold_175), case_fold_175 },
+    { __PHYSFS_ARRAYLEN(case_fold_176), case_fold_176 },
+    { __PHYSFS_ARRAYLEN(case_fold_177), case_fold_177 },
+    { __PHYSFS_ARRAYLEN(case_fold_178), case_fold_178 },
+    { __PHYSFS_ARRAYLEN(case_fold_179), case_fold_179 },
+    { __PHYSFS_ARRAYLEN(case_fold_180), case_fold_180 },
+    { __PHYSFS_ARRAYLEN(case_fold_181), case_fold_181 },
+    { __PHYSFS_ARRAYLEN(case_fold_182), case_fold_182 },
+    { __PHYSFS_ARRAYLEN(case_fold_183), case_fold_183 },
+    { __PHYSFS_ARRAYLEN(case_fold_184), case_fold_184 },
+    { __PHYSFS_ARRAYLEN(case_fold_185), case_fold_185 },
+    { __PHYSFS_ARRAYLEN(case_fold_186), case_fold_186 },
+    { __PHYSFS_ARRAYLEN(case_fold_187), case_fold_187 },
+    { __PHYSFS_ARRAYLEN(case_fold_188), case_fold_188 },
+    { __PHYSFS_ARRAYLEN(case_fold_189), case_fold_189 },
+    { __PHYSFS_ARRAYLEN(case_fold_190), case_fold_190 },
+    { __PHYSFS_ARRAYLEN(case_fold_191), case_fold_191 },
+    { __PHYSFS_ARRAYLEN(case_fold_192), case_fold_192 },
+    { __PHYSFS_ARRAYLEN(case_fold_193), case_fold_193 },
+    { __PHYSFS_ARRAYLEN(case_fold_194), case_fold_194 },
+    { __PHYSFS_ARRAYLEN(case_fold_195), case_fold_195 },
+    { __PHYSFS_ARRAYLEN(case_fold_196), case_fold_196 },
+    { __PHYSFS_ARRAYLEN(case_fold_197), case_fold_197 },
+    { __PHYSFS_ARRAYLEN(case_fold_198), case_fold_198 },
+    { __PHYSFS_ARRAYLEN(case_fold_199), case_fold_199 },
+    { __PHYSFS_ARRAYLEN(case_fold_200), case_fold_200 },
+    { __PHYSFS_ARRAYLEN(case_fold_201), case_fold_201 },
+    { __PHYSFS_ARRAYLEN(case_fold_202), case_fold_202 },
+    { __PHYSFS_ARRAYLEN(case_fold_203), case_fold_203 },
+    { __PHYSFS_ARRAYLEN(case_fold_204), case_fold_204 },
+    { __PHYSFS_ARRAYLEN(case_fold_205), case_fold_205 },
+    { __PHYSFS_ARRAYLEN(case_fold_206), case_fold_206 },
+    { __PHYSFS_ARRAYLEN(case_fold_207), case_fold_207 },
+    { __PHYSFS_ARRAYLEN(case_fold_208), case_fold_208 },
+    { __PHYSFS_ARRAYLEN(case_fold_209), case_fold_209 },
+    { __PHYSFS_ARRAYLEN(case_fold_210), case_fold_210 },
+    { __PHYSFS_ARRAYLEN(case_fold_211), case_fold_211 },
+    { __PHYSFS_ARRAYLEN(case_fold_212), case_fold_212 },
+    { __PHYSFS_ARRAYLEN(case_fold_213), case_fold_213 },
+    { __PHYSFS_ARRAYLEN(case_fold_214), case_fold_214 },
+    { __PHYSFS_ARRAYLEN(case_fold_215), case_fold_215 },
+    { __PHYSFS_ARRAYLEN(case_fold_216), case_fold_216 },
+    { __PHYSFS_ARRAYLEN(case_fold_217), case_fold_217 },
+    { __PHYSFS_ARRAYLEN(case_fold_218), case_fold_218 },
+    { __PHYSFS_ARRAYLEN(case_fold_219), case_fold_219 },
+    { __PHYSFS_ARRAYLEN(case_fold_220), case_fold_220 },
+    { __PHYSFS_ARRAYLEN(case_fold_221), case_fold_221 },
+    { __PHYSFS_ARRAYLEN(case_fold_222), case_fold_222 },
+    { __PHYSFS_ARRAYLEN(case_fold_223), case_fold_223 },
+    { __PHYSFS_ARRAYLEN(case_fold_224), case_fold_224 },
+    { __PHYSFS_ARRAYLEN(case_fold_225), case_fold_225 },
+    { __PHYSFS_ARRAYLEN(case_fold_226), case_fold_226 },
+    { __PHYSFS_ARRAYLEN(case_fold_227), case_fold_227 },
+    { __PHYSFS_ARRAYLEN(case_fold_228), case_fold_228 },
+    { __PHYSFS_ARRAYLEN(case_fold_229), case_fold_229 },
+    { __PHYSFS_ARRAYLEN(case_fold_230), case_fold_230 },
+    { __PHYSFS_ARRAYLEN(case_fold_231), case_fold_231 },
+    { __PHYSFS_ARRAYLEN(case_fold_232), case_fold_232 },
+    { __PHYSFS_ARRAYLEN(case_fold_233), case_fold_233 },
+    { __PHYSFS_ARRAYLEN(case_fold_234), case_fold_234 },
+    { __PHYSFS_ARRAYLEN(case_fold_235), case_fold_235 },
+    { __PHYSFS_ARRAYLEN(case_fold_236), case_fold_236 },
+    { __PHYSFS_ARRAYLEN(case_fold_237), case_fold_237 },
+    { __PHYSFS_ARRAYLEN(case_fold_238), case_fold_238 },
+    { __PHYSFS_ARRAYLEN(case_fold_239), case_fold_239 },
+    { __PHYSFS_ARRAYLEN(case_fold_240), case_fold_240 },
+    { __PHYSFS_ARRAYLEN(case_fold_241), case_fold_241 },
+    { __PHYSFS_ARRAYLEN(case_fold_242), case_fold_242 },
+    { __PHYSFS_ARRAYLEN(case_fold_243), case_fold_243 },
+    { __PHYSFS_ARRAYLEN(case_fold_244), case_fold_244 },
+    { __PHYSFS_ARRAYLEN(case_fold_245), case_fold_245 },
+    { __PHYSFS_ARRAYLEN(case_fold_246), case_fold_246 },
+    { __PHYSFS_ARRAYLEN(case_fold_247), case_fold_247 },
+    { __PHYSFS_ARRAYLEN(case_fold_248), case_fold_248 },
+    { __PHYSFS_ARRAYLEN(case_fold_249), case_fold_249 },
+    { __PHYSFS_ARRAYLEN(case_fold_250), case_fold_250 },
+    { __PHYSFS_ARRAYLEN(case_fold_251), case_fold_251 },
+    { __PHYSFS_ARRAYLEN(case_fold_252), case_fold_252 },
+    { __PHYSFS_ARRAYLEN(case_fold_253), case_fold_253 },
+    { __PHYSFS_ARRAYLEN(case_fold_254), case_fold_254 },
+    { __PHYSFS_ARRAYLEN(case_fold_255), case_fold_255 },
+};
+
diff --git a/physfs_internal.h b/physfs_internal.h
new file mode 100644 (file)
index 0000000..eebec98
--- /dev/null
@@ -0,0 +1,1496 @@
+/*
+ * Internal function/structure declaration. Do NOT include in your
+ *  application.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_INTERNAL_H_
+#define _INCLUDE_PHYSFS_INTERNAL_H_
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+#include "physfs.h"
+
+#include <stdlib.h>  /* make sure NULL is defined... */
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#elif (!defined assert)
+#define assert(x)
+#endif
+
+/* !!! FIXME: remove this when revamping stack allocation code... */
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <malloc.h>
+#endif
+
+#if defined(__sun) || defined(sun)
+#include <alloca.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) \
+    ( ((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)) )
+#else
+#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) (0)
+#endif
+
+/*
+ * 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
+
+/* All language strings are UTF-8 encoded! */
+#define PHYSFS_LANG_ENGLISH            1  /* English by Ryan C. Gordon  */
+#define PHYSFS_LANG_RUSSIAN            2  /* Russian by Ed Sinjiashvili */
+#define PHYSFS_LANG_SPANISH            3  /* Spanish by Pedro J. Pérez  */
+#define PHYSFS_LANG_FRENCH             4  /*  French by Stéphane Peter  */
+#define PHYSFS_LANG_GERMAN             5  /*  German by Michael Renner  */
+#define PHYSFS_LANG_PORTUGUESE_BR      6  /* 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)
+ #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(_M_IX86) || defined(_M_IA64) || \
+    (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/physfs_platforms.h b/physfs_platforms.h
new file mode 100644 (file)
index 0000000..9a185fc
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _INCL_PHYSFS_PLATFORMS
+#define _INCL_PHYSFS_PLATFORMS
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+/*
+ * These only define the platforms to determine which files in the platforms
+ *  directory should be compiled. For example, technically BeOS can be called
+ *  a "unix" system, but since it doesn't use unix.c, we don't define
+ *  PHYSFS_PLATFORM_UNIX on that system.
+ */
+
+#if (defined __HAIKU__)
+#  define PHYSFS_PLATFORM_HAIKU
+#  define PHYSFS_PLATFORM_BEOS
+#  define PHYSFS_PLATFORM_POSIX
+#elif ((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__))
+/* To check if iphone or not, we need to include this file */
+# include <TargetConditionals.h> 
+# if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE))
+#    define PHYSFS_PLATFORM_UNIX
+#    define PHYSFS_PLATFORM_POSIX
+#    define PHYSFS_NO_CDROM_SUPPORT
+#  else
+#    define PHYSFS_PLATFORM_MACOSX
+#    define PHYSFS_PLATFORM_POSIX
+#  endif
+#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/physfs_unicode.c b/physfs_unicode.c
new file mode 100644 (file)
index 0000000..d9cc73f
--- /dev/null
@@ -0,0 +1,460 @@
+#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) \
+    if (len == 0) return; \
+    len--;  \
+    while (len) \
+    { \
+        const PHYSFS_uint32 cp = (PHYSFS_uint32) ((typ) (*(src++))); \
+        if (cp == 0) break; \
+        utf8fromcodepoint(cp, &dst, &len); \
+    } \
+    *dst = '\0'; \
+
+void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint32, src, dst, len);
+} /* PHYSFS_utf8FromUcs4 */
+
+void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint64, src, dst, len);
+} /* PHYSFS_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/platform/beos.cpp b/platform/beos.cpp
new file mode 100644 (file)
index 0000000..414b272
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * BeOS platform-dependent support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_BEOS
+
+#ifdef PHYSFS_PLATFORM_HAIKU
+#include <os/kernel/OS.h>
+#include <os/app/Roster.h>
+#include <os/storage/Volume.h>
+#include <os/storage/VolumeRoster.h>
+#include <os/storage/Directory.h>
+#include <os/storage/Entry.h>
+#include <os/storage/Path.h>
+#include <os/kernel/fs_info.h>
+#include <os/device/scsi.h>
+#include <os/support/Locker.h>
+#else
+#include <be/kernel/OS.h>
+#include <be/app/Roster.h>
+#include <be/storage/Volume.h>
+#include <be/storage/VolumeRoster.h>
+#include <be/storage/Directory.h>
+#include <be/storage/Entry.h>
+#include <be/storage/Path.h>
+#include <be/kernel/fs_info.h>
+#include <be/device/scsi.h>
+#include <be/support/Locker.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "physfs_internal.h"
+
+
+int __PHYSFS_platformInit(void)
+{
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+static char *getMountPoint(const char *devname)
+{
+    BVolumeRoster mounts;
+    BVolume vol;
+
+    mounts.Rewind();
+    while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
+    {
+        fs_info fsinfo;
+        fs_stat_dev(vol.Device(), &fsinfo);
+        if (strcmp(devname, fsinfo.device_name) == 0)
+        {
+            //char buf[B_FILE_NAME_LENGTH];
+            BDirectory directory;
+            BEntry entry;
+            BPath path;
+            status_t rc;
+            rc = vol.GetRootDirectory(&directory);
+            BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+            rc = directory.GetEntry(&entry);
+            BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+            rc = entry.GetPath(&path);
+            BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+            const char *str = path.Path();
+            BAIL_IF_MACRO(str == NULL, ERR_OS_ERROR, NULL);  /* ?! */
+            char *retval = (char *) allocator.Malloc(strlen(str) + 1);
+            BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+            strcpy(retval, str);
+            return(retval);
+        } /* if */
+    } /* while */
+
+    return(NULL);
+} /* getMountPoint */
+
+
+    /*
+     * This function is lifted from Simple Directmedia Layer (SDL):
+     *  http://www.libsdl.org/
+     */
+static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
+{
+    BDirectory dir;
+    dir.SetTo(d);
+    if (dir.InitCheck() != B_NO_ERROR)
+        return;
+
+    dir.Rewind();
+    BEntry entry;
+    while (dir.GetNextEntry(&entry) >= 0)
+    {
+        BPath path;
+        const char *name;
+        entry_ref e;
+
+        if (entry.GetPath(&path) != B_NO_ERROR)
+            continue;
+
+        name = path.Path();
+
+        if (entry.GetRef(&e) != B_NO_ERROR)
+            continue;
+
+        if (entry.IsDirectory())
+        {
+            if (strcmp(e.name, "floppy") != 0)
+                tryDir(name, callback, data);
+        } /* if */
+
+        else
+        {
+            bool add_it = false;
+            int devfd;
+            device_geometry g;
+
+            if (strcmp(e.name, "raw") == 0)  /* ignore partitions. */
+            {
+                int devfd = open(name, O_RDONLY);
+                if (devfd >= 0)
+                {
+                    if (ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
+                    {
+                        if (g.device_type == B_CD)
+                        {
+                            char *mntpnt = getMountPoint(name);
+                            if (mntpnt != NULL)
+                            {
+                                callback(data, mntpnt);
+                                allocator.Free(mntpnt);  /* !!! FIXME: lose this malloc! */
+                            } /* if */
+                        } /* if */
+                    } /* if */
+                } /* if */
+            } /* if */
+
+            close(devfd);
+        } /* else */
+    } /* while */
+} /* tryDir */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    tryDir("/dev/disk", cb, data);
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static team_id getTeamID(void)
+{
+    thread_info info;
+    thread_id tid = find_thread(NULL);
+    get_thread_info(tid, &info);
+    return(info.team);
+} /* getTeamID */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    image_info info;
+    int32 cookie = 0;
+
+    while (get_next_image_info(0, &cookie, &info) == B_OK) {
+        if (info.type == B_APP_IMAGE)
+            break;
+    }
+
+    BEntry entry(info.name, true);
+    BPath path;
+    status_t rc = entry.GetPath(&path);  /* (path) now has binary's path. */
+    assert(rc == B_OK);
+    rc = path.GetParent(&path); /* chop filename, keep directory. */
+    assert(rc == B_OK);
+    const char *str = path.Path();
+    assert(str != NULL);
+    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/platform/macosx.c b/platform/macosx.c
new file mode 100644 (file)
index 0000000..4dde270
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Mac OS X support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_MACOSX
+
+#include <Carbon/Carbon.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IODVDMedia.h>
+#include <sys/mount.h>
+
+/* Seems to get defined in some system header... */
+#ifdef Free
+#undef Free
+#endif
+
+#include "physfs_internal.h"
+
+
+/* Wrap PHYSFS_Allocator in a CFAllocator... */
+static CFAllocatorRef cfallocator = NULL;
+
+CFStringRef cfallocDesc(const void *info)
+{
+    return(CFStringCreateWithCString(cfallocator, "PhysicsFS",
+                                     kCFStringEncodingASCII));
+} /* cfallocDesc */
+
+
+static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
+{
+    return allocator.Malloc(allocSize);
+} /* cfallocMalloc */
+
+
+static void cfallocFree(void *ptr, void *info)
+{
+    allocator.Free(ptr);
+} /* cfallocFree */
+
+
+static void *cfallocRealloc(void *ptr, CFIndex newsize,
+                            CFOptionFlags hint, void *info)
+{
+    if ((ptr == NULL) || (newsize <= 0))
+        return NULL;  /* ADC docs say you should always return NULL here. */
+    return allocator.Realloc(ptr, newsize);
+} /* cfallocRealloc */
+
+
+int __PHYSFS_platformInit(void)
+{
+    /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
+    CFAllocatorContext ctx;
+    memset(&ctx, '\0', sizeof (ctx));
+    ctx.copyDescription = cfallocDesc;
+    ctx.allocate = cfallocMalloc;
+    ctx.reallocate = cfallocRealloc;
+    ctx.deallocate = cfallocFree;
+    cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
+    BAIL_IF_MACRO(cfallocator == NULL, ERR_OUT_OF_MEMORY, 0);
+    return(1);  /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    CFRelease(cfallocator);
+    cfallocator = NULL;
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+/* CD-ROM detection code... */
+
+/*
+ * Code based on sample from Apple Developer Connection:
+ *  http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
+ */
+
+static int darwinIsWholeMedia(io_service_t service)
+{
+    int retval = 0;
+    CFTypeRef wholeMedia;
+
+    if (!IOObjectConformsTo(service, kIOMediaClass))
+        return(0);
+        
+    wholeMedia = IORegistryEntryCreateCFProperty(service,
+                                                 CFSTR(kIOMediaWholeKey),
+                                                 cfallocator, 0);
+    if (wholeMedia == NULL)
+        return(0);
+
+    retval = CFBooleanGetValue(wholeMedia);
+    CFRelease(wholeMedia);
+
+    return retval;
+} /* darwinIsWholeMedia */
+
+
+static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
+{
+    int retval = 0;
+    CFMutableDictionaryRef matchingDict;
+    kern_return_t rc;
+    io_iterator_t iter;
+    io_service_t service;
+
+    if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
+        return(0);
+
+    rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
+    if ((rc != KERN_SUCCESS) || (!iter))
+        return(0);
+
+    service = IOIteratorNext(iter);
+    IOObjectRelease(iter);
+    if (!service)
+        return(0);
+
+    rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
+             kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
+    
+    if (!iter)
+        return(0);
+
+    if (rc != KERN_SUCCESS)
+    {
+        IOObjectRelease(iter);
+        return(0);
+    } /* if */
+
+    IOObjectRetain(service);  /* add an extra object reference... */
+
+    do
+    {
+        if (darwinIsWholeMedia(service))
+        {
+            if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
+                 (IOObjectConformsTo(service, kIODVDMediaClass)) )
+            {
+                retval = 1;
+            } /* if */
+        } /* if */
+        IOObjectRelease(service);
+    } while ((service = IOIteratorNext(iter)) && (!retval));
+                
+    IOObjectRelease(iter);
+    IOObjectRelease(service);
+
+    return(retval);
+} /* darwinIsMountedDisc */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    const char *devPrefix = "/dev/";
+    const int prefixLen = strlen(devPrefix);
+    mach_port_t masterPort = 0;
+    struct statfs *mntbufp;
+    int i, mounts;
+
+    if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
+        BAIL_MACRO(ERR_OS_ERROR, ) /*return void*/;
+
+    mounts = getmntinfo(&mntbufp, MNT_WAIT);  /* NOT THREAD SAFE! */
+    for (i = 0; i < mounts; i++)
+    {
+        char *dev = mntbufp[i].f_mntfromname;
+        char *mnt = mntbufp[i].f_mntonname;
+        if (strncmp(dev, devPrefix, prefixLen) != 0)  /* a virtual device? */
+            continue;
+
+        dev += prefixLen;
+        if (darwinIsMountedDisc(dev, masterPort))
+            cb(data, mnt);
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static char *convertCFString(CFStringRef cfstr)
+{
+    CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+                                                    kCFStringEncodingUTF8) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
+    {
+        /* shrink overallocated buffer if possible... */
+        CFIndex newlen = strlen(retval) + 1;
+        if (newlen < len)
+        {
+            void *ptr = allocator.Realloc(retval, newlen);
+            if (ptr != NULL)
+                retval = (char *) ptr;
+        } /* if */
+    } /* if */
+
+    else  /* probably shouldn't fail, but just in case... */
+    {
+        allocator.Free(retval);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* else */
+
+    return(retval);
+} /* convertCFString */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    ProcessSerialNumber psn = { 0, kCurrentProcess };
+    FSRef fsref;
+    CFRange cfrange;
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    CFMutableStringRef cfmutstr = NULL;
+    char *retval = NULL;
+
+    BAIL_IF_MACRO(GetProcessBundleLocation(&psn, &fsref) != noErr, NULL, NULL);
+    cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
+    BAIL_IF_MACRO(cfurl == NULL, NULL, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(cfstr == NULL, NULL, NULL);
+    cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
+    CFRelease(cfstr);
+    BAIL_IF_MACRO(cfmutstr == NULL, NULL, NULL);
+
+    /* Find last dirsep so we can chop the binary's filename from the path. */
+    cfrange = CFStringFind(cfmutstr, CFSTR("/"), kCFCompareBackwards);
+    if (cfrange.location == kCFNotFound)
+    {
+        assert(0);  /* shouldn't ever hit this... */
+        CFRelease(cfmutstr);
+        return(NULL);
+    } /* if */
+
+    /* chop the "/exename" from the end of the path string... */
+    cfrange.length = CFStringGetLength(cfmutstr) - cfrange.location;
+    CFStringDelete(cfmutstr, cfrange);
+
+    /* If we're an Application Bundle, chop everything but the base. */
+    cfrange = CFStringFind(cfmutstr, CFSTR("/Contents/MacOS"),
+                           kCFCompareCaseInsensitive |
+                           kCFCompareBackwards |
+                           kCFCompareAnchored);
+
+    if (cfrange.location != kCFNotFound)
+        CFStringDelete(cfmutstr, cfrange);  /* chop that, too. */
+
+    retval = convertCFString(cfmutstr);
+    CFRelease(cfmutstr);
+
+    return(retval);  /* whew. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+/* !!! FIXME */
+#define osxerr(x) x
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    /* The symlink and relative path resolving happens in FSPathMakeRef() */
+    FSRef fsref;
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    char *retval = NULL;
+    OSStatus rc = osxerr(FSPathMakeRef((UInt8 *) path, &fsref, NULL));
+    BAIL_IF_MACRO(rc != noErr, NULL, NULL);
+
+    /* Now get it to spit out a full path. */
+    cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
+    BAIL_IF_MACRO(cfurl == NULL, ERR_OUT_OF_MEMORY, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(cfstr == NULL, ERR_OUT_OF_MEMORY, NULL);
+    retval = convertCFString(cfstr);
+    CFRelease(cfstr);
+
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return(__PHYSFS_platformRealPath("."));  /* let CFURL sort it out. */
+} /* __PHYSFS_platformCurrentDir */
+
+
+/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
+
+static CFAllocatorRef cfallocdef = NULL;
+
+static int macosxAllocatorInit(void)
+{
+    int retval = 0;
+    cfallocdef = CFAllocatorGetDefault();
+    retval = (cfallocdef != NULL);
+    if (retval)
+        CFRetain(cfallocdef);
+    return(retval);
+} /* macosxAllocatorInit */
+
+
+static void macosxAllocatorDeinit(void)
+{
+    if (cfallocdef != NULL)
+    {
+        CFRelease(cfallocdef);
+        cfallocdef = NULL;
+    } /* if */
+} /* macosxAllocatorDeinit */
+
+
+static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    return(CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0));
+} /* macosxAllocatorMalloc */
+
+
+static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    return(CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0));
+} /* macosxAllocatorRealloc */
+
+
+static void macosxAllocatorFree(void *ptr)
+{
+    CFAllocatorDeallocate(cfallocdef, ptr);
+} /* macosxAllocatorFree */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    allocator.Init = macosxAllocatorInit;
+    allocator.Deinit = macosxAllocatorDeinit;
+    allocator.Malloc = macosxAllocatorMalloc;
+    allocator.Realloc = macosxAllocatorRealloc;
+    allocator.Free = macosxAllocatorFree;
+    return(1);  /* return non-zero: we're supplying custom allocator. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return( (PHYSFS_uint64) ((size_t) MPCurrentTaskID()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    MPCriticalRegionID m = NULL;
+    if (osxerr(MPCreateCriticalRegion(&m)) != noErr)
+        return NULL;
+    return m;
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    MPDeleteCriticalRegion(m);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    if (MPEnterCriticalRegion(m, kDurationForever) != noErr)
+        return(0);
+    return(1);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    MPExitCriticalRegion(m);
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* PHYSFS_PLATFORM_MACOSX */
+
+/* end of macosx.c ... */
+
diff --git a/platform/os2.c b/platform/os2.c
new file mode 100644 (file)
index 0000000..3a6b0d8
--- /dev/null
@@ -0,0 +1,702 @@
+/*
+ * OS/2 support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_OS2
+
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSDATETIME
+#define INCL_DOSFILEMGR
+#define INCL_DOSMODULEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSPROCESS
+#define INCL_DOSDEVICES
+#define INCL_DOSDEVIOCTL
+#define INCL_DOSMISC
+#include <os2.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "physfs_internal.h"
+
+const char *__PHYSFS_platformDirSeparator = "\\";
+
+
+static const char *get_os2_error_string(APIRET rc)
+{
+    switch (rc)
+    {
+        case NO_ERROR: return(NULL);  /* not an error. */
+        case ERROR_INTERRUPT: return(NULL);  /* not an error. */
+        case ERROR_TIMEOUT: return(NULL);  /* not an error. */
+        case ERROR_NOT_ENOUGH_MEMORY: return(ERR_OUT_OF_MEMORY);
+        case ERROR_FILE_NOT_FOUND: return(ERR_NO_SUCH_FILE);
+        case ERROR_PATH_NOT_FOUND: return(ERR_NO_SUCH_PATH);
+        case ERROR_ACCESS_DENIED: return(ERR_ACCESS_DENIED);
+        case ERROR_NOT_DOS_DISK: return(ERR_NOT_A_DOS_DISK);
+        case ERROR_SHARING_VIOLATION: return(ERR_SHARING_VIOLATION);
+        case ERROR_CANNOT_MAKE: return(ERR_CANNOT_MAKE);
+        case ERROR_DEVICE_IN_USE: return(ERR_DEV_IN_USE);
+        case ERROR_OPEN_FAILED: return(ERR_OPEN_FAILED);
+        case ERROR_DISK_FULL: return(ERR_DISK_FULL);
+        case ERROR_PIPE_BUSY: return(ERR_PIPE_BUSY);
+        case ERROR_SHARING_BUFFER_EXCEEDED: return(ERR_SHARING_BUF_EXCEEDED);
+        case ERROR_FILENAME_EXCED_RANGE: return(ERR_BAD_FILENAME);
+        case ERROR_META_EXPANSION_TOO_LONG: return(ERR_BAD_FILENAME);
+        case ERROR_TOO_MANY_HANDLES: return(ERR_TOO_MANY_HANDLES);
+        case ERROR_TOO_MANY_OPEN_FILES: return(ERR_TOO_MANY_HANDLES);
+        case ERROR_NO_MORE_SEARCH_HANDLES: return(ERR_TOO_MANY_HANDLES);
+        case ERROR_SEEK_ON_DEVICE: return(ERR_SEEK_ERROR);
+        case ERROR_NEGATIVE_SEEK: return(ERR_SEEK_OUT_OF_RANGE);
+        /*!!! FIXME: Where did this go?  case ERROR_DEL_CURRENT_DIRECTORY: return(ERR_DEL_CWD);*/
+        case ERROR_WRITE_PROTECT: return(ERR_WRITE_PROTECT_ERROR);
+        case ERROR_WRITE_FAULT: return(ERR_WRITE_FAULT);
+        case ERROR_LOCK_VIOLATION: return(ERR_LOCK_VIOLATION);
+        case ERROR_GEN_FAILURE: return(ERR_GEN_FAILURE);
+        case ERROR_UNCERTAIN_MEDIA: return(ERR_UNCERTAIN_MEDIA);
+        case ERROR_PROTECTION_VIOLATION: return(ERR_PROT_VIOLATION);
+        case ERROR_BROKEN_PIPE: return(ERR_BROKEN_PIPE);
+
+        case ERROR_INVALID_PARAMETER:
+        case ERROR_INVALID_NAME:
+        case ERROR_INVALID_DRIVE:
+        case ERROR_INVALID_HANDLE:
+        case ERROR_INVALID_FUNCTION:
+        case ERROR_INVALID_LEVEL:
+        case ERROR_INVALID_CATEGORY:
+        case ERROR_DUPLICATE_NAME:
+        case ERROR_BUFFER_OVERFLOW:
+        case ERROR_BAD_LENGTH:
+        case ERROR_BAD_DRIVER_LEVEL:
+        case ERROR_DIRECT_ACCESS_HANDLE:
+        case ERROR_NOT_OWNER:
+            return(ERR_PHYSFS_BAD_OS_CALL);
+
+        default: return(ERR_OS2_GENERIC);
+    } /* switch */
+
+    return(NULL);
+} /* get_os2_error_string */
+
+
+static APIRET os2err(APIRET retval)
+{
+    char buf[128];
+    const char *err = get_os2_error_string(retval);
+    if (err == ERR_OS2_GENERIC)
+    {
+        snprintf(buf, sizeof (buf), ERR_OS2_GENERIC, (int) retval);
+        err = buf;
+    } /* if */
+
+    if (err != NULL)
+        __PHYSFS_setError(err);
+
+    return(retval);
+} /* os2err */
+
+
+/* (be gentle, this function isn't very robust.) */
+static void cvt_path_to_correct_case(char *buf)
+{
+    char *fname = buf + 3;            /* point to first element. */
+    char *ptr = strchr(fname, '\\');  /* find end of first element. */
+
+    buf[0] = toupper(buf[0]);  /* capitalize drive letter. */
+
+    /*
+     * Go through each path element, and enumerate its parent dir until
+     *  a case-insensitive match is found. If one is (and it SHOULD be)
+     *  then overwrite the original element with the correct case.
+     * If there's an error, or the path has vanished for some reason, it
+     *  won't hurt to have the original case, so we just keep going.
+     */
+    while (fname != NULL)
+    {
+        char spec[CCHMAXPATH];
+        FILEFINDBUF3 fb;
+        HDIR hdir = HDIR_CREATE;
+        ULONG count = 1;
+        APIRET rc;
+
+        *(fname - 1) = '\0';  /* isolate parent dir string. */
+
+        strcpy(spec, buf);      /* copy isolated parent dir... */
+        strcat(spec, "\\*.*");  /*  ...and add wildcard search spec. */
+
+        if (ptr != NULL)  /* isolate element to find (fname is the start). */
+            *ptr = '\0';
+
+        rc = DosFindFirst(spec, &hdir, FILE_DIRECTORY,
+                          &fb, sizeof (fb), &count, FIL_STANDARD);
+        if (rc == NO_ERROR)
+        {
+            while (count == 1)  /* while still entries to enumerate... */
+            {
+                if (__PHYSFS_stricmpASCII(fb.achName, fname) == 0)
+                {
+                    strcpy(fname, fb.achName);
+                    break;  /* there it is. Overwrite and stop searching. */
+                } /* if */
+
+                DosFindNext(hdir, &fb, sizeof (fb), &count);
+            } /* while */
+            DosFindClose(hdir);
+        } /* if */
+
+        *(fname - 1) = '\\';   /* unisolate parent dir. */
+        fname = ptr;           /* point to next element. */
+        if (ptr != NULL)
+        {
+            *ptr = '\\';       /* unisolate element. */
+            ptr = strchr(++fname, '\\');  /* find next element. */
+        } /* if */
+    } /* while */
+} /* cvt_file_to_correct_case */
+
+
+static char *baseDir = NULL;
+
+int __PHYSFS_platformInit(void)
+{
+    char buf[CCHMAXPATH];
+    APIRET rc;
+    PTIB ptib;
+    PPIB ppib;
+    PHYSFS_sint32 len;
+
+    assert(baseDir == NULL);
+    BAIL_IF_MACRO(os2err(DosGetInfoBlocks(&ptib, &ppib)) != NO_ERROR, NULL, 0);
+    rc = DosQueryModuleName(ppib->pib_hmte, sizeof (buf), (PCHAR) buf);
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0);
+
+    /* chop off filename, leave path. */
+    for (len = strlen(buf) - 1; len >= 0; len--)
+    {
+        if (buf[len] == '\\')
+        {
+            buf[len] = '\0';
+            break;
+        } /* if */
+    } /* for */
+
+    assert(len > 0);  /* should have been a "x:\\" on the front on string. */
+
+    /* The string is capitalized! Figure out the REAL case... */
+    cvt_path_to_correct_case(buf);
+
+    baseDir = (char *) allocator.Malloc(len + 1);
+    BAIL_IF_MACRO(baseDir == NULL, ERR_OUT_OF_MEMORY, 0);
+    strcpy(baseDir, buf);
+    return(1);  /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    assert(baseDir != NULL);
+    allocator.Free(baseDir);
+    baseDir = NULL;
+    return(1);  /* success. */
+} /* __PHYSFS_platformDeinit */
+
+
+static int disc_is_inserted(ULONG drive)
+{
+    int rc;
+    char buf[20];
+    DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
+    rc = DosQueryFSInfo(drive + 1, FSIL_VOLSER, buf, sizeof (buf));
+    DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
+    return(rc == NO_ERROR);
+} /* is_cdrom_inserted */
+
+
+/* looks like "CD01" in ASCII (littleendian)...used for an ioctl. */
+#define CD01 0x31304443
+
+static int is_cdrom_drive(ULONG drive)
+{
+    PHYSFS_uint32 param, data;
+    ULONG ul1, ul2;
+    APIRET rc;
+    HFILE hfile = NULLHANDLE;
+    char drivename[3] = { 'A' + drive, ':', '\0' };
+
+    rc = DosOpen(drivename, &hfile, &ul1, 0, 0,
+                 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
+                 OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
+                 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE, NULL);
+    BAIL_IF_MACRO(rc != NO_ERROR, NULL, 0);
+
+    data = 0;
+    param = PHYSFS_swapULE32(CD01);
+    ul1 = ul2 = sizeof (PHYSFS_uint32);
+    rc = DosDevIOCtl(hfile, IOCTL_CDROMDISK, CDROMDISK_GETDRIVER,
+                     &param, sizeof (param), &ul1, &data, sizeof (data), &ul2);
+
+    DosClose(hfile);
+    return((rc == NO_ERROR) && (PHYSFS_swapULE32(data) == CD01));
+} /* is_cdrom_drive */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    ULONG dummy = 0;
+    ULONG drivemap = 0;
+    ULONG i, bit;
+    APIRET rc = DosQueryCurrentDisk(&dummy, &drivemap);
+    if (os2err(rc) != NO_ERROR)
+        return;
+
+    for (i = 0, bit = 1; i < 26; i++, bit <<= 1)
+    {
+        if (drivemap & bit)  /* this logical drive exists. */
+        {
+            if ((is_cdrom_drive(i)) && (disc_is_inserted(i)))
+            {
+                char drive[4] = "x:\\";
+                drive[0] = ('A' + i);
+                cb(data, drive);
+            } /* if */
+        } /* if */
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    char *retval = (char *) allocator.Malloc(strlen(baseDir) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, baseDir); /* calculated at init time. */
+    return(retval);
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    return(NULL);  /* (*shrug*) */
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    return(__PHYSFS_platformCalcBaseDir(NULL));
+} /* __PHYSFS_platformGetUserDir */
+
+
+int __PHYSFS_platformExists(const char *fname)
+{
+    FILESTATUS3 fs;
+    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+    return(os2err(rc) == NO_ERROR);
+} /* __PHYSFS_platformExists */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
+{
+    return(0);  /* no symlinks in OS/2. */
+} /* __PHYSFS_platformIsSymlink */
+
+
+int __PHYSFS_platformIsDirectory(const char *fname)
+{
+    FILESTATUS3 fs;
+    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0)
+    return((fs.attrFile & FILE_DIRECTORY) != 0);
+} /* __PHYSFS_platformIsDirectory */
+
+
+/* !!! FIXME: can we lose the malloc here? */
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+              ((append) ? strlen(append) : 0) +
+              strlen(dirName) + 1;
+    char *retval = allocator.Malloc(len);
+    char *p;
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
+        *p = '\\';
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    char spec[CCHMAXPATH];
+    FILEFINDBUF3 fb;
+    HDIR hdir = HDIR_CREATE;
+    ULONG count = 1;
+    APIRET rc;
+
+    if (strlen(dirname) > sizeof (spec) - 5)
+    {
+        __PHYSFS_setError(ERR_BAD_FILENAME);
+        return;
+    } /* if */
+
+    strcpy(spec, dirname);
+    strcat(spec, (spec[strlen(spec) - 1] != '\\') ? "\\*.*" : "*.*");
+
+    rc = DosFindFirst(spec, &hdir,
+                      FILE_DIRECTORY | FILE_ARCHIVED |
+                      FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM,
+                      &fb, sizeof (fb), &count, FIL_STANDARD);
+
+    if (os2err(rc) != NO_ERROR)
+        return;
+
+    while (count == 1)
+    {
+        if ((strcmp(fb.achName, ".") != 0) && (strcmp(fb.achName, "..") != 0))
+            callback(callbackdata, origdir, fb.achName);
+
+        DosFindNext(hdir, &fb, sizeof (fb), &count);
+    } /* while */
+
+    DosFindClose(hdir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    char *retval;
+    ULONG currentDisk;
+    ULONG dummy;
+    ULONG pathSize = 0;
+    APIRET rc;
+    BYTE byte;
+
+    rc = DosQueryCurrentDisk(&currentDisk, &dummy);
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, NULL);
+
+    /* The first call just tells us how much space we need for the string. */
+    rc = DosQueryCurrentDir(currentDisk, &byte, &pathSize);
+    pathSize++; /* Add space for null terminator. */
+    retval = (char *) allocator.Malloc(pathSize + 3);  /* plus "x:\\" */
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    /* Actually get the string this time. */
+    rc = DosQueryCurrentDir(currentDisk, (PBYTE) (retval + 3), &pathSize);
+    if (os2err(rc) != NO_ERROR)
+    {
+        allocator.Free(retval);
+        return(NULL);
+    } /* if */
+
+    retval[0] = ('A' + (currentDisk - 1));
+    retval[1] = ':';
+    retval[2] = '\\';
+    return(retval);
+} /* __PHYSFS_platformCurrentDir */
+
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    char buf[CCHMAXPATH];
+    char *retval;
+    APIRET rc = DosQueryPathInfo(path, FIL_QUERYFULLNAME, buf, sizeof (buf));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, NULL);
+    retval = (char *) allocator.Malloc(strlen(buf) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, buf);
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    return(os2err(DosCreateDir(path, NULL)) == NO_ERROR);
+} /* __PHYSFS_platformMkDir */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    ULONG actionTaken = 0;
+    HFILE hfile = NULLHANDLE;
+
+    /*
+     * File must be opened SHARE_DENYWRITE and ACCESS_READONLY, otherwise
+     *  DosQueryFileInfo() will fail if we try to get a file length, etc.
+     */
+    os2err(DosOpen(filename, &hfile, &actionTaken, 0, FILE_NORMAL,
+                   OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
+                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
+                   OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
+                   OPEN_ACCESS_READONLY, NULL));
+
+    return((void *) hfile);
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    ULONG actionTaken = 0;
+    HFILE hfile = NULLHANDLE;
+
+    /*
+     * File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
+     *  DosQueryFileInfo() will fail if we try to get a file length, etc.
+     */
+    os2err(DosOpen(filename, &hfile, &actionTaken, 0, FILE_NORMAL,
+                   OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
+                   OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
+                   OPEN_ACCESS_READWRITE, NULL));
+
+    return((void *) hfile);
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    ULONG dummy = 0;
+    HFILE hfile = NULLHANDLE;
+    APIRET rc;
+
+    /*
+     * File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
+     *  DosQueryFileInfo() will fail if we try to get a file length, etc.
+     */
+    rc = os2err(DosOpen(filename, &hfile, &dummy, 0, FILE_NORMAL,
+                   OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
+                   OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
+                   OPEN_ACCESS_READWRITE, NULL));
+
+    if (rc == NO_ERROR)
+    {
+        if (os2err(DosSetFilePtr(hfile, 0, FILE_END, &dummy)) != NO_ERROR)
+        {
+            DosClose(hfile);
+            hfile = NULLHANDLE;
+        } /* if */
+    } /* if */
+
+    return((void *) hfile);
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HFILE hfile = (HFILE) opaque;
+    PHYSFS_sint64 retval;
+    ULONG br;
+
+    for (retval = 0; retval < count; retval++)
+    {
+        os2err(DosRead(hfile, buffer, size, &br));
+        if (br < size)
+        {
+            DosSetFilePtr(hfile, -br, FILE_CURRENT, &br); /* try to cleanup. */
+            return(retval);
+        } /* if */
+
+        buffer = (void *) ( ((char *) buffer) + size );
+    } /* for */
+
+    return(retval);
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HFILE hfile = (HFILE) opaque;
+    PHYSFS_sint64 retval;
+    ULONG bw;
+
+    for (retval = 0; retval < count; retval++)
+    {
+        os2err(DosWrite(hfile, buffer, size, &bw));
+        if (bw < size)
+        {
+            DosSetFilePtr(hfile, -bw, FILE_CURRENT, &bw); /* try to cleanup. */
+            return(retval);
+        } /* if */
+
+        buffer = (void *) ( ((char *) buffer) + size );
+    } /* for */
+
+    return(retval);
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    ULONG dummy;
+    HFILE hfile = (HFILE) opaque;
+    LONG dist = (LONG) pos;
+
+    /* hooray for 32-bit filesystem limits!  :) */
+    BAIL_IF_MACRO((PHYSFS_uint64) dist != pos, ERR_SEEK_OUT_OF_RANGE, 0);
+
+    return(os2err(DosSetFilePtr(hfile, dist, FILE_BEGIN, &dummy)) == NO_ERROR);
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    ULONG pos;
+    HFILE hfile = (HFILE) opaque;
+    APIRET rc = os2err(DosSetFilePtr(hfile, 0, FILE_CURRENT, &pos));
+    BAIL_IF_MACRO(rc != NO_ERROR, NULL, -1);
+    return((PHYSFS_sint64) pos);
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    FILESTATUS3 fs;
+    HFILE hfile = (HFILE) opaque;
+    APIRET rc = DosQueryFileInfo(hfile, FIL_STANDARD, &fs, sizeof (fs));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
+    return((PHYSFS_sint64) fs.cbFile);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformEOF(void *opaque)
+{
+    PHYSFS_sint64 len, pos;
+
+    len = __PHYSFS_platformFileLength(opaque);
+    BAIL_IF_MACRO(len == -1, NULL, 1);  /* (*shrug*) */
+    pos = __PHYSFS_platformTell(opaque);
+    BAIL_IF_MACRO(pos == -1, NULL, 1);  /* (*shrug*) */
+
+    return(pos >= len);
+} /* __PHYSFS_platformEOF */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    return(os2err(DosResetBuffer((HFILE) opaque)) == NO_ERROR);
+} /* __PHYSFS_platformFlush */
+
+
+int __PHYSFS_platformClose(void *opaque)
+{
+    return(os2err(DosClose((HFILE) opaque)) == NO_ERROR);
+} /* __PHYSFS_platformClose */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    if (__PHYSFS_platformIsDirectory(path))
+        return(os2err(DosDeleteDir(path)) == NO_ERROR);
+
+    return(os2err(DosDelete(path)) == NO_ERROR);
+} /* __PHYSFS_platformDelete */
+
+
+PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
+{
+    PHYSFS_sint64 retval;
+    struct tm tm;
+    FILESTATUS3 fs;
+    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
+
+    /* Convert to a format that mktime() can grok... */
+    tm.tm_sec = ((PHYSFS_uint32) fs.ftimeLastWrite.twosecs) * 2;
+    tm.tm_min = fs.ftimeLastWrite.minutes;
+    tm.tm_hour = fs.ftimeLastWrite.hours;
+    tm.tm_mday = fs.fdateLastWrite.day;
+    tm.tm_mon = fs.fdateLastWrite.month;
+    tm.tm_year = ((PHYSFS_uint32) fs.fdateLastWrite.year) + 80;
+    tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+    tm.tm_yday = -1;
+    tm.tm_isdst = -1;
+
+    /* Convert to a format PhysicsFS can grok... */
+    retval = (PHYSFS_sint64) mktime(&tm);
+    BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
+    return(retval);
+} /* __PHYSFS_platformGetLastModTime */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    PTIB ptib;
+    PPIB ppib;
+
+    /*
+     * Allegedly, this API never fails, but we'll punt and return a
+     *  default value (zero might as well do) if it does.
+     */
+    BAIL_IF_MACRO(os2err(DosGetInfoBlocks(&ptib, &ppib)) != NO_ERROR, 0, 0);
+    return((PHYSFS_uint64) ptib->tib_ordinal);
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    HMTX hmtx = NULLHANDLE;
+    os2err(DosCreateMutexSem(NULL, &hmtx, 0, 0));
+    return((void *) hmtx);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    DosCloseMutexSem((HMTX) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    /* Do _NOT_ call os2err() (which sets the physfs error msg) in here! */
+    return(DosRequestMutexSem((HMTX) mutex, SEM_INDEFINITE_WAIT) == NO_ERROR);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    DosReleaseMutexSem((HMTX) mutex);
+} /* __PHYSFS_platformReleaseMutex */
+
+
+/* !!! FIXME: Don't use C runtime for allocators? */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return(0);  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_OS2 */
+
+/* end of os2.c ... */
+
diff --git a/platform/pocketpc.c b/platform/pocketpc.c
new file mode 100644 (file)
index 0000000..15137fc
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * PocketPC support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_POCKETPC
+
+#include <stdio.h>
+#include <windows.h>
+
+#include "physfs_internal.h"
+
+#define INVALID_FILE_ATTRIBUTES  0xFFFFFFFF
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+typedef struct
+{
+    HANDLE handle;
+    int readonly;
+} winCEfile;
+
+
+const char *__PHYSFS_platformDirSeparator = "\\";
+static char *userDir = NULL;
+
+/*
+ * Figure out what the last failing Win32 API call was, and
+ *  generate a human-readable string for the error message.
+ *
+ * The return value is a static buffer that is overwritten with
+ *  each call to this function.
+ */
+static const char *win32strerror(void)
+{
+    static TCHAR msgbuf[255];
+    TCHAR *ptr = msgbuf;
+
+    FormatMessage(
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        GetLastError(),
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+        msgbuf,
+        sizeof (msgbuf) / sizeof (TCHAR),
+        NULL 
+        );
+
+    /* chop off newlines. */
+    for (ptr = msgbuf; *ptr; ptr++)
+    {
+        if ((*ptr == '\n') || (*ptr == '\r'))
+        {
+            *ptr = ' ';
+            break;
+        } /* if */
+    } /* for */
+
+    return((const char *) msgbuf);
+} /* win32strerror */
+
+
+/* !!! FIXME: need to check all of these for NULLs. */
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+    if (str == NULL) \
+        w_assignto = NULL; \
+    else { \
+        const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
+        w_assignto = (char *) __PHYSFS_smallAlloc(len); \
+        PHYSFS_uc2fromutf8(str, (PHYSFS_uint16 *) w_assignto, len); \
+    } \
+} \
+
+
+static char *getExePath()
+{
+    DWORD buflen;
+    int success = 0;
+    TCHAR *ptr = NULL;
+    TCHAR *retval = (TCHAR*) allocator.Malloc(sizeof (TCHAR) * (MAX_PATH + 1));
+    char *charretval;
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    retval[0] = _T('\0');
+    /* !!! FIXME: don't preallocate here? */
+    /* !!! FIXME: use smallAlloc? */
+    buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
+    if (buflen <= 0)
+        __PHYSFS_setError(win32strerror());
+    else
+    {
+        retval[buflen] = '\0';  /* does API always null-terminate this? */
+        ptr = retval+buflen;
+        while( ptr != retval )
+        {
+            if( *ptr != _T('\\') )
+                *ptr-- = _T('\0');
+            else
+                break;
+        } /* while */
+        success = 1;
+    } /* else */
+
+    if (!success)
+    {
+        allocator.Free(retval);
+        return(NULL);  /* physfs error message will be set, above. */
+    } /* if */
+
+    buflen = (buflen * 4) + 1;
+    charretval = (char *) allocator.Malloc(buflen);
+    if (charretval != NULL)
+        PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) retval, charretval, buflen);
+    allocator.Free(retval);
+    return(charretval);   /* w00t. */
+} /* getExePath */
+
+
+int __PHYSFS_platformInit(void)
+{
+    userDir = getExePath();
+    BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* failed? */
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    allocator.Free(userDir);
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    /* no-op on this platform. */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    return(getExePath());
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    return userDir;
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
+} /* __PHYSFS_platformGetUserDir */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return(1);  /* single threaded. */
+} /* __PHYSFS_platformGetThreadID */
+
+
+int __PHYSFS_platformExists(const char *fname)
+{
+    int retval = 0;
+    wchar_t *w_fname = NULL;
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
+    if (w_fname != NULL)
+        retval = (GetFileAttributes(w_fname) != INVALID_FILE_ATTRIBUTES);
+    __PHYSFS_smallFree(w_fname);
+
+    return(retval);
+} /* __PHYSFS_platformExists */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
+{
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, 0);
+} /* __PHYSFS_platformIsSymlink */
+
+
+int __PHYSFS_platformIsDirectory(const char *fname)
+{
+    int retval = 0;
+    wchar_t *w_fname = NULL;
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
+    if (w_fname != NULL)
+        retval = ((GetFileAttributes(w_fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    __PHYSFS_smallFree(w_fname);
+
+    return(retval);
+} /* __PHYSFS_platformIsDirectory */
+
+
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+    ((append) ? strlen(append) : 0) +
+    strlen(dirName) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    char *p;
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
+        *p = '\\';
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+static int doEnumCallback(const wchar_t *w_fname)
+{
+    const PHYSFS_uint64 len = (PHYSFS_uint64) ((wcslen(w_fname) * 4) + 1);
+    char *str = (char *) __PHYSFS_smallAlloc(len);
+    PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) w_fname, str, len);
+    callback(callbackdata, origdir, str);
+    __PHYSFS_smallFree(str);
+    return 1;
+} /* doEnumCallback */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    HANDLE dir;
+    WIN32_FIND_DATA ent;
+    char *SearchPath;
+    wchar_t *w_SearchPath;
+    size_t len = strlen(dirname);
+
+    /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
+    SearchPath = (char *) __PHYSFS_smallAlloc(len + 3);
+    BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);    
+
+    /* Copy current dirname */
+    strcpy(SearchPath, dirname);
+
+    /* if there's no '\\' at the end of the path, stick one in there. */
+    if (SearchPath[len - 1] != '\\')
+    {
+        SearchPath[len++] = '\\';
+        SearchPath[len] = '\0';
+    } /* if */
+
+    /* Append the "*" to the end of the string */
+    strcat(SearchPath, "*");
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_SearchPath, SearchPath);
+    __PHYSFS_smallFree(SearchPath);
+    dir = FindFirstFile(w_SearchPath, &ent);
+    __PHYSFS_smallFree(w_SearchPath);
+
+    if (dir == INVALID_HANDLE_VALUE)
+        return;
+
+    do
+    {
+        const char *str = NULL;
+
+        if (wcscmp(ent.cFileName, L".") == 0)
+            continue;
+
+        if (wcscmp(ent.cFileName, L"..") == 0)
+            continue;
+
+        if (!doEnumCallback(ent.cFileName))
+            break;
+    } while (FindNextFile(dir, &ent) != 0);
+
+    FindClose(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return("\\");
+} /* __PHYSFS_platformCurrentDir */
+
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    char *retval = (char *) allocator.Malloc(strlen(path) + 1);
+    strcpy(retval,path);
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    int retval = 0;
+    wchar_t *w_path = NULL;
+    UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
+    if (w_path != NULL)
+    {
+        retval = CreateDirectory(w_path, NULL);
+        __PHYSFS_smallFree(w_fname);
+    } /* if */
+    return(retval);
+} /* __PHYSFS_platformMkDir */
+
+
+static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
+{
+    HANDLE fileHandle;
+    winCEfile *retval;
+    wchar_t *w_fname = NULL;
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
+    fileHandle = CreateFile(w_fname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                            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/platform/posix.c b/platform/posix.c
new file mode 100644 (file)
index 0000000..dd7a209
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Posix-esque support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_POSIX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef PHYSFS_HAVE_LLSEEK
+#include <linux/unistd.h>
+#endif
+
+#include "physfs_internal.h"
+
+
+const char *__PHYSFS_platformDirSeparator = "/";
+
+
+char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
+{
+    const char *envr = getenv(varname);
+    char *retval = NULL;
+
+    if (envr != NULL)
+    {
+        retval = (char *) allocator.Malloc(strlen(envr) + 1);
+        if (retval != NULL)
+            strcpy(retval, envr);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformCopyEnvironmentVariable */
+
+
+static char *getUserNameByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_name != NULL))
+    {
+        retval = (char *) allocator.Malloc(strlen(pw->pw_name) + 1);
+        if (retval != NULL)
+            strcpy(retval, pw->pw_name);
+    } /* if */
+    
+    return(retval);
+} /* getUserNameByUID */
+
+
+static char *getUserDirByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_dir != NULL))
+    {
+        retval = (char *) allocator.Malloc(strlen(pw->pw_dir) + 1);
+        if (retval != NULL)
+            strcpy(retval, pw->pw_dir);
+    } /* if */
+    
+    return(retval);
+} /* getUserDirByUID */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    char *retval = getUserNameByUID();
+    if (retval == NULL)
+        retval = __PHYSFS_platformCopyEnvironmentVariable("USER");
+    return(retval);
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
+
+    /* if the environment variable was set, make sure it's really a dir. */
+    if (retval != NULL)
+    {
+        struct stat statbuf;
+        if ((stat(retval, &statbuf) == -1) || (S_ISDIR(statbuf.st_mode) == 0))
+        {
+            allocator.Free(retval);
+            retval = NULL;
+        } /* if */
+    } /* if */
+
+    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)
+{
+    const int appending = (mode & O_APPEND);
+    int fd;
+    int *retval;
+    errno = 0;
+
+    /* O_APPEND doesn't actually behave as we'd like. */
+    mode &= ~O_APPEND;
+
+    fd = open(filename, mode, S_IRUSR | S_IWUSR);
+    BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
+
+    if (appending)
+    {
+        if (lseek(fd, 0, SEEK_END) < 0)
+        {
+            close(fd);
+            BAIL_MACRO(strerror(errno), NULL);
+        } /* if */
+    } /* if */
+
+    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/platform/unix.c b/platform/unix.c
new file mode 100644 (file)
index 0000000..4e714b4
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Unix support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_UNIX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <time.h>
+#include <errno.h>
+
+#if (!defined PHYSFS_NO_THREAD_SUPPORT)
+#include <pthread.h>
+#endif
+
+#ifdef PHYSFS_HAVE_SYS_UCRED_H
+#  ifdef PHYSFS_HAVE_MNTENT_H
+#    undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
+#  endif
+#  include <sys/ucred.h>
+#  include <sys/mount.h>
+#endif
+
+#ifdef PHYSFS_HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#include "physfs_internal.h"
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+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;
+        else if (strcmp(ent->mnt_type, "udf") == 0)
+            add_it = 1;
+
+        /* !!! FIXME: these might pick up floppy drives, right? */
+        else if (strcmp(ent->mnt_type, "auto") == 0)
+            add_it = 1;
+        else if (strcmp(ent->mnt_type, "supermount") == 0)
+            add_it = 1;
+
+        /* 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 */
+
+
+static char *readSymLink(const char *path)
+{
+    ssize_t len = 64;
+    ssize_t rc = -1;
+    char *retval = NULL;
+
+    while (1)
+    {
+         char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
+         if (ptr == NULL)
+             break;   /* out of memory. */
+         retval = ptr;
+
+         rc = readlink(path, retval, len);
+         if (rc == -1)
+             break;  /* not a symlink, i/o error, etc. */
+
+         else if (rc < len)
+         {
+             retval[rc] = '\0';  /* readlink doesn't null-terminate. */
+             return retval;  /* we're good to go. */
+         } /* else if */
+
+         len *= 2;  /* grow buffer, try again. */
+    } /* while */
+
+    if (retval != NULL)
+        allocator.Free(retval);
+    return NULL;
+} /* readSymLink */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    char *retval = NULL;
+    char *envr = NULL;
+
+    /* 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.
+     */
+    retval = readSymLink("/proc/self/exe");
+    if (retval == NULL)
+    {
+        /* older kernels don't have /proc/self ... try PID version... */
+        const unsigned long long pid = (unsigned long long) getpid();
+        char path[64];
+        const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
+        if ( (rc > 0) && (rc < sizeof(path)) )
+            retval = readSymLink(path);
+    } /* if */
+
+    if (retval != NULL)  /* chop off filename. */
+    {
+        char *ptr = strrchr(retval, '/');
+        if (ptr != NULL)
+            *ptr = '\0';
+    } /* 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 */
+
+    if (retval != NULL)
+    {
+        /* try to shrink buffer... */
+        char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
+        if (ptr != NULL)
+            retval = ptr;  /* oh well if it failed. */
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_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_THREAD_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_THREAD_SUPPORT */
+
+#endif /* PHYSFS_PLATFORM_UNIX */
+
+/* end of unix.c ... */
+
diff --git a/platform/windows.c b/platform/windows.c
new file mode 100644 (file)
index 0000000..b50952e
--- /dev/null
@@ -0,0 +1,1403 @@
+/*
+ * Windows support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon, and made sane by Gregory S. Read.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_WINDOWS
+
+/* Forcibly disable UNICODE, since we manage this ourselves. */
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "physfs_internal.h"
+
+#define LOWORDER_UINT64(pos) ((PHYSFS_uint32) (pos & 0xFFFFFFFF))
+#define HIGHORDER_UINT64(pos) ((PHYSFS_uint32) ((pos >> 32) & 0xFFFFFFFF))
+
+/*
+ * Users without the platform SDK don't have this defined.  The original docs
+ *  for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
+ *  work as desired.
+ */
+#define PHYSFS_INVALID_SET_FILE_POINTER  0xFFFFFFFF
+
+/* just in case... */
+#define PHYSFS_INVALID_FILE_ATTRIBUTES   0xFFFFFFFF
+
+/* Not defined before the Vista SDK. */
+#define PHYSFS_IO_REPARSE_TAG_SYMLINK    0xA000000C
+
+
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+    if (str == NULL) \
+        w_assignto = NULL; \
+    else { \
+        const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) + 1) * 2); \
+        w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \
+        if (w_assignto != NULL) \
+            PHYSFS_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 */
+
+
+#if (PHYSFS_MINIMUM_GCC_VERSION(3,3))
+    typedef FARPROC __attribute__((__may_alias__)) PHYSFS_FARPROC;
+#else
+    typedef FARPROC PHYSFS_FARPROC;
+#endif
+
+
+static void symLookup(HMODULE dll, PHYSFS_FARPROC *addr, const char *sym,
+                      int reallyLook, PHYSFS_FARPROC fallback)
+{
+    PHYSFS_FARPROC proc;
+    proc = (PHYSFS_FARPROC) ((reallyLook) ? GetProcAddress(dll, sym) : NULL);
+    if (proc == NULL)
+        proc = fallback;  /* may also be NULL. */
+    *addr = proc;
+} /* symLookup */
+
+
+static int findApiSymbols(void)
+{
+    HMODULE dll = NULL;
+
+    #define LOOKUP_NOFALLBACK(x, reallyLook) \
+        symLookup(dll, (PHYSFS_FARPROC *) &p##x, #x, reallyLook, NULL)
+
+    #define LOOKUP(x, reallyLook) \
+        symLookup(dll, (PHYSFS_FARPROC *) &p##x, #x, \
+                  reallyLook, (PHYSFS_FARPROC) 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);
+
+    if (rc == 0)
+        msgbuf[0] = '\0';  /* oh well. */
+
+    /* 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;
+    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: this should return NULL if (path) doesn't exist? */
+    /* !!! FIXME: Need to handle symlinks in Vista... */
+    /* !!! 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 | FILE_SHARE_WRITE,
+                              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;
+    LONG HighOrderPos;
+    PLONG pHighOrderPos;
+    DWORD rc;
+
+    /* Get the high order 32-bits of the position */
+    HighOrderPos = HIGHORDER_UINT64(pos);
+
+    /*
+     * MSDN: "If you do not need the high-order 32 bits, this
+     *         pointer must be set to NULL."
+     */
+    pHighOrderPos = (HighOrderPos) ? &HighOrderPos : NULL;
+
+    /*
+     * !!! 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;
+    LONG HighPos = 0;
+    DWORD LowPos;
+    PHYSFS_sint64 retval;
+
+    /* Get current position */
+    LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
+    if ( (LowPos == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(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/test/test_physfs.c b/test/test_physfs.c
new file mode 100644 (file)
index 0000000..2b2f446
--- /dev/null
@@ -0,0 +1,1224 @@
+/**
+ * Test program for PhysicsFS. May only work on Unix.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#if (defined __MWERKS__)
+#include <SIOUX.h>
+#endif
+
+#if (defined PHYSFS_HAVE_READLINE)
+#include <unistd.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include <time.h>
+
+#include "physfs.h"
+
+#define TEST_VERSION_MAJOR  2
+#define TEST_VERSION_MINOR  0
+#define TEST_VERSION_PATCH  2
+
+static FILE *history_file = NULL;
+static PHYSFS_uint32 do_buffer_size = 0;
+
+static void output_versions(void)
+{
+    PHYSFS_Version compiled;
+    PHYSFS_Version linked;
+
+    PHYSFS_VERSION(&compiled);
+    PHYSFS_getLinkedVersion(&linked);
+
+    printf("test_physfs version %d.%d.%d.\n"
+           " Compiled against PhysicsFS version %d.%d.%d,\n"
+           " and linked against %d.%d.%d.\n\n",
+            TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH,
+            (int) compiled.major, (int) compiled.minor, (int) compiled.patch,
+            (int) linked.major, (int) linked.minor, (int) linked.patch);
+} /* output_versions */
+
+
+static void output_archivers(void)
+{
+    const PHYSFS_ArchiveInfo **rc = PHYSFS_supportedArchiveTypes();
+    const PHYSFS_ArchiveInfo **i;
+
+    printf("Supported archive types:\n");
+    if (*rc == NULL)
+        printf(" * Apparently, NONE!\n");
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            printf(" * %s: %s\n    Written by %s.\n    %s\n",
+                    (*i)->extension, (*i)->description,
+                    (*i)->author, (*i)->url);
+        } /* for */
+    } /* else */
+
+    printf("\n");
+} /* output_archivers */
+
+
+static int cmd_quit(char *args)
+{
+    return(0);
+} /* cmd_quit */
+
+
+static int cmd_init(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_init(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_init */
+
+
+static int cmd_deinit(char *args)
+{
+    if (PHYSFS_deinit())
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_deinit */
+
+
+static int cmd_addarchive(char *args)
+{
+    char *ptr = strrchr(args, ' ');
+    int appending = atoi(ptr + 1);
+    *ptr = '\0';
+
+    if (*args == '\"')
+    {
+        args++;
+        *(ptr - 1) = '\0';
+    } /* if */
+
+    /*printf("[%s], [%d]\n", args, appending);*/
+
+    if (PHYSFS_addToSearchPath(args, appending))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_addarchive */
+
+
+static int cmd_mount(char *args)
+{
+    char *ptr;
+    char *mntpoint = NULL;
+    int appending = 0;
+
+    if (*args == '\"')
+    {
+        args++;
+        ptr = strchr(args, '\"');
+        if (ptr == NULL)
+        {
+            printf("missing string terminator in argument.\n");
+            return(1);
+        } /* if */
+        *(ptr) = '\0';
+    } /* if */
+    else
+    {
+        ptr = strchr(args, ' ');
+        *ptr = '\0';
+    } /* else */
+
+    mntpoint = ptr + 1;
+    if (*mntpoint == '\"')
+    {
+        mntpoint++;
+        ptr = strchr(mntpoint, '\"');
+        if (ptr == NULL)
+        {
+            printf("missing string terminator in argument.\n");
+            return(1);
+        } /* if */
+        *(ptr) = '\0';
+    } /* if */
+    else
+    {
+        ptr = strchr(mntpoint, ' ');
+        *(ptr) = '\0';
+    } /* else */
+    appending = atoi(ptr + 1);
+
+    /*printf("[%s], [%s], [%d]\n", args, mntpoint, appending);*/
+
+    if (PHYSFS_mount(args, mntpoint, appending))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_mount */
+
+
+static int cmd_removearchive(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_removeFromSearchPath(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_removearchive */
+
+
+static int cmd_enumerate(char *args)
+{
+    char **rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_enumerateFiles(args);
+
+    if (rc == NULL)
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+    else
+    {
+        int file_count;
+        char **i;
+        for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) files.\n", file_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_enumerate */
+
+
+static int cmd_getdirsep(char *args)
+{
+    printf("Directory separator is [%s].\n", PHYSFS_getDirSeparator());
+    return(1);
+} /* cmd_getdirsep */
+
+
+static int cmd_getlasterror(char *args)
+{
+    printf("last error is [%s].\n", PHYSFS_getLastError());
+    return(1);
+} /* cmd_getlasterror */
+
+
+static int cmd_getcdromdirs(char *args)
+{
+    char **rc = PHYSFS_getCdRomDirs();
+
+    if (rc == NULL)
+        printf("Failure. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        int dir_count;
+        char **i;
+        for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) drives.\n", dir_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getcdromdirs */
+
+
+static int cmd_getsearchpath(char *args)
+{
+    char **rc = PHYSFS_getSearchPath();
+
+    if (rc == NULL)
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+    else
+    {
+        int dir_count;
+        char **i;
+        for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) directories.\n", dir_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getcdromdirs */
+
+
+static int cmd_getbasedir(char *args)
+{
+    printf("Base dir is [%s].\n", PHYSFS_getBaseDir());
+    return(1);
+} /* cmd_getbasedir */
+
+
+static int cmd_getuserdir(char *args)
+{
+    printf("User dir is [%s].\n", PHYSFS_getUserDir());
+    return(1);
+} /* cmd_getuserdir */
+
+
+static int cmd_getwritedir(char *args)
+{
+    printf("Write dir is [%s].\n", PHYSFS_getWriteDir());
+    return(1);
+} /* cmd_getwritedir */
+
+
+static int cmd_setwritedir(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_setWriteDir(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_setwritedir */
+
+
+static int cmd_permitsyms(char *args)
+{
+    int num;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    num = atoi(args);
+    PHYSFS_permitSymbolicLinks(num);
+    printf("Symlinks are now %s.\n", num ? "permitted" : "forbidden");
+    return(1);
+} /* cmd_permitsyms */
+
+
+static int cmd_setbuffer(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    do_buffer_size = (unsigned int) atoi(args);
+    if (do_buffer_size)
+    {
+        printf("Further tests will set a (%lu) size buffer.\n",
+                (unsigned long) do_buffer_size);
+    } /* if */
+
+    else
+    {
+        printf("Further tests will NOT use a buffer.\n");
+    } /* else */
+
+    return(1);
+} /* cmd_setbuffer */
+
+
+static int cmd_stressbuffer(char *args)
+{
+    int num;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    num = atoi(args);
+    if (num < 0)
+        printf("buffer must be greater than or equal to zero.\n");
+    else
+    {
+        PHYSFS_File *f;
+        int rndnum;
+
+        printf("Stress testing with (%d) byte buffer...\n", num);
+        f = PHYSFS_openWrite("test.txt");
+        if (f == NULL)
+            printf("Couldn't open test.txt for writing: %s.\n", PHYSFS_getLastError());
+        else
+        {
+            int i, j;
+            char buf[37];
+            char buf2[37];
+
+            if (!PHYSFS_setBuffer(f, num))
+            {
+                printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
+                PHYSFS_close(f);
+                PHYSFS_delete("test.txt");
+                return(1);
+            } /* if */
+
+            strcpy(buf, "abcdefghijklmnopqrstuvwxyz0123456789");
+            srand((unsigned int) time(NULL));
+
+            for (i = 0; i < 10; i++)
+            {
+                for (j = 0; j < 10000; j++)
+                {
+                    PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
+                    PHYSFS_uint32 left = 36 - right;
+                    if (PHYSFS_write(f, buf, left, 1) != 1)
+                    {
+                        printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (PHYSFS_write(f, buf + left, 1, right) != right)
+                    {
+                        printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+                } /* for */
+
+                if (!PHYSFS_flush(f))
+                {
+                    printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                    PHYSFS_close(f);
+                    return(1);
+                } /* if */
+
+            } /* for */
+
+            if (!PHYSFS_close(f))
+            {
+                printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
+                return(1);  /* oh well. */
+            } /* if */
+
+            printf(" ... test file written ...\n");
+            f = PHYSFS_openRead("test.txt");
+            if (f == NULL)
+            {
+                printf("Failed to reopen stress file for reading: %s.\n", PHYSFS_getLastError());
+                return(1);
+            } /* if */
+
+            if (!PHYSFS_setBuffer(f, num))
+            {
+                printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+
+            for (i = 0; i < 10; i++)
+            {
+                for (j = 0; j < 10000; j++)
+                {
+                    PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
+                    PHYSFS_uint32 left = 36 - right;
+                    if (PHYSFS_read(f, buf2, left, 1) != 1)
+                    {
+                        printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (PHYSFS_read(f, buf2 + left, 1, right) != right)
+                    {
+                        printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (memcmp(buf, buf2, 36) != 0)
+                    {
+                        printf("readback is mismatched on iterations (%d, %d).\n", i, j);
+                        printf("wanted: [");
+                        for (i = 0; i < 36; i++)
+                            printf("%c", buf[i]);
+                        printf("]\n");
+
+                        printf("   got: [");
+                        for (i = 0; i < 36; i++)
+                            printf("%c", buf2[i]);
+                        printf("]\n");
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+                } /* for */
+
+                if (!PHYSFS_flush(f))
+                {
+                    printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                    PHYSFS_close(f);
+                    return(1);
+                } /* if */
+
+            } /* for */
+
+            printf(" ... test file read ...\n");
+
+            if (!PHYSFS_eof(f))
+                printf("PHYSFS_eof() returned true! That's wrong.\n");
+
+            if (!PHYSFS_close(f))
+            {
+                printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
+                return(1);  /* oh well. */
+            } /* if */
+
+            PHYSFS_delete("test.txt");
+            printf("stress test completed successfully.\n");
+        } /* else */
+    } /* else */
+
+    return(1);
+} /* cmd_stressbuffer */
+
+
+static int cmd_setsaneconfig(char *args)
+{
+    char *org;
+    char *appName;
+    char *arcExt;
+    int inclCD;
+    int arcsFirst;
+    char *ptr = args;
+
+        /* ugly. */
+    org = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; arcExt = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; inclCD = atoi(arcExt);
+    arcsFirst = atoi(ptr);
+
+    if (strcmp(arcExt, "!") == 0)
+        arcExt = NULL;
+
+    if (PHYSFS_setSaneConfig(org, appName, arcExt, inclCD, arcsFirst))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_setsaneconfig */
+
+
+static int cmd_mkdir(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_mkdir(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_mkdir */
+
+
+static int cmd_delete(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_delete(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_delete */
+
+
+static int cmd_getrealdir(char *args)
+{
+    const char *rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_getRealDir(args);
+    if (rc)
+        printf("Found at [%s].\n", rc);
+    else
+        printf("Not found.\n");
+
+    return(1);
+} /* cmd_getrealdir */
+
+
+static int cmd_exists(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_exists(args);
+    printf("File %sexists.\n", rc ? "" : "does not ");
+    return(1);
+} /* cmd_exists */
+
+
+static int cmd_isdir(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_isDirectory(args);
+    printf("File %s a directory.\n", rc ? "is" : "is NOT");
+    return(1);
+} /* cmd_isdir */
+
+
+static int cmd_issymlink(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_isSymbolicLink(args);
+    printf("File %s a symlink.\n", rc ? "is" : "is NOT");
+    return(1);
+} /* cmd_issymlink */
+
+
+static int cmd_cat(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openRead(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        while (1)
+        {
+            char buffer[128];
+            PHYSFS_sint64 rc;
+            PHYSFS_sint64 i;
+            rc = PHYSFS_read(f, buffer, 1, sizeof (buffer));
+
+            for (i = 0; i < rc; i++)
+                fputc((int) buffer[i], stdout);
+
+            if (rc < sizeof (buffer))
+            {
+                printf("\n\n");
+                if (!PHYSFS_eof(f))
+                {
+                    printf("\n (Error condition in reading. Reason: [%s])\n\n",
+                           PHYSFS_getLastError());
+                } /* if */
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* while */
+    } /* else */
+
+    return(1);
+} /* cmd_cat */
+
+
+static int cmd_filelength(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openRead(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(f);
+        if (len == -1)
+            printf("failed to determine length. Reason: [%s].\n", PHYSFS_getLastError());
+        else
+            printf(" (cast to int) %d bytes.\n", (int) len);
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_filelength */
+
+
+#define WRITESTR "The cat sat on the mat.\n\n"
+
+static int cmd_append(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openAppend(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        size_t bw;
+        PHYSFS_sint64 rc;
+
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        bw = strlen(WRITESTR);
+        rc = PHYSFS_write(f, WRITESTR, 1, bw);
+        if (rc != bw)
+        {
+            printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
+                   (int) rc, (int) bw, PHYSFS_getLastError());
+        } /* if */
+        else
+        {
+            printf("Successful.\n");
+        } /* else */
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_append */
+
+
+static int cmd_write(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openWrite(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        size_t bw;
+        PHYSFS_sint64 rc;
+
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        bw = strlen(WRITESTR);
+        rc = PHYSFS_write(f, WRITESTR, 1, bw);
+        if (rc != bw)
+        {
+            printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
+                   (int) rc, (int) bw, PHYSFS_getLastError());
+        } /* if */
+        else
+        {
+            printf("Successful.\n");
+        } /* else */
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_write */
+
+
+static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
+{
+    time_t t = (time_t) modtime;
+    char *str = ctime(&t);
+    strncpy(modstr, str, strsize);
+    modstr[strsize-1] = '\0';
+} /* modTimeToStr */
+
+
+static int cmd_getlastmodtime(char *args)
+{
+    PHYSFS_sint64 rc = PHYSFS_getLastModTime(args);
+    if (rc == -1)
+        printf("Failed to determine. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        char modstr[64];
+        modTimeToStr(rc, modstr, sizeof (modstr));
+        printf("Last modified: %s (%ld).\n", modstr, (long) rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getLastModTime */
+
+
+/* must have spaces trimmed prior to this call. */
+static int count_args(const char *str)
+{
+    int retval = 0;
+    int in_quotes = 0;
+
+    if (str != NULL)
+    {
+        for (; *str != '\0'; str++)
+        {
+            if (*str == '\"')
+                in_quotes = !in_quotes;
+            else if ((*str == ' ') && (!in_quotes))
+                retval++;
+        } /* for */
+        retval++;
+    } /* if */
+
+    return(retval);
+} /* count_args */
+
+
+static int cmd_help(char *args);
+
+typedef struct
+{
+    const char *cmd;
+    int (*func)(char *args);
+    int argcount;
+    const char *usage;
+} command_info;
+
+static const command_info commands[] =
+{
+    { "quit",           cmd_quit,           0, NULL                         },
+    { "q",              cmd_quit,           0, NULL                         },
+    { "help",           cmd_help,           0, NULL                         },
+    { "init",           cmd_init,           1, "<argv0>"                    },
+    { "deinit",         cmd_deinit,         0, NULL                         },
+    { "addarchive",     cmd_addarchive,     2, "<archiveLocation> <append>" },
+    { "mount",          cmd_mount,          3, "<archiveLocation> <mntpoint> <append>" },
+    { "removearchive",  cmd_removearchive,  1, "<archiveLocation>"          },
+    { "enumerate",      cmd_enumerate,      1, "<dirToEnumerate>"           },
+    { "ls",             cmd_enumerate,      1, "<dirToEnumerate>"           },
+    { "getlasterror",   cmd_getlasterror,   0, NULL                         },
+    { "getdirsep",      cmd_getdirsep,      0, NULL                         },
+    { "getcdromdirs",   cmd_getcdromdirs,   0, NULL                         },
+    { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
+    { "getbasedir",     cmd_getbasedir,     0, NULL                         },
+    { "getuserdir",     cmd_getuserdir,     0, NULL                         },
+    { "getwritedir",    cmd_getwritedir,    0, NULL                         },
+    { "setwritedir",    cmd_setwritedir,    1, "<newWriteDir>"              },
+    { "permitsymlinks", cmd_permitsyms,     1, "<1or0>"                     },
+    { "setsaneconfig",  cmd_setsaneconfig,  5, "<org> <appName> <arcExt> <includeCdRoms> <archivesFirst>" },
+    { "mkdir",          cmd_mkdir,          1, "<dirToMk>"                  },
+    { "delete",         cmd_delete,         1, "<dirToDelete>"              },
+    { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
+    { "exists",         cmd_exists,         1, "<fileToCheck>"              },
+    { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
+    { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
+    { "cat",            cmd_cat,            1, "<fileToCat>"                },
+    { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
+    { "append",         cmd_append,         1, "<fileToAppend>"             },
+    { "write",          cmd_write,          1, "<fileToCreateOrTrash>"      },
+    { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
+    { "setbuffer",      cmd_setbuffer,      1, "<bufferSize>"               },
+    { "stressbuffer",   cmd_stressbuffer,   1, "<bufferSize>"               },
+    { NULL,             NULL,              -1, NULL                         }
+};
+
+
+static void output_usage(const char *intro, const command_info *cmdinfo)
+{
+    if (cmdinfo->argcount == 0)
+        printf("%s \"%s\" (no arguments)\n", intro, cmdinfo->cmd);
+    else
+        printf("%s \"%s %s\"\n", intro, cmdinfo->cmd, cmdinfo->usage);
+} /* output_usage */
+
+
+static int cmd_help(char *args)
+{
+    const command_info *i;
+
+    printf("Commands:\n");
+    for (i = commands; i->cmd != NULL; i++)
+        output_usage("  -", i);
+
+    return(1);
+} /* output_cmd_help */
+
+
+static void trim_command(const char *orig, char *copy)
+{
+    const char *i;
+    char *writeptr = copy;
+    int spacecount = 0;
+    int have_first = 0;
+
+    for (i = orig; *i != '\0'; i++)
+    {
+        if (*i == ' ')
+        {
+            if ((*(i + 1) != ' ') && (*(i + 1) != '\0'))
+            {
+                if ((have_first) && (!spacecount))
+                {
+                    spacecount++;
+                    *writeptr = ' ';
+                    writeptr++;
+                } /* if */
+            } /* if */
+        } /* if */
+        else
+        {
+            have_first = 1;
+            spacecount = 0;
+            *writeptr = *i;
+            writeptr++;
+        } /* else */
+    } /* for */
+
+    *writeptr = '\0';
+
+    /*
+    printf("\n command is [%s].\n", copy);
+    */
+} /* trim_command */
+
+
+static int process_command(char *complete_cmd)
+{
+    const command_info *i;
+    char *cmd_copy;
+    char *args;
+    int rc = 1;
+
+    if (complete_cmd == NULL)  /* can happen if user hits CTRL-D, etc. */
+    {
+        printf("\n");
+        return(0);
+    } /* if */
+
+    cmd_copy = (char *) malloc(strlen(complete_cmd) + 1);
+    if (cmd_copy == NULL)
+    {
+        printf("\n\n\nOUT OF MEMORY!\n\n\n");
+        return(0);
+    } /* if */
+
+    trim_command(complete_cmd, cmd_copy);
+    args = strchr(cmd_copy, ' ');
+    if (args != NULL)
+    {
+        *args = '\0';
+        args++;
+    } /* else */
+
+    if (cmd_copy[0] != '\0')
+    {
+        for (i = commands; i->cmd != NULL; i++)
+        {
+            if (strcmp(i->cmd, cmd_copy) == 0)
+            {
+                if ((i->argcount >= 0) && (count_args(args) != i->argcount))
+                    output_usage("usage:", i);
+                else
+                    rc = i->func(args);
+                break;
+            } /* if */
+        } /* for */
+
+        if (i->cmd == NULL)
+            printf("Unknown command. Enter \"help\" for instructions.\n");
+
+#if (defined PHYSFS_HAVE_READLINE)
+        add_history(complete_cmd);
+        if (history_file)
+        {
+            fprintf(history_file, "%s\n", complete_cmd);
+            fflush(history_file);
+        } /* if */
+#endif
+
+    } /* if */
+
+    free(cmd_copy);
+    return(rc);
+} /* process_command */
+
+
+static void open_history_file(void)
+{
+#if (defined PHYSFS_HAVE_READLINE)
+#if 0
+    const char *envr = getenv("TESTPHYSFS_HISTORY");
+    if (!envr)
+        return;
+#else
+    char envr[256];
+    strcpy(envr, PHYSFS_getUserDir());
+    strcat(envr, ".testphys_history");
+#endif
+
+    if (access(envr, F_OK) == 0)
+    {
+        char buf[512];
+        FILE *f = fopen(envr, "r");
+        if (!f)
+        {
+            printf("\n\n"
+                   "Could not open history file [%s] for reading!\n"
+                   "  Will not have past history available.\n\n",
+                    envr);
+            return;
+        } /* if */
+
+        do
+        {
+            if (fgets(buf, sizeof (buf), f) == NULL)
+                break;
+
+            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/test/wxtest_physfs.cpp b/test/wxtest_physfs.cpp
new file mode 100644 (file)
index 0000000..96b993b
--- /dev/null
@@ -0,0 +1,486 @@
+/**
+ * Test program for PhysicsFS, using wxWidgets. May only work on Unix.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
+#define PLATFORM_MACOSX 1
+#include <Carbon/Carbon.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <wx/wx.h>
+#include <wx/treectrl.h>
+
+#include "physfs.h"
+
+#define TEST_VER_MAJOR  2
+#define TEST_VER_MINOR  0
+#define TEST_VER_PATCH  2
+
+//static PHYSFS_uint32 do_buffer_size = 0;
+
+enum WxTestPhysfsMenuCommands
+{
+    // start with standard menu items, since using the wxIDs will map them
+    //  to sane things in the platform's UI (gnome icons in GTK+, moves the
+    //  about and quit items to the Apple menu on Mac OS X, etc).
+    MENUCMD_About = wxID_ABOUT,
+    MENUCMD_Quit = wxID_EXIT,
+
+    // non-standard menu items go here.
+    MENUCMD_Init = wxID_HIGHEST,
+    MENUCMD_Deinit,
+    MENUCMD_AddArchive,
+    MENUCMD_Mount,
+    MENUCMD_Remove,
+    MENUCMD_GetCDs,
+    MENUCMD_SetWriteDir,
+    MENUCMD_PermitSymLinks,
+    MENUCMD_SetSaneConfig,
+    MENUCMD_MkDir,
+    MENUCMD_Delete,
+    MENUCMD_Cat,
+    MENUCMD_SetBuffer,
+    MENUCMD_StressBuffer,
+    MENUCMD_Append,
+    MENUCMD_Write,
+    MENUCMD_GetLastError,
+
+/*
+    { "getdirsep",      cmd_getdirsep,      0, NULL                         },
+    { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
+    { "getbasedir",     cmd_getbasedir,     0, NULL                         },
+    { "getuserdir",     cmd_getuserdir,     0, NULL                         },
+    { "getwritedir",    cmd_getwritedir,    0, NULL                         },
+    { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
+    { "exists",         cmd_exists,         1, "<fileToCheck>"              },
+    { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
+    { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
+    { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
+    { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
+*/
+};
+
+
+class WxTestPhysfsFrame : public wxFrame
+{
+public:
+    WxTestPhysfsFrame(const wxChar *argv0);
+
+    void rebuildTree();
+
+    void onMenuInit(wxCommandEvent &evt);
+    void onMenuDeinit(wxCommandEvent &evt);
+    void onMenuAddArchive(wxCommandEvent &evt);
+    void onMenuGetCDs(wxCommandEvent &evt);
+    void onMenuPermitSymLinks(wxCommandEvent &evt);
+
+private:
+    wxTreeCtrl *fileTree;
+    wxTreeItemId stateItem;
+    wxTreeItemId fsItem;
+
+    int err(int success);
+    void fillFileSystemTree(const char *path, const wxTreeItemId &item);
+    void doInit(const char *argv0);
+    void doDeinit();
+
+    DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(WxTestPhysfsFrame, wxFrame)
+    EVT_MENU(MENUCMD_Init, WxTestPhysfsFrame::onMenuInit)
+    EVT_MENU(MENUCMD_Deinit, WxTestPhysfsFrame::onMenuDeinit)
+    EVT_MENU(MENUCMD_AddArchive, WxTestPhysfsFrame::onMenuAddArchive)
+    EVT_MENU(MENUCMD_GetCDs, WxTestPhysfsFrame::onMenuGetCDs)
+    EVT_MENU(MENUCMD_PermitSymLinks, WxTestPhysfsFrame::onMenuPermitSymLinks)
+END_EVENT_TABLE()
+
+
+
+// This is the the Application itself.
+class WxTestPhysfsApp : public wxApp
+{
+public:
+    WxTestPhysfsApp() : mainWindow(NULL) { /* no-op. */ }
+    virtual bool OnInit();
+
+private:
+    WxTestPhysfsFrame *mainWindow;
+};
+
+DECLARE_APP(WxTestPhysfsApp)
+
+
+static inline char *newstr(const char *str)
+{
+    char *retval = NULL;
+    if (str != NULL)
+    {
+        retval = new char[strlen(str) + 1];
+        strcpy(retval, str);
+    } // if
+    return retval;
+} // newstr
+
+static char *newutf8(const wxString &wxstr)
+{
+    #if wxUSE_UNICODE
+    size_t len = wxstr.Len() + 1;
+    char *utf8text = new char[len * 6];
+    wxConvUTF8.WC2MB(utf8text, wxstr, len);
+    return utf8text;
+    #else
+    return newstr(wxstr);
+    #endif
+} // newutf8
+
+
+WxTestPhysfsFrame::WxTestPhysfsFrame(const wxChar *argv0)
+    : wxFrame(NULL, -1, wxT("WxTestPhysfs"))
+{
+    this->CreateStatusBar();
+
+    wxMenuBar *menuBar = new wxMenuBar;
+
+    wxMenu *stuffMenu = new wxMenu;
+    stuffMenu->Append(MENUCMD_Init, wxT("&Init"));
+    stuffMenu->Append(MENUCMD_Deinit, wxT("&Deinit"));
+    stuffMenu->Append(MENUCMD_AddArchive, wxT("&Add Archive"));
+    stuffMenu->Append(MENUCMD_Mount, wxT("&Mount Archive"));
+    stuffMenu->Append(MENUCMD_Remove, wxT("&Remove Archive"));
+    stuffMenu->Append(MENUCMD_GetCDs, wxT("&Get CD-ROM drives"));
+    stuffMenu->Append(MENUCMD_SetWriteDir, wxT("&Set Write Dir"));
+    stuffMenu->Append(MENUCMD_SetSaneConfig, wxT("Set Sane &Config"));
+    stuffMenu->Append(MENUCMD_MkDir, wxT("M&kDir"));
+    stuffMenu->Append(MENUCMD_Delete, wxT("D&elete"));
+    stuffMenu->Append(MENUCMD_Cat, wxT("&Cat"));
+    stuffMenu->Append(MENUCMD_SetBuffer, wxT("Set &Buffer"));
+    stuffMenu->Append(MENUCMD_StressBuffer, wxT("Stress &Test Buffer"));
+    stuffMenu->Append(MENUCMD_Append, wxT("&Append"));
+    stuffMenu->Append(MENUCMD_Write, wxT("&Write"));
+    stuffMenu->Append(MENUCMD_Write, wxT("&Update getLastError"));
+    stuffMenu->AppendCheckItem(MENUCMD_PermitSymLinks, wxT("&Permit symlinks"));
+    menuBar->Append(stuffMenu, wxT("&Stuff"));
+
+    //wxMenu *helpMenu = new wxMenu;
+    //helpMenu->Append(MENUCMD_About, wxT("&About\tF1"));
+    //menuBar->Append(helpMenu, wxT("&Help"));
+
+    this->SetMenuBar(menuBar);
+
+    this->fileTree = new wxTreeCtrl(this, -1);
+
+    // The sizer just makes sure that fileTree owns whole client area.
+    wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
+    sizer->Add(this->fileTree, 1, wxALL | wxEXPAND | wxALIGN_CENTRE);
+    sizer->SetItemMinSize(this->fileTree, 1, 1);
+    this->SetSizer(sizer);
+
+    char *utf8argv0 = newutf8(wxString(argv0));
+    this->doInit(utf8argv0);
+    delete[] utf8argv0;
+} // WxTestPhysfsFrame::WxTestPhysfsFrame
+
+
+int WxTestPhysfsFrame::err(int success)
+{
+    if (success)
+        this->SetStatusText(wxT(""));
+    else
+        this->SetStatusText(wxString(PHYSFS_getLastError(), wxConvUTF8));
+    return success;
+} // WxTestPhysfsFrame::err
+
+
+void WxTestPhysfsFrame::fillFileSystemTree(const char *path,
+                                           const wxTreeItemId &item)
+{
+    char **rc = PHYSFS_enumerateFiles(path);
+    char **i;
+    wxTreeItemId id;
+
+    if (rc == NULL)
+    {
+        const wxString quote(wxT("'"));
+        wxString str(wxT("Enumeration error: "));
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            id = this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+            const int len = strlen(path) + strlen(*i) + 2;
+            char *fname = new char[len];
+            const char *origdir = path;
+            if (strcmp(origdir, "/") == 0)
+                origdir = "";
+            snprintf(fname, len, "%s/%s", origdir, *i);
+
+            if (PHYSFS_isDirectory(fname))
+            {
+                this->fileTree->SetItemTextColour(id, wxColour(0, 0, 255));
+                this->fillFileSystemTree(fname, id);
+            } // if
+
+            else if (PHYSFS_isSymbolicLink(fname))
+            {
+                this->fileTree->SetItemTextColour(id, wxColour(0, 255, 0));
+            } // else if
+
+            else  // ...file.
+            {
+            } // else
+
+            delete[] fname;
+        } // for
+
+        PHYSFS_freeList(rc);
+    } // else
+} // fillFileSystemTree
+
+
+void WxTestPhysfsFrame::rebuildTree()
+{
+    const wxString dot(wxT("."));
+    const wxString quote(wxT("'"));
+    wxTreeItemId item;
+    wxString str;
+    const char *cstr = NULL;
+    const bool wasInit = PHYSFS_isInit() ? true : false;
+
+    this->fileTree->DeleteAllItems();
+    wxTreeItemId root = this->fileTree->AddRoot(wxT("PhysicsFS"));
+    this->stateItem = this->fileTree->AppendItem(root, wxT("Library state"));
+
+    str = wxT("Initialized: ");
+    str << ((wasInit) ? wxT("true") : wxT("false"));
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    this->fileTree->Expand(this->stateItem);
+    this->fileTree->Expand(root);
+
+    // Fill in version information...
+
+    PHYSFS_Version ver;
+    item = this->stateItem;
+    str = wxT("wxtest_physfs version: ");
+    str << TEST_VER_MAJOR << dot << TEST_VER_MINOR << dot << TEST_VER_PATCH;
+    this->fileTree->AppendItem(item, str);
+    PHYSFS_VERSION(&ver);
+    str = wxT("Compiled against PhysicsFS version: ");
+    str << (int) ver.major << dot << (int) ver.minor << dot << ver.patch;
+    this->fileTree->AppendItem(item, str);
+    PHYSFS_getLinkedVersion(&ver);
+    str = wxT("Linked against PhysicsFS version: ");
+    str << (int) ver.major << dot << (int) ver.minor << dot << ver.patch;
+    this->fileTree->AppendItem(item, str);
+
+    if (!wasInit)
+        return;   // nothing else to do before initialization...
+
+    str = wxT("Symbolic links permitted: ");
+    str << ((PHYSFS_symbolicLinksPermitted()) ? wxT("true") : wxT("false"));
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    str = wxT("Native directory separator: ");
+    str << quote << wxString(PHYSFS_getDirSeparator(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    // Fill in supported archives...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Archivers"));
+    const PHYSFS_ArchiveInfo **arcs = PHYSFS_supportedArchiveTypes();
+    if (*arcs == NULL)
+        this->fileTree->AppendItem(item, wxT("(none)"));
+    else
+    {
+        const PHYSFS_ArchiveInfo **i;
+        for (i = arcs; *i != NULL; i++)
+        {
+            const wxString ext((*i)->extension, wxConvUTF8);
+            const wxString desc((*i)->description, wxConvUTF8);
+            const wxString auth((*i)->author, wxConvUTF8);
+            const wxString url((*i)->url, wxConvUTF8);
+            wxTreeItemId arcitem = this->fileTree->AppendItem(item, ext);
+            this->fileTree->AppendItem(arcitem, desc);
+            this->fileTree->AppendItem(arcitem, auth);
+            this->fileTree->AppendItem(arcitem, url);
+        } // for
+    } // else
+
+
+    // Fill in the standard paths...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Paths"));
+    str = wxT("Base directory: ");
+    str << quote << wxString(PHYSFS_getBaseDir(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    str = wxT("User directory: ");
+    str << quote << wxString(PHYSFS_getUserDir(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    str = wxT("Write directory: ");
+    if ((cstr = PHYSFS_getWriteDir()) == NULL)
+        str << wxT("(NULL)");
+    else
+        str << quote << wxString(cstr ? cstr : "(NULL)", wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    //str = wxT("Preference directory: ");
+    //str << wxString(PHYSFS_getUserDir(), wxConvUTF8);
+    //this->fileTree->AppendItem(item, str);
+
+    // Fill in the CD-ROMs...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("CD-ROMs"));
+    char **cds = PHYSFS_getCdRomDirs();
+    if (cds == NULL)
+    {
+        str = wxT("Error: ");
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        wxTreeItemId id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        if (*cds == NULL)
+            this->fileTree->AppendItem(item, wxT("(none)"));
+        else
+        {
+            char **i;
+            for (i = cds; *i != NULL; i++)
+                this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+        } // else
+        PHYSFS_freeList(cds);
+    } // else
+
+    // Fill in search path...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Search path"));
+    char **sp = PHYSFS_getSearchPath();
+    if (sp == NULL)
+    {
+        str = wxT("Error: ");
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        wxTreeItemId id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        if (*sp == NULL)
+            this->fileTree->AppendItem(item, wxT("(none)"));
+        else
+        {
+            char **i;
+            for (i = sp; *i != NULL; i++)
+                this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+        } // else
+        PHYSFS_freeList(sp);
+    } // else
+
+    // Now fill in the filesystem...
+
+    this->fsItem = this->fileTree->AppendItem(root, wxT("Filesystem"));
+    this->fillFileSystemTree("/", this->fsItem);
+    this->fileTree->Expand(this->fsItem);
+} // WxTestPhysfsFrame::rebuildTree
+
+
+void WxTestPhysfsFrame::doInit(const char *argv0)
+{
+    if (!this->err(PHYSFS_init(argv0)))
+        ::wxMessageBox(wxT("PHYSFS_init() failed!"), wxT("wxTestPhysfs"));
+    this->rebuildTree();
+} // WxTestPhysfsFrame::doInit
+
+
+void WxTestPhysfsFrame::doDeinit()
+{
+    if (!this->err(PHYSFS_deinit()))
+        ::wxMessageBox(wxT("PHYSFS_deinit() failed!"), wxT("wxTestPhysfs"));
+    this->rebuildTree();
+} // WxTestPhysfsFrame::doDeinit
+
+
+void WxTestPhysfsFrame::onMenuInit(wxCommandEvent &evt)
+{
+    wxString argv0(wxGetApp().argv[0] == NULL ? wxT("") : wxGetApp().argv[0]);
+    wxString str(wxGetTextFromUser(wxT("PHYSFS_init"),
+                 wxT("argv[0]? (cancel for NULL)"), argv0));
+    char *cstr = str.IsEmpty() ? NULL : newutf8(str);
+    this->doInit(cstr);
+    delete[] cstr;
+} // WxTestPhysfsFrame::onMenuInit
+
+
+void WxTestPhysfsFrame::onMenuDeinit(wxCommandEvent &evt)
+{
+    this->doDeinit();
+} // WxTestPhysfsFrame::onMenuDeinit
+
+
+void WxTestPhysfsFrame::onMenuAddArchive(wxCommandEvent &evt)
+{
+    wxString arc = wxFileSelector(wxT("Choose archive to add"));
+    if (!arc.IsEmpty())
+    {
+        char *cstr = newutf8(arc);
+        // !!! FIXME: add to start/end?
+        if (!this->err(PHYSFS_addToSearchPath(cstr, 1)))
+            ::wxMessageBox(wxT("PHYSFS_addToSearchPath() failed!"), wxT("wxTestPhysfs"));
+        delete[] cstr;
+        this->rebuildTree();
+    } // if
+} // WxTestPhysfsFrame::onMenuAddArchive
+
+
+void WxTestPhysfsFrame::onMenuGetCDs(wxCommandEvent &evt)
+{
+    this->rebuildTree();  // This will call PHYSFS_getCdRomDirs()...
+} // WxTestPhysfsFrame::onMenuGetCDs
+
+
+void WxTestPhysfsFrame::onMenuPermitSymLinks(wxCommandEvent &evt)
+{
+    PHYSFS_permitSymbolicLinks(evt.IsChecked() ? 1 : 0);
+    this->rebuildTree();
+} // WxTestPhysfsFrame::onMenuPermitSymLinks
+
+
+
+IMPLEMENT_APP(WxTestPhysfsApp)
+
+bool WxTestPhysfsApp::OnInit()
+{
+    #if PLATFORM_MACOSX
+    // This lets a stdio app become a GUI app. Otherwise, you won't get
+    //  GUI events from the system and other things will fail to work.
+    // Putting the app in an application bundle does the same thing.
+    //  TransformProcessType() is a 10.3+ API. SetFrontProcess() is 10.0+.
+    if (TransformProcessType != NULL)  // check it as a weak symbol.
+    {
+        ProcessSerialNumber psn = { 0, kCurrentProcess };
+        TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+        SetFrontProcess(&psn);
+    } // if
+    #endif
+
+    this->mainWindow = new WxTestPhysfsFrame(this->argv[0]);
+    this->mainWindow->Show(true);
+    SetTopWindow(this->mainWindow);
+    return true;
+} // WxTestPhysfsApp::OnInit
+
+// end of wxtest_physfs.cpp ...
+
diff --git a/welcome b/welcome
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/zlib123/README b/zlib123/README
new file mode 100644 (file)
index 0000000..758cc50
--- /dev/null
@@ -0,0 +1,125 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.3 is a general purpose data compression library.  All the code is
+thread safe.  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). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install". For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of  Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.3 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+  -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+  compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+  when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+  necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+  other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+  installed before testing (do "make install" before "make test"), since the
+  library location is specified in the library.
+
+
+Acknowledgments:
+
+  The deflate format used by zlib was defined by Phil Katz. The deflate
+  and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+  people who reported problems and suggested various improvements in zlib;
+  they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2004 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
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind.  The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
diff --git a/zlib123/adler32.c b/zlib123/adler32.c
new file mode 100644 (file)
index 0000000..007ba26
--- /dev/null
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL    /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+#  define MOD(a) \
+    do { \
+        if (a >= (BASE << 16)) a -= (BASE << 16); \
+        if (a >= (BASE << 15)) a -= (BASE << 15); \
+        if (a >= (BASE << 14)) a -= (BASE << 14); \
+        if (a >= (BASE << 13)) a -= (BASE << 13); \
+        if (a >= (BASE << 12)) a -= (BASE << 12); \
+        if (a >= (BASE << 11)) a -= (BASE << 11); \
+        if (a >= (BASE << 10)) a -= (BASE << 10); \
+        if (a >= (BASE << 9)) a -= (BASE << 9); \
+        if (a >= (BASE << 8)) a -= (BASE << 8); \
+        if (a >= (BASE << 7)) a -= (BASE << 7); \
+        if (a >= (BASE << 6)) a -= (BASE << 6); \
+        if (a >= (BASE << 5)) a -= (BASE << 5); \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD4(a) \
+    do { \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD4(sum2);             /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    rem = (unsigned)(len2 % BASE);
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 > BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
diff --git a/zlib123/compress.c b/zlib123/compress.c
new file mode 100644 (file)
index 0000000..df04f01
--- /dev/null
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/zlib123/crc32.c b/zlib123/crc32.c
new file mode 100644 (file)
index 0000000..f658a9e
--- /dev/null
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+#  ifdef STDC           /* need ANSI C limits.h to determine sizes */
+#    include <limits.h>
+#    define BYFOUR
+#    if (UINT_MAX == 0xffffffffUL)
+       typedef unsigned int u4;
+#    else
+#      if (ULONG_MAX == 0xffffffffUL)
+         typedef unsigned long u4;
+#      else
+#        if (USHRT_MAX == 0xffffffffUL)
+           typedef unsigned short u4;
+#        else
+#          undef BYFOUR     /* can't find a four-byte integer type! */
+#        endif
+#      endif
+#    endif
+#  endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+#  define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    unsigned long poly;                 /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0UL;
+        for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+            poly |= 1UL << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (unsigned long)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = REV(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = REV(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const unsigned long FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const unsigned long FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        u4 endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = (u4)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = REV((u4)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case */
+    if (len2 == 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320L;           /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
diff --git a/zlib123/crc32.h b/zlib123/crc32.h
new file mode 100644 (file)
index 0000000..8053b61
--- /dev/null
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/zlib123/deflate.c b/zlib123/deflate.c
new file mode 100644 (file)
index 0000000..29ce1f6
--- /dev/null
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->wrap == 2 ||
+        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+        return Z_STREAM_ERROR;
+
+    s = strm->state;
+    if (s->wrap)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+        length = MAX_DIST(s);
+        dictionary += dictLength - length; /* use the tail of the dictionary */
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+        INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    strm->state->bi_valid = bits;
+    strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong destLen;
+
+    /* conservative upper bound */
+    destLen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+    /* if can't get parameters, return conservative bound */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return destLen;
+
+    /* if not default parameters, return conservative bound */
+    s = strm->state;
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return destLen;
+
+    /* default settings: return tight bound for that case */
+    return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy(dest, source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, strm->next_in, len);
+    }
+#endif
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            /* %%% avoid this when Z_RLE */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+#ifdef FASTEST
+            if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+                (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#else
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#endif
+            /* longest_match() or longest_match_fast() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+            /* longest_match() or longest_match_fast() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;         /* set if current block must be flushed */
+    uInt run;           /* length of run */
+    uInt max;           /* maximum length of run */
+    uInt prev;          /* byte at distance one to match */
+    Bytef *scan;        /* scan for end of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest encodable run.
+         */
+        if (s->lookahead < MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        run = 0;
+        if (s->strstart > 0) {      /* if there is a previous byte, that is */
+            max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+            scan = s->window + s->strstart - 1;
+            prev = *scan++;
+            do {
+                if (*scan++ != prev)
+                    break;
+            } while (++run < max);
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (run >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, run);
+            _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+            s->lookahead -= run;
+            s->strstart += run;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/zlib123/deflate.h b/zlib123/deflate.h
new file mode 100644 (file)
index 0000000..05a5ab3
--- /dev/null
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/zlib123/gzio.c b/zlib123/gzio.c
new file mode 100644 (file)
index 0000000..7e90f49
--- /dev/null
@@ -0,0 +1,1026 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE       /* for compatibility with old definition */
+#  define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+#  ifdef MAXSEG_64K
+#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+#  else
+#    define Z_BUFSIZE 16384
+#  endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+#  define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+#  pragma map (fdopen , "\174\174FDOPEN")
+   FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+    Byte     *inbuf;  /* input buffer */
+    Byte     *outbuf; /* output buffer */
+    uLong    crc;     /* crc32 of uncompressed data */
+    char     *msg;    /* error message */
+    char     *path;   /* path name for debugging only */
+    int      transparent; /* 1 if input file is not a .gz file */
+    char     mode;    /* 'w' or 'r' */
+    z_off_t  start;   /* start of compressed data in file (header skipped) */
+    z_off_t  in;      /* bytes into deflate or inflate */
+    z_off_t  out;     /* bytes out of deflate or inflate */
+    int      back;    /* one character push-back */
+    int      last;    /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
+local int do_flush        OF((gzFile file, int flush));
+local int    get_byte     OF((gz_stream *s));
+local void   check_header OF((gz_stream *s));
+local int    destroy      OF((gz_stream *s));
+local void   putLong      OF((FILE *file, uLong x));
+local uLong  getLong      OF((gz_stream *s));
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+   or path name (if fd == -1).
+     gz_open returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+    const char *path;
+    const char *mode;
+    int  fd;
+{
+    int err;
+    int level = Z_DEFAULT_COMPRESSION; /* compression level */
+    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+    char *p = (char*)mode;
+    gz_stream *s;
+    char fmode[80]; /* copy of mode, without the compression level */
+    char *m = fmode;
+
+    if (!path || !mode) return Z_NULL;
+
+    s = (gz_stream *)ALLOC(sizeof(gz_stream));
+    if (!s) return Z_NULL;
+
+    s->stream.zalloc = (alloc_func)0;
+    s->stream.zfree = (free_func)0;
+    s->stream.opaque = (voidpf)0;
+    s->stream.next_in = s->inbuf = Z_NULL;
+    s->stream.next_out = s->outbuf = Z_NULL;
+    s->stream.avail_in = s->stream.avail_out = 0;
+    s->file = NULL;
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->in = 0;
+    s->out = 0;
+    s->back = EOF;
+    s->crc = crc32(0L, Z_NULL, 0);
+    s->msg = NULL;
+    s->transparent = 0;
+
+    s->path = (char*)ALLOC(strlen(path)+1);
+    if (s->path == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    strcpy(s->path, path); /* do this early for debugging */
+
+    s->mode = '\0';
+    do {
+        if (*p == 'r') s->mode = 'r';
+        if (*p == 'w' || *p == 'a') s->mode = 'w';
+        if (*p >= '0' && *p <= '9') {
+            level = *p - '0';
+        } else if (*p == 'f') {
+          strategy = Z_FILTERED;
+        } else if (*p == 'h') {
+          strategy = Z_HUFFMAN_ONLY;
+        } else if (*p == 'R') {
+          strategy = Z_RLE;
+        } else {
+            *m++ = *p; /* copy the mode */
+        }
+    } while (*p++ && m != fmode + sizeof(fmode));
+    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        err = Z_STREAM_ERROR;
+#else
+        err = deflateInit2(&(s->stream), level,
+                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+        /* windowBits is passed < 0 to suppress zlib header */
+
+        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+        if (err != Z_OK || s->outbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    } else {
+        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+        err = inflateInit2(&(s->stream), -MAX_WBITS);
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+         * present after the compressed stream.
+         */
+        if (err != Z_OK || s->inbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    }
+    s->stream.avail_out = Z_BUFSIZE;
+
+    errno = 0;
+    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+    if (s->file == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    if (s->mode == 'w') {
+        /* Write a very simple .gz header:
+         */
+        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+        s->start = 10L;
+        /* We use 10L instead of ftell(s->file) to because ftell causes an
+         * fflush on some systems. This version of the library doesn't use
+         * start anyway in write mode, so this initialization is not
+         * necessary.
+         */
+    } else {
+        check_header(s); /* skip the .gz header */
+        s->start = ftell(s->file) - s->stream.avail_in;
+    }
+
+    return (gzFile)s;
+}
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+   to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+    int fd;
+    const char *mode;
+{
+    char name[46];      /* allow for up to 128-bit integers */
+
+    if (fd < 0) return (gzFile)Z_NULL;
+    sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+    return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    /* Make room to allow flushing */
+    if (s->stream.avail_out == 0) {
+
+        s->stream.next_out = s->outbuf;
+        if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+            s->z_err = Z_ERRNO;
+        }
+        s->stream.avail_out = Z_BUFSIZE;
+    }
+
+    return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+    gz_stream *s;
+{
+    if (s->z_eof) return EOF;
+    if (s->stream.avail_in == 0) {
+        errno = 0;
+        s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+        if (s->stream.avail_in == 0) {
+            s->z_eof = 1;
+            if (ferror(s->file)) s->z_err = Z_ERRNO;
+            return EOF;
+        }
+        s->stream.next_in = s->inbuf;
+    }
+    s->stream.avail_in--;
+    return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+      Check the gzip header of a gz_stream opened for reading. Set the stream
+    mode to transparent if the gzip magic header is not present; set s->err
+    to Z_DATA_ERROR if the magic header is present but the rest of the header
+    is incorrect.
+    IN assertion: the stream s has already been created sucessfully;
+       s->stream.avail_in is zero for the first time, but may be non-zero
+       for concatenated .gz files.
+*/
+local void check_header(s)
+    gz_stream *s;
+{
+    int method; /* method byte */
+    int flags;  /* flags byte */
+    uInt len;
+    int c;
+
+    /* Assure two bytes in the buffer so we can peek ahead -- handle case
+       where first byte of header is at the end of the buffer after the last
+       gzip segment */
+    len = s->stream.avail_in;
+    if (len < 2) {
+        if (len) s->inbuf[0] = s->stream.next_in[0];
+        errno = 0;
+        len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+        if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+        s->stream.avail_in += len;
+        s->stream.next_in = s->inbuf;
+        if (s->stream.avail_in < 2) {
+            s->transparent = s->stream.avail_in;
+            return;
+        }
+    }
+
+    /* Peek ahead to check the gzip magic header */
+    if (s->stream.next_in[0] != gz_magic[0] ||
+        s->stream.next_in[1] != gz_magic[1]) {
+        s->transparent = 1;
+        return;
+    }
+    s->stream.avail_in -= 2;
+    s->stream.next_in += 2;
+
+    /* Check the rest of the gzip header */
+    method = get_byte(s);
+    flags = get_byte(s);
+    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+        s->z_err = Z_DATA_ERROR;
+        return;
+    }
+
+    /* Discard time, xflags and OS code: */
+    for (len = 0; len < 6; len++) (void)get_byte(s);
+
+    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+        len  =  (uInt)get_byte(s);
+        len += ((uInt)get_byte(s))<<8;
+        /* len is garbage if EOF but the loop below will quit anyway */
+        while (len-- != 0 && get_byte(s) != EOF) ;
+    }
+    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+        while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
+        while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
+        for (len = 0; len < 2; len++) (void)get_byte(s);
+    }
+    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+   Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+    gz_stream *s;
+{
+    int err = Z_OK;
+
+    if (!s) return Z_STREAM_ERROR;
+
+    TRYFREE(s->msg);
+
+    if (s->stream.state != NULL) {
+        if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+            err = Z_STREAM_ERROR;
+#else
+            err = deflateEnd(&(s->stream));
+#endif
+        } else if (s->mode == 'r') {
+            err = inflateEnd(&(s->stream));
+        }
+    }
+    if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+        if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+            err = Z_ERRNO;
+    }
+    if (s->z_err < 0) err = s->z_err;
+
+    TRYFREE(s->inbuf);
+    TRYFREE(s->outbuf);
+    TRYFREE(s->path);
+    TRYFREE(s);
+    return err;
+}
+
+/* ===========================================================================
+     Reads the given number of uncompressed bytes from the compressed file.
+   gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
+
+    next_out = (Byte*)buf;
+    s->stream.next_out = (Bytef*)buf;
+    s->stream.avail_out = len;
+
+    if (s->stream.avail_out && s->back != EOF) {
+        *next_out++ = s->back;
+        s->stream.next_out++;
+        s->stream.avail_out--;
+        s->back = EOF;
+        s->out++;
+        start++;
+        if (s->last) {
+            s->z_err = Z_STREAM_END;
+            return 1;
+        }
+    }
+
+    while (s->stream.avail_out != 0) {
+
+        if (s->transparent) {
+            /* Copy first the lookahead bytes: */
+            uInt n = s->stream.avail_in;
+            if (n > s->stream.avail_out) n = s->stream.avail_out;
+            if (n > 0) {
+                zmemcpy(s->stream.next_out, s->stream.next_in, n);
+                next_out += n;
+                s->stream.next_out = next_out;
+                s->stream.next_in   += n;
+                s->stream.avail_out -= n;
+                s->stream.avail_in  -= n;
+            }
+            if (s->stream.avail_out > 0) {
+                s->stream.avail_out -=
+                    (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+            }
+            len -= s->stream.avail_out;
+            s->in  += len;
+            s->out += len;
+            if (len == 0) s->z_eof = 1;
+            return (int)len;
+        }
+        if (s->stream.avail_in == 0 && !s->z_eof) {
+
+            errno = 0;
+            s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+            if (s->stream.avail_in == 0) {
+                s->z_eof = 1;
+                if (ferror(s->file)) {
+                    s->z_err = Z_ERRNO;
+                    break;
+                }
+            }
+            s->stream.next_in = s->inbuf;
+        }
+        s->in += s->stream.avail_in;
+        s->out += s->stream.avail_out;
+        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+        s->in -= s->stream.avail_in;
+        s->out -= s->stream.avail_out;
+
+        if (s->z_err == Z_STREAM_END) {
+            /* Check CRC and original size */
+            s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+            start = s->stream.next_out;
+
+            if (getLong(s) != s->crc) {
+                s->z_err = Z_DATA_ERROR;
+            } else {
+                (void)getLong(s);
+                /* The uncompressed length returned by above getlong() may be
+                 * different from s->out in case of concatenated .gz files.
+                 * Check for such files:
+                 */
+                check_header(s);
+                if (s->z_err == Z_OK) {
+                    inflateReset(&(s->stream));
+                    s->crc = crc32(0L, Z_NULL, 0);
+                }
+            }
+        }
+        if (s->z_err != Z_OK || s->z_eof) break;
+    }
+    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+    if (len == s->stream.avail_out &&
+        (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+        return -1;
+    return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    unsigned char c;
+
+    return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+      Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+    int c;
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+    s->back = c;
+    s->out--;
+    s->last = (s->z_err == Z_STREAM_END);
+    if (s->last) s->z_err = Z_OK;
+    s->z_eof = 0;
+    return c;
+}
+
+
+/* ===========================================================================
+      Reads bytes from the compressed file until len-1 characters are
+   read, or a newline character is read and transferred to buf, or an
+   end-of-file condition is encountered.  The string is then terminated
+   with a null character.
+      gzgets returns buf, or Z_NULL in case of error.
+
+      The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    char *b = buf;
+    if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+    *buf = '\0';
+    return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+    gzFile file;
+    voidpc buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.next_in = (Bytef*)buf;
+    s->stream.avail_in = len;
+
+    while (s->stream.avail_in != 0) {
+
+        if (s->stream.avail_out == 0) {
+
+            s->stream.next_out = s->outbuf;
+            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+                s->z_err = Z_ERRNO;
+                break;
+            }
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        s->in += s->stream.avail_in;
+        s->out += s->stream.avail_out;
+        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+        s->in -= s->stream.avail_in;
+        s->out -= s->stream.avail_out;
+        if (s->z_err != Z_OK) break;
+    }
+    s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+    return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    va_list va;
+    int len;
+
+    buf[sizeof(buf) - 1] = 0;
+    va_start(va, format);
+#ifdef NO_vsnprintf
+#  ifdef HAS_vsprintf_void
+    (void)vsprintf(buf, format, va);
+    va_end(va);
+    for (len = 0; len < sizeof(buf); len++)
+        if (buf[len] == 0) break;
+#  else
+    len = vsprintf(buf, format, va);
+    va_end(va);
+#  endif
+#else
+#  ifdef HAS_vsnprintf_void
+    (void)vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+    len = strlen(buf);
+#  else
+    len = vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+#  endif
+#endif
+    if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+        return 0;
+    return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    int len;
+
+    buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+#  ifdef HAS_sprintf_void
+    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    for (len = 0; len < sizeof(buf); len++)
+        if (buf[len] == 0) break;
+#  else
+    len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#else
+#  ifdef HAS_snprintf_void
+    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    len = strlen(buf);
+#  else
+    len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#endif
+    if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+        return 0;
+    return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+    gzFile file;
+    const char *s;
+{
+    return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+    gzFile file;
+    int flush;
+{
+    uInt len;
+    int done = 0;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.avail_in = 0; /* should be zero already anyway */
+
+    for (;;) {
+        len = Z_BUFSIZE - s->stream.avail_out;
+
+        if (len != 0) {
+            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+                s->z_err = Z_ERRNO;
+                return Z_ERRNO;
+            }
+            s->stream.next_out = s->outbuf;
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        if (done) break;
+        s->out += s->stream.avail_out;
+        s->z_err = deflate(&(s->stream), flush);
+        s->out -= s->stream.avail_out;
+
+        /* Ignore the second of two consecutive flushes: */
+        if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+        /* deflate has finished flushing only when it hasn't used up
+         * all the available space in the output buffer:
+         */
+        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+    }
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+     gzFile file;
+     int flush;
+{
+    gz_stream *s = (gz_stream*)file;
+    int err = do_flush (file, flush);
+
+    if (err) return err;
+    fflush(s->file);
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+      Sets the starting position for the next gzread or gzwrite on the given
+   compressed file. The offset represents a number of bytes in the
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error.
+      SEEK_END is not implemented, returns error.
+      In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || whence == SEEK_END ||
+        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+        return -1L;
+    }
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        return -1L;
+#else
+        if (whence == SEEK_SET) {
+            offset -= s->in;
+        }
+        if (offset < 0) return -1L;
+
+        /* At this point, offset is the number of zero bytes to write. */
+        if (s->inbuf == Z_NULL) {
+            s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+            if (s->inbuf == Z_NULL) return -1L;
+            zmemzero(s->inbuf, Z_BUFSIZE);
+        }
+        while (offset > 0)  {
+            uInt size = Z_BUFSIZE;
+            if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+            size = gzwrite(file, s->inbuf, size);
+            if (size == 0) return -1L;
+
+            offset -= size;
+        }
+        return s->in;
+#endif
+    }
+    /* Rest of function is for reading only */
+
+    /* compute absolute position */
+    if (whence == SEEK_CUR) {
+        offset += s->out;
+    }
+    if (offset < 0) return -1L;
+
+    if (s->transparent) {
+        /* map to fseek */
+        s->back = EOF;
+        s->stream.avail_in = 0;
+        s->stream.next_in = s->inbuf;
+        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+        s->in = s->out = offset;
+        return offset;
+    }
+
+    /* For a negative seek, rewind and use positive seek */
+    if (offset >= s->out) {
+        offset -= s->out;
+    } else if (gzrewind(file) < 0) {
+        return -1L;
+    }
+    /* offset is now the number of bytes to skip. */
+
+    if (offset != 0 && s->outbuf == Z_NULL) {
+        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+        if (s->outbuf == Z_NULL) return -1L;
+    }
+    if (offset && s->back != EOF) {
+        s->back = EOF;
+        s->out++;
+        offset--;
+        if (s->last) s->z_err = Z_STREAM_END;
+    }
+    while (offset > 0)  {
+        int size = Z_BUFSIZE;
+        if (offset < Z_BUFSIZE) size = (int)offset;
+
+        size = gzread(file, s->outbuf, (uInt)size);
+        if (size <= 0) return -1L;
+        offset -= size;
+    }
+    return s->out;
+}
+
+/* ===========================================================================
+     Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r') return -1;
+
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->back = EOF;
+    s->stream.avail_in = 0;
+    s->stream.next_in = s->inbuf;
+    s->crc = crc32(0L, Z_NULL, 0);
+    if (!s->transparent) (void)inflateReset(&s->stream);
+    s->in = 0;
+    s->out = 0;
+    return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+    gzFile file;
+{
+    return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    /* With concatenated compressed files that can have embedded
+     * crc trailers, z_eof is no longer the only/best indicator of EOF
+     * on a gz_stream. Handle end-of-stream error explicitly here.
+     */
+    if (s == NULL || s->mode != 'r') return 0;
+    if (s->z_eof) return 1;
+    return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+     Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r') return 0;
+    return s->transparent;
+}
+
+/* ===========================================================================
+   Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+    FILE *file;
+    uLong x;
+{
+    int n;
+    for (n = 0; n < 4; n++) {
+        fputc((int)(x & 0xff), file);
+        x >>= 8;
+    }
+}
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets z_err in case
+   of error.
+*/
+local uLong getLong (s)
+    gz_stream *s;
+{
+    uLong x = (uLong)get_byte(s);
+    int c;
+
+    x += ((uLong)get_byte(s))<<8;
+    x += ((uLong)get_byte(s))<<16;
+    c = get_byte(s);
+    if (c == EOF) s->z_err = Z_DATA_ERROR;
+    x += ((uLong)c)<<24;
+    return x;
+}
+
+/* ===========================================================================
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return Z_STREAM_ERROR;
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        return Z_STREAM_ERROR;
+#else
+        if (do_flush (file, Z_FINISH) != Z_OK)
+            return destroy((gz_stream*)file);
+
+        putLong (s->file, s->crc);
+        putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+    }
+    return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    char *m;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) {
+        *errnum = Z_STREAM_ERROR;
+        return (const char*)ERR_MSG(Z_STREAM_ERROR);
+    }
+    *errnum = s->z_err;
+    if (*errnum == Z_OK) return (const char*)"";
+
+    m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+    TRYFREE(s->msg);
+    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+    if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+    strcpy(s->msg, s->path);
+    strcat(s->msg, ": ");
+    strcat(s->msg, m);
+    return (const char*)s->msg;
+}
+
+/* ===========================================================================
+     Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return;
+    if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+    s->z_eof = 0;
+    clearerr(s->file);
+}
diff --git a/zlib123/infback.c b/zlib123/infback.c
new file mode 100644 (file)
index 0000000..455dbc9
--- /dev/null
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->write = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+
+            /* process literal */
+            if (this.op == 0) {
+                Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", this.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (this.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(this.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(this.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
diff --git a/zlib123/inffast.c b/zlib123/inffast.c
new file mode 100644 (file)
index 0000000..bbee92e
--- /dev/null
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *in;      /* local strm->next_in */
+    unsigned char FAR *last;    /* while in < last, enough input available */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code this;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    write = state->write;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        this = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(this.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(this.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", this.val));
+            PUP(out) = (unsigned char)(this.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(this.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            this = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(this.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(this.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(this.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+                    from = window - OFF;
+                    if (write == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (write < op) {      /* wrap around window */
+                        from += wsize + write - op;
+                        op -= write;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (write < len) {  /* some from start of window */
+                                op = write;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += write - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                this = dcode[this.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            this = lcode[this.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and write == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/zlib123/inffast.h b/zlib123/inffast.h
new file mode 100644 (file)
index 0000000..1e88d2d
--- /dev/null
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/zlib123/inffixed.h b/zlib123/inffixed.h
new file mode 100644 (file)
index 0000000..75ed4b5
--- /dev/null
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/zlib123/inflate.c b/zlib123/inflate.c
new file mode 100644 (file)
index 0000000..792fdee
--- /dev/null
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->wsize = 0;
+    state->whave = 0;
+    state->write = 0;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    if (windowBits < 0) {
+        state->wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48) windowBits &= 15;
+#endif
+    }
+    if (windowBits < 8 || windowBits > 15) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+        return Z_STREAM_ERROR;
+    }
+    state->wbits = (unsigned)windowBits;
+    state->window = Z_NULL;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+               state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+    struct inflate_state FAR *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->write = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->write = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->write;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, strm->next_out - copy, copy);
+            state->write = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->write += dist;
+            if (state->write == state->wsize) state->write = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                break;
+            }
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+            if ((int)(this.op) == 0) {
+                Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", this.val));
+                state->mode = LIT;
+                break;
+            }
+            if (this.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            if (state->offset > state->whave + out - left) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->write) {
+                    copy -= state->write;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->write - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        if (updatewindow(strm, out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = adler32(0L, Z_NULL, 0);
+        id = adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    if (updatewindow(strm, strm->avail_out)) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    if (dictLength > state->wsize) {
+        zmemcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        zmemcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
diff --git a/zlib123/inflate.h b/zlib123/inflate.h
new file mode 100644 (file)
index 0000000..07bd3e7
--- /dev/null
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN,        /* i: waiting for length/lit code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+        NAME -> COMMENT -> HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+    Read deflate blocks:
+            TYPE -> STORED or TABLE or LEN or CHECK
+            STORED -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN
+    Read deflate codes:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 7K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+};
diff --git a/zlib123/inftrees.c b/zlib123/inftrees.c
new file mode 100644 (file)
index 0000000..8a9c13f
--- /dev/null
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code this;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        this.op = (unsigned char)64;    /* invalid code marker */
+        this.bits = (unsigned char)1;
+        this.val = (unsigned short)0;
+        *(*table)++ = this;             /* make a table to force an error */
+        *(*table)++ = this;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min <= MAXBITS; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked when a LENS table is being made
+       against the space in *table, ENOUGH, minus the maximum space needed by
+       the worst case distance code, MAXD.  This should never happen, but the
+       sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+       This assumes that when type == LENS, bits == 9.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if (type == LENS && used >= ENOUGH - MAXD)
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        this.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            this.op = (unsigned char)0;
+            this.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            this.op = (unsigned char)(extra[work[sym]]);
+            this.val = base[work[sym]];
+        }
+        else {
+            this.op = (unsigned char)(32 + 64);         /* end of block */
+            this.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = this;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if (type == LENS && used >= ENOUGH - MAXD)
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    this.op = (unsigned char)64;                /* invalid code marker */
+    this.bits = (unsigned char)(len - drop);
+    this.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            this.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = this;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/zlib123/inftrees.h b/zlib123/inftrees.h
new file mode 100644 (file)
index 0000000..b1104c8
--- /dev/null
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1444 code structures (852 for length/literals
+   and 592 for distances, the latter actually the result of an
+   exhaustive search).  The true maximum is not known, but the value
+   below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
diff --git a/zlib123/trees.c b/zlib123/trees.c
new file mode 100644 (file)
index 0000000..395e4e1
--- /dev/null
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+            set_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n;
+
+    for (n = 0; n < 9; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            break;
+    if (n == 9)
+        for (n = 14; n < 32; n++)
+            if (s->dyn_ltree[n].Freq != 0)
+                break;
+    s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/zlib123/trees.h b/zlib123/trees.h
new file mode 100644 (file)
index 0000000..72facf9
--- /dev/null
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
diff --git a/zlib123/uncompr.c b/zlib123/uncompr.c
new file mode 100644 (file)
index 0000000..b59e3d0
--- /dev/null
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/zlib123/zconf.h b/zlib123/zconf.h
new file mode 100644 (file)
index 0000000..03a9431
--- /dev/null
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/zlib123/zlib.h b/zlib123/zlib.h
new file mode 100644 (file)
index 0000000..0228179
--- /dev/null
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.3, July 18th, 2005
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     This library can optionally read and write gzip streams in memory as well.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumualte before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.  Z_FIXED prevents the
+   use of dynamic Huffman codes, allowing for a simpler decoder for special
+   applications.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front. In addition, the
+   current implementation of deflate will use at most the window size minus
+   262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+      If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+  that this function is used to start inflating at a bit position in the
+  middle of a byte.  The provided bits will be used before any bytes are used
+  from next_in.  This function should only be used with raw inflate, and
+  should be used before the first inflate() call after inflateInit2() or
+  inflateReset().  bits must be less than or equal to 16, and that many of the
+  least significant bits of value will be inserted in the input.
+
+      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
+   force inflate() to return immediately after header processing is complete
+   and before any actual data is decompressed.
+
+      The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When
+   any of extra, name, or comment are not Z_NULL and the respective field is
+   not present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+      If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file,
+                                   voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                      z_off_t offset, int whence));
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns 1 if file is being read directly without decompression, otherwise
+   zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+/*
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32. If buf is NULL, this function returns the required initial
+   value for the for the crc. Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+        ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/zlib123/zutil.c b/zlib123/zutil.c
new file mode 100644 (file)
index 0000000..d55f594
--- /dev/null
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch (sizeof(uInt)) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch (sizeof(uLong)) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch (sizeof(voidpf)) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch (sizeof(z_off_t)) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#ifdef STDC
+#  ifdef NO_vsnprintf
+        flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#else
+        flags += 1L << 24;
+#  ifdef NO_snprintf
+        flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int z_verbose = verbose;
+
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/zlib123/zutil.h b/zlib123/zutil.h
new file mode 100644 (file)
index 0000000..b7d5eff
--- /dev/null
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+#  ifndef _WIN32_WCE
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+#   ifdef _WIN32_WCE
+      /* The Microsoft C Run-Time Library for Windows CE doesn't have
+       * errno.  We define it as a global variable to simplify porting.
+       * Its value is always 0 and should not be used.  We rename it to
+       * avoid conflict with other libraries that use the same workaround.
+       */
+#     define errno z_errno
+#   endif
+    extern int errno;
+#else
+#  ifndef _WIN32_WCE
+#    include <errno.h>
+#  endif
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#      include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  ifdef M_I86
+     #include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#if defined(__CYGWIN__)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#ifndef HAVE_VSNPRINTF
+#  ifdef MSDOS
+     /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+        but for now we just assume it doesn't. */
+#    define NO_vsnprintf
+#  endif
+#  ifdef __TURBOC__
+#    define NO_vsnprintf
+#  endif
+#  ifdef WIN32
+     /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
+#      define vsnprintf _vsnprintf
+#    endif
+#  endif
+#  ifdef __SASC
+#    define NO_vsnprintf
+#  endif
+#endif
+#ifdef VMS
+#  define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */