From 49707498a5ea40f119b796eb02a2d5c7becae609 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Wed, 30 Dec 2015 11:19:42 +0000 Subject: [PATCH] move files around --- .../SharpCompress.Test.Portable.csproj | 113 - SharpCompress.Test/SharpCompress.Test.csproj | 113 - SharpCompress.Test/global.json | 5 - SharpCompress.sln | 14 +- SharpCompress/sharpcompress.DotSettings | 134 - global.json | 6 + .../SharpCompress}/Archive/AbstractArchive.cs | 422 +- .../Archive/AbstractWritableArchive.cs | 296 +- .../SharpCompress}/Archive/ArchiveFactory.cs | 342 +- .../Archive/GZip/GZipArchive.cs | 434 +- .../Archive/GZip/GZipArchiveEntry.cs | 60 +- .../Archive/GZip/GZipWritableArchiveEntry.cs | 220 +- .../Archive/IArchive.Extensions.cs | 42 +- .../SharpCompress}/Archive/IArchive.cs | 96 +- .../Archive/IArchiveEntry.Extensions.cs | 244 +- .../SharpCompress}/Archive/IArchiveEntry.cs | 46 +- .../Archive/IArchiveExtractionListener.cs | 20 +- .../Archive/IWritableArchive.Extensions.cs | 0 .../Archive/IWritableArchive.cs | 0 .../Archive/IWritableArchiveEntry.cs | 16 +- .../Archive/Rar/FileInfoRarArchiveVolume.cs | 94 +- .../Archive/Rar/FileInfoRarFilePart.cs | 60 +- .../Archive/Rar/RarArchive.Extensions.cs | 44 +- .../SharpCompress}/Archive/Rar/RarArchive.cs | 338 +- .../Archive/Rar/RarArchiveEntry.cs | 184 +- .../Archive/Rar/RarArchiveEntryFactory.cs | 96 +- .../Archive/Rar/RarArchiveVolumeFactory.cs | 288 +- .../Archive/Rar/SeekableFilePart.cs | 68 +- .../Archive/Rar/StreamRarArchiveVolume.cs | 52 +- .../Archive/SevenZip/SevenZipArchive.cs | 502 +- .../Archive/SevenZip/SevenZipArchiveEntry.cs | 64 +- .../SharpCompress}/Archive/Tar/TarArchive.cs | 460 +- .../Archive/Tar/TarArchiveEntry.cs | 60 +- .../Archive/Tar/TarWritableArchiveEntry.cs | 218 +- .../SharpCompress}/Archive/Zip/ZipArchive.cs | 488 +- .../Archive/Zip/ZipArchiveEntry.cs | 70 +- .../Archive/Zip/ZipWritableArchiveEntry.cs | 224 +- .../SharpCompress}/AssemblyInfo.cs | 26 +- .../SharpCompress}/Common/ArchiveEncoding.cs | 44 +- .../SharpCompress}/Common/ArchiveException.cs | 22 +- .../Common/ArchiveExtractionEventArgs.cs | 26 +- .../SharpCompress}/Common/ArchiveType.cs | 20 +- .../Common/CompressedBytesReadEventArgs.cs | 32 +- .../SharpCompress}/Common/CompressionInfo.cs | 58 +- .../SharpCompress}/Common/CompressionType.cs | 30 +- .../Common/CryptographicException.cs | 22 +- .../SharpCompress}/Common/Entry.cs | 168 +- .../SharpCompress}/Common/EntryStream.cs | 204 +- .../SharpCompress}/Common/ExtractOptions.cs | 58 +- .../Common/ExtractionException.cs | 32 +- .../SharpCompress}/Common/FilePart.cs | 22 +- .../FilePartExtractionBeginEventArgs.cs | 42 +- .../SharpCompress}/Common/FlagUtility.cs | 216 +- .../SharpCompress}/Common/GZip/GZipEntry.cs | 170 +- .../Common/GZip/GZipFilePart.cs | 204 +- .../SharpCompress}/Common/GZip/GZipVolume.cs | 66 +- .../SharpCompress}/Common/IEntry.cs | 40 +- .../Common/IExtractionListener.cs | 14 +- .../SharpCompress}/Common/IVolume.cs | 20 +- .../Common/IncompleteArchiveException.cs | 18 +- .../Common/InvalidFormatException.cs | 32 +- .../Common/MultiVolumeExtractionException.cs | 32 +- .../MultipartStreamRequiredException.cs | 18 +- .../SharpCompress}/Common/Options.cs | 44 +- .../Common/PasswordProtectedException.cs | 32 +- .../Common/Rar/Headers/AVHeader.cs | 38 +- .../Common/Rar/Headers/ArchiveHeader.cs | 70 +- .../Common/Rar/Headers/CommentHeader.cs | 42 +- .../Common/Rar/Headers/EndArchiveHeader.cs | 54 +- .../Common/Rar/Headers/FileHeader.cs | 464 +- .../Common/Rar/Headers/FileNameDecoder.cs | 154 +- .../Common/Rar/Headers/Flags.cs | 168 +- .../Common/Rar/Headers/MarkHeader.cs | 116 +- .../Common/Rar/Headers/NewSubHeader.cs | 116 +- .../Common/Rar/Headers/ProtectHeader.cs | 0 .../Common/Rar/Headers/RarHeader.cs | 188 +- .../Common/Rar/Headers/RarHeaderFactory.cs | 484 +- .../Common/Rar/Headers/SignHeader.cs | 44 +- .../Common/Rar/RarCryptoBinaryReader.cs | 160 +- .../Common/Rar/RarCryptoWrapper.cs | 214 +- .../SharpCompress}/Common/Rar/RarEntry.cs | 168 +- .../SharpCompress}/Common/Rar/RarFilePart.cs | 50 +- .../SharpCompress}/Common/Rar/RarRijndael.cs | 230 +- .../SharpCompress}/Common/Rar/RarVolume.cs | 232 +- .../Common/ReaderExtractionEventArgs.cs | 26 +- .../Common/SevenZip/ArchiveDatabase.cs | 320 +- .../Common/SevenZip/ArchiveReader.cs | 2904 ++++---- .../Common/SevenZip/CBindPair.cs | 14 +- .../Common/SevenZip/CCoderInfo.cs | 18 +- .../Common/SevenZip/CFileItem.cs | 82 +- .../SharpCompress}/Common/SevenZip/CFolder.cs | 276 +- .../Common/SevenZip/CMethodId.cs | 108 +- .../Common/SevenZip/CStreamSwitch.cs | 134 +- .../Common/SevenZip/DataReader.cs | 338 +- .../Common/SevenZip/SevenZipEntry.cs | 168 +- .../Common/SevenZip/SevenZipFilePart.cs | 216 +- .../Common/SevenZip/SevenZipVolume.cs | 22 +- .../Common/Tar/Headers/EntryType.cs | 0 .../Common/Tar/Headers/TarHeader.cs | 444 +- .../SharpCompress}/Common/Tar/TarEntry.cs | 206 +- .../SharpCompress}/Common/Tar/TarFilePart.cs | 76 +- .../Common/Tar/TarHeaderFactory.cs | 120 +- .../Common/Tar/TarReadOnlySubStream.cs | 208 +- .../SharpCompress}/Common/Tar/TarVolume.cs | 22 +- .../SharpCompress}/Common/Volume.cs | 100 +- .../Common/Zip/Headers/DirectoryEndHeader.cs | 102 +- .../Zip/Headers/DirectoryEntryHeader.cs | 174 +- .../Common/Zip/Headers/HeaderFlags.cs | 28 +- .../Common/Zip/Headers/IgnoreHeader.cs | 42 +- .../Common/Zip/Headers/LocalEntryHeader.cs | 120 +- .../Headers/LocalEntryHeaderExtraFactory.cs | 150 +- .../Common/Zip/Headers/SplitHeader.cs | 42 +- .../Common/Zip/Headers/ZipFileEntry.cs | 174 +- .../Common/Zip/Headers/ZipHeader.cs | 40 +- .../Common/Zip/Headers/ZipHeaderType.cs | 20 +- .../Zip/PkwareTraditionalCryptoStream.cs | 238 +- .../Zip/PkwareTraditionalEncryptionData.cs | 214 +- .../Common/Zip/SeekableZipFilePart.cs | 88 +- .../Common/Zip/SeekableZipHeaderFactory.cs | 152 +- .../Common/Zip/StreamingZipFilePart.cs | 120 +- .../Common/Zip/StreamingZipHeaderFactory.cs | 128 +- .../Common/Zip/WinzipAesCryptoStream.cs | 374 +- .../Common/Zip/WinzipAesEncryptionData.cs | 150 +- .../Common/Zip/WinzipAesKeySize.cs | 16 +- .../Common/Zip/ZipCompressionMethod.cs | 24 +- .../SharpCompress}/Common/Zip/ZipEntry.cs | 230 +- .../SharpCompress}/Common/Zip/ZipFilePart.cs | 336 +- .../Common/Zip/ZipHeaderFactory.cs | 366 +- .../SharpCompress}/Common/Zip/ZipVolume.cs | 26 +- .../Compressor/BZip2/BZip2Constants.cs | 200 +- .../Compressor/BZip2/BZip2Stream.cs | 224 +- .../Compressor/BZip2/CBZip2InputStream.cs | 2236 +++--- .../Compressor/BZip2/CBZip2OutputStream.cs | 3960 +++++------ .../SharpCompress}/Compressor/BZip2/CRC.cs | 404 +- .../Compressor/CompressionMode.cs | 14 +- .../Compressor/Deflate/CRC32.cs | 574 +- .../Compressor/Deflate/DeflateManager.cs | 3810 +++++----- .../Compressor/Deflate/DeflateStream.cs | 670 +- .../Compressor/Deflate/FlushType.cs | 86 +- .../Compressor/Deflate/GZipStream.cs | 902 +-- .../Compressor/Deflate/InfTree.cs | 1124 +-- .../Compressor/Deflate/Inflate.cs | 3834 +++++----- .../SharpCompress}/Compressor/Deflate/Tree.cs | 926 +-- .../SharpCompress}/Compressor/Deflate/Zlib.cs | 964 +-- .../Compressor/Deflate/ZlibBaseStream.cs | 1172 +-- .../Compressor/Deflate/ZlibCodec.cs | 1432 ++-- .../Compressor/Deflate/ZlibConstants.cs | 248 +- .../Compressor/Deflate/ZlibStream.cs | 622 +- .../Compressor/Filters/BCJ2Filter.cs | 436 +- .../Compressor/Filters/BCJFilter.cs | 204 +- .../Compressor/Filters/Filter.cs | 306 +- .../Compressor/LZMA/AesDecoderStream.cs | 462 +- .../Compressor/LZMA/Bcj2DecoderStream.cs | 488 +- .../Compressor/LZMA/BitVector.cs | 172 +- .../SharpCompress}/Compressor/LZMA/CRC.cs | 164 +- .../Compressor/LZMA/DecoderStream.cs | 350 +- .../SharpCompress}/Compressor/LZMA/ICoder.cs | 338 +- .../SharpCompress}/Compressor/LZMA/LZ/CRC.cs | 116 +- .../Compressor/LZMA/LZ/LzBinTree.cs | 762 +- .../Compressor/LZMA/LZ/LzInWindow.cs | 318 +- .../Compressor/LZMA/LZ/LzOutWindow.cs | 348 +- .../SharpCompress}/Compressor/LZMA/Log.cs | 180 +- .../Compressor/LZMA/LzmaBase.cs | 192 +- .../Compressor/LZMA/LzmaDecoder.cs | 834 +-- .../Compressor/LZMA/LzmaEncoder.cs | 3208 ++++----- .../Compressor/LZMA/LzmaEncoderProperties.cs | 108 +- .../Compressor/LZMA/LzmaStream.cs | 614 +- .../Compressor/LZMA/RangeCoder/RangeCoder.cs | 484 +- .../LZMA/RangeCoder/RangeCoderBit.cs | 264 +- .../LZMA/RangeCoder/RangeCoderBitTree.cs | 312 +- .../Compressor/LZMA/Registry.cs | 104 +- .../LZMA/Utilites/CrcBuilderStream.cs | 416 +- .../LZMA/Utilites/CrcCheckStream.cs | 226 +- .../LZMA/Utilites/IPasswordProvider.cs | 12 +- .../Compressor/LZMA/Utilites/Utils.cs | 158 +- .../Compressor/PPMd/H/FreqData.cs | 134 +- .../Compressor/PPMd/H/ModelPPM.cs | 1854 ++--- .../Compressor/PPMd/H/PPMContext.cs | 1094 +-- .../Compressor/PPMd/H/Pointer.cs | 48 +- .../Compressor/PPMd/H/RangeCoder.cs | 330 +- .../Compressor/PPMd/H/RarMemBlock.cs | 244 +- .../Compressor/PPMd/H/RarNode.cs | 104 +- .../Compressor/PPMd/H/SEE2Context.cs | 176 +- .../SharpCompress}/Compressor/PPMd/H/State.cs | 212 +- .../Compressor/PPMd/H/StateRef.cs | 152 +- .../Compressor/PPMd/H/SubAllocator.cs | 930 +-- .../Compressor/PPMd/I1/Allocator.cs | 914 +-- .../Compressor/PPMd/I1/Coder.cs | 204 +- .../Compressor/PPMd/I1/MemoryNode.cs | 518 +- .../Compressor/PPMd/I1/Model.cs | 1662 ++--- .../PPMd/I1/ModelRestorationMethod.cs | 56 +- .../Compressor/PPMd/I1/Pointer.cs | 656 +- .../Compressor/PPMd/I1/PpmContext.cs | 1618 ++--- .../Compressor/PPMd/I1/PpmState.cs | 422 +- .../Compressor/PPMd/I1/See2Context.cs | 108 +- .../Compressor/PPMd/PpmdProperties.cs | 160 +- .../Compressor/PPMd/PpmdStream.cs | 282 +- .../Compressor/Rar/Decode/AudioVariables.cs | 50 +- .../Compressor/Rar/Decode/BitDecode.cs | 18 +- .../Compressor/Rar/Decode/CodeType.cs | 28 +- .../Compressor/Rar/Decode/Compress.cs | 50 +- .../Compressor/Rar/Decode/Decode.cs | 66 +- .../Compressor/Rar/Decode/DistDecode.cs | 18 +- .../Compressor/Rar/Decode/FilterType.cs | 30 +- .../Compressor/Rar/Decode/LitDecode.cs | 18 +- .../Compressor/Rar/Decode/LowDistDecode.cs | 18 +- .../Compressor/Rar/Decode/MultDecode.cs | 18 +- .../Compressor/Rar/Decode/RepDecode.cs | 18 +- .../Rar/MultiVolumeReadOnlyStream.cs | 322 +- .../Compressor/Rar/PPM/BlockTypes.cs | 14 +- .../SharpCompress}/Compressor/Rar/RarCRC.cs | 86 +- .../Compressor/Rar/RarStream.cs | 306 +- .../SharpCompress}/Compressor/Rar/Unpack.cs | 2454 +++---- .../SharpCompress}/Compressor/Rar/Unpack15.cs | 1474 ++-- .../SharpCompress}/Compressor/Rar/Unpack20.cs | 1062 +-- .../Compressor/Rar/UnpackFilter.cs | 50 +- .../Compressor/Rar/UnpackUtility.cs | 400 +- .../Compressor/Rar/VM/BitInput.cs | 128 +- .../SharpCompress}/Compressor/Rar/VM/RarVM.cs | 2876 ++++---- .../Compressor/Rar/VM/VMCmdFlags.cs | 90 +- .../Compressor/Rar/VM/VMCommands.cs | 154 +- .../Compressor/Rar/VM/VMFlags.cs | 18 +- .../Compressor/Rar/VM/VMOpType.cs | 18 +- .../Compressor/Rar/VM/VMPreparedCommand.cs | 32 +- .../Compressor/Rar/VM/VMPreparedOperand.cs | 18 +- .../Compressor/Rar/VM/VMPreparedProgram.cs | 40 +- .../Rar/VM/VMStandardFilterSignature.cs | 34 +- .../Compressor/Rar/VM/VMStandardFilters.cs | 26 +- .../SharpCompress}/Crypto/BigInteger.cs | 6290 ++++++++--------- .../Crypto/BufferedBlockCipher.cs | 752 +- .../Crypto/BufferedCipherBase.cs | 226 +- .../SharpCompress}/Crypto/CryptoException.cs | 48 +- .../Crypto/DataLengthException.cs | 64 +- .../SharpCompress}/Crypto/GeneralDigest.cs | 254 +- .../SharpCompress}/Crypto/HMac.cs | 268 +- .../SharpCompress}/Crypto/IBlockCipher.cs | 68 +- .../SharpCompress}/Crypto/IBufferedCipher.cs | 88 +- .../Crypto/ICipherParameters.cs | 12 +- .../SharpCompress}/Crypto/IDigest.cs | 110 +- .../SharpCompress}/Crypto/IMac.cs | 126 +- .../SharpCompress}/Crypto/IMemoable.cs | 0 .../SharpCompress}/Crypto/KeyParameter.cs | 78 +- .../SharpCompress}/Crypto/PBKDF2.cs | 238 +- .../SharpCompress}/Crypto/Pack.cs | 256 +- .../SharpCompress}/Crypto/RijndaelEngine.cs | 1478 ++-- .../SharpCompress}/Crypto/Sha1Digest.cs | 566 +- .../SharpCompress}/Crypto/Sha256Digest.cs | 0 .../SharpCompress}/EnumExtensions.cs | 28 +- .../SharpCompress}/IO/AppendingStream.cs | 198 +- .../IO/CountingWritableSubStream.cs | 134 +- .../SharpCompress}/IO/ListeningStream.cs | 160 +- .../SharpCompress}/IO/MarkingBinaryReader.cs | 266 +- .../SharpCompress}/IO/NonDisposingStream.cs | 138 +- .../SharpCompress}/IO/ReadOnlySubStream.cs | 186 +- .../SharpCompress}/IO/RewindableStream.cs | 324 +- .../SharpCompress}/IO/StreamingMode.cs | 14 +- .../SharpCompress}/LazyReadOnlyCollection.cs | 316 +- .../SharpCompress}/ReadOnlyCollection.cs | 118 +- .../SharpCompress}/Reader/AbstractReader.cs | 554 +- .../SharpCompress}/Reader/GZip/GZipReader.cs | 88 +- .../Reader/IReader.Extensions.cs | 188 +- .../SharpCompress}/Reader/IReader.cs | 78 +- .../Reader/IReaderExtractionListener.cs | 32 +- .../Reader/Rar/MultiVolumeRarReader.cs | 250 +- .../Reader/Rar/NonSeekableStreamFilePart.cs | 46 +- .../SharpCompress}/Reader/Rar/RarReader.cs | 172 +- .../Reader/Rar/RarReaderEntry.cs | 96 +- .../Reader/Rar/RarReaderVolume.cs | 52 +- .../Reader/Rar/SingleVolumeRarReader.cs | 66 +- .../SharpCompress}/Reader/ReaderFactory.cs | 158 +- .../SharpCompress}/Reader/Tar/TarReader.cs | 210 +- .../SharpCompress}/Reader/Zip/ZipReader.cs | 132 +- .../SharpCompress}/SharpCompress.pfx | Bin .../SharpCompress}/SharpCompress.xproj | 0 .../SharpCompress}/Utility.cs | 958 +-- .../SharpCompress}/Writer/AbstractWriter.cs | 110 +- .../SharpCompress}/Writer/GZip/GZipWriter.cs | 84 +- .../Writer/IWriter.Extensions.cs | 96 +- .../SharpCompress}/Writer/IWriter.cs | 22 +- .../SharpCompress}/Writer/Tar/TarWriter.cs | 196 +- .../SharpCompress}/Writer/WriterFactory.cs | 92 +- .../Writer/Zip/ZipCentralDirectoryEntry.cs | 118 +- .../Writer/Zip/ZipCompressionInfo.cs | 0 .../SharpCompress}/Writer/Zip/ZipWriter.cs | 588 +- .../SharpCompress}/project.json | 2 +- .../SharpCompress.Test}/ArchiveTests.cs | 366 +- .../GZip/GZipArchiveTests.cs | 118 +- .../GZip/GZipWriterTests.cs | 120 +- .../Rar/RarArchiveTests.cs | 484 +- .../Rar/RarHeaderFactoryTest.cs | 116 +- .../SharpCompress.Test}/Rar/RarReaderTests.cs | 508 +- .../SharpCompress.Test}/ReaderTests.cs | 86 +- .../RewindableStreamTest.cs | 166 +- .../SevenZip/SevenZipArchiveTests.cs | 152 +- .../SharpCompress.Test.xproj | 0 .../Streams/StreamTests.cs | 38 +- .../Tar/TarArchiveTests.cs | 298 +- .../SharpCompress.Test}/Tar/TarReaderTests.cs | 182 +- .../SharpCompress.Test}/Tar/TarWriterTests.cs | 64 +- .../SharpCompress.Test}/TestBase.cs | 466 +- .../SharpCompress.Test}/TestStream.cs | 170 +- .../SharpCompress.Test}/WriterTests.cs | 72 +- .../Zip/ZipArchiveTests.cs | 810 +-- .../SharpCompress.Test}/Zip/ZipReaderTests.cs | 462 +- .../SharpCompress.Test}/Zip/ZipWriterTests.cs | 104 +- .../SharpCompress.Test}/project.json | 2 +- 306 files changed, 49104 insertions(+), 49455 deletions(-) delete mode 100644 SharpCompress.Test/SharpCompress.Test.Portable.csproj delete mode 100644 SharpCompress.Test/SharpCompress.Test.csproj delete mode 100644 SharpCompress.Test/global.json delete mode 100644 SharpCompress/sharpcompress.DotSettings create mode 100644 global.json rename {SharpCompress => src/SharpCompress}/Archive/AbstractArchive.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/AbstractWritableArchive.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/ArchiveFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/GZip/GZipArchive.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/GZip/GZipArchiveEntry.cs (95%) rename {SharpCompress => src/SharpCompress}/Archive/GZip/GZipWritableArchiveEntry.cs (95%) rename {SharpCompress => src/SharpCompress}/Archive/IArchive.Extensions.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/IArchive.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/IArchiveEntry.Extensions.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/IArchiveEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/IArchiveExtractionListener.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/IWritableArchive.Extensions.cs (100%) rename {SharpCompress => src/SharpCompress}/Archive/IWritableArchive.cs (100%) rename {SharpCompress => src/SharpCompress}/Archive/IWritableArchiveEntry.cs (94%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/FileInfoRarArchiveVolume.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/FileInfoRarFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/RarArchive.Extensions.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/RarArchive.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/RarArchiveEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/RarArchiveEntryFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/RarArchiveVolumeFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/SeekableFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Rar/StreamRarArchiveVolume.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/SevenZip/SevenZipArchive.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/SevenZip/SevenZipArchiveEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Tar/TarArchive.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/Tar/TarArchiveEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Tar/TarWritableArchiveEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Archive/Zip/ZipArchive.cs (97%) rename {SharpCompress => src/SharpCompress}/Archive/Zip/ZipArchiveEntry.cs (95%) rename {SharpCompress => src/SharpCompress}/Archive/Zip/ZipWritableArchiveEntry.cs (95%) rename {SharpCompress => src/SharpCompress}/AssemblyInfo.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/ArchiveEncoding.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/ArchiveException.cs (94%) rename {SharpCompress => src/SharpCompress}/Common/ArchiveExtractionEventArgs.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/ArchiveType.cs (93%) rename {SharpCompress => src/SharpCompress}/Common/CompressedBytesReadEventArgs.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/CompressionInfo.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/CompressionType.cs (93%) rename {SharpCompress => src/SharpCompress}/Common/CryptographicException.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Entry.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/EntryStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/ExtractOptions.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/ExtractionException.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/FilePart.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/FilePartExtractionBeginEventArgs.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/FlagUtility.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/GZip/GZipEntry.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/GZip/GZipFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/GZip/GZipVolume.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/IEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/IExtractionListener.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/IVolume.cs (93%) rename {SharpCompress => src/SharpCompress}/Common/IncompleteArchiveException.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/InvalidFormatException.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/MultiVolumeExtractionException.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/MultipartStreamRequiredException.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Options.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/PasswordProtectedException.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/AVHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/ArchiveHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/CommentHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/EndArchiveHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/FileHeader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/FileNameDecoder.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/Flags.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/MarkHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/NewSubHeader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/ProtectHeader.cs (100%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/RarHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/RarHeaderFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Rar/Headers/SignHeader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/RarCryptoBinaryReader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/RarCryptoWrapper.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/RarEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/RarFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Rar/RarRijndael.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Rar/RarVolume.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/ReaderExtractionEventArgs.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/ArchiveDatabase.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/ArchiveReader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/CBindPair.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/CCoderInfo.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/CFileItem.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/CFolder.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/CMethodId.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/CStreamSwitch.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/DataReader.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/SevenZipEntry.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/SevenZipFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/SevenZip/SevenZipVolume.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Tar/Headers/EntryType.cs (100%) rename {SharpCompress => src/SharpCompress}/Common/Tar/Headers/TarHeader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Tar/TarEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Tar/TarFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Tar/TarHeaderFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Tar/TarReadOnlySubStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Tar/TarVolume.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Volume.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/DirectoryEndHeader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/DirectoryEntryHeader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/HeaderFlags.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/IgnoreHeader.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/LocalEntryHeader.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/SplitHeader.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/ZipFileEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/ZipHeader.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/Headers/ZipHeaderType.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/PkwareTraditionalCryptoStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/PkwareTraditionalEncryptionData.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/SeekableZipFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/SeekableZipHeaderFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/StreamingZipFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/StreamingZipHeaderFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/WinzipAesCryptoStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/WinzipAesEncryptionData.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/WinzipAesKeySize.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/ZipCompressionMethod.cs (95%) rename {SharpCompress => src/SharpCompress}/Common/Zip/ZipEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Common/Zip/ZipFilePart.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/ZipHeaderFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Common/Zip/ZipVolume.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/BZip2/BZip2Constants.cs (98%) rename {SharpCompress => src/SharpCompress}/Compressor/BZip2/BZip2Stream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/BZip2/CBZip2InputStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/BZip2/CBZip2OutputStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/BZip2/CRC.cs (98%) rename {SharpCompress => src/SharpCompress}/Compressor/CompressionMode.cs (94%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/CRC32.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/DeflateManager.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/DeflateStream.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/FlushType.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/GZipStream.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/InfTree.cs (98%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/Inflate.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/Tree.cs (98%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/Zlib.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/ZlibBaseStream.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/ZlibCodec.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/ZlibConstants.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Deflate/ZlibStream.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Filters/BCJ2Filter.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Filters/BCJFilter.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Filters/Filter.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/AesDecoderStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Bcj2DecoderStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/BitVector.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/CRC.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/DecoderStream.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/ICoder.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LZ/CRC.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LZ/LzBinTree.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LZ/LzInWindow.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LZ/LzOutWindow.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Log.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LzmaBase.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LzmaDecoder.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LzmaEncoder.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LzmaEncoderProperties.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/LzmaStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/RangeCoder/RangeCoder.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/RangeCoder/RangeCoderBit.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Registry.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Utilites/CrcBuilderStream.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Utilites/CrcCheckStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Utilites/IPasswordProvider.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/LZMA/Utilites/Utils.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/FreqData.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/ModelPPM.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/PPMContext.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/Pointer.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/RangeCoder.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/RarMemBlock.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/RarNode.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/SEE2Context.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/State.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/StateRef.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/H/SubAllocator.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/Allocator.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/Coder.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/MemoryNode.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/Model.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/ModelRestorationMethod.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/Pointer.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/PpmContext.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/PpmState.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/I1/See2Context.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/PpmdProperties.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/PPMd/PpmdStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/AudioVariables.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/BitDecode.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/CodeType.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/Compress.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/Decode.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/DistDecode.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/FilterType.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/LitDecode.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/LowDistDecode.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/MultDecode.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Decode/RepDecode.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/MultiVolumeReadOnlyStream.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/PPM/BlockTypes.cs (94%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/RarCRC.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/RarStream.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Unpack.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Unpack15.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/Unpack20.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/UnpackFilter.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/UnpackUtility.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/BitInput.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/RarVM.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMCmdFlags.cs (98%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMCommands.cs (94%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMFlags.cs (94%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMOpType.cs (95%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMPreparedCommand.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMPreparedOperand.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMPreparedProgram.cs (97%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMStandardFilterSignature.cs (96%) rename {SharpCompress => src/SharpCompress}/Compressor/Rar/VM/VMStandardFilters.cs (95%) rename {SharpCompress => src/SharpCompress}/Crypto/BigInteger.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/BufferedBlockCipher.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/BufferedCipherBase.cs (95%) rename {SharpCompress => src/SharpCompress}/Crypto/CryptoException.cs (94%) rename {SharpCompress => src/SharpCompress}/Crypto/DataLengthException.cs (95%) rename {SharpCompress => src/SharpCompress}/Crypto/GeneralDigest.cs (95%) rename {SharpCompress => src/SharpCompress}/Crypto/HMac.cs (95%) rename {SharpCompress => src/SharpCompress}/Crypto/IBlockCipher.cs (97%) rename {SharpCompress => src/SharpCompress}/Crypto/IBufferedCipher.cs (97%) rename {SharpCompress => src/SharpCompress}/Crypto/ICipherParameters.cs (93%) rename {SharpCompress => src/SharpCompress}/Crypto/IDigest.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/IMac.cs (97%) rename {SharpCompress => src/SharpCompress}/Crypto/IMemoable.cs (100%) rename {SharpCompress => src/SharpCompress}/Crypto/KeyParameter.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/PBKDF2.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/Pack.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/RijndaelEngine.cs (97%) rename {SharpCompress => src/SharpCompress}/Crypto/Sha1Digest.cs (96%) rename {SharpCompress => src/SharpCompress}/Crypto/Sha256Digest.cs (100%) rename {SharpCompress => src/SharpCompress}/EnumExtensions.cs (95%) rename {SharpCompress => src/SharpCompress}/IO/AppendingStream.cs (96%) rename {SharpCompress => src/SharpCompress}/IO/CountingWritableSubStream.cs (95%) rename {SharpCompress => src/SharpCompress}/IO/ListeningStream.cs (96%) rename {SharpCompress => src/SharpCompress}/IO/MarkingBinaryReader.cs (96%) rename {SharpCompress => src/SharpCompress}/IO/NonDisposingStream.cs (95%) rename {SharpCompress => src/SharpCompress}/IO/ReadOnlySubStream.cs (96%) rename {SharpCompress => src/SharpCompress}/IO/RewindableStream.cs (96%) rename {SharpCompress => src/SharpCompress}/IO/StreamingMode.cs (94%) rename {SharpCompress => src/SharpCompress}/LazyReadOnlyCollection.cs (95%) rename {SharpCompress => src/SharpCompress}/ReadOnlyCollection.cs (95%) rename {SharpCompress => src/SharpCompress}/Reader/AbstractReader.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/GZip/GZipReader.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/IReader.Extensions.cs (97%) rename {SharpCompress => src/SharpCompress}/Reader/IReader.cs (97%) rename {SharpCompress => src/SharpCompress}/Reader/IReaderExtractionListener.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/Rar/MultiVolumeRarReader.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/Rar/NonSeekableStreamFilePart.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/Rar/RarReader.cs (97%) rename {SharpCompress => src/SharpCompress}/Reader/Rar/RarReaderEntry.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/Rar/RarReaderVolume.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/Rar/SingleVolumeRarReader.cs (96%) rename {SharpCompress => src/SharpCompress}/Reader/ReaderFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Reader/Tar/TarReader.cs (97%) rename {SharpCompress => src/SharpCompress}/Reader/Zip/ZipReader.cs (97%) rename {SharpCompress => src/SharpCompress}/SharpCompress.pfx (100%) rename {SharpCompress => src/SharpCompress}/SharpCompress.xproj (100%) rename {SharpCompress => src/SharpCompress}/Utility.cs (97%) rename {SharpCompress => src/SharpCompress}/Writer/AbstractWriter.cs (95%) rename {SharpCompress => src/SharpCompress}/Writer/GZip/GZipWriter.cs (96%) rename {SharpCompress => src/SharpCompress}/Writer/IWriter.Extensions.cs (97%) rename {SharpCompress => src/SharpCompress}/Writer/IWriter.cs (96%) rename {SharpCompress => src/SharpCompress}/Writer/Tar/TarWriter.cs (97%) rename {SharpCompress => src/SharpCompress}/Writer/WriterFactory.cs (97%) rename {SharpCompress => src/SharpCompress}/Writer/Zip/ZipCentralDirectoryEntry.cs (98%) rename {SharpCompress => src/SharpCompress}/Writer/Zip/ZipCompressionInfo.cs (100%) rename {SharpCompress => src/SharpCompress}/Writer/Zip/ZipWriter.cs (97%) rename {SharpCompress => src/SharpCompress}/project.json (98%) rename {SharpCompress.Test => test/SharpCompress.Test}/ArchiveTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/GZip/GZipArchiveTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/GZip/GZipWriterTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Rar/RarArchiveTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Rar/RarHeaderFactoryTest.cs (96%) rename {SharpCompress.Test => test/SharpCompress.Test}/Rar/RarReaderTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/ReaderTests.cs (88%) rename {SharpCompress.Test => test/SharpCompress.Test}/RewindableStreamTest.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/SevenZip/SevenZipArchiveTests.cs (96%) rename {SharpCompress.Test => test/SharpCompress.Test}/SharpCompress.Test.xproj (100%) rename {SharpCompress.Test => test/SharpCompress.Test}/Streams/StreamTests.cs (96%) rename {SharpCompress.Test => test/SharpCompress.Test}/Tar/TarArchiveTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Tar/TarReaderTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Tar/TarWriterTests.cs (96%) rename {SharpCompress.Test => test/SharpCompress.Test}/TestBase.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/TestStream.cs (95%) rename {SharpCompress.Test => test/SharpCompress.Test}/WriterTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Zip/ZipArchiveTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Zip/ZipReaderTests.cs (97%) rename {SharpCompress.Test => test/SharpCompress.Test}/Zip/ZipWriterTests.cs (96%) rename {SharpCompress.Test => test/SharpCompress.Test}/project.json (96%) diff --git a/SharpCompress.Test/SharpCompress.Test.Portable.csproj b/SharpCompress.Test/SharpCompress.Test.Portable.csproj deleted file mode 100644 index 944e5eb4..00000000 --- a/SharpCompress.Test/SharpCompress.Test.Portable.csproj +++ /dev/null @@ -1,113 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {E9C3C94B-FB27-4B4F-B225-57513C254D37} - Library - Properties - SharpCompress.Test - SharpCompress.Test.Portable - v4.0 - - - 512 - ..\..\sharpcompress\ - true - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - AnyCPU - true - full - false - bin\DebugPortable\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - false - - - ..\SharpCompress\SharpCompress.pfx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - SharpCompress.pfx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {efdcaf57-fd4d-4e5d-a3d5-f26b875817ed} - SharpCompress.PortableTest - - - - - \ No newline at end of file diff --git a/SharpCompress.Test/SharpCompress.Test.csproj b/SharpCompress.Test/SharpCompress.Test.csproj deleted file mode 100644 index 98b88909..00000000 --- a/SharpCompress.Test/SharpCompress.Test.csproj +++ /dev/null @@ -1,113 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {15679D7A-F22C-4943-87FF-BF5C76C4A6FD} - Library - Properties - SharpCompress.Test - SharpCompress.Test - v4.0 - - - 512 - ..\..\sharpcompress\ - true - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - false - - - ..\SharpCompress\SharpCompress.pfx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - SharpCompress.pfx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {27d535cb-2fd3-4621-8c9a-46161fc77a5d} - SharpCompress.Unsigned - - - - - \ No newline at end of file diff --git a/SharpCompress.Test/global.json b/SharpCompress.Test/global.json deleted file mode 100644 index b09540bb..00000000 --- a/SharpCompress.Test/global.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sdk": { - "version": "1.0.0-rc1-final" - } -} diff --git a/SharpCompress.sln b/SharpCompress.sln index 898da837..db973c5a 100644 --- a/SharpCompress.sln +++ b/SharpCompress.sln @@ -5,13 +5,17 @@ VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}" ProjectSection(SolutionItems) = preProject - SharpCompress.Test\global.json = SharpCompress.Test\global.json + global.json = global.json NuGet\sharpcompress.nuspec = NuGet\sharpcompress.nuspec EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress", "SharpCompress\SharpCompress.xproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress", "src\SharpCompress\SharpCompress.xproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress.Test", "SharpCompress.Test\SharpCompress.Test.xproj", "{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress.Test", "test\SharpCompress.Test\SharpCompress.Test.xproj", "{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -31,4 +35,8 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C} + {3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529} + EndGlobalSection EndGlobal diff --git a/SharpCompress/sharpcompress.DotSettings b/SharpCompress/sharpcompress.DotSettings deleted file mode 100644 index cb391bb6..00000000 --- a/SharpCompress/sharpcompress.DotSettings +++ /dev/null @@ -1,134 +0,0 @@ - - True - True - True - True - True - True - False - True - True - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - DoHide - True - ERROR - ERROR - ERROR - ERROR - ERROR - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - ERROR - DO_NOT_SHOW - <?xml version="1.0" encoding="utf-16"?><Profile name="Adam Clean"><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSReformatCode>True</CSReformatCode><CSShortenReferences>True</CSShortenReferences><HtmlReformatCode>True</HtmlReformatCode><JsInsertSemicolon>True</JsInsertSemicolon><JsReformatCode>True</JsReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier></Profile> - <?xml version="1.0" encoding="utf-16"?><Profile name="NaaS Clean"><CSReformatCode>True</CSReformatCode><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReorderTypeMembers>True</CSReorderTypeMembers><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty></Profile> - NaaS Clean - Default: Full Cleanup - True - NEXT_LINE - NEXT_LINE - SEPARATE - True - True - True - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - ALWAYS_ADD - True - NEXT_LINE - False - False - False - False - False - False - False - True - LINE_BREAK - False - False - True - WRAP_IF_LONG - WRAP_IF_LONG - WRAP_IF_LONG - CHOP_ALWAYS - CHOP_ALWAYS - WRAP_IF_LONG - True - True - True - False - True - Automatic property - True - False - False - True - False - False - True - False - False - True - False - False - EC - IIS - <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> - <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - $object$_On$event$ - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - True - True - True - True \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 00000000..29fdab68 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "projects": ["src","test"], + "sdk": { + "version": "1.0.0-rc1-final" + } +} diff --git a/SharpCompress/Archive/AbstractArchive.cs b/src/SharpCompress/Archive/AbstractArchive.cs similarity index 97% rename from SharpCompress/Archive/AbstractArchive.cs rename to src/SharpCompress/Archive/AbstractArchive.cs index 27c01366..8f51d31d 100644 --- a/SharpCompress/Archive/AbstractArchive.cs +++ b/src/SharpCompress/Archive/AbstractArchive.cs @@ -1,212 +1,212 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Reader; - -namespace SharpCompress.Archive -{ - public abstract class AbstractArchive : IArchive, IArchiveExtractionListener - where TEntry : IArchiveEntry - where TVolume : IVolume - { - private readonly LazyReadOnlyCollection lazyVolumes; - private readonly LazyReadOnlyCollection lazyEntries; - - public event EventHandler> EntryExtractionBegin; - public event EventHandler> EntryExtractionEnd; - - public event EventHandler CompressedBytesRead; - public event EventHandler FilePartExtractionBegin; - - protected string Password { get; private set; } - -#if !DOTNET51 - internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options, string password) - { - Type = type; - Password = password; - if (!fileInfo.Exists) - { - throw new ArgumentException("File does not exist: " + fileInfo.FullName); - } - options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); - lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(fileInfo, options)); - lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); - } - - - protected abstract IEnumerable LoadVolumes(FileInfo file, Options options); -#endif - - internal AbstractArchive(ArchiveType type, IEnumerable streams, Options options, string password) - { - Type = type; - Password = password; - lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(streams.Select(CheckStreams), options)); - lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); - } - - internal AbstractArchive(ArchiveType type) - { - Type = type; - lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty()); - lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty()); - } - public ArchiveType Type { get; private set; } - - void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) - { - if (EntryExtractionBegin != null) - { - EntryExtractionBegin(this, new ArchiveExtractionEventArgs(entry)); - } - } - - void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) - { - if (EntryExtractionEnd != null) - { - EntryExtractionEnd(this, new ArchiveExtractionEventArgs(entry)); - } - } - - private static Stream CheckStreams(Stream stream) - { - if (!stream.CanSeek || !stream.CanRead) - { - throw new ArgumentException("Archive streams must be Readable and Seekable"); - } - return stream; - } - - /// - /// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive. - /// - public virtual ICollection Entries - { - get { return lazyEntries; } - } - - /// - /// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive. - /// - public ICollection Volumes - { - get { return lazyVolumes; } - } - - /// - /// The total size of the files compressed in the archive. - /// - public virtual long TotalSize - { - get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); } - } - - /// - /// The total size of the files as uncompressed in the archive. - /// - public virtual long TotalUncompressSize - { - get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); } - } - - protected abstract IEnumerable LoadVolumes(IEnumerable streams, Options options); - protected abstract IEnumerable LoadEntries(IEnumerable volumes); - - IEnumerable IArchive.Entries - { - get { return Entries.Cast(); } - } - - IEnumerable IArchive.Volumes - { - get { return lazyVolumes.Cast(); } - } - - private bool disposed; - - public virtual void Dispose() - { - if (!disposed) - { - lazyVolumes.ForEach(v => v.Dispose()); - lazyEntries.GetLoaded().Cast().ForEach(x => x.Close()); - disposed = true; - } - } - - void IArchiveExtractionListener.EnsureEntriesLoaded() - { - lazyEntries.EnsureFullyLoaded(); - lazyVolumes.EnsureFullyLoaded(); - } - - void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) - { - if (CompressedBytesRead != null) - { - CompressedBytesRead(this, new CompressedBytesReadEventArgs() - { - CurrentFilePartCompressedBytesRead = currentPartCompressedBytes, - CompressedBytesRead = compressedReadBytes - }); - } - } - - void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) - { - if (FilePartExtractionBegin != null) - { - FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs() - { - CompressedSize = compressedSize, - Size = size, - Name = name, - }); - } - } - - /// - /// Use this method to extract all entries in an archive in order. - /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be - /// extracted sequentially for the best performance. - /// - /// This method will load all entry information from the archive. - /// - /// WARNING: this will reuse the underlying stream for the archive. Errors may - /// occur if this is used at the same time as other extraction methods on this instance. - /// - /// - public IReader ExtractAllEntries() - { - ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); - return CreateReaderForSolidExtraction(); - } - - protected abstract IReader CreateReaderForSolidExtraction(); - - /// - /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). - /// - public virtual bool IsSolid - { - get { return false; } - } - - - /// - /// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive. - /// - public bool IsComplete - { - get - { - ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); - return Entries.All(x => x.IsComplete); - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Reader; + +namespace SharpCompress.Archive +{ + public abstract class AbstractArchive : IArchive, IArchiveExtractionListener + where TEntry : IArchiveEntry + where TVolume : IVolume + { + private readonly LazyReadOnlyCollection lazyVolumes; + private readonly LazyReadOnlyCollection lazyEntries; + + public event EventHandler> EntryExtractionBegin; + public event EventHandler> EntryExtractionEnd; + + public event EventHandler CompressedBytesRead; + public event EventHandler FilePartExtractionBegin; + + protected string Password { get; private set; } + +#if !DOTNET51 + internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options, string password) + { + Type = type; + Password = password; + if (!fileInfo.Exists) + { + throw new ArgumentException("File does not exist: " + fileInfo.FullName); + } + options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); + lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(fileInfo, options)); + lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); + } + + + protected abstract IEnumerable LoadVolumes(FileInfo file, Options options); +#endif + + internal AbstractArchive(ArchiveType type, IEnumerable streams, Options options, string password) + { + Type = type; + Password = password; + lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(streams.Select(CheckStreams), options)); + lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); + } + + internal AbstractArchive(ArchiveType type) + { + Type = type; + lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty()); + lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty()); + } + public ArchiveType Type { get; private set; } + + void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) + { + if (EntryExtractionBegin != null) + { + EntryExtractionBegin(this, new ArchiveExtractionEventArgs(entry)); + } + } + + void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) + { + if (EntryExtractionEnd != null) + { + EntryExtractionEnd(this, new ArchiveExtractionEventArgs(entry)); + } + } + + private static Stream CheckStreams(Stream stream) + { + if (!stream.CanSeek || !stream.CanRead) + { + throw new ArgumentException("Archive streams must be Readable and Seekable"); + } + return stream; + } + + /// + /// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive. + /// + public virtual ICollection Entries + { + get { return lazyEntries; } + } + + /// + /// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive. + /// + public ICollection Volumes + { + get { return lazyVolumes; } + } + + /// + /// The total size of the files compressed in the archive. + /// + public virtual long TotalSize + { + get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); } + } + + /// + /// The total size of the files as uncompressed in the archive. + /// + public virtual long TotalUncompressSize + { + get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); } + } + + protected abstract IEnumerable LoadVolumes(IEnumerable streams, Options options); + protected abstract IEnumerable LoadEntries(IEnumerable volumes); + + IEnumerable IArchive.Entries + { + get { return Entries.Cast(); } + } + + IEnumerable IArchive.Volumes + { + get { return lazyVolumes.Cast(); } + } + + private bool disposed; + + public virtual void Dispose() + { + if (!disposed) + { + lazyVolumes.ForEach(v => v.Dispose()); + lazyEntries.GetLoaded().Cast().ForEach(x => x.Close()); + disposed = true; + } + } + + void IArchiveExtractionListener.EnsureEntriesLoaded() + { + lazyEntries.EnsureFullyLoaded(); + lazyVolumes.EnsureFullyLoaded(); + } + + void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) + { + if (CompressedBytesRead != null) + { + CompressedBytesRead(this, new CompressedBytesReadEventArgs() + { + CurrentFilePartCompressedBytesRead = currentPartCompressedBytes, + CompressedBytesRead = compressedReadBytes + }); + } + } + + void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) + { + if (FilePartExtractionBegin != null) + { + FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs() + { + CompressedSize = compressedSize, + Size = size, + Name = name, + }); + } + } + + /// + /// Use this method to extract all entries in an archive in order. + /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be + /// extracted sequentially for the best performance. + /// + /// This method will load all entry information from the archive. + /// + /// WARNING: this will reuse the underlying stream for the archive. Errors may + /// occur if this is used at the same time as other extraction methods on this instance. + /// + /// + public IReader ExtractAllEntries() + { + ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); + return CreateReaderForSolidExtraction(); + } + + protected abstract IReader CreateReaderForSolidExtraction(); + + /// + /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). + /// + public virtual bool IsSolid + { + get { return false; } + } + + + /// + /// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive. + /// + public bool IsComplete + { + get + { + ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); + return Entries.All(x => x.IsComplete); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/AbstractWritableArchive.cs b/src/SharpCompress/Archive/AbstractWritableArchive.cs similarity index 97% rename from SharpCompress/Archive/AbstractWritableArchive.cs rename to src/SharpCompress/Archive/AbstractWritableArchive.cs index 074a95c3..3efa2ba3 100644 --- a/SharpCompress/Archive/AbstractWritableArchive.cs +++ b/src/SharpCompress/Archive/AbstractWritableArchive.cs @@ -1,149 +1,149 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; - -namespace SharpCompress.Archive -{ - public abstract class AbstractWritableArchive : AbstractArchive, IWritableArchive - where TEntry : IArchiveEntry - where TVolume : IVolume - { - private readonly List newEntries = new List(); - private readonly List removedEntries = new List(); - - private readonly List modifiedEntries = new List(); - private bool hasModifications; - - internal AbstractWritableArchive(ArchiveType type) - : base(type) - { - } - - internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options) - : base(type, stream.AsEnumerable(), options, null) - { - } - -#if !DOTNET51 - internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options) - : base(type, fileInfo, options, null) - { - } -#endif - - public override ICollection Entries - { - get - { - if (hasModifications) - { - return modifiedEntries; - } - return base.Entries; - } - } - - private void RebuildModifiedCollection() - { - hasModifications = true; - newEntries.RemoveAll(v => removedEntries.Contains(v)); - modifiedEntries.Clear(); - modifiedEntries.AddRange(OldEntries.Concat(newEntries)); - } - - private IEnumerable OldEntries - { - get { return base.Entries.Where(x => !removedEntries.Contains(x)); } - } - - public void RemoveEntry(TEntry entry) - { - if (!removedEntries.Contains(entry)) - { - removedEntries.Add(entry); - RebuildModifiedCollection(); - } - } - void IWritableArchive.RemoveEntry(IArchiveEntry entry) - { - RemoveEntry((TEntry)entry); - } - - public TEntry AddEntry(string key, Stream source, - long size = 0, DateTime? modified = null) - { - return AddEntry(key, source, false, size, modified); - } - - - IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified) - { - return AddEntry(key, source, closeStream, size, modified); - } - - public TEntry AddEntry(string key, Stream source, bool closeStream, - long size = 0, DateTime? modified = null) - { - if (key.StartsWith("/") - || key.StartsWith("\\")) - { - key = key.Substring(1); - } - if (DoesKeyMatchExisting(key)) - { - throw new ArchiveException("Cannot add entry with duplicate key: " + key); - } - var entry = CreateEntry(key, source, size, modified, closeStream); - newEntries.Add(entry); - RebuildModifiedCollection(); - return entry; - } - - private bool DoesKeyMatchExisting(string key) - { - foreach (var path in Entries.Select(x => x.Key)) - { - var p = path.Replace('/','\\'); - if (p.StartsWith("\\")) - { - p = p.Substring(1); - } - return string.Equals(p, key, StringComparison.OrdinalIgnoreCase); - } - return false; - } - - public void SaveTo(Stream stream, CompressionInfo compressionType) - { - //reset streams of new entries - newEntries.Cast().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); - SaveTo(stream, compressionType, OldEntries, newEntries); - } - - protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified, - bool closeStream) - { - if (!source.CanRead || !source.CanSeek) - { - throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API"); - } - return CreateEntryInternal(key, source, size, modified, closeStream); - } - - protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified, - bool closeStream); - - protected abstract void SaveTo(Stream stream, CompressionInfo compressionType, - IEnumerable oldEntries, IEnumerable newEntries); - - public override void Dispose() - { - base.Dispose(); - newEntries.Cast().ForEach(x => x.Close()); - removedEntries.Cast().ForEach(x => x.Close()); - modifiedEntries.Cast().ForEach(x => x.Close()); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; + +namespace SharpCompress.Archive +{ + public abstract class AbstractWritableArchive : AbstractArchive, IWritableArchive + where TEntry : IArchiveEntry + where TVolume : IVolume + { + private readonly List newEntries = new List(); + private readonly List removedEntries = new List(); + + private readonly List modifiedEntries = new List(); + private bool hasModifications; + + internal AbstractWritableArchive(ArchiveType type) + : base(type) + { + } + + internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options) + : base(type, stream.AsEnumerable(), options, null) + { + } + +#if !DOTNET51 + internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options) + : base(type, fileInfo, options, null) + { + } +#endif + + public override ICollection Entries + { + get + { + if (hasModifications) + { + return modifiedEntries; + } + return base.Entries; + } + } + + private void RebuildModifiedCollection() + { + hasModifications = true; + newEntries.RemoveAll(v => removedEntries.Contains(v)); + modifiedEntries.Clear(); + modifiedEntries.AddRange(OldEntries.Concat(newEntries)); + } + + private IEnumerable OldEntries + { + get { return base.Entries.Where(x => !removedEntries.Contains(x)); } + } + + public void RemoveEntry(TEntry entry) + { + if (!removedEntries.Contains(entry)) + { + removedEntries.Add(entry); + RebuildModifiedCollection(); + } + } + void IWritableArchive.RemoveEntry(IArchiveEntry entry) + { + RemoveEntry((TEntry)entry); + } + + public TEntry AddEntry(string key, Stream source, + long size = 0, DateTime? modified = null) + { + return AddEntry(key, source, false, size, modified); + } + + + IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified) + { + return AddEntry(key, source, closeStream, size, modified); + } + + public TEntry AddEntry(string key, Stream source, bool closeStream, + long size = 0, DateTime? modified = null) + { + if (key.StartsWith("/") + || key.StartsWith("\\")) + { + key = key.Substring(1); + } + if (DoesKeyMatchExisting(key)) + { + throw new ArchiveException("Cannot add entry with duplicate key: " + key); + } + var entry = CreateEntry(key, source, size, modified, closeStream); + newEntries.Add(entry); + RebuildModifiedCollection(); + return entry; + } + + private bool DoesKeyMatchExisting(string key) + { + foreach (var path in Entries.Select(x => x.Key)) + { + var p = path.Replace('/','\\'); + if (p.StartsWith("\\")) + { + p = p.Substring(1); + } + return string.Equals(p, key, StringComparison.OrdinalIgnoreCase); + } + return false; + } + + public void SaveTo(Stream stream, CompressionInfo compressionType) + { + //reset streams of new entries + newEntries.Cast().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); + SaveTo(stream, compressionType, OldEntries, newEntries); + } + + protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified, + bool closeStream) + { + if (!source.CanRead || !source.CanSeek) + { + throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API"); + } + return CreateEntryInternal(key, source, size, modified, closeStream); + } + + protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified, + bool closeStream); + + protected abstract void SaveTo(Stream stream, CompressionInfo compressionType, + IEnumerable oldEntries, IEnumerable newEntries); + + public override void Dispose() + { + base.Dispose(); + newEntries.Cast().ForEach(x => x.Close()); + removedEntries.Cast().ForEach(x => x.Close()); + modifiedEntries.Cast().ForEach(x => x.Close()); + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/ArchiveFactory.cs b/src/SharpCompress/Archive/ArchiveFactory.cs similarity index 97% rename from SharpCompress/Archive/ArchiveFactory.cs rename to src/SharpCompress/Archive/ArchiveFactory.cs index a5411b74..bba5c9fe 100644 --- a/SharpCompress/Archive/ArchiveFactory.cs +++ b/src/SharpCompress/Archive/ArchiveFactory.cs @@ -1,172 +1,172 @@ -using System; -using System.IO; -using SharpCompress.Archive.GZip; -using SharpCompress.Archive.Rar; -using SharpCompress.Archive.SevenZip; -using SharpCompress.Archive.Tar; -using SharpCompress.Archive.Zip; -using SharpCompress.Common; - -namespace SharpCompress.Archive -{ - public class ArchiveFactory - { - /// - /// Opens an Archive for random access - /// - /// - /// - /// - public static IArchive Open(Stream stream, Options options = Options.KeepStreamsOpen) - { - stream.CheckNotNull("stream"); - if (!stream.CanRead || !stream.CanSeek) - { - throw new ArgumentException("Stream should be readable and seekable"); - } - - if (ZipArchive.IsZipFile(stream, null)) - { - stream.Seek(0, SeekOrigin.Begin); - return ZipArchive.Open(stream, options, null); - } - stream.Seek(0, SeekOrigin.Begin); - if (TarArchive.IsTarFile(stream)) - { - stream.Seek(0, SeekOrigin.Begin); - return TarArchive.Open(stream, options); - } - stream.Seek(0, SeekOrigin.Begin); - if (SevenZipArchive.IsSevenZipFile(stream)) - { - stream.Seek(0, SeekOrigin.Begin); - return SevenZipArchive.Open(stream, options); - } - stream.Seek(0, SeekOrigin.Begin); - if (GZipArchive.IsGZipFile(stream)) - { - stream.Seek(0, SeekOrigin.Begin); - return GZipArchive.Open(stream, options); - } - stream.Seek(0, SeekOrigin.Begin); - if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen)) - { - stream.Seek(0, SeekOrigin.Begin); - return RarArchive.Open(stream, options); - } - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); - } - - public static IWritableArchive Create(ArchiveType type) - { - switch (type) - { - case ArchiveType.Zip: - { - return ZipArchive.Create(); - } - case ArchiveType.Tar: - { - return TarArchive.Create(); - } - case ArchiveType.GZip: - { - return GZipArchive.Create(); - } - default: - { - throw new NotSupportedException("Cannot create Archives of type: " + type); - } - } - } - -#if !DOTNET51 - /// - /// Constructor expects a filepath to an existing file. - /// - /// - public static IArchive Open(string filePath) - { - return Open(filePath, Options.None); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - public static IArchive Open(FileInfo fileInfo) - { - return Open(fileInfo, Options.None); - } - - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static IArchive Open(string filePath, Options options) - { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), options); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static IArchive Open(FileInfo fileInfo, Options options) - { - fileInfo.CheckNotNull("fileInfo"); - using (var stream = fileInfo.OpenRead()) - { - if (ZipArchive.IsZipFile(stream, null)) - { - stream.Dispose(); - return ZipArchive.Open(fileInfo, options, null); - } - stream.Seek(0, SeekOrigin.Begin); - if (TarArchive.IsTarFile(stream)) - { - stream.Dispose(); - return TarArchive.Open(fileInfo, options); - } - stream.Seek(0, SeekOrigin.Begin); - if (SevenZipArchive.IsSevenZipFile(stream)) - { - stream.Dispose(); - return SevenZipArchive.Open(fileInfo, options); - } - stream.Seek(0, SeekOrigin.Begin); - if (GZipArchive.IsGZipFile(stream)) - { - stream.Dispose(); - return GZipArchive.Open(fileInfo, options); - } - stream.Seek(0, SeekOrigin.Begin); - if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen)) - { - stream.Dispose(); - return RarArchive.Open(fileInfo, options); - } - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); - } - } - - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteToDirectory(string sourceArchive, string destinationDirectory, - ExtractOptions options = ExtractOptions.Overwrite) - { - using (IArchive archive = Open(sourceArchive)) - { - foreach (IArchiveEntry entry in archive.Entries) - { - entry.WriteToDirectory(destinationDirectory, options); - } - } - } -#endif - } +using System; +using System.IO; +using SharpCompress.Archive.GZip; +using SharpCompress.Archive.Rar; +using SharpCompress.Archive.SevenZip; +using SharpCompress.Archive.Tar; +using SharpCompress.Archive.Zip; +using SharpCompress.Common; + +namespace SharpCompress.Archive +{ + public class ArchiveFactory + { + /// + /// Opens an Archive for random access + /// + /// + /// + /// + public static IArchive Open(Stream stream, Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + if (!stream.CanRead || !stream.CanSeek) + { + throw new ArgumentException("Stream should be readable and seekable"); + } + + if (ZipArchive.IsZipFile(stream, null)) + { + stream.Seek(0, SeekOrigin.Begin); + return ZipArchive.Open(stream, options, null); + } + stream.Seek(0, SeekOrigin.Begin); + if (TarArchive.IsTarFile(stream)) + { + stream.Seek(0, SeekOrigin.Begin); + return TarArchive.Open(stream, options); + } + stream.Seek(0, SeekOrigin.Begin); + if (SevenZipArchive.IsSevenZipFile(stream)) + { + stream.Seek(0, SeekOrigin.Begin); + return SevenZipArchive.Open(stream, options); + } + stream.Seek(0, SeekOrigin.Begin); + if (GZipArchive.IsGZipFile(stream)) + { + stream.Seek(0, SeekOrigin.Begin); + return GZipArchive.Open(stream, options); + } + stream.Seek(0, SeekOrigin.Begin); + if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen)) + { + stream.Seek(0, SeekOrigin.Begin); + return RarArchive.Open(stream, options); + } + throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); + } + + public static IWritableArchive Create(ArchiveType type) + { + switch (type) + { + case ArchiveType.Zip: + { + return ZipArchive.Create(); + } + case ArchiveType.Tar: + { + return TarArchive.Create(); + } + case ArchiveType.GZip: + { + return GZipArchive.Create(); + } + default: + { + throw new NotSupportedException("Cannot create Archives of type: " + type); + } + } + } + +#if !DOTNET51 + /// + /// Constructor expects a filepath to an existing file. + /// + /// + public static IArchive Open(string filePath) + { + return Open(filePath, Options.None); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + public static IArchive Open(FileInfo fileInfo) + { + return Open(fileInfo, Options.None); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static IArchive Open(string filePath, Options options) + { + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), options); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static IArchive Open(FileInfo fileInfo, Options options) + { + fileInfo.CheckNotNull("fileInfo"); + using (var stream = fileInfo.OpenRead()) + { + if (ZipArchive.IsZipFile(stream, null)) + { + stream.Dispose(); + return ZipArchive.Open(fileInfo, options, null); + } + stream.Seek(0, SeekOrigin.Begin); + if (TarArchive.IsTarFile(stream)) + { + stream.Dispose(); + return TarArchive.Open(fileInfo, options); + } + stream.Seek(0, SeekOrigin.Begin); + if (SevenZipArchive.IsSevenZipFile(stream)) + { + stream.Dispose(); + return SevenZipArchive.Open(fileInfo, options); + } + stream.Seek(0, SeekOrigin.Begin); + if (GZipArchive.IsGZipFile(stream)) + { + stream.Dispose(); + return GZipArchive.Open(fileInfo, options); + } + stream.Seek(0, SeekOrigin.Begin); + if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen)) + { + stream.Dispose(); + return RarArchive.Open(fileInfo, options); + } + throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip"); + } + } + + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteToDirectory(string sourceArchive, string destinationDirectory, + ExtractOptions options = ExtractOptions.Overwrite) + { + using (IArchive archive = Open(sourceArchive)) + { + foreach (IArchiveEntry entry in archive.Entries) + { + entry.WriteToDirectory(destinationDirectory, options); + } + } + } +#endif + } } \ No newline at end of file diff --git a/SharpCompress/Archive/GZip/GZipArchive.cs b/src/SharpCompress/Archive/GZip/GZipArchive.cs similarity index 96% rename from SharpCompress/Archive/GZip/GZipArchive.cs rename to src/SharpCompress/Archive/GZip/GZipArchive.cs index 17c5845f..ff3c57a8 100644 --- a/SharpCompress/Archive/GZip/GZipArchive.cs +++ b/src/SharpCompress/Archive/GZip/GZipArchive.cs @@ -1,218 +1,218 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.GZip; -using SharpCompress.Reader; -using SharpCompress.Reader.GZip; -using SharpCompress.Writer.GZip; - -namespace SharpCompress.Archive.GZip -{ - public class GZipArchive : AbstractWritableArchive - { -#if !DOTNET51 - /// - /// Constructor expects a filepath to an existing file. - /// - /// - public static GZipArchive Open(string filePath) - { - return Open(filePath, Options.None); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - public static GZipArchive Open(FileInfo fileInfo) - { - return Open(fileInfo, Options.None); - } - - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static GZipArchive Open(string filePath, Options options) - { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), options); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static GZipArchive Open(FileInfo fileInfo, Options options) - { - fileInfo.CheckNotNull("fileInfo"); - return new GZipArchive(fileInfo, options); - } -#endif - - /// - /// Takes a seekable Stream as a source - /// - /// - public static GZipArchive Open(Stream stream) - { - stream.CheckNotNull("stream"); - return Open(stream, Options.None); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static GZipArchive Open(Stream stream, Options options) - { - stream.CheckNotNull("stream"); - return new GZipArchive(stream, options); - } - - public static GZipArchive Create() - { - return new GZipArchive(); - } - -#if !DOTNET51 - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - internal GZipArchive(FileInfo fileInfo, Options options) - : base(ArchiveType.GZip, fileInfo, options) - { - } - - protected override IEnumerable LoadVolumes(FileInfo file, Options options) - { - return new GZipVolume(file, options).AsEnumerable(); - } - - public static bool IsGZipFile(string filePath) - { - return IsGZipFile(new FileInfo(filePath)); - } - - public static bool IsGZipFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsGZipFile(stream); - } - } - - public void SaveTo(string filePath) - { - SaveTo(new FileInfo(filePath)); - } - - public void SaveTo(FileInfo fileInfo) - { - using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write)) - { - SaveTo(stream); - } - } -#endif - - public static bool IsGZipFile(Stream stream) - { - // read the header on the first read - byte[] header = new byte[10]; - int n = stream.Read(header, 0, header.Length); - - // workitem 8501: handle edge case (decompress empty stream) - if (n == 0) - return false; - - if (n != 10) - return false; - - if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) - return false; - - return true; - } - - /// - /// Takes multiple seekable Streams for a multi-part archive - /// - /// - /// - internal GZipArchive(Stream stream, Options options) - : base(ArchiveType.GZip, stream, options) - { - } - - internal GZipArchive() - : base(ArchiveType.GZip) - { - } - - public void SaveTo(Stream stream) - { - SaveTo(stream, CompressionType.GZip); - } - - protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, - bool closeStream) - { - if (Entries.Any()) - { - throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); - } - return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); - } - - protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, - IEnumerable oldEntries, - IEnumerable newEntries) - { - if (Entries.Count > 1) - { - throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); - } - using (var writer = new GZipWriter(stream)) - { - foreach (var entry in oldEntries.Concat(newEntries) - .Where(x => !x.IsDirectory)) - { - using (var entryStream = entry.OpenEntryStream()) - { - writer.Write(entry.Key, entryStream, entry.LastModifiedTime); - } - } - } - } - - protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) - { - return new GZipVolume(streams.First(), options).AsEnumerable(); - } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - Stream stream = volumes.Single().Stream; - yield return new GZipArchiveEntry(this, new GZipFilePart(stream)); - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.Single().Stream; - stream.Position = 0; - return GZipReader.Open(stream); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.GZip; +using SharpCompress.Reader; +using SharpCompress.Reader.GZip; +using SharpCompress.Writer.GZip; + +namespace SharpCompress.Archive.GZip +{ + public class GZipArchive : AbstractWritableArchive + { +#if !DOTNET51 + /// + /// Constructor expects a filepath to an existing file. + /// + /// + public static GZipArchive Open(string filePath) + { + return Open(filePath, Options.None); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + public static GZipArchive Open(FileInfo fileInfo) + { + return Open(fileInfo, Options.None); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static GZipArchive Open(string filePath, Options options) + { + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), options); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static GZipArchive Open(FileInfo fileInfo, Options options) + { + fileInfo.CheckNotNull("fileInfo"); + return new GZipArchive(fileInfo, options); + } +#endif + + /// + /// Takes a seekable Stream as a source + /// + /// + public static GZipArchive Open(Stream stream) + { + stream.CheckNotNull("stream"); + return Open(stream, Options.None); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static GZipArchive Open(Stream stream, Options options) + { + stream.CheckNotNull("stream"); + return new GZipArchive(stream, options); + } + + public static GZipArchive Create() + { + return new GZipArchive(); + } + +#if !DOTNET51 + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + internal GZipArchive(FileInfo fileInfo, Options options) + : base(ArchiveType.GZip, fileInfo, options) + { + } + + protected override IEnumerable LoadVolumes(FileInfo file, Options options) + { + return new GZipVolume(file, options).AsEnumerable(); + } + + public static bool IsGZipFile(string filePath) + { + return IsGZipFile(new FileInfo(filePath)); + } + + public static bool IsGZipFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) + { + return false; + } + using (Stream stream = fileInfo.OpenRead()) + { + return IsGZipFile(stream); + } + } + + public void SaveTo(string filePath) + { + SaveTo(new FileInfo(filePath)); + } + + public void SaveTo(FileInfo fileInfo) + { + using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write)) + { + SaveTo(stream); + } + } +#endif + + public static bool IsGZipFile(Stream stream) + { + // read the header on the first read + byte[] header = new byte[10]; + int n = stream.Read(header, 0, header.Length); + + // workitem 8501: handle edge case (decompress empty stream) + if (n == 0) + return false; + + if (n != 10) + return false; + + if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) + return false; + + return true; + } + + /// + /// Takes multiple seekable Streams for a multi-part archive + /// + /// + /// + internal GZipArchive(Stream stream, Options options) + : base(ArchiveType.GZip, stream, options) + { + } + + internal GZipArchive() + : base(ArchiveType.GZip) + { + } + + public void SaveTo(Stream stream) + { + SaveTo(stream, CompressionType.GZip); + } + + protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, + bool closeStream) + { + if (Entries.Any()) + { + throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); + } + return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); + } + + protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, + IEnumerable oldEntries, + IEnumerable newEntries) + { + if (Entries.Count > 1) + { + throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); + } + using (var writer = new GZipWriter(stream)) + { + foreach (var entry in oldEntries.Concat(newEntries) + .Where(x => !x.IsDirectory)) + { + using (var entryStream = entry.OpenEntryStream()) + { + writer.Write(entry.Key, entryStream, entry.LastModifiedTime); + } + } + } + } + + protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) + { + return new GZipVolume(streams.First(), options).AsEnumerable(); + } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + Stream stream = volumes.Single().Stream; + yield return new GZipArchiveEntry(this, new GZipFilePart(stream)); + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.Single().Stream; + stream.Position = 0; + return GZipReader.Open(stream); + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/GZip/GZipArchiveEntry.cs b/src/SharpCompress/Archive/GZip/GZipArchiveEntry.cs similarity index 95% rename from SharpCompress/Archive/GZip/GZipArchiveEntry.cs rename to src/SharpCompress/Archive/GZip/GZipArchiveEntry.cs index 4526956d..6c46f7a1 100644 --- a/SharpCompress/Archive/GZip/GZipArchiveEntry.cs +++ b/src/SharpCompress/Archive/GZip/GZipArchiveEntry.cs @@ -1,31 +1,31 @@ -using System.IO; -using System.Linq; -using SharpCompress.Common.GZip; - -namespace SharpCompress.Archive.GZip -{ - public class GZipArchiveEntry : GZipEntry, IArchiveEntry - { - - internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) - : base(part) - { - Archive = archive; - } - - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } - - #region IArchiveEntry Members - public IArchive Archive { get; private set; } - - public bool IsComplete - { - get { return true; } - } - - #endregion - } +using System.IO; +using System.Linq; +using SharpCompress.Common.GZip; + +namespace SharpCompress.Archive.GZip +{ + public class GZipArchiveEntry : GZipEntry, IArchiveEntry + { + + internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) + : base(part) + { + Archive = archive; + } + + public virtual Stream OpenEntryStream() + { + return Parts.Single().GetCompressedStream(); + } + + #region IArchiveEntry Members + public IArchive Archive { get; private set; } + + public bool IsComplete + { + get { return true; } + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Archive/GZip/GZipWritableArchiveEntry.cs b/src/SharpCompress/Archive/GZip/GZipWritableArchiveEntry.cs similarity index 95% rename from SharpCompress/Archive/GZip/GZipWritableArchiveEntry.cs rename to src/SharpCompress/Archive/GZip/GZipWritableArchiveEntry.cs index 8ef98379..0c5067b5 100644 --- a/SharpCompress/Archive/GZip/GZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archive/GZip/GZipWritableArchiveEntry.cs @@ -1,111 +1,111 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.IO; - -namespace SharpCompress.Archive.GZip -{ - internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry - { - private readonly string path; - private readonly long size; - private readonly DateTime? lastModified; - private readonly bool closeStream; - private readonly Stream stream; - - internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream, - string path, long size, DateTime? lastModified, bool closeStream) - : base(archive, null) - { - this.stream = stream; - this.path = path; - this.size = size; - this.lastModified = lastModified; - this.closeStream = closeStream; - } - - public override long Crc - { - get { return 0; } - } - - public override string Key - { - get { return path; } - } - - public override long CompressedSize - { - get { return 0; } - } - - public override long Size - { - get { return size; } - } - - public override DateTime? LastModifiedTime - { - get { return lastModified; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return false; } - } - - public override bool IsDirectory - { - get { return false; } - } - - public override bool IsSplit - { - get { return false; } - } - - internal override IEnumerable Parts - { - get { throw new NotImplementedException(); } - } - - Stream IWritableArchiveEntry.Stream - { - get - { - return stream; - } - } - - public override Stream OpenEntryStream() - { - //ensure new stream is at the start, this could be reset - stream.Seek(0, SeekOrigin.Begin); - return new NonDisposingStream(stream); - } - - internal override void Close() - { - if (closeStream) - { - stream.Dispose(); - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.IO; + +namespace SharpCompress.Archive.GZip +{ + internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry + { + private readonly string path; + private readonly long size; + private readonly DateTime? lastModified; + private readonly bool closeStream; + private readonly Stream stream; + + internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream, + string path, long size, DateTime? lastModified, bool closeStream) + : base(archive, null) + { + this.stream = stream; + this.path = path; + this.size = size; + this.lastModified = lastModified; + this.closeStream = closeStream; + } + + public override long Crc + { + get { return 0; } + } + + public override string Key + { + get { return path; } + } + + public override long CompressedSize + { + get { return 0; } + } + + public override long Size + { + get { return size; } + } + + public override DateTime? LastModifiedTime + { + get { return lastModified; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return false; } + } + + public override bool IsDirectory + { + get { return false; } + } + + public override bool IsSplit + { + get { return false; } + } + + internal override IEnumerable Parts + { + get { throw new NotImplementedException(); } + } + + Stream IWritableArchiveEntry.Stream + { + get + { + return stream; + } + } + + public override Stream OpenEntryStream() + { + //ensure new stream is at the start, this could be reset + stream.Seek(0, SeekOrigin.Begin); + return new NonDisposingStream(stream); + } + + internal override void Close() + { + if (closeStream) + { + stream.Dispose(); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/IArchive.Extensions.cs b/src/SharpCompress/Archive/IArchive.Extensions.cs similarity index 96% rename from SharpCompress/Archive/IArchive.Extensions.cs rename to src/SharpCompress/Archive/IArchive.Extensions.cs index 6c961998..bb337551 100644 --- a/SharpCompress/Archive/IArchive.Extensions.cs +++ b/src/SharpCompress/Archive/IArchive.Extensions.cs @@ -1,22 +1,22 @@ -using System.Linq; -using SharpCompress.Common; - -namespace SharpCompress.Archive -{ - public static class IArchiveExtensions - { -#if !DOTNET51 - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteToDirectory(this IArchive archive, string destinationDirectory, - ExtractOptions options = ExtractOptions.Overwrite) - { - foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory)) - { - entry.WriteToDirectory(destinationDirectory, options); - } - } -#endif - } +using System.Linq; +using SharpCompress.Common; + +namespace SharpCompress.Archive +{ + public static class IArchiveExtensions + { +#if !DOTNET51 + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteToDirectory(this IArchive archive, string destinationDirectory, + ExtractOptions options = ExtractOptions.Overwrite) + { + foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory)) + { + entry.WriteToDirectory(destinationDirectory, options); + } + } +#endif + } } \ No newline at end of file diff --git a/SharpCompress/Archive/IArchive.cs b/src/SharpCompress/Archive/IArchive.cs similarity index 97% rename from SharpCompress/Archive/IArchive.cs rename to src/SharpCompress/Archive/IArchive.cs index c70e49d3..a34f7f9d 100644 --- a/SharpCompress/Archive/IArchive.cs +++ b/src/SharpCompress/Archive/IArchive.cs @@ -1,49 +1,49 @@ -using System; -using System.Collections.Generic; -using SharpCompress.Common; -using SharpCompress.Reader; - -namespace SharpCompress.Archive -{ - public interface IArchive : IDisposable - { - event EventHandler> EntryExtractionBegin; - event EventHandler> EntryExtractionEnd; - - event EventHandler CompressedBytesRead; - event EventHandler FilePartExtractionBegin; - - IEnumerable Entries { get; } - IEnumerable Volumes { get; } - - ArchiveType Type { get; } - - /// - /// Use this method to extract all entries in an archive in order. - /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be - /// extracted sequentially for the best performance. - /// - IReader ExtractAllEntries(); - - /// - /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). - /// Rar Archives can be SOLID while all 7Zip archives are considered SOLID. - /// - bool IsSolid { get; } - - /// - /// This checks to see if all the known entries have IsComplete = true - /// - bool IsComplete { get; } - - /// - /// The total size of the files compressed in the archive. - /// - long TotalSize { get; } - - /// - /// The total size of the files as uncompressed in the archive. - /// - long TotalUncompressSize { get; } - } +using System; +using System.Collections.Generic; +using SharpCompress.Common; +using SharpCompress.Reader; + +namespace SharpCompress.Archive +{ + public interface IArchive : IDisposable + { + event EventHandler> EntryExtractionBegin; + event EventHandler> EntryExtractionEnd; + + event EventHandler CompressedBytesRead; + event EventHandler FilePartExtractionBegin; + + IEnumerable Entries { get; } + IEnumerable Volumes { get; } + + ArchiveType Type { get; } + + /// + /// Use this method to extract all entries in an archive in order. + /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be + /// extracted sequentially for the best performance. + /// + IReader ExtractAllEntries(); + + /// + /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). + /// Rar Archives can be SOLID while all 7Zip archives are considered SOLID. + /// + bool IsSolid { get; } + + /// + /// This checks to see if all the known entries have IsComplete = true + /// + bool IsComplete { get; } + + /// + /// The total size of the files compressed in the archive. + /// + long TotalSize { get; } + + /// + /// The total size of the files as uncompressed in the archive. + /// + long TotalUncompressSize { get; } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/IArchiveEntry.Extensions.cs b/src/SharpCompress/Archive/IArchiveEntry.Extensions.cs similarity index 97% rename from SharpCompress/Archive/IArchiveEntry.Extensions.cs rename to src/SharpCompress/Archive/IArchiveEntry.Extensions.cs index dc4140de..0d5924a4 100644 --- a/SharpCompress/Archive/IArchiveEntry.Extensions.cs +++ b/src/SharpCompress/Archive/IArchiveEntry.Extensions.cs @@ -1,123 +1,123 @@ -using System.IO; -using SharpCompress.Common; -using SharpCompress.IO; - -namespace SharpCompress.Archive -{ - public static class IArchiveEntryExtensions - { - public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo) - { - if (archiveEntry.Archive.Type == ArchiveType.Rar && archiveEntry.Archive.IsSolid) - { - throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files."); - } - - if (archiveEntry.IsDirectory) - { - throw new ExtractionException("Entry is a file directory and cannot be extracted."); - } - - var streamListener = archiveEntry.Archive as IArchiveExtractionListener; - streamListener.EnsureEntriesLoaded(); - streamListener.FireEntryExtractionBegin(archiveEntry); - streamListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize); - var entryStream = archiveEntry.OpenEntryStream(); - if (entryStream == null) - { - return; - } - using(entryStream) - using (Stream s = new ListeningStream(streamListener, entryStream)) - { - s.TransferTo(streamToWriteTo); - } - streamListener.FireEntryExtractionEnd(archiveEntry); - } - -#if !DOTNET51 - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory, - ExtractOptions options = ExtractOptions.Overwrite) - { - string destinationFileName; - string file = Path.GetFileName(entry.Key); - - - if (options.HasFlag(ExtractOptions.ExtractFullPath)) - { - string folder = Path.GetDirectoryName(entry.Key); - string destdir = Path.Combine(destinationDirectory, folder); - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - destinationFileName = Path.Combine(destdir, file); - } - else - { - destinationFileName = Path.Combine(destinationDirectory, file); - } - entry.WriteToFile(destinationFileName, options); - } - - /// - /// Extract to specific file - /// - public static void WriteToFile(this IArchiveEntry entry, string destinationFileName, - ExtractOptions options = ExtractOptions.Overwrite) - { - if (entry.IsDirectory) - { - return; - } - FileMode fm = FileMode.Create; - - if (!options.HasFlag(ExtractOptions.Overwrite)) - { - fm = FileMode.CreateNew; - } - using (FileStream fs = File.Open(destinationFileName, fm)) - { - entry.WriteTo(fs); - } - - if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes)) - { - // update file time to original packed time - FileInfo nf = new FileInfo(destinationFileName); - if (nf.Exists) - { - if (options.HasFlag(ExtractOptions.PreserveFileTime)) - { - if (entry.CreatedTime.HasValue) - { - nf.CreationTime = entry.CreatedTime.Value; - } - - if (entry.LastModifiedTime.HasValue) - { - nf.LastWriteTime = entry.LastModifiedTime.Value; - } - - if (entry.LastAccessedTime.HasValue) - { - nf.LastAccessTime = entry.CreatedTime.Value; - } - } - - if (options.HasFlag(ExtractOptions.PreserveAttributes)) - { - if (entry.Attrib.HasValue) - { - nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); - } - } - } - } - } -#endif - } +using System.IO; +using SharpCompress.Common; +using SharpCompress.IO; + +namespace SharpCompress.Archive +{ + public static class IArchiveEntryExtensions + { + public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo) + { + if (archiveEntry.Archive.Type == ArchiveType.Rar && archiveEntry.Archive.IsSolid) + { + throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files."); + } + + if (archiveEntry.IsDirectory) + { + throw new ExtractionException("Entry is a file directory and cannot be extracted."); + } + + var streamListener = archiveEntry.Archive as IArchiveExtractionListener; + streamListener.EnsureEntriesLoaded(); + streamListener.FireEntryExtractionBegin(archiveEntry); + streamListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize); + var entryStream = archiveEntry.OpenEntryStream(); + if (entryStream == null) + { + return; + } + using(entryStream) + using (Stream s = new ListeningStream(streamListener, entryStream)) + { + s.TransferTo(streamToWriteTo); + } + streamListener.FireEntryExtractionEnd(archiveEntry); + } + +#if !DOTNET51 + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory, + ExtractOptions options = ExtractOptions.Overwrite) + { + string destinationFileName; + string file = Path.GetFileName(entry.Key); + + + if (options.HasFlag(ExtractOptions.ExtractFullPath)) + { + string folder = Path.GetDirectoryName(entry.Key); + string destdir = Path.Combine(destinationDirectory, folder); + if (!Directory.Exists(destdir)) + { + Directory.CreateDirectory(destdir); + } + destinationFileName = Path.Combine(destdir, file); + } + else + { + destinationFileName = Path.Combine(destinationDirectory, file); + } + entry.WriteToFile(destinationFileName, options); + } + + /// + /// Extract to specific file + /// + public static void WriteToFile(this IArchiveEntry entry, string destinationFileName, + ExtractOptions options = ExtractOptions.Overwrite) + { + if (entry.IsDirectory) + { + return; + } + FileMode fm = FileMode.Create; + + if (!options.HasFlag(ExtractOptions.Overwrite)) + { + fm = FileMode.CreateNew; + } + using (FileStream fs = File.Open(destinationFileName, fm)) + { + entry.WriteTo(fs); + } + + if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes)) + { + // update file time to original packed time + FileInfo nf = new FileInfo(destinationFileName); + if (nf.Exists) + { + if (options.HasFlag(ExtractOptions.PreserveFileTime)) + { + if (entry.CreatedTime.HasValue) + { + nf.CreationTime = entry.CreatedTime.Value; + } + + if (entry.LastModifiedTime.HasValue) + { + nf.LastWriteTime = entry.LastModifiedTime.Value; + } + + if (entry.LastAccessedTime.HasValue) + { + nf.LastAccessTime = entry.CreatedTime.Value; + } + } + + if (options.HasFlag(ExtractOptions.PreserveAttributes)) + { + if (entry.Attrib.HasValue) + { + nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); + } + } + } + } + } +#endif + } } \ No newline at end of file diff --git a/SharpCompress/Archive/IArchiveEntry.cs b/src/SharpCompress/Archive/IArchiveEntry.cs similarity index 96% rename from SharpCompress/Archive/IArchiveEntry.cs rename to src/SharpCompress/Archive/IArchiveEntry.cs index b9f04364..ac52485b 100644 --- a/SharpCompress/Archive/IArchiveEntry.cs +++ b/src/SharpCompress/Archive/IArchiveEntry.cs @@ -1,24 +1,24 @@ -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.Archive -{ - public interface IArchiveEntry : IEntry - { - /// - /// Opens the current entry as a stream that will decompress as it is read. - /// Read the entire stream or use SkipEntry on EntryStream. - /// - Stream OpenEntryStream(); - - /// - /// The archive can find all the parts of the archive needed to extract this entry. - /// - bool IsComplete { get; } - - /// - /// The archive instance this entry belongs to - /// - IArchive Archive { get; } - } +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Archive +{ + public interface IArchiveEntry : IEntry + { + /// + /// Opens the current entry as a stream that will decompress as it is read. + /// Read the entire stream or use SkipEntry on EntryStream. + /// + Stream OpenEntryStream(); + + /// + /// The archive can find all the parts of the archive needed to extract this entry. + /// + bool IsComplete { get; } + + /// + /// The archive instance this entry belongs to + /// + IArchive Archive { get; } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/IArchiveExtractionListener.cs b/src/SharpCompress/Archive/IArchiveExtractionListener.cs similarity index 96% rename from SharpCompress/Archive/IArchiveExtractionListener.cs rename to src/SharpCompress/Archive/IArchiveExtractionListener.cs index aa15a875..12a1e9ff 100644 --- a/SharpCompress/Archive/IArchiveExtractionListener.cs +++ b/src/SharpCompress/Archive/IArchiveExtractionListener.cs @@ -1,11 +1,11 @@ -using SharpCompress.Common; - -namespace SharpCompress.Archive -{ - internal interface IArchiveExtractionListener : IExtractionListener - { - void EnsureEntriesLoaded(); - void FireEntryExtractionBegin(IArchiveEntry entry); - void FireEntryExtractionEnd(IArchiveEntry entry); - } +using SharpCompress.Common; + +namespace SharpCompress.Archive +{ + internal interface IArchiveExtractionListener : IExtractionListener + { + void EnsureEntriesLoaded(); + void FireEntryExtractionBegin(IArchiveEntry entry); + void FireEntryExtractionEnd(IArchiveEntry entry); + } } \ No newline at end of file diff --git a/SharpCompress/Archive/IWritableArchive.Extensions.cs b/src/SharpCompress/Archive/IWritableArchive.Extensions.cs similarity index 100% rename from SharpCompress/Archive/IWritableArchive.Extensions.cs rename to src/SharpCompress/Archive/IWritableArchive.Extensions.cs diff --git a/SharpCompress/Archive/IWritableArchive.cs b/src/SharpCompress/Archive/IWritableArchive.cs similarity index 100% rename from SharpCompress/Archive/IWritableArchive.cs rename to src/SharpCompress/Archive/IWritableArchive.cs diff --git a/SharpCompress/Archive/IWritableArchiveEntry.cs b/src/SharpCompress/Archive/IWritableArchiveEntry.cs similarity index 94% rename from SharpCompress/Archive/IWritableArchiveEntry.cs rename to src/SharpCompress/Archive/IWritableArchiveEntry.cs index 2175fdae..74ebb935 100644 --- a/SharpCompress/Archive/IWritableArchiveEntry.cs +++ b/src/SharpCompress/Archive/IWritableArchiveEntry.cs @@ -1,9 +1,9 @@ -using System.IO; - -namespace SharpCompress.Archive -{ - internal interface IWritableArchiveEntry - { - Stream Stream { get; } - } +using System.IO; + +namespace SharpCompress.Archive +{ + internal interface IWritableArchiveEntry + { + Stream Stream { get; } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/FileInfoRarArchiveVolume.cs b/src/SharpCompress/Archive/Rar/FileInfoRarArchiveVolume.cs similarity index 96% rename from SharpCompress/Archive/Rar/FileInfoRarArchiveVolume.cs rename to src/SharpCompress/Archive/Rar/FileInfoRarArchiveVolume.cs index ddfb8724..2b022d4b 100644 --- a/SharpCompress/Archive/Rar/FileInfoRarArchiveVolume.cs +++ b/src/SharpCompress/Archive/Rar/FileInfoRarArchiveVolume.cs @@ -1,48 +1,48 @@ -#if !DOTNET51 -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Archive.Rar -{ - /// - /// A rar part based on a FileInfo object - /// - internal class FileInfoRarArchiveVolume : RarVolume - { - internal FileInfoRarArchiveVolume(FileInfo fileInfo, string password, Options options) - : base(StreamingMode.Seekable, fileInfo.OpenRead(), password, FixOptions(options)) - { - FileInfo = fileInfo; - FileParts = base.GetVolumeFileParts().ToReadOnly(); - } - - private static Options FixOptions(Options options) - { - //make sure we're closing streams with fileinfo - if (options.HasFlag(Options.KeepStreamsOpen)) - { - options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); - } - return options; - } - - internal ReadOnlyCollection FileParts { get; private set; } - - internal FileInfo FileInfo { get; private set; } - - internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader) - { - return new FileInfoRarFilePart(this, markHeader, fileHeader, FileInfo); - } - - internal override IEnumerable ReadFileParts() - { - return FileParts; - } - } -} +#if !DOTNET51 +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Archive.Rar +{ + /// + /// A rar part based on a FileInfo object + /// + internal class FileInfoRarArchiveVolume : RarVolume + { + internal FileInfoRarArchiveVolume(FileInfo fileInfo, string password, Options options) + : base(StreamingMode.Seekable, fileInfo.OpenRead(), password, FixOptions(options)) + { + FileInfo = fileInfo; + FileParts = base.GetVolumeFileParts().ToReadOnly(); + } + + private static Options FixOptions(Options options) + { + //make sure we're closing streams with fileinfo + if (options.HasFlag(Options.KeepStreamsOpen)) + { + options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); + } + return options; + } + + internal ReadOnlyCollection FileParts { get; private set; } + + internal FileInfo FileInfo { get; private set; } + + internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader) + { + return new FileInfoRarFilePart(this, markHeader, fileHeader, FileInfo); + } + + internal override IEnumerable ReadFileParts() + { + return FileParts; + } + } +} #endif \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs b/src/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs similarity index 96% rename from SharpCompress/Archive/Rar/FileInfoRarFilePart.cs rename to src/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs index 0de3993f..9718e06a 100644 --- a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs +++ b/src/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs @@ -1,31 +1,31 @@ -#if !DOTNET51 -using System.IO; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Archive.Rar -{ - internal class FileInfoRarFilePart : SeekableFilePart - { - private readonly FileInfoRarArchiveVolume volume; - - internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi) - : base(mh, fh, volume.Stream, volume.Password) - { - this.volume = volume; - FileInfo = fi; - } - - internal FileInfo FileInfo { get; private set; } - - internal override string FilePartName - { - get - { - return "Rar File: " + FileInfo.FullName - + " File Entry: " + FileHeader.FileName; - } - } - } -} +#if !DOTNET51 +using System.IO; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Archive.Rar +{ + internal class FileInfoRarFilePart : SeekableFilePart + { + private readonly FileInfoRarArchiveVolume volume; + + internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi) + : base(mh, fh, volume.Stream, volume.Password) + { + this.volume = volume; + FileInfo = fi; + } + + internal FileInfo FileInfo { get; private set; } + + internal override string FilePartName + { + get + { + return "Rar File: " + FileInfo.FullName + + " File Entry: " + FileHeader.FileName; + } + } + } +} #endif \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/RarArchive.Extensions.cs b/src/SharpCompress/Archive/Rar/RarArchive.Extensions.cs similarity index 97% rename from SharpCompress/Archive/Rar/RarArchive.Extensions.cs rename to src/SharpCompress/Archive/Rar/RarArchive.Extensions.cs index bb9d952b..38db8bee 100644 --- a/SharpCompress/Archive/Rar/RarArchive.Extensions.cs +++ b/src/SharpCompress/Archive/Rar/RarArchive.Extensions.cs @@ -1,23 +1,23 @@ -using System.Linq; - -namespace SharpCompress.Archive.Rar -{ - public static class RarArchiveExtensions - { - /// - /// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing. - /// - public static bool IsFirstVolume(this RarArchive archive) - { - return archive.Volumes.First().IsFirstVolume; - } - - /// - /// RarArchive is part of a multi-part archive. - /// - public static bool IsMultipartVolume(this RarArchive archive) - { - return archive.Volumes.First().IsMultiVolume; - } - } +using System.Linq; + +namespace SharpCompress.Archive.Rar +{ + public static class RarArchiveExtensions + { + /// + /// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing. + /// + public static bool IsFirstVolume(this RarArchive archive) + { + return archive.Volumes.First().IsFirstVolume; + } + + /// + /// RarArchive is part of a multi-part archive. + /// + public static bool IsMultipartVolume(this RarArchive archive) + { + return archive.Volumes.First().IsMultiVolume; + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/RarArchive.cs b/src/SharpCompress/Archive/Rar/RarArchive.cs similarity index 97% rename from SharpCompress/Archive/Rar/RarArchive.cs rename to src/SharpCompress/Archive/Rar/RarArchive.cs index 09b0a2e7..57850546 100644 --- a/SharpCompress/Archive/Rar/RarArchive.cs +++ b/src/SharpCompress/Archive/Rar/RarArchive.cs @@ -1,170 +1,170 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.Compressor.Rar; -using SharpCompress.IO; -using SharpCompress.Reader; -using SharpCompress.Reader.Rar; - -namespace SharpCompress.Archive.Rar -{ - public class RarArchive : AbstractArchive - { - private readonly Unpack unpack = new Unpack(); - - internal Unpack Unpack - { - get { return unpack; } - } - -#if !DOTNET51 - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - /// - internal RarArchive(FileInfo fileInfo, Options options, string password) - : base(ArchiveType.Rar, fileInfo, options, password) - { - } - - protected override IEnumerable LoadVolumes(FileInfo file, Options options) - { - return RarArchiveVolumeFactory.GetParts(file, Password, options); - } -#endif - - /// - /// Takes multiple seekable Streams for a multi-part archive - /// - /// - /// - /// - internal RarArchive(IEnumerable streams, Options options, string password) - : base(ArchiveType.Rar, streams, options, password) - { - } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - return RarArchiveEntryFactory.GetEntries(this, volumes); - } - - protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) - { - return RarArchiveVolumeFactory.GetParts(streams, Password, options); - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.First().Stream; - stream.Position = 0; - return RarReader.Open(stream); - } - - public override bool IsSolid - { - get { return Volumes.First().IsSolidArchive; } - } - - #region Creation - -#if !DOTNET51 - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - /// - public static RarArchive Open(string filePath, Options options = Options.None, string password = null) - { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), options, password); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - /// - public static RarArchive Open(FileInfo fileInfo, Options options = Options.None, string password = null) - { - fileInfo.CheckNotNull("fileInfo"); - return new RarArchive(fileInfo, options, password); - } -#endif - /// - /// Takes a seekable Stream as a source - /// - /// - /// - /// - public static RarArchive Open(Stream stream, Options options = Options.KeepStreamsOpen, string password = null) - { - stream.CheckNotNull("stream"); - return Open(stream.AsEnumerable(), options, password); - } - - /// - /// Takes multiple seekable Streams for a multi-part archive - /// - /// - /// - /// - public static RarArchive Open(IEnumerable streams, Options options = Options.KeepStreamsOpen, string password = null) - { - streams.CheckNotNull("streams"); - return new RarArchive(streams, options, password); - } - -#if !DOTNET51 - public static bool IsRarFile(string filePath) - { - return IsRarFile(new FileInfo(filePath)); - } - - public static bool IsRarFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsRarFile(stream); - } - } -#endif - - public static bool IsRarFile(Stream stream) - { - return IsRarFile(stream, Options.None); - } - - public static bool IsRarFile(Stream stream, Options options) - { - try - { - var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options); - RarHeader header = headerFactory.ReadHeaders(stream).FirstOrDefault(); - if (header == null) - { - return false; - } - return Enum.IsDefined(typeof (HeaderType), header.HeaderType); - } - catch - { - return false; - } - } - - #endregion - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.Compressor.Rar; +using SharpCompress.IO; +using SharpCompress.Reader; +using SharpCompress.Reader.Rar; + +namespace SharpCompress.Archive.Rar +{ + public class RarArchive : AbstractArchive + { + private readonly Unpack unpack = new Unpack(); + + internal Unpack Unpack + { + get { return unpack; } + } + +#if !DOTNET51 + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + /// + internal RarArchive(FileInfo fileInfo, Options options, string password) + : base(ArchiveType.Rar, fileInfo, options, password) + { + } + + protected override IEnumerable LoadVolumes(FileInfo file, Options options) + { + return RarArchiveVolumeFactory.GetParts(file, Password, options); + } +#endif + + /// + /// Takes multiple seekable Streams for a multi-part archive + /// + /// + /// + /// + internal RarArchive(IEnumerable streams, Options options, string password) + : base(ArchiveType.Rar, streams, options, password) + { + } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + return RarArchiveEntryFactory.GetEntries(this, volumes); + } + + protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) + { + return RarArchiveVolumeFactory.GetParts(streams, Password, options); + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.First().Stream; + stream.Position = 0; + return RarReader.Open(stream); + } + + public override bool IsSolid + { + get { return Volumes.First().IsSolidArchive; } + } + + #region Creation + +#if !DOTNET51 + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + /// + public static RarArchive Open(string filePath, Options options = Options.None, string password = null) + { + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), options, password); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + /// + public static RarArchive Open(FileInfo fileInfo, Options options = Options.None, string password = null) + { + fileInfo.CheckNotNull("fileInfo"); + return new RarArchive(fileInfo, options, password); + } +#endif + /// + /// Takes a seekable Stream as a source + /// + /// + /// + /// + public static RarArchive Open(Stream stream, Options options = Options.KeepStreamsOpen, string password = null) + { + stream.CheckNotNull("stream"); + return Open(stream.AsEnumerable(), options, password); + } + + /// + /// Takes multiple seekable Streams for a multi-part archive + /// + /// + /// + /// + public static RarArchive Open(IEnumerable streams, Options options = Options.KeepStreamsOpen, string password = null) + { + streams.CheckNotNull("streams"); + return new RarArchive(streams, options, password); + } + +#if !DOTNET51 + public static bool IsRarFile(string filePath) + { + return IsRarFile(new FileInfo(filePath)); + } + + public static bool IsRarFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) + { + return false; + } + using (Stream stream = fileInfo.OpenRead()) + { + return IsRarFile(stream); + } + } +#endif + + public static bool IsRarFile(Stream stream) + { + return IsRarFile(stream, Options.None); + } + + public static bool IsRarFile(Stream stream, Options options) + { + try + { + var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options); + RarHeader header = headerFactory.ReadHeaders(stream).FirstOrDefault(); + if (header == null) + { + return false; + } + return Enum.IsDefined(typeof (HeaderType), header.HeaderType); + } + catch + { + return false; + } + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/RarArchiveEntry.cs b/src/SharpCompress/Archive/Rar/RarArchiveEntry.cs similarity index 96% rename from SharpCompress/Archive/Rar/RarArchiveEntry.cs rename to src/SharpCompress/Archive/Rar/RarArchiveEntry.cs index 17f32170..9234e569 100644 --- a/SharpCompress/Archive/Rar/RarArchiveEntry.cs +++ b/src/SharpCompress/Archive/Rar/RarArchiveEntry.cs @@ -1,93 +1,93 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.Compressor.Rar; - -namespace SharpCompress.Archive.Rar -{ - public class RarArchiveEntry : RarEntry, IArchiveEntry - { - private readonly ICollection parts; - private readonly RarArchive archive; - - internal RarArchiveEntry(RarArchive archive, IEnumerable parts) - { - this.parts = parts.ToList(); - this.archive = archive; - } - - public override CompressionType CompressionType - { - get { return CompressionType.Rar; } - } - - public IArchive Archive - { - get - { - return archive; - } - } - - internal override IEnumerable Parts - { - get { return parts.Cast(); } - } - - internal override FileHeader FileHeader - { - get { return parts.First().FileHeader; } - } - - public override long Crc - { - get - { - CheckIncomplete(); - return parts.Select(fp => fp.FileHeader) - .Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC; - } - } - - - public override long Size - { - get - { - CheckIncomplete(); - return parts.First().FileHeader.UncompressedSize; - } - } - - public override long CompressedSize - { - get - { - CheckIncomplete(); - return parts.Aggregate(0L, (total, fp) => { return total + fp.FileHeader.CompressedSize; }); - } - } - - public Stream OpenEntryStream() - { - return new RarStream(archive.Unpack, FileHeader, - new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); - } - - public bool IsComplete - { - get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); } - } - - private void CheckIncomplete() - { - if (!IsComplete) - { - throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation."); - } - } - } +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.Compressor.Rar; + +namespace SharpCompress.Archive.Rar +{ + public class RarArchiveEntry : RarEntry, IArchiveEntry + { + private readonly ICollection parts; + private readonly RarArchive archive; + + internal RarArchiveEntry(RarArchive archive, IEnumerable parts) + { + this.parts = parts.ToList(); + this.archive = archive; + } + + public override CompressionType CompressionType + { + get { return CompressionType.Rar; } + } + + public IArchive Archive + { + get + { + return archive; + } + } + + internal override IEnumerable Parts + { + get { return parts.Cast(); } + } + + internal override FileHeader FileHeader + { + get { return parts.First().FileHeader; } + } + + public override long Crc + { + get + { + CheckIncomplete(); + return parts.Select(fp => fp.FileHeader) + .Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC; + } + } + + + public override long Size + { + get + { + CheckIncomplete(); + return parts.First().FileHeader.UncompressedSize; + } + } + + public override long CompressedSize + { + get + { + CheckIncomplete(); + return parts.Aggregate(0L, (total, fp) => { return total + fp.FileHeader.CompressedSize; }); + } + } + + public Stream OpenEntryStream() + { + return new RarStream(archive.Unpack, FileHeader, + new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); + } + + public bool IsComplete + { + get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); } + } + + private void CheckIncomplete() + { + if (!IsComplete) + { + throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation."); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/RarArchiveEntryFactory.cs b/src/SharpCompress/Archive/Rar/RarArchiveEntryFactory.cs similarity index 97% rename from SharpCompress/Archive/Rar/RarArchiveEntryFactory.cs rename to src/SharpCompress/Archive/Rar/RarArchiveEntryFactory.cs index 9f6ca64a..ec55c28d 100644 --- a/SharpCompress/Archive/Rar/RarArchiveEntryFactory.cs +++ b/src/SharpCompress/Archive/Rar/RarArchiveEntryFactory.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Archive.Rar -{ - internal static class RarArchiveEntryFactory - { - private static IEnumerable GetFileParts(IEnumerable parts) - { - foreach (RarVolume rarPart in parts) - { - foreach (RarFilePart fp in rarPart.ReadFileParts()) - { - yield return fp; - } - } - } - - private static IEnumerable> GetMatchedFileParts(IEnumerable parts) - { - var groupedParts = new List(); - foreach (RarFilePart fp in GetFileParts(parts)) - { - groupedParts.Add(fp); - - if (!FlagUtility.HasFlag((long) fp.FileHeader.FileFlags, (long) FileFlags.SPLIT_AFTER)) - { - yield return groupedParts; - groupedParts = new List(); - } - } - if (groupedParts.Count > 0) - { - yield return groupedParts; - } - } - - internal static IEnumerable GetEntries(RarArchive archive, - IEnumerable rarParts) - { - foreach (var groupedParts in GetMatchedFileParts(rarParts)) - { - yield return new RarArchiveEntry(archive, groupedParts); - } - } - } +using System.Collections.Generic; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Archive.Rar +{ + internal static class RarArchiveEntryFactory + { + private static IEnumerable GetFileParts(IEnumerable parts) + { + foreach (RarVolume rarPart in parts) + { + foreach (RarFilePart fp in rarPart.ReadFileParts()) + { + yield return fp; + } + } + } + + private static IEnumerable> GetMatchedFileParts(IEnumerable parts) + { + var groupedParts = new List(); + foreach (RarFilePart fp in GetFileParts(parts)) + { + groupedParts.Add(fp); + + if (!FlagUtility.HasFlag((long) fp.FileHeader.FileFlags, (long) FileFlags.SPLIT_AFTER)) + { + yield return groupedParts; + groupedParts = new List(); + } + } + if (groupedParts.Count > 0) + { + yield return groupedParts; + } + } + + internal static IEnumerable GetEntries(RarArchive archive, + IEnumerable rarParts) + { + foreach (var groupedParts in GetMatchedFileParts(rarParts)) + { + yield return new RarArchiveEntry(archive, groupedParts); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/RarArchiveVolumeFactory.cs b/src/SharpCompress/Archive/Rar/RarArchiveVolumeFactory.cs similarity index 97% rename from SharpCompress/Archive/Rar/RarArchiveVolumeFactory.cs rename to src/SharpCompress/Archive/Rar/RarArchiveVolumeFactory.cs index 7568e386..9c4ab885 100644 --- a/SharpCompress/Archive/Rar/RarArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archive/Rar/RarArchiveVolumeFactory.cs @@ -1,145 +1,145 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.Common; -using SharpCompress.Common.Rar; - -namespace SharpCompress.Archive.Rar -{ - internal static class RarArchiveVolumeFactory - { - internal static IEnumerable GetParts(IEnumerable streams, string password, Options options) - { - foreach (Stream s in streams) - { - if (!s.CanRead || !s.CanSeek) - { - throw new ArgumentException("Stream is not readable and seekable"); - } - StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, password, options); - yield return part; - } - } - -#if !DOTNET51 - internal static IEnumerable GetParts(FileInfo fileInfo, string password, Options options) - { - FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options); - yield return part; - - if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME)) - { - yield break; //if file isn't volume then there is no reason to look - } - ArchiveHeader ah = part.ArchiveHeader; - fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); - //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume - while (fileInfo != null && fileInfo.Exists) - { - part = new FileInfoRarArchiveVolume(fileInfo, password, options); - - fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); - yield return part; - } - } - - private static FileInfo GetNextFileInfo(ArchiveHeader ah, FileInfoRarFilePart currentFilePart) - { - if (currentFilePart == null) - { - return null; - } - bool oldNumbering = !ah.ArchiveHeaderFlags.HasFlag(ArchiveFlags.NEWNUMBERING) - || currentFilePart.MarkHeader.OldFormat; - if (oldNumbering) - { - return FindNextFileWithOldNumbering(currentFilePart.FileInfo); - } - else - { - return FindNextFileWithNewNumbering(currentFilePart.FileInfo); - } - } - - private static FileInfo FindNextFileWithOldNumbering(FileInfo currentFileInfo) - { - // .rar, .r00, .r01, ... - string extension = currentFileInfo.Extension; - - StringBuilder buffer = new StringBuilder(currentFileInfo.FullName.Length); - buffer.Append(currentFileInfo.FullName.Substring(0, - currentFileInfo.FullName.Length - extension.Length)); - if (string.Compare(extension, ".rar", StringComparison.OrdinalIgnoreCase) == 0) - { - buffer.Append(".r00"); - } - else - { - int num = 0; - if (int.TryParse(extension.Substring(2, 2), out num)) - { - num++; - buffer.Append(".r"); - if (num < 10) - { - buffer.Append('0'); - } - buffer.Append(num); - } - else - { - ThrowInvalidFileName(currentFileInfo); - } - } - return new FileInfo(buffer.ToString()); - } - - private static FileInfo FindNextFileWithNewNumbering(FileInfo currentFileInfo) - { - // part1.rar, part2.rar, ... - string extension = currentFileInfo.Extension; - if (string.Compare(extension, ".rar", StringComparison.OrdinalIgnoreCase) != 0) - { - throw new ArgumentException("Invalid extension, expected 'rar': " + currentFileInfo.FullName); - } - int startIndex = currentFileInfo.FullName.LastIndexOf(".part"); - if (startIndex < 0) - { - ThrowInvalidFileName(currentFileInfo); - } - StringBuilder buffer = new StringBuilder(currentFileInfo.FullName.Length); - buffer.Append(currentFileInfo.FullName, 0, startIndex); - int num = 0; - string numString = currentFileInfo.FullName.Substring(startIndex + 5, - currentFileInfo.FullName.IndexOf('.', startIndex + 5) - - startIndex - 5); - buffer.Append(".part"); - if (int.TryParse(numString, out num)) - { - num++; - for (int i = 0; i < numString.Length - num.ToString().Length; i++) - { - buffer.Append('0'); - } - buffer.Append(num); - } - else - { - ThrowInvalidFileName(currentFileInfo); - } - buffer.Append(".rar"); - return new FileInfo(buffer.ToString()); - } - - private static void ThrowInvalidFileName(FileInfo fileInfo) - { - throw new ArgumentException("Filename invalid or next archive could not be found:" - + fileInfo.FullName); - } - -#endif - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.Common; +using SharpCompress.Common.Rar; + +namespace SharpCompress.Archive.Rar +{ + internal static class RarArchiveVolumeFactory + { + internal static IEnumerable GetParts(IEnumerable streams, string password, Options options) + { + foreach (Stream s in streams) + { + if (!s.CanRead || !s.CanSeek) + { + throw new ArgumentException("Stream is not readable and seekable"); + } + StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, password, options); + yield return part; + } + } + +#if !DOTNET51 + internal static IEnumerable GetParts(FileInfo fileInfo, string password, Options options) + { + FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options); + yield return part; + + if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME)) + { + yield break; //if file isn't volume then there is no reason to look + } + ArchiveHeader ah = part.ArchiveHeader; + fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); + //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume + while (fileInfo != null && fileInfo.Exists) + { + part = new FileInfoRarArchiveVolume(fileInfo, password, options); + + fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); + yield return part; + } + } + + private static FileInfo GetNextFileInfo(ArchiveHeader ah, FileInfoRarFilePart currentFilePart) + { + if (currentFilePart == null) + { + return null; + } + bool oldNumbering = !ah.ArchiveHeaderFlags.HasFlag(ArchiveFlags.NEWNUMBERING) + || currentFilePart.MarkHeader.OldFormat; + if (oldNumbering) + { + return FindNextFileWithOldNumbering(currentFilePart.FileInfo); + } + else + { + return FindNextFileWithNewNumbering(currentFilePart.FileInfo); + } + } + + private static FileInfo FindNextFileWithOldNumbering(FileInfo currentFileInfo) + { + // .rar, .r00, .r01, ... + string extension = currentFileInfo.Extension; + + StringBuilder buffer = new StringBuilder(currentFileInfo.FullName.Length); + buffer.Append(currentFileInfo.FullName.Substring(0, + currentFileInfo.FullName.Length - extension.Length)); + if (string.Compare(extension, ".rar", StringComparison.OrdinalIgnoreCase) == 0) + { + buffer.Append(".r00"); + } + else + { + int num = 0; + if (int.TryParse(extension.Substring(2, 2), out num)) + { + num++; + buffer.Append(".r"); + if (num < 10) + { + buffer.Append('0'); + } + buffer.Append(num); + } + else + { + ThrowInvalidFileName(currentFileInfo); + } + } + return new FileInfo(buffer.ToString()); + } + + private static FileInfo FindNextFileWithNewNumbering(FileInfo currentFileInfo) + { + // part1.rar, part2.rar, ... + string extension = currentFileInfo.Extension; + if (string.Compare(extension, ".rar", StringComparison.OrdinalIgnoreCase) != 0) + { + throw new ArgumentException("Invalid extension, expected 'rar': " + currentFileInfo.FullName); + } + int startIndex = currentFileInfo.FullName.LastIndexOf(".part"); + if (startIndex < 0) + { + ThrowInvalidFileName(currentFileInfo); + } + StringBuilder buffer = new StringBuilder(currentFileInfo.FullName.Length); + buffer.Append(currentFileInfo.FullName, 0, startIndex); + int num = 0; + string numString = currentFileInfo.FullName.Substring(startIndex + 5, + currentFileInfo.FullName.IndexOf('.', startIndex + 5) - + startIndex - 5); + buffer.Append(".part"); + if (int.TryParse(numString, out num)) + { + num++; + for (int i = 0; i < numString.Length - num.ToString().Length; i++) + { + buffer.Append('0'); + } + buffer.Append(num); + } + else + { + ThrowInvalidFileName(currentFileInfo); + } + buffer.Append(".rar"); + return new FileInfo(buffer.ToString()); + } + + private static void ThrowInvalidFileName(FileInfo fileInfo) + { + throw new ArgumentException("Filename invalid or next archive could not be found:" + + fileInfo.FullName); + } + +#endif + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/SeekableFilePart.cs b/src/SharpCompress/Archive/Rar/SeekableFilePart.cs similarity index 96% rename from SharpCompress/Archive/Rar/SeekableFilePart.cs rename to src/SharpCompress/Archive/Rar/SeekableFilePart.cs index e097a0c2..d89fb1ba 100644 --- a/SharpCompress/Archive/Rar/SeekableFilePart.cs +++ b/src/SharpCompress/Archive/Rar/SeekableFilePart.cs @@ -1,35 +1,35 @@ -using System; -using System.IO; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Archive.Rar -{ - internal class SeekableFilePart : RarFilePart - { - private readonly Stream stream; - private readonly string password; - - internal SeekableFilePart(MarkHeader mh, FileHeader fh, Stream stream, string password) - : base(mh, fh) - { - this.stream = stream; - this.password = password; - } - - internal override Stream GetCompressedStream() - { - stream.Position = FileHeader.DataStartPosition; - if (FileHeader.Salt != null) - { - return new RarCryptoWrapper(stream, password, FileHeader.Salt); - } - return stream; - } - - internal override string FilePartName - { - get { return "Unknown Stream - File Entry: " + FileHeader.FileName; } - } - } +using System; +using System.IO; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Archive.Rar +{ + internal class SeekableFilePart : RarFilePart + { + private readonly Stream stream; + private readonly string password; + + internal SeekableFilePart(MarkHeader mh, FileHeader fh, Stream stream, string password) + : base(mh, fh) + { + this.stream = stream; + this.password = password; + } + + internal override Stream GetCompressedStream() + { + stream.Position = FileHeader.DataStartPosition; + if (FileHeader.Salt != null) + { + return new RarCryptoWrapper(stream, password, FileHeader.Salt); + } + return stream; + } + + internal override string FilePartName + { + get { return "Unknown Stream - File Entry: " + FileHeader.FileName; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Rar/StreamRarArchiveVolume.cs b/src/SharpCompress/Archive/Rar/StreamRarArchiveVolume.cs similarity index 96% rename from SharpCompress/Archive/Rar/StreamRarArchiveVolume.cs rename to src/SharpCompress/Archive/Rar/StreamRarArchiveVolume.cs index d33ffdd8..3b499f12 100644 --- a/SharpCompress/Archive/Rar/StreamRarArchiveVolume.cs +++ b/src/SharpCompress/Archive/Rar/StreamRarArchiveVolume.cs @@ -1,27 +1,27 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Archive.Rar -{ - internal class StreamRarArchiveVolume : RarVolume - { - internal StreamRarArchiveVolume(Stream stream, string password, Options options) - : base(StreamingMode.Seekable, stream, password, options) - { - } - - internal override IEnumerable ReadFileParts() - { - return GetVolumeFileParts(); - } - - internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader) - { - return new SeekableFilePart(markHeader, fileHeader, Stream, Password); - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Archive.Rar +{ + internal class StreamRarArchiveVolume : RarVolume + { + internal StreamRarArchiveVolume(Stream stream, string password, Options options) + : base(StreamingMode.Seekable, stream, password, options) + { + } + + internal override IEnumerable ReadFileParts() + { + return GetVolumeFileParts(); + } + + internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader) + { + return new SeekableFilePart(markHeader, fileHeader, Stream, Password); + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archive/SevenZip/SevenZipArchive.cs similarity index 96% rename from SharpCompress/Archive/SevenZip/SevenZipArchive.cs rename to src/SharpCompress/Archive/SevenZip/SevenZipArchive.cs index cc2f1b42..5d5f6778 100644 --- a/SharpCompress/Archive/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archive/SevenZip/SevenZipArchive.cs @@ -1,252 +1,252 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.SevenZip; -using SharpCompress.IO; -using SharpCompress.Reader; - -namespace SharpCompress.Archive.SevenZip -{ - public class SevenZipArchive : AbstractArchive - { - private ArchiveDatabase database; -#if !DOTNET51 - /// - /// Constructor expects a filepath to an existing file. - /// - /// - public static SevenZipArchive Open(string filePath) - { - return Open(filePath, Options.None); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - public static SevenZipArchive Open(FileInfo fileInfo) - { - return Open(fileInfo, Options.None); - } - - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static SevenZipArchive Open(string filePath, Options options) - { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), options); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static SevenZipArchive Open(FileInfo fileInfo, Options options) - { - fileInfo.CheckNotNull("fileInfo"); - return new SevenZipArchive(fileInfo, options); - } -#endif - - /// - /// Takes a seekable Stream as a source - /// - /// - public static SevenZipArchive Open(Stream stream) - { - stream.CheckNotNull("stream"); - return Open(stream, Options.None); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static SevenZipArchive Open(Stream stream, Options options) - { - stream.CheckNotNull("stream"); - return new SevenZipArchive(stream, options); - } - -#if !DOTNET51 - internal SevenZipArchive(FileInfo fileInfo, Options options) - : base(ArchiveType.SevenZip, fileInfo, options, null) - { - } - - protected override IEnumerable LoadVolumes(FileInfo file, Options options) - { - if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen)) - { - options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); - } - return new SevenZipVolume(file.OpenRead(), options).AsEnumerable(); - } - - public static bool IsSevenZipFile(string filePath) - { - return IsSevenZipFile(new FileInfo(filePath)); - } - - public static bool IsSevenZipFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsSevenZipFile(stream); - } - } -#endif - - internal SevenZipArchive(Stream stream, Options options) - : base(ArchiveType.SevenZip, stream.AsEnumerable(), options, null) - { - } - - internal SevenZipArchive() - : base(ArchiveType.SevenZip) - { - } - - protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) - { - foreach (Stream s in streams) - { - if (!s.CanRead || !s.CanSeek) - { - throw new ArgumentException("Stream is not readable and seekable"); - } - SevenZipVolume volume = new SevenZipVolume(s, options); - yield return volume; - } - } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - var stream = volumes.Single().Stream; - LoadFactory(stream); - for (int i = 0; i < database.Files.Count; i++) - { - var file = database.Files[i]; - if (!file.IsDir) - { - yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file)); - } - } - } - - private void LoadFactory(Stream stream) - { - if (database == null) - { - stream.Position = 0; - var reader = new ArchiveReader(); - reader.Open(stream); - database = reader.ReadDatabase(null); - } - } - - - public static bool IsSevenZipFile(Stream stream) - { - try - { - return SignatureMatch(stream); - } - catch - { - return false; - } - } - - private static readonly byte[] SIGNATURE = new byte[] {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C}; - - private static bool SignatureMatch(Stream stream) - { - BinaryReader reader = new BinaryReader(stream); - byte[] signatureBytes = reader.ReadBytes(6); - return signatureBytes.BinaryEquals(SIGNATURE); - } - - protected override IReader CreateReaderForSolidExtraction() - { - return new SevenZipReader(this); - } - - public override bool IsSolid - { - get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } - } - - public override long TotalSize - { - get - { - int i = Entries.Count; - return database.PackSizes.Aggregate(0L, (total, packSize) => total + packSize); - } - } - - private class SevenZipReader : AbstractReader - { - private readonly SevenZipArchive archive; - private CFolder currentFolder; - private Stream currentStream; - private CFileItem currentItem; - - internal SevenZipReader(SevenZipArchive archive) - : base(Options.KeepStreamsOpen, ArchiveType.SevenZip) - { - this.archive = archive; - } - - - public override SevenZipVolume Volume - { - get { return archive.Volumes.Single(); } - } - - internal override IEnumerable GetEntries(Stream stream) - { - List entries = archive.Entries.ToList(); - stream.Position = 0; - foreach (var dir in entries.Where(x => x.IsDirectory)) - { - yield return dir; - } - foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)) - { - currentFolder = group.Key; - if (group.Key == null) - { - currentStream = Stream.Null; - } - else - { - currentStream = archive.database.GetFolderStream(stream, currentFolder, null); - } - foreach (var entry in group) - { - currentItem = entry.FilePart.Header; - yield return entry; - } - } - } - - protected override EntryStream GetEntryStream() - { - return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.SevenZip; +using SharpCompress.IO; +using SharpCompress.Reader; + +namespace SharpCompress.Archive.SevenZip +{ + public class SevenZipArchive : AbstractArchive + { + private ArchiveDatabase database; +#if !DOTNET51 + /// + /// Constructor expects a filepath to an existing file. + /// + /// + public static SevenZipArchive Open(string filePath) + { + return Open(filePath, Options.None); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + public static SevenZipArchive Open(FileInfo fileInfo) + { + return Open(fileInfo, Options.None); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static SevenZipArchive Open(string filePath, Options options) + { + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), options); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static SevenZipArchive Open(FileInfo fileInfo, Options options) + { + fileInfo.CheckNotNull("fileInfo"); + return new SevenZipArchive(fileInfo, options); + } +#endif + + /// + /// Takes a seekable Stream as a source + /// + /// + public static SevenZipArchive Open(Stream stream) + { + stream.CheckNotNull("stream"); + return Open(stream, Options.None); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static SevenZipArchive Open(Stream stream, Options options) + { + stream.CheckNotNull("stream"); + return new SevenZipArchive(stream, options); + } + +#if !DOTNET51 + internal SevenZipArchive(FileInfo fileInfo, Options options) + : base(ArchiveType.SevenZip, fileInfo, options, null) + { + } + + protected override IEnumerable LoadVolumes(FileInfo file, Options options) + { + if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen)) + { + options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); + } + return new SevenZipVolume(file.OpenRead(), options).AsEnumerable(); + } + + public static bool IsSevenZipFile(string filePath) + { + return IsSevenZipFile(new FileInfo(filePath)); + } + + public static bool IsSevenZipFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) + { + return false; + } + using (Stream stream = fileInfo.OpenRead()) + { + return IsSevenZipFile(stream); + } + } +#endif + + internal SevenZipArchive(Stream stream, Options options) + : base(ArchiveType.SevenZip, stream.AsEnumerable(), options, null) + { + } + + internal SevenZipArchive() + : base(ArchiveType.SevenZip) + { + } + + protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) + { + foreach (Stream s in streams) + { + if (!s.CanRead || !s.CanSeek) + { + throw new ArgumentException("Stream is not readable and seekable"); + } + SevenZipVolume volume = new SevenZipVolume(s, options); + yield return volume; + } + } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + var stream = volumes.Single().Stream; + LoadFactory(stream); + for (int i = 0; i < database.Files.Count; i++) + { + var file = database.Files[i]; + if (!file.IsDir) + { + yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file)); + } + } + } + + private void LoadFactory(Stream stream) + { + if (database == null) + { + stream.Position = 0; + var reader = new ArchiveReader(); + reader.Open(stream); + database = reader.ReadDatabase(null); + } + } + + + public static bool IsSevenZipFile(Stream stream) + { + try + { + return SignatureMatch(stream); + } + catch + { + return false; + } + } + + private static readonly byte[] SIGNATURE = new byte[] {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C}; + + private static bool SignatureMatch(Stream stream) + { + BinaryReader reader = new BinaryReader(stream); + byte[] signatureBytes = reader.ReadBytes(6); + return signatureBytes.BinaryEquals(SIGNATURE); + } + + protected override IReader CreateReaderForSolidExtraction() + { + return new SevenZipReader(this); + } + + public override bool IsSolid + { + get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } + } + + public override long TotalSize + { + get + { + int i = Entries.Count; + return database.PackSizes.Aggregate(0L, (total, packSize) => total + packSize); + } + } + + private class SevenZipReader : AbstractReader + { + private readonly SevenZipArchive archive; + private CFolder currentFolder; + private Stream currentStream; + private CFileItem currentItem; + + internal SevenZipReader(SevenZipArchive archive) + : base(Options.KeepStreamsOpen, ArchiveType.SevenZip) + { + this.archive = archive; + } + + + public override SevenZipVolume Volume + { + get { return archive.Volumes.Single(); } + } + + internal override IEnumerable GetEntries(Stream stream) + { + List entries = archive.Entries.ToList(); + stream.Position = 0; + foreach (var dir in entries.Where(x => x.IsDirectory)) + { + yield return dir; + } + foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)) + { + currentFolder = group.Key; + if (group.Key == null) + { + currentStream = Stream.Null; + } + else + { + currentStream = archive.database.GetFolderStream(stream, currentFolder, null); + } + foreach (var entry in group) + { + currentItem = entry.FilePart.Header; + yield return entry; + } + } + } + + protected override EntryStream GetEntryStream() + { + return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs b/src/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs similarity index 96% rename from SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs rename to src/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs index ca893e22..e921733a 100644 --- a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs +++ b/src/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs @@ -1,33 +1,33 @@ -using System.IO; -using SharpCompress.Common.SevenZip; - -namespace SharpCompress.Archive.SevenZip -{ - public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry - { - internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) - : base(part) - { - Archive = archive; - } - - public Stream OpenEntryStream() - { - return FilePart.GetCompressedStream(); - } - public IArchive Archive { get; private set; } - - public bool IsComplete - { - get { return true; } - } - - /// - /// This is a 7Zip Anti item - /// - public bool IsAnti - { - get { return FilePart.Header.IsAnti; } - } - } +using System.IO; +using SharpCompress.Common.SevenZip; + +namespace SharpCompress.Archive.SevenZip +{ + public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry + { + internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) + : base(part) + { + Archive = archive; + } + + public Stream OpenEntryStream() + { + return FilePart.GetCompressedStream(); + } + public IArchive Archive { get; private set; } + + public bool IsComplete + { + get { return true; } + } + + /// + /// This is a 7Zip Anti item + /// + public bool IsAnti + { + get { return FilePart.Header.IsAnti; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Tar/TarArchive.cs b/src/SharpCompress/Archive/Tar/TarArchive.cs similarity index 97% rename from SharpCompress/Archive/Tar/TarArchive.cs rename to src/SharpCompress/Archive/Tar/TarArchive.cs index 236988d9..07311d85 100644 --- a/SharpCompress/Archive/Tar/TarArchive.cs +++ b/src/SharpCompress/Archive/Tar/TarArchive.cs @@ -1,231 +1,231 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Tar; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.IO; -using SharpCompress.Reader; -using SharpCompress.Reader.Tar; -using SharpCompress.Writer.Tar; - -namespace SharpCompress.Archive.Tar -{ - public class TarArchive : AbstractWritableArchive - { -#if !DOTNET51 - /// - /// Constructor expects a filepath to an existing file. - /// - /// - public static TarArchive Open(string filePath) - { - return Open(filePath, Options.None); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - public static TarArchive Open(FileInfo fileInfo) - { - return Open(fileInfo, Options.None); - } - - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static TarArchive Open(string filePath, Options options) - { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), options); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static TarArchive Open(FileInfo fileInfo, Options options) - { - fileInfo.CheckNotNull("fileInfo"); - return new TarArchive(fileInfo, options); - } -#endif - - /// - /// Takes a seekable Stream as a source - /// - /// - public static TarArchive Open(Stream stream) - { - stream.CheckNotNull("stream"); - return Open(stream, Options.None); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static TarArchive Open(Stream stream, Options options) - { - stream.CheckNotNull("stream"); - return new TarArchive(stream, options); - } - -#if !DOTNET51 - public static bool IsTarFile(string filePath) - { - return IsTarFile(new FileInfo(filePath)); - } - - public static bool IsTarFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsTarFile(stream); - } - } -#endif - - public static bool IsTarFile(Stream stream) - { - try - { - TarHeader tar = new TarHeader(); - tar.Read(new BinaryReader(stream)); - return tar.Name.Length > 0 && Enum.IsDefined(typeof (EntryType), tar.EntryType); - } - catch - { - } - return false; - } - -#if !DOTNET51 - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - internal TarArchive(FileInfo fileInfo, Options options) - : base(ArchiveType.Tar, fileInfo, options) - { - } - - protected override IEnumerable LoadVolumes(FileInfo file, Options options) - { - if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen)) - { - options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); - } - return new TarVolume(file.OpenRead(), options).AsEnumerable(); - } -#endif - - /// - /// Takes multiple seekable Streams for a multi-part archive - /// - /// - /// - internal TarArchive(Stream stream, Options options) - : base(ArchiveType.Tar, stream, options) - { - } - - internal TarArchive() - : base(ArchiveType.Tar) - { - } - - protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) - { - return new TarVolume(streams.First(), options).AsEnumerable(); - } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - Stream stream = volumes.Single().Stream; - TarHeader previousHeader = null; - foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream)) - { - if (header != null) - { - if (header.EntryType == EntryType.LongName) - { - previousHeader = header; - } - else - { - if (previousHeader != null) - { - var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream), - CompressionType.None); - - var oldStreamPos = stream.Position; - - using(var entryStream = entry.OpenEntryStream()) - using(var memoryStream = new MemoryStream()) - { - entryStream.TransferTo(memoryStream); - memoryStream.Position = 0; - var bytes = memoryStream.ToArray(); - - header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls(); - } - - stream.Position = oldStreamPos; - - previousHeader = null; - } - yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None); - } - } - } - } - - public static TarArchive Create() - { - return new TarArchive(); - } - - protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source, - long size, DateTime? modified, bool closeStream) - { - return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified, - closeStream); - } - - protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, - IEnumerable oldEntries, - IEnumerable newEntries) - { - using (var writer = new TarWriter(stream, compressionInfo)) - { - foreach (var entry in oldEntries.Concat(newEntries) - .Where(x => !x.IsDirectory)) - { - using (var entryStream = entry.OpenEntryStream()) - { - writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size); - } - } - } - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.Single().Stream; - stream.Position = 0; - return TarReader.Open(stream); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Tar; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.IO; +using SharpCompress.Reader; +using SharpCompress.Reader.Tar; +using SharpCompress.Writer.Tar; + +namespace SharpCompress.Archive.Tar +{ + public class TarArchive : AbstractWritableArchive + { +#if !DOTNET51 + /// + /// Constructor expects a filepath to an existing file. + /// + /// + public static TarArchive Open(string filePath) + { + return Open(filePath, Options.None); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + public static TarArchive Open(FileInfo fileInfo) + { + return Open(fileInfo, Options.None); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static TarArchive Open(string filePath, Options options) + { + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), options); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static TarArchive Open(FileInfo fileInfo, Options options) + { + fileInfo.CheckNotNull("fileInfo"); + return new TarArchive(fileInfo, options); + } +#endif + + /// + /// Takes a seekable Stream as a source + /// + /// + public static TarArchive Open(Stream stream) + { + stream.CheckNotNull("stream"); + return Open(stream, Options.None); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static TarArchive Open(Stream stream, Options options) + { + stream.CheckNotNull("stream"); + return new TarArchive(stream, options); + } + +#if !DOTNET51 + public static bool IsTarFile(string filePath) + { + return IsTarFile(new FileInfo(filePath)); + } + + public static bool IsTarFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) + { + return false; + } + using (Stream stream = fileInfo.OpenRead()) + { + return IsTarFile(stream); + } + } +#endif + + public static bool IsTarFile(Stream stream) + { + try + { + TarHeader tar = new TarHeader(); + tar.Read(new BinaryReader(stream)); + return tar.Name.Length > 0 && Enum.IsDefined(typeof (EntryType), tar.EntryType); + } + catch + { + } + return false; + } + +#if !DOTNET51 + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + internal TarArchive(FileInfo fileInfo, Options options) + : base(ArchiveType.Tar, fileInfo, options) + { + } + + protected override IEnumerable LoadVolumes(FileInfo file, Options options) + { + if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen)) + { + options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); + } + return new TarVolume(file.OpenRead(), options).AsEnumerable(); + } +#endif + + /// + /// Takes multiple seekable Streams for a multi-part archive + /// + /// + /// + internal TarArchive(Stream stream, Options options) + : base(ArchiveType.Tar, stream, options) + { + } + + internal TarArchive() + : base(ArchiveType.Tar) + { + } + + protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) + { + return new TarVolume(streams.First(), options).AsEnumerable(); + } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + Stream stream = volumes.Single().Stream; + TarHeader previousHeader = null; + foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream)) + { + if (header != null) + { + if (header.EntryType == EntryType.LongName) + { + previousHeader = header; + } + else + { + if (previousHeader != null) + { + var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream), + CompressionType.None); + + var oldStreamPos = stream.Position; + + using(var entryStream = entry.OpenEntryStream()) + using(var memoryStream = new MemoryStream()) + { + entryStream.TransferTo(memoryStream); + memoryStream.Position = 0; + var bytes = memoryStream.ToArray(); + + header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls(); + } + + stream.Position = oldStreamPos; + + previousHeader = null; + } + yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None); + } + } + } + } + + public static TarArchive Create() + { + return new TarArchive(); + } + + protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source, + long size, DateTime? modified, bool closeStream) + { + return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified, + closeStream); + } + + protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, + IEnumerable oldEntries, + IEnumerable newEntries) + { + using (var writer = new TarWriter(stream, compressionInfo)) + { + foreach (var entry in oldEntries.Concat(newEntries) + .Where(x => !x.IsDirectory)) + { + using (var entryStream = entry.OpenEntryStream()) + { + writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size); + } + } + } + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.Single().Stream; + stream.Position = 0; + return TarReader.Open(stream); + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Tar/TarArchiveEntry.cs b/src/SharpCompress/Archive/Tar/TarArchiveEntry.cs similarity index 96% rename from SharpCompress/Archive/Tar/TarArchiveEntry.cs rename to src/SharpCompress/Archive/Tar/TarArchiveEntry.cs index cf07aad4..16585964 100644 --- a/SharpCompress/Archive/Tar/TarArchiveEntry.cs +++ b/src/SharpCompress/Archive/Tar/TarArchiveEntry.cs @@ -1,31 +1,31 @@ -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Tar; - -namespace SharpCompress.Archive.Tar -{ - public class TarArchiveEntry : TarEntry, IArchiveEntry - { - internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType) - : base(part, compressionType) - { - Archive = archive; - } - - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } - - #region IArchiveEntry Members - public IArchive Archive { get; private set; } - - public bool IsComplete - { - get { return true; } - } - - #endregion - } +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Tar; + +namespace SharpCompress.Archive.Tar +{ + public class TarArchiveEntry : TarEntry, IArchiveEntry + { + internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType) + : base(part, compressionType) + { + Archive = archive; + } + + public virtual Stream OpenEntryStream() + { + return Parts.Single().GetCompressedStream(); + } + + #region IArchiveEntry Members + public IArchive Archive { get; private set; } + + public bool IsComplete + { + get { return true; } + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Tar/TarWritableArchiveEntry.cs b/src/SharpCompress/Archive/Tar/TarWritableArchiveEntry.cs similarity index 96% rename from SharpCompress/Archive/Tar/TarWritableArchiveEntry.cs rename to src/SharpCompress/Archive/Tar/TarWritableArchiveEntry.cs index b1b1d608..5830fb68 100644 --- a/SharpCompress/Archive/Tar/TarWritableArchiveEntry.cs +++ b/src/SharpCompress/Archive/Tar/TarWritableArchiveEntry.cs @@ -1,110 +1,110 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.IO; - -namespace SharpCompress.Archive.Tar -{ - internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry - { - private readonly string path; - private readonly long size; - private readonly DateTime? lastModified; - private readonly bool closeStream; - private readonly Stream stream; - - internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType, - string path, long size, DateTime? lastModified, bool closeStream) - : base(archive, null, compressionType) - { - this.stream = stream; - this.path = path; - this.size = size; - this.lastModified = lastModified; - this.closeStream = closeStream; - } - - public override long Crc - { - get { return 0; } - } - - public override string Key - { - get { return path; } - } - - public override long CompressedSize - { - get { return 0; } - } - - public override long Size - { - get { return size; } - } - - public override DateTime? LastModifiedTime - { - get { return lastModified; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return false; } - } - - public override bool IsDirectory - { - get { return false; } - } - - public override bool IsSplit - { - get { return false; } - } - - internal override IEnumerable Parts - { - get { throw new NotImplementedException(); } - } - Stream IWritableArchiveEntry.Stream - { - get - { - return stream; - } - } - - public override Stream OpenEntryStream() - { - //ensure new stream is at the start, this could be reset - stream.Seek(0, SeekOrigin.Begin); - return new NonDisposingStream(stream); - } - - internal override void Close() - { - if (closeStream) - { - stream.Dispose(); - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.IO; + +namespace SharpCompress.Archive.Tar +{ + internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry + { + private readonly string path; + private readonly long size; + private readonly DateTime? lastModified; + private readonly bool closeStream; + private readonly Stream stream; + + internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType, + string path, long size, DateTime? lastModified, bool closeStream) + : base(archive, null, compressionType) + { + this.stream = stream; + this.path = path; + this.size = size; + this.lastModified = lastModified; + this.closeStream = closeStream; + } + + public override long Crc + { + get { return 0; } + } + + public override string Key + { + get { return path; } + } + + public override long CompressedSize + { + get { return 0; } + } + + public override long Size + { + get { return size; } + } + + public override DateTime? LastModifiedTime + { + get { return lastModified; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return false; } + } + + public override bool IsDirectory + { + get { return false; } + } + + public override bool IsSplit + { + get { return false; } + } + + internal override IEnumerable Parts + { + get { throw new NotImplementedException(); } + } + Stream IWritableArchiveEntry.Stream + { + get + { + return stream; + } + } + + public override Stream OpenEntryStream() + { + //ensure new stream is at the start, this could be reset + stream.Seek(0, SeekOrigin.Begin); + return new NonDisposingStream(stream); + } + + internal override void Close() + { + if (closeStream) + { + stream.Dispose(); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Zip/ZipArchive.cs b/src/SharpCompress/Archive/Zip/ZipArchive.cs similarity index 97% rename from SharpCompress/Archive/Zip/ZipArchive.cs rename to src/SharpCompress/Archive/Zip/ZipArchive.cs index 52fef9ef..40f1ff4e 100644 --- a/SharpCompress/Archive/Zip/ZipArchive.cs +++ b/src/SharpCompress/Archive/Zip/ZipArchive.cs @@ -1,245 +1,245 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Zip; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.Compressor.Deflate; -using SharpCompress.Reader; -using SharpCompress.Reader.Zip; -using SharpCompress.Writer.Zip; - -namespace SharpCompress.Archive.Zip -{ - public class ZipArchive : AbstractWritableArchive - { - private readonly SeekableZipHeaderFactory headerFactory; - - /// - /// Gets or sets the compression level applied to files added to the archive, - /// if the compression method is set to deflate - /// - public CompressionLevel DeflateCompressionLevel { get; set; } - -#if !DOTNET51 - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static ZipArchive Open(string filePath, string password = null) - { - return Open(filePath, Options.None, password); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static ZipArchive Open(FileInfo fileInfo, string password = null) - { - return Open(fileInfo, Options.None, password); - } - - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - /// - public static ZipArchive Open(string filePath, Options options, string password = null) - { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), options, password); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - /// - public static ZipArchive Open(FileInfo fileInfo, Options options, string password = null) - { - fileInfo.CheckNotNull("fileInfo"); - return new ZipArchive(fileInfo, options, password); - } -#endif - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static ZipArchive Open(Stream stream, string password = null) - { - stream.CheckNotNull("stream"); - return Open(stream, Options.None, password); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - /// - public static ZipArchive Open(Stream stream, Options options, string password = null) - { - stream.CheckNotNull("stream"); - return new ZipArchive(stream, options, password); - } - -#if !DOTNET51 - public static bool IsZipFile(string filePath, string password = null) - { - return IsZipFile(new FileInfo(filePath), password); - } - - public static bool IsZipFile(FileInfo fileInfo, string password = null) - { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsZipFile(stream, password); - } - } -#endif - - public static bool IsZipFile(Stream stream, string password = null) - { - StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password); - try - { - ZipHeader header = - headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); - if (header == null) - { - return false; - } - return Enum.IsDefined(typeof (ZipHeaderType), header.ZipHeaderType); - } - catch (CryptographicException) - { - return true; - } - catch - { - return false; - } - } - -#if !DOTNET51 - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - /// - internal ZipArchive(FileInfo fileInfo, Options options, string password = null) - : base(ArchiveType.Zip, fileInfo, options) - { - headerFactory = new SeekableZipHeaderFactory(password); - } - - protected override IEnumerable LoadVolumes(FileInfo file, Options options) - { - if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen)) - { - options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); - } - return new ZipVolume(file.OpenRead(), options).AsEnumerable(); - } -#endif - - internal ZipArchive() - : base(ArchiveType.Zip) - { - } - - /// - /// Takes multiple seekable Streams for a multi-part archive - /// - /// - /// - /// - internal ZipArchive(Stream stream, Options options, string password = null) - : base(ArchiveType.Zip, stream, options) - { - headerFactory = new SeekableZipHeaderFactory(password); - } - - protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) - { - return new ZipVolume(streams.First(), options).AsEnumerable(); - } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - var volume = volumes.Single(); - Stream stream = volume.Stream; - foreach (ZipHeader h in headerFactory.ReadSeekableHeader(stream)) - { - if (h != null) - { - switch (h.ZipHeaderType) - { - case ZipHeaderType.DirectoryEntry: - { - yield return new ZipArchiveEntry(this, - new SeekableZipFilePart(headerFactory, - h as DirectoryEntryHeader, - stream)); - } - break; - case ZipHeaderType.DirectoryEnd: - { - byte[] bytes = (h as DirectoryEndHeader).Comment; - volume.Comment = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length); - yield break; - } - } - } - } - } - - protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, - IEnumerable oldEntries, - IEnumerable newEntries) - { - using (var writer = new ZipWriter(stream, compressionInfo, string.Empty)) - { - foreach (var entry in oldEntries.Concat(newEntries) - .Where(x => !x.IsDirectory)) - { - using (var entryStream = entry.OpenEntryStream()) - { - writer.Write(entry.Key, entryStream, entry.LastModifiedTime, string.Empty); - } - } - } - } - - protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, - bool closeStream) - { - return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); - } - - public static ZipArchive Create() - { - return new ZipArchive(); - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.Single().Stream; - stream.Position = 0; - return ZipReader.Open(stream); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Zip; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.Compressor.Deflate; +using SharpCompress.Reader; +using SharpCompress.Reader.Zip; +using SharpCompress.Writer.Zip; + +namespace SharpCompress.Archive.Zip +{ + public class ZipArchive : AbstractWritableArchive + { + private readonly SeekableZipHeaderFactory headerFactory; + + /// + /// Gets or sets the compression level applied to files added to the archive, + /// if the compression method is set to deflate + /// + public CompressionLevel DeflateCompressionLevel { get; set; } + +#if !DOTNET51 + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static ZipArchive Open(string filePath, string password = null) + { + return Open(filePath, Options.None, password); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static ZipArchive Open(FileInfo fileInfo, string password = null) + { + return Open(fileInfo, Options.None, password); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + /// + public static ZipArchive Open(string filePath, Options options, string password = null) + { + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), options, password); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + /// + public static ZipArchive Open(FileInfo fileInfo, Options options, string password = null) + { + fileInfo.CheckNotNull("fileInfo"); + return new ZipArchive(fileInfo, options, password); + } +#endif + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static ZipArchive Open(Stream stream, string password = null) + { + stream.CheckNotNull("stream"); + return Open(stream, Options.None, password); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + /// + public static ZipArchive Open(Stream stream, Options options, string password = null) + { + stream.CheckNotNull("stream"); + return new ZipArchive(stream, options, password); + } + +#if !DOTNET51 + public static bool IsZipFile(string filePath, string password = null) + { + return IsZipFile(new FileInfo(filePath), password); + } + + public static bool IsZipFile(FileInfo fileInfo, string password = null) + { + if (!fileInfo.Exists) + { + return false; + } + using (Stream stream = fileInfo.OpenRead()) + { + return IsZipFile(stream, password); + } + } +#endif + + public static bool IsZipFile(Stream stream, string password = null) + { + StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password); + try + { + ZipHeader header = + headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); + if (header == null) + { + return false; + } + return Enum.IsDefined(typeof (ZipHeaderType), header.ZipHeaderType); + } + catch (CryptographicException) + { + return true; + } + catch + { + return false; + } + } + +#if !DOTNET51 + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + /// + internal ZipArchive(FileInfo fileInfo, Options options, string password = null) + : base(ArchiveType.Zip, fileInfo, options) + { + headerFactory = new SeekableZipHeaderFactory(password); + } + + protected override IEnumerable LoadVolumes(FileInfo file, Options options) + { + if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen)) + { + options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false); + } + return new ZipVolume(file.OpenRead(), options).AsEnumerable(); + } +#endif + + internal ZipArchive() + : base(ArchiveType.Zip) + { + } + + /// + /// Takes multiple seekable Streams for a multi-part archive + /// + /// + /// + /// + internal ZipArchive(Stream stream, Options options, string password = null) + : base(ArchiveType.Zip, stream, options) + { + headerFactory = new SeekableZipHeaderFactory(password); + } + + protected override IEnumerable LoadVolumes(IEnumerable streams, Options options) + { + return new ZipVolume(streams.First(), options).AsEnumerable(); + } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + var volume = volumes.Single(); + Stream stream = volume.Stream; + foreach (ZipHeader h in headerFactory.ReadSeekableHeader(stream)) + { + if (h != null) + { + switch (h.ZipHeaderType) + { + case ZipHeaderType.DirectoryEntry: + { + yield return new ZipArchiveEntry(this, + new SeekableZipFilePart(headerFactory, + h as DirectoryEntryHeader, + stream)); + } + break; + case ZipHeaderType.DirectoryEnd: + { + byte[] bytes = (h as DirectoryEndHeader).Comment; + volume.Comment = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length); + yield break; + } + } + } + } + } + + protected override void SaveTo(Stream stream, CompressionInfo compressionInfo, + IEnumerable oldEntries, + IEnumerable newEntries) + { + using (var writer = new ZipWriter(stream, compressionInfo, string.Empty)) + { + foreach (var entry in oldEntries.Concat(newEntries) + .Where(x => !x.IsDirectory)) + { + using (var entryStream = entry.OpenEntryStream()) + { + writer.Write(entry.Key, entryStream, entry.LastModifiedTime, string.Empty); + } + } + } + } + + protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, + bool closeStream) + { + return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); + } + + public static ZipArchive Create() + { + return new ZipArchive(); + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.Single().Stream; + stream.Position = 0; + return ZipReader.Open(stream); + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Zip/ZipArchiveEntry.cs b/src/SharpCompress/Archive/Zip/ZipArchiveEntry.cs similarity index 95% rename from SharpCompress/Archive/Zip/ZipArchiveEntry.cs rename to src/SharpCompress/Archive/Zip/ZipArchiveEntry.cs index 70d4b229..607f7a58 100644 --- a/SharpCompress/Archive/Zip/ZipArchiveEntry.cs +++ b/src/SharpCompress/Archive/Zip/ZipArchiveEntry.cs @@ -1,36 +1,36 @@ -using System.IO; -using System.Linq; -using SharpCompress.Common.Zip; - -namespace SharpCompress.Archive.Zip -{ - public class ZipArchiveEntry : ZipEntry, IArchiveEntry - { - internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart part) - : base(part) - { - Archive = archive; - } - - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } - - #region IArchiveEntry Members - - public IArchive Archive { get; private set; } - - public bool IsComplete - { - get { return true; } - } - - #endregion - - public string Comment - { - get { return (Parts.Single() as SeekableZipFilePart).Comment; } - } - } +using System.IO; +using System.Linq; +using SharpCompress.Common.Zip; + +namespace SharpCompress.Archive.Zip +{ + public class ZipArchiveEntry : ZipEntry, IArchiveEntry + { + internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart part) + : base(part) + { + Archive = archive; + } + + public virtual Stream OpenEntryStream() + { + return Parts.Single().GetCompressedStream(); + } + + #region IArchiveEntry Members + + public IArchive Archive { get; private set; } + + public bool IsComplete + { + get { return true; } + } + + #endregion + + public string Comment + { + get { return (Parts.Single() as SeekableZipFilePart).Comment; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Archive/Zip/ZipWritableArchiveEntry.cs b/src/SharpCompress/Archive/Zip/ZipWritableArchiveEntry.cs similarity index 95% rename from SharpCompress/Archive/Zip/ZipWritableArchiveEntry.cs rename to src/SharpCompress/Archive/Zip/ZipWritableArchiveEntry.cs index ce99ce40..f1946e7a 100644 --- a/SharpCompress/Archive/Zip/ZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archive/Zip/ZipWritableArchiveEntry.cs @@ -1,113 +1,113 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.IO; - -namespace SharpCompress.Archive.Zip -{ - internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry - { - private readonly string path; - private readonly long size; - private readonly DateTime? lastModified; - private readonly bool closeStream; - private readonly Stream stream; - private bool isDisposed; - - internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size, - DateTime? lastModified, bool closeStream) - : base(archive, null) - { - this.stream = stream; - this.path = path; - this.size = size; - this.lastModified = lastModified; - this.closeStream = closeStream; - } - - public override long Crc - { - get { return 0; } - } - - public override string Key - { - get { return path; } - } - - public override long CompressedSize - { - get { return 0; } - } - - public override long Size - { - get { return size; } - } - - public override DateTime? LastModifiedTime - { - get { return lastModified; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return false; } - } - - public override bool IsDirectory - { - get { return false; } - } - - public override bool IsSplit - { - get { return false; } - } - - internal override IEnumerable Parts - { - get { throw new NotImplementedException(); } - } - - Stream IWritableArchiveEntry.Stream - { - get - { - return stream; - } - } - - public override Stream OpenEntryStream() - { - //ensure new stream is at the start, this could be reset - stream.Seek(0, SeekOrigin.Begin); - return new NonDisposingStream(stream); - } - - internal override void Close() - { - if (closeStream && !isDisposed) - { - stream.Dispose(); - isDisposed = true; - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.IO; + +namespace SharpCompress.Archive.Zip +{ + internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry + { + private readonly string path; + private readonly long size; + private readonly DateTime? lastModified; + private readonly bool closeStream; + private readonly Stream stream; + private bool isDisposed; + + internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size, + DateTime? lastModified, bool closeStream) + : base(archive, null) + { + this.stream = stream; + this.path = path; + this.size = size; + this.lastModified = lastModified; + this.closeStream = closeStream; + } + + public override long Crc + { + get { return 0; } + } + + public override string Key + { + get { return path; } + } + + public override long CompressedSize + { + get { return 0; } + } + + public override long Size + { + get { return size; } + } + + public override DateTime? LastModifiedTime + { + get { return lastModified; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return false; } + } + + public override bool IsDirectory + { + get { return false; } + } + + public override bool IsSplit + { + get { return false; } + } + + internal override IEnumerable Parts + { + get { throw new NotImplementedException(); } + } + + Stream IWritableArchiveEntry.Stream + { + get + { + return stream; + } + } + + public override Stream OpenEntryStream() + { + //ensure new stream is at the start, this could be reset + stream.Seek(0, SeekOrigin.Begin); + return new NonDisposingStream(stream); + } + + internal override void Close() + { + if (closeStream && !isDisposed) + { + stream.Dispose(); + isDisposed = true; + } + } + } } \ No newline at end of file diff --git a/SharpCompress/AssemblyInfo.cs b/src/SharpCompress/AssemblyInfo.cs similarity index 96% rename from SharpCompress/AssemblyInfo.cs rename to src/SharpCompress/AssemblyInfo.cs index 2caef4ba..8978eeba 100644 --- a/SharpCompress/AssemblyInfo.cs +++ b/src/SharpCompress/AssemblyInfo.cs @@ -1,13 +1,13 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; - - -[assembly: AssemblyTitle("SharpCompress")] -[assembly: AssemblyProduct("SharpCompress")] - - -[assembly: InternalsVisibleTo("SharpCompress.Test")] -[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")] - -[assembly: CLSCompliant(true)] +using System; +using System.Reflection; +using System.Runtime.CompilerServices; + + +[assembly: AssemblyTitle("SharpCompress")] +[assembly: AssemblyProduct("SharpCompress")] + + +[assembly: InternalsVisibleTo("SharpCompress.Test")] +[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")] + +[assembly: CLSCompliant(true)] diff --git a/SharpCompress/Common/ArchiveEncoding.cs b/src/SharpCompress/Common/ArchiveEncoding.cs similarity index 96% rename from SharpCompress/Common/ArchiveEncoding.cs rename to src/SharpCompress/Common/ArchiveEncoding.cs index 98cb6f7d..c973c7cb 100644 --- a/SharpCompress/Common/ArchiveEncoding.cs +++ b/src/SharpCompress/Common/ArchiveEncoding.cs @@ -1,23 +1,23 @@ -using System.Text; - -namespace SharpCompress.Common -{ - public static class ArchiveEncoding - { - /// - /// Default encoding to use when archive format doesn't specify one. - /// - public static Encoding Default { get; set; } - - /// - /// Encoding used by encryption schemes which don't comply with RFC 2898. - /// - public static Encoding Password { get; set; } - - static ArchiveEncoding() - { - Default = Encoding.UTF8; - Password = Encoding.UTF8; - } - } +using System.Text; + +namespace SharpCompress.Common +{ + public static class ArchiveEncoding + { + /// + /// Default encoding to use when archive format doesn't specify one. + /// + public static Encoding Default { get; set; } + + /// + /// Encoding used by encryption schemes which don't comply with RFC 2898. + /// + public static Encoding Password { get; set; } + + static ArchiveEncoding() + { + Default = Encoding.UTF8; + Password = Encoding.UTF8; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/ArchiveException.cs b/src/SharpCompress/Common/ArchiveException.cs similarity index 94% rename from SharpCompress/Common/ArchiveException.cs rename to src/SharpCompress/Common/ArchiveException.cs index 3a969784..18207c64 100644 --- a/SharpCompress/Common/ArchiveException.cs +++ b/src/SharpCompress/Common/ArchiveException.cs @@ -1,12 +1,12 @@ -using System; - -namespace SharpCompress.Common -{ - public class ArchiveException : Exception - { - public ArchiveException(string message) - : base(message) - { - } - } +using System; + +namespace SharpCompress.Common +{ + public class ArchiveException : Exception + { + public ArchiveException(string message) + : base(message) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/ArchiveExtractionEventArgs.cs b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs similarity index 95% rename from SharpCompress/Common/ArchiveExtractionEventArgs.cs rename to src/SharpCompress/Common/ArchiveExtractionEventArgs.cs index 1a4cba25..7295fdf4 100644 --- a/SharpCompress/Common/ArchiveExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs @@ -1,14 +1,14 @@ -using System; - -namespace SharpCompress.Common -{ - public class ArchiveExtractionEventArgs : EventArgs - { - internal ArchiveExtractionEventArgs(T entry) - { - Item = entry; - } - - public T Item { get; private set; } - } +using System; + +namespace SharpCompress.Common +{ + public class ArchiveExtractionEventArgs : EventArgs + { + internal ArchiveExtractionEventArgs(T entry) + { + Item = entry; + } + + public T Item { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/ArchiveType.cs b/src/SharpCompress/Common/ArchiveType.cs similarity index 93% rename from SharpCompress/Common/ArchiveType.cs rename to src/SharpCompress/Common/ArchiveType.cs index 2b405356..ca905f42 100644 --- a/SharpCompress/Common/ArchiveType.cs +++ b/src/SharpCompress/Common/ArchiveType.cs @@ -1,11 +1,11 @@ -namespace SharpCompress.Common -{ - public enum ArchiveType - { - Rar, - Zip, - Tar, - SevenZip, - GZip, - } +namespace SharpCompress.Common +{ + public enum ArchiveType + { + Rar, + Zip, + Tar, + SevenZip, + GZip, + } } \ No newline at end of file diff --git a/SharpCompress/Common/CompressedBytesReadEventArgs.cs b/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs similarity index 96% rename from SharpCompress/Common/CompressedBytesReadEventArgs.cs rename to src/SharpCompress/Common/CompressedBytesReadEventArgs.cs index 7c8ed598..fdae9c4d 100644 --- a/SharpCompress/Common/CompressedBytesReadEventArgs.cs +++ b/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs @@ -1,17 +1,17 @@ -using System; - -namespace SharpCompress.Common -{ - public class CompressedBytesReadEventArgs : EventArgs - { - /// - /// Compressed bytes read for the current entry - /// - public long CompressedBytesRead { get; internal set; } - - /// - /// Current file part read for Multipart files (e.g. Rar) - /// - public long CurrentFilePartCompressedBytesRead { get; internal set; } - } +using System; + +namespace SharpCompress.Common +{ + public class CompressedBytesReadEventArgs : EventArgs + { + /// + /// Compressed bytes read for the current entry + /// + public long CompressedBytesRead { get; internal set; } + + /// + /// Current file part read for Multipart files (e.g. Rar) + /// + public long CurrentFilePartCompressedBytesRead { get; internal set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/CompressionInfo.cs b/src/SharpCompress/Common/CompressionInfo.cs similarity index 96% rename from SharpCompress/Common/CompressionInfo.cs rename to src/SharpCompress/Common/CompressionInfo.cs index f62ea405..2ad5703b 100644 --- a/SharpCompress/Common/CompressionInfo.cs +++ b/src/SharpCompress/Common/CompressionInfo.cs @@ -1,30 +1,30 @@ -using SharpCompress.Compressor.Deflate; - -namespace SharpCompress.Common -{ - /// - /// Detailed compression properties when saving. - /// - public class CompressionInfo - { - public CompressionInfo() - { - DeflateCompressionLevel = CompressionLevel.Default; - } - - /// - /// The algorthm to use. Must be valid for the format type. - /// - public CompressionType Type { get; set; } - - /// - /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. - /// - public CompressionLevel DeflateCompressionLevel { get; set; } - - public static implicit operator CompressionInfo(CompressionType compressionType) - { - return new CompressionInfo() {Type = compressionType}; - } - } +using SharpCompress.Compressor.Deflate; + +namespace SharpCompress.Common +{ + /// + /// Detailed compression properties when saving. + /// + public class CompressionInfo + { + public CompressionInfo() + { + DeflateCompressionLevel = CompressionLevel.Default; + } + + /// + /// The algorthm to use. Must be valid for the format type. + /// + public CompressionType Type { get; set; } + + /// + /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. + /// + public CompressionLevel DeflateCompressionLevel { get; set; } + + public static implicit operator CompressionInfo(CompressionType compressionType) + { + return new CompressionInfo() {Type = compressionType}; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/CompressionType.cs b/src/SharpCompress/Common/CompressionType.cs similarity index 93% rename from SharpCompress/Common/CompressionType.cs rename to src/SharpCompress/Common/CompressionType.cs index d51e6545..20d59a2b 100644 --- a/SharpCompress/Common/CompressionType.cs +++ b/src/SharpCompress/Common/CompressionType.cs @@ -1,16 +1,16 @@ -namespace SharpCompress.Common -{ - public enum CompressionType - { - None, - GZip, - BZip2, - PPMd, - Deflate, - Rar, - LZMA, - BCJ, - BCJ2, - Unknown, - } +namespace SharpCompress.Common +{ + public enum CompressionType + { + None, + GZip, + BZip2, + PPMd, + Deflate, + Rar, + LZMA, + BCJ, + BCJ2, + Unknown, + } } \ No newline at end of file diff --git a/SharpCompress/Common/CryptographicException.cs b/src/SharpCompress/Common/CryptographicException.cs similarity index 95% rename from SharpCompress/Common/CryptographicException.cs rename to src/SharpCompress/Common/CryptographicException.cs index 4e17f303..450cd237 100644 --- a/SharpCompress/Common/CryptographicException.cs +++ b/src/SharpCompress/Common/CryptographicException.cs @@ -1,12 +1,12 @@ -using System; - -namespace SharpCompress.Common -{ - public class CryptographicException : Exception - { - public CryptographicException(string message) - : base(message) - { - } - } +using System; + +namespace SharpCompress.Common +{ + public class CryptographicException : Exception + { + public CryptographicException(string message) + : base(message) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Entry.cs b/src/SharpCompress/Common/Entry.cs similarity index 96% rename from SharpCompress/Common/Entry.cs rename to src/SharpCompress/Common/Entry.cs index 42d90faf..3f1aac1b 100644 --- a/SharpCompress/Common/Entry.cs +++ b/src/SharpCompress/Common/Entry.cs @@ -1,85 +1,85 @@ -using System; -using System.Collections.Generic; - -namespace SharpCompress.Common -{ - public abstract class Entry : IEntry - { - /// - /// The File's 32 bit CRC Hash - /// - public abstract long Crc { get; } - - /// - /// The string key of the file internal to the Archive. - /// - public abstract string Key { get; } - - /// - /// The compressed file size - /// - public abstract long CompressedSize { get; } - - /// - /// The compression type - /// - public abstract CompressionType CompressionType { get; } - - /// - /// The uncompressed file size - /// - public abstract long Size { get; } - - /// - /// The entry last modified time in the archive, if recorded - /// - public abstract DateTime? LastModifiedTime { get; } - - /// - /// The entry create time in the archive, if recorded - /// - public abstract DateTime? CreatedTime { get; } - - /// - /// The entry last accessed time in the archive, if recorded - /// - public abstract DateTime? LastAccessedTime { get; } - - /// - /// The entry time when archived, if recorded - /// - public abstract DateTime? ArchivedTime { get; } - - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public abstract bool IsEncrypted { get; } - - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public abstract bool IsDirectory { get; } - - /// - /// Entry is split among multiple volumes - /// - public abstract bool IsSplit { get; } - - internal abstract IEnumerable Parts { get; } - internal bool IsSolid { get; set; } - - internal virtual void Close() - { - - } - - /// - /// Entry file attribute. - /// - public virtual int? Attrib - { - get { throw new NotImplementedException(); } - } - - } +using System; +using System.Collections.Generic; + +namespace SharpCompress.Common +{ + public abstract class Entry : IEntry + { + /// + /// The File's 32 bit CRC Hash + /// + public abstract long Crc { get; } + + /// + /// The string key of the file internal to the Archive. + /// + public abstract string Key { get; } + + /// + /// The compressed file size + /// + public abstract long CompressedSize { get; } + + /// + /// The compression type + /// + public abstract CompressionType CompressionType { get; } + + /// + /// The uncompressed file size + /// + public abstract long Size { get; } + + /// + /// The entry last modified time in the archive, if recorded + /// + public abstract DateTime? LastModifiedTime { get; } + + /// + /// The entry create time in the archive, if recorded + /// + public abstract DateTime? CreatedTime { get; } + + /// + /// The entry last accessed time in the archive, if recorded + /// + public abstract DateTime? LastAccessedTime { get; } + + /// + /// The entry time when archived, if recorded + /// + public abstract DateTime? ArchivedTime { get; } + + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public abstract bool IsEncrypted { get; } + + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public abstract bool IsDirectory { get; } + + /// + /// Entry is split among multiple volumes + /// + public abstract bool IsSplit { get; } + + internal abstract IEnumerable Parts { get; } + internal bool IsSolid { get; set; } + + internal virtual void Close() + { + + } + + /// + /// Entry file attribute. + /// + public virtual int? Attrib + { + get { throw new NotImplementedException(); } + } + + } } \ No newline at end of file diff --git a/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs similarity index 96% rename from SharpCompress/Common/EntryStream.cs rename to src/SharpCompress/Common/EntryStream.cs index 86e50978..f3fd99ac 100644 --- a/SharpCompress/Common/EntryStream.cs +++ b/src/SharpCompress/Common/EntryStream.cs @@ -1,103 +1,103 @@ -using System; -using System.IO; -using SharpCompress.Reader; - -namespace SharpCompress.Common -{ - public class EntryStream : Stream - { - public IReader Reader { get; private set; } - private Stream stream; - private bool completed; - private bool isDisposed; - - internal EntryStream(IReader reader, Stream stream) - { - this.Reader = reader; - this.stream = stream; - } - - /// - /// When reading a stream from OpenEntryStream, the stream must be completed so use this to finish reading the entire entry. - /// - public void SkipEntry() - { - var buffer = new byte[4096]; - while (Read(buffer, 0, buffer.Length) > 0) - { - } - completed = true; - } - - protected override void Dispose(bool disposing) - { - if (!(completed || Reader.Cancelled)) - { - SkipEntry(); - } - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - stream.Dispose(); - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - int read = stream.Read(buffer, offset, count); - if (read <= 0) - { - completed = true; - } - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - } +using System; +using System.IO; +using SharpCompress.Reader; + +namespace SharpCompress.Common +{ + public class EntryStream : Stream + { + public IReader Reader { get; private set; } + private Stream stream; + private bool completed; + private bool isDisposed; + + internal EntryStream(IReader reader, Stream stream) + { + this.Reader = reader; + this.stream = stream; + } + + /// + /// When reading a stream from OpenEntryStream, the stream must be completed so use this to finish reading the entire entry. + /// + public void SkipEntry() + { + var buffer = new byte[4096]; + while (Read(buffer, 0, buffer.Length) > 0) + { + } + completed = true; + } + + protected override void Dispose(bool disposing) + { + if (!(completed || Reader.Cancelled)) + { + SkipEntry(); + } + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + stream.Dispose(); + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int read = stream.Read(buffer, offset, count); + if (read <= 0) + { + completed = true; + } + return read; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/ExtractOptions.cs b/src/SharpCompress/Common/ExtractOptions.cs similarity index 95% rename from SharpCompress/Common/ExtractOptions.cs rename to src/SharpCompress/Common/ExtractOptions.cs index 0aff140e..85c92668 100644 --- a/SharpCompress/Common/ExtractOptions.cs +++ b/src/SharpCompress/Common/ExtractOptions.cs @@ -1,30 +1,30 @@ -using System; - -namespace SharpCompress.Common -{ - [Flags] - public enum ExtractOptions - { - None = 0, - - /// - /// overwrite target if it exists - /// - Overwrite = 1 << 0, - - /// - /// extract with internal directory structure - /// - ExtractFullPath = 1 << 1, - - /// - /// preserve file time - /// - PreserveFileTime = 1 << 2, - - /// - /// preserve windows file attributes - /// - PreserveAttributes = 1 << 3, - } +using System; + +namespace SharpCompress.Common +{ + [Flags] + public enum ExtractOptions + { + None = 0, + + /// + /// overwrite target if it exists + /// + Overwrite = 1 << 0, + + /// + /// extract with internal directory structure + /// + ExtractFullPath = 1 << 1, + + /// + /// preserve file time + /// + PreserveFileTime = 1 << 2, + + /// + /// preserve windows file attributes + /// + PreserveAttributes = 1 << 3, + } } \ No newline at end of file diff --git a/SharpCompress/Common/ExtractionException.cs b/src/SharpCompress/Common/ExtractionException.cs similarity index 95% rename from SharpCompress/Common/ExtractionException.cs rename to src/SharpCompress/Common/ExtractionException.cs index 15224d4d..be5e688c 100644 --- a/SharpCompress/Common/ExtractionException.cs +++ b/src/SharpCompress/Common/ExtractionException.cs @@ -1,17 +1,17 @@ -using System; - -namespace SharpCompress.Common -{ - public class ExtractionException : Exception - { - public ExtractionException(string message) - : base(message) - { - } - - public ExtractionException(string message, Exception inner) - : base(message, inner) - { - } - } +using System; + +namespace SharpCompress.Common +{ + public class ExtractionException : Exception + { + public ExtractionException(string message) + : base(message) + { + } + + public ExtractionException(string message, Exception inner) + : base(message, inner) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/FilePart.cs b/src/SharpCompress/Common/FilePart.cs similarity index 95% rename from SharpCompress/Common/FilePart.cs rename to src/SharpCompress/Common/FilePart.cs index c9bbd636..b57ef613 100644 --- a/SharpCompress/Common/FilePart.cs +++ b/src/SharpCompress/Common/FilePart.cs @@ -1,12 +1,12 @@ -using System.IO; - -namespace SharpCompress.Common -{ - public abstract class FilePart - { - internal abstract string FilePartName { get; } - - internal abstract Stream GetCompressedStream(); - internal abstract Stream GetRawStream(); - } +using System.IO; + +namespace SharpCompress.Common +{ + public abstract class FilePart + { + internal abstract string FilePartName { get; } + + internal abstract Stream GetCompressedStream(); + internal abstract Stream GetRawStream(); + } } \ No newline at end of file diff --git a/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs b/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs similarity index 96% rename from SharpCompress/Common/FilePartExtractionBeginEventArgs.cs rename to src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs index b5742b6c..913f2093 100644 --- a/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs +++ b/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs @@ -1,22 +1,22 @@ -using System; - -namespace SharpCompress.Common -{ - public class FilePartExtractionBeginEventArgs : EventArgs - { - /// - /// File name for the part for the current entry - /// - public string Name { get; internal set; } - - /// - /// Uncompressed size of the current entry in the part - /// - public long Size { get; internal set; } - - /// - /// Compressed size of the current entry in the part - /// - public long CompressedSize { get; internal set; } - } +using System; + +namespace SharpCompress.Common +{ + public class FilePartExtractionBeginEventArgs : EventArgs + { + /// + /// File name for the part for the current entry + /// + public string Name { get; internal set; } + + /// + /// Uncompressed size of the current entry in the part + /// + public long Size { get; internal set; } + + /// + /// Compressed size of the current entry in the part + /// + public long CompressedSize { get; internal set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/FlagUtility.cs b/src/SharpCompress/Common/FlagUtility.cs similarity index 97% rename from SharpCompress/Common/FlagUtility.cs rename to src/SharpCompress/Common/FlagUtility.cs index e4568348..b6fc8664 100644 --- a/SharpCompress/Common/FlagUtility.cs +++ b/src/SharpCompress/Common/FlagUtility.cs @@ -1,109 +1,109 @@ -using System; - -namespace SharpCompress.Common -{ - internal static class FlagUtility - { - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(long bitField, T flag) - where T : struct - { - return HasFlag(bitField, flag); - } - - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(ulong bitField, T flag) - where T : struct - { - return HasFlag(bitField, flag); - } - - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(ulong bitField, ulong flag) - { - return ((bitField & flag) == flag); - } - - public static bool HasFlag(short bitField, short flag) - { - return ((bitField & flag) == flag); - } - - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(T bitField, T flag) - where T : struct - { - return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); - } - - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(long bitField, long flag) - { - return ((bitField & flag) == flag); - } - - - /// - /// Sets a bit-field to either on or off for the specified flag. - /// - /// Flagged variable - /// Flag to change - /// bool - /// The flagged variable with the flag changed - public static long SetFlag(long bitField, long flag, bool @on) - { - if (@on) - { - return bitField | flag; - } - return bitField & (~flag); - } - - /// - /// Sets a bit-field to either on or off for the specified flag. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to change - /// bool - /// The flagged variable with the flag changed - public static long SetFlag(T bitField, T flag, bool @on) - where T : struct - { - return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), @on); - } - } +using System; + +namespace SharpCompress.Common +{ + internal static class FlagUtility + { + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(long bitField, T flag) + where T : struct + { + return HasFlag(bitField, flag); + } + + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(ulong bitField, T flag) + where T : struct + { + return HasFlag(bitField, flag); + } + + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(ulong bitField, ulong flag) + { + return ((bitField & flag) == flag); + } + + public static bool HasFlag(short bitField, short flag) + { + return ((bitField & flag) == flag); + } + + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(T bitField, T flag) + where T : struct + { + return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); + } + + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(long bitField, long flag) + { + return ((bitField & flag) == flag); + } + + + /// + /// Sets a bit-field to either on or off for the specified flag. + /// + /// Flagged variable + /// Flag to change + /// bool + /// The flagged variable with the flag changed + public static long SetFlag(long bitField, long flag, bool @on) + { + if (@on) + { + return bitField | flag; + } + return bitField & (~flag); + } + + /// + /// Sets a bit-field to either on or off for the specified flag. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to change + /// bool + /// The flagged variable with the flag changed + public static long SetFlag(T bitField, T flag, bool @on) + where T : struct + { + return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), @on); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/GZip/GZipEntry.cs b/src/SharpCompress/Common/GZip/GZipEntry.cs similarity index 95% rename from SharpCompress/Common/GZip/GZipEntry.cs rename to src/SharpCompress/Common/GZip/GZipEntry.cs index f6408f5c..3d3a23e6 100644 --- a/SharpCompress/Common/GZip/GZipEntry.cs +++ b/src/SharpCompress/Common/GZip/GZipEntry.cs @@ -1,86 +1,86 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace SharpCompress.Common.GZip -{ - public class GZipEntry : Entry - { - private readonly GZipFilePart filePart; - - internal GZipEntry(GZipFilePart filePart) - { - this.filePart = filePart; - } - - public override CompressionType CompressionType - { - get { return CompressionType.GZip; } - } - - public override long Crc - { - get { return 0; } - } - - public override string Key - { - get { return filePart.FilePartName; } - } - - public override long CompressedSize - { - get { return 0; } - } - - public override long Size - { - get { return 0; } - } - - public override DateTime? LastModifiedTime - { - get { return filePart.DateModified; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return false; } - } - - public override bool IsDirectory - { - get { return false; } - } - - public override bool IsSplit - { - get { return false; } - } - - internal override IEnumerable Parts - { - get { return filePart.AsEnumerable(); } - } - - internal static IEnumerable GetEntries(Stream stream) - { - yield return new GZipEntry(new GZipFilePart(stream)); - } - } +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress.Common.GZip +{ + public class GZipEntry : Entry + { + private readonly GZipFilePart filePart; + + internal GZipEntry(GZipFilePart filePart) + { + this.filePart = filePart; + } + + public override CompressionType CompressionType + { + get { return CompressionType.GZip; } + } + + public override long Crc + { + get { return 0; } + } + + public override string Key + { + get { return filePart.FilePartName; } + } + + public override long CompressedSize + { + get { return 0; } + } + + public override long Size + { + get { return 0; } + } + + public override DateTime? LastModifiedTime + { + get { return filePart.DateModified; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return false; } + } + + public override bool IsDirectory + { + get { return false; } + } + + public override bool IsSplit + { + get { return false; } + } + + internal override IEnumerable Parts + { + get { return filePart.AsEnumerable(); } + } + + internal static IEnumerable GetEntries(Stream stream) + { + yield return new GZipEntry(new GZipFilePart(stream)); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/GZip/GZipFilePart.cs b/src/SharpCompress/Common/GZip/GZipFilePart.cs similarity index 96% rename from SharpCompress/Common/GZip/GZipFilePart.cs rename to src/SharpCompress/Common/GZip/GZipFilePart.cs index 5aab3dba..1500d83a 100644 --- a/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/src/SharpCompress/Common/GZip/GZipFilePart.cs @@ -1,103 +1,103 @@ -using System; -using System.IO; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.Compressor; -using SharpCompress.Compressor.Deflate; - -namespace SharpCompress.Common.GZip -{ - internal class GZipFilePart : FilePart - { - private string name; - private readonly Stream stream; - - internal GZipFilePart(Stream stream) - { - ReadAndValidateGzipHeader(stream); - this.stream = stream; - } - - internal DateTime? DateModified { get; private set; } - - internal override string FilePartName - { - get { return name; } - } - - internal override Stream GetCompressedStream() - { - return new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false); - } - - internal override Stream GetRawStream() - { - return stream; - } - - private void ReadAndValidateGzipHeader(Stream stream) - { - // read the header on the first read - byte[] header = new byte[10]; - int n = stream.Read(header, 0, header.Length); - - // workitem 8501: handle edge case (decompress empty stream) - if (n == 0) - return; - - if (n != 10) - throw new ZlibException("Not a valid GZIP stream."); - - if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) - throw new ZlibException("Bad GZIP header."); - - Int32 timet = BitConverter.ToInt32(header, 4); - DateModified = TarHeader.Epoch.AddSeconds(timet); - if ((header[3] & 0x04) == 0x04) - { - // read and discard extra field - n = stream.Read(header, 0, 2); // 2-byte length field - - Int16 extraLength = (Int16) (header[0] + header[1]*256); - byte[] extra = new byte[extraLength]; - n = stream.Read(extra, 0, extra.Length); - if (n != extraLength) - { - throw new ZlibException("Unexpected end-of-file reading GZIP header."); - } - } - if ((header[3] & 0x08) == 0x08) - name = ReadZeroTerminatedString(stream); - if ((header[3] & 0x10) == 0x010) - ReadZeroTerminatedString(stream); - if ((header[3] & 0x02) == 0x02) - stream.ReadByte(); // CRC16, ignore - } - - - private static string ReadZeroTerminatedString(Stream stream) - { - byte[] buf1 = new byte[1]; - var list = new System.Collections.Generic.List(); - bool done = false; - do - { - // workitem 7740 - int n = stream.Read(buf1, 0, 1); - if (n != 1) - { - throw new ZlibException("Unexpected EOF reading GZIP header."); - } - if (buf1[0] == 0) - { - done = true; - } - else - { - list.Add(buf1[0]); - } - } while (!done); - byte[] a = list.ToArray(); - return ArchiveEncoding.Default.GetString(a, 0, a.Length); - } - } +using System; +using System.IO; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.Compressor; +using SharpCompress.Compressor.Deflate; + +namespace SharpCompress.Common.GZip +{ + internal class GZipFilePart : FilePart + { + private string name; + private readonly Stream stream; + + internal GZipFilePart(Stream stream) + { + ReadAndValidateGzipHeader(stream); + this.stream = stream; + } + + internal DateTime? DateModified { get; private set; } + + internal override string FilePartName + { + get { return name; } + } + + internal override Stream GetCompressedStream() + { + return new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false); + } + + internal override Stream GetRawStream() + { + return stream; + } + + private void ReadAndValidateGzipHeader(Stream stream) + { + // read the header on the first read + byte[] header = new byte[10]; + int n = stream.Read(header, 0, header.Length); + + // workitem 8501: handle edge case (decompress empty stream) + if (n == 0) + return; + + if (n != 10) + throw new ZlibException("Not a valid GZIP stream."); + + if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) + throw new ZlibException("Bad GZIP header."); + + Int32 timet = BitConverter.ToInt32(header, 4); + DateModified = TarHeader.Epoch.AddSeconds(timet); + if ((header[3] & 0x04) == 0x04) + { + // read and discard extra field + n = stream.Read(header, 0, 2); // 2-byte length field + + Int16 extraLength = (Int16) (header[0] + header[1]*256); + byte[] extra = new byte[extraLength]; + n = stream.Read(extra, 0, extra.Length); + if (n != extraLength) + { + throw new ZlibException("Unexpected end-of-file reading GZIP header."); + } + } + if ((header[3] & 0x08) == 0x08) + name = ReadZeroTerminatedString(stream); + if ((header[3] & 0x10) == 0x010) + ReadZeroTerminatedString(stream); + if ((header[3] & 0x02) == 0x02) + stream.ReadByte(); // CRC16, ignore + } + + + private static string ReadZeroTerminatedString(Stream stream) + { + byte[] buf1 = new byte[1]; + var list = new System.Collections.Generic.List(); + bool done = false; + do + { + // workitem 7740 + int n = stream.Read(buf1, 0, 1); + if (n != 1) + { + throw new ZlibException("Unexpected EOF reading GZIP header."); + } + if (buf1[0] == 0) + { + done = true; + } + else + { + list.Add(buf1[0]); + } + } while (!done); + byte[] a = list.ToArray(); + return ArchiveEncoding.Default.GetString(a, 0, a.Length); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/GZip/GZipVolume.cs b/src/SharpCompress/Common/GZip/GZipVolume.cs similarity index 95% rename from SharpCompress/Common/GZip/GZipVolume.cs rename to src/SharpCompress/Common/GZip/GZipVolume.cs index 5b8b6fcc..17adc11d 100644 --- a/SharpCompress/Common/GZip/GZipVolume.cs +++ b/src/SharpCompress/Common/GZip/GZipVolume.cs @@ -1,34 +1,34 @@ -using System.IO; - -namespace SharpCompress.Common.GZip -{ - public class GZipVolume : Volume - { -#if !DOTNET51 - private readonly FileInfo fileInfo; -#endif - - public GZipVolume(Stream stream, Options options) - : base(stream, options) - { - } - -#if !DOTNET51 - public GZipVolume(FileInfo fileInfo, Options options) - : base(fileInfo.OpenRead(), options) - { - this.fileInfo = fileInfo; - } -#endif - - public override bool IsFirstVolume - { - get { return true; } - } - - public override bool IsMultiVolume - { - get { return true; } - } - } +using System.IO; + +namespace SharpCompress.Common.GZip +{ + public class GZipVolume : Volume + { +#if !DOTNET51 + private readonly FileInfo fileInfo; +#endif + + public GZipVolume(Stream stream, Options options) + : base(stream, options) + { + } + +#if !DOTNET51 + public GZipVolume(FileInfo fileInfo, Options options) + : base(fileInfo.OpenRead(), options) + { + this.fileInfo = fileInfo; + } +#endif + + public override bool IsFirstVolume + { + get { return true; } + } + + public override bool IsMultiVolume + { + get { return true; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/IEntry.cs b/src/SharpCompress/Common/IEntry.cs similarity index 96% rename from SharpCompress/Common/IEntry.cs rename to src/SharpCompress/Common/IEntry.cs index 22a18c50..ac15828c 100644 --- a/SharpCompress/Common/IEntry.cs +++ b/src/SharpCompress/Common/IEntry.cs @@ -1,21 +1,21 @@ -using System; - -namespace SharpCompress.Common -{ - public interface IEntry - { - CompressionType CompressionType { get; } - DateTime? ArchivedTime { get; } - long CompressedSize { get; } - long Crc { get; } - DateTime? CreatedTime { get; } - string Key { get; } - bool IsDirectory { get; } - bool IsEncrypted { get; } - bool IsSplit { get; } - DateTime? LastAccessedTime { get; } - DateTime? LastModifiedTime { get; } - long Size { get; } - int? Attrib { get; } - } +using System; + +namespace SharpCompress.Common +{ + public interface IEntry + { + CompressionType CompressionType { get; } + DateTime? ArchivedTime { get; } + long CompressedSize { get; } + long Crc { get; } + DateTime? CreatedTime { get; } + string Key { get; } + bool IsDirectory { get; } + bool IsEncrypted { get; } + bool IsSplit { get; } + DateTime? LastAccessedTime { get; } + DateTime? LastModifiedTime { get; } + long Size { get; } + int? Attrib { get; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/IExtractionListener.cs b/src/SharpCompress/Common/IExtractionListener.cs similarity index 97% rename from SharpCompress/Common/IExtractionListener.cs rename to src/SharpCompress/Common/IExtractionListener.cs index b46a37e4..b6fb50fc 100644 --- a/SharpCompress/Common/IExtractionListener.cs +++ b/src/SharpCompress/Common/IExtractionListener.cs @@ -1,8 +1,8 @@ -namespace SharpCompress.Common -{ - internal interface IExtractionListener - { - void FireFilePartExtractionBegin(string name, long size, long compressedSize); - void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes); - } +namespace SharpCompress.Common +{ + internal interface IExtractionListener + { + void FireFilePartExtractionBegin(string name, long size, long compressedSize); + void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes); + } } \ No newline at end of file diff --git a/SharpCompress/Common/IVolume.cs b/src/SharpCompress/Common/IVolume.cs similarity index 93% rename from SharpCompress/Common/IVolume.cs rename to src/SharpCompress/Common/IVolume.cs index 5b3ae795..bf373383 100644 --- a/SharpCompress/Common/IVolume.cs +++ b/src/SharpCompress/Common/IVolume.cs @@ -1,11 +1,11 @@ -using System; -#if !DOTNET51 -using System.IO; -#endif - -namespace SharpCompress.Common -{ - public interface IVolume : IDisposable - { - } +using System; +#if !DOTNET51 +using System.IO; +#endif + +namespace SharpCompress.Common +{ + public interface IVolume : IDisposable + { + } } \ No newline at end of file diff --git a/SharpCompress/Common/IncompleteArchiveException.cs b/src/SharpCompress/Common/IncompleteArchiveException.cs similarity index 96% rename from SharpCompress/Common/IncompleteArchiveException.cs rename to src/SharpCompress/Common/IncompleteArchiveException.cs index 21b24cfd..78d567f4 100644 --- a/SharpCompress/Common/IncompleteArchiveException.cs +++ b/src/SharpCompress/Common/IncompleteArchiveException.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Common -{ - public class IncompleteArchiveException : ArchiveException - { - public IncompleteArchiveException(string message) - : base(message) - { - } - } +namespace SharpCompress.Common +{ + public class IncompleteArchiveException : ArchiveException + { + public IncompleteArchiveException(string message) + : base(message) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/InvalidFormatException.cs b/src/SharpCompress/Common/InvalidFormatException.cs similarity index 95% rename from SharpCompress/Common/InvalidFormatException.cs rename to src/SharpCompress/Common/InvalidFormatException.cs index d0b16865..fa141cb4 100644 --- a/SharpCompress/Common/InvalidFormatException.cs +++ b/src/SharpCompress/Common/InvalidFormatException.cs @@ -1,17 +1,17 @@ -using System; - -namespace SharpCompress.Common -{ - public class InvalidFormatException : ExtractionException - { - public InvalidFormatException(string message) - : base(message) - { - } - - public InvalidFormatException(string message, Exception inner) - : base(message, inner) - { - } - } +using System; + +namespace SharpCompress.Common +{ + public class InvalidFormatException : ExtractionException + { + public InvalidFormatException(string message) + : base(message) + { + } + + public InvalidFormatException(string message, Exception inner) + : base(message, inner) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/MultiVolumeExtractionException.cs b/src/SharpCompress/Common/MultiVolumeExtractionException.cs similarity index 95% rename from SharpCompress/Common/MultiVolumeExtractionException.cs rename to src/SharpCompress/Common/MultiVolumeExtractionException.cs index a0ea22ac..d9b97fa3 100644 --- a/SharpCompress/Common/MultiVolumeExtractionException.cs +++ b/src/SharpCompress/Common/MultiVolumeExtractionException.cs @@ -1,17 +1,17 @@ -using System; - -namespace SharpCompress.Common -{ - public class MultiVolumeExtractionException : ExtractionException - { - public MultiVolumeExtractionException(string message) - : base(message) - { - } - - public MultiVolumeExtractionException(string message, Exception inner) - : base(message, inner) - { - } - } +using System; + +namespace SharpCompress.Common +{ + public class MultiVolumeExtractionException : ExtractionException + { + public MultiVolumeExtractionException(string message) + : base(message) + { + } + + public MultiVolumeExtractionException(string message, Exception inner) + : base(message, inner) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/MultipartStreamRequiredException.cs b/src/SharpCompress/Common/MultipartStreamRequiredException.cs similarity index 96% rename from SharpCompress/Common/MultipartStreamRequiredException.cs rename to src/SharpCompress/Common/MultipartStreamRequiredException.cs index 2c441407..cf030ed6 100644 --- a/SharpCompress/Common/MultipartStreamRequiredException.cs +++ b/src/SharpCompress/Common/MultipartStreamRequiredException.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Common -{ - public class MultipartStreamRequiredException : ExtractionException - { - public MultipartStreamRequiredException(string message) - : base(message) - { - } - } +namespace SharpCompress.Common +{ + public class MultipartStreamRequiredException : ExtractionException + { + public MultipartStreamRequiredException(string message) + : base(message) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Options.cs b/src/SharpCompress/Common/Options.cs similarity index 96% rename from SharpCompress/Common/Options.cs rename to src/SharpCompress/Common/Options.cs index d7d4b372..32ec2d0c 100644 --- a/SharpCompress/Common/Options.cs +++ b/src/SharpCompress/Common/Options.cs @@ -1,23 +1,23 @@ -using System; - -namespace SharpCompress.Common -{ - [Flags] - public enum Options - { - /// - /// No options specified - /// - None = 0, - - /// - /// SharpCompress will keep the supplied streams open - /// - KeepStreamsOpen = 1, - - /// - /// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file) - /// - LookForHeader = 2, - } +using System; + +namespace SharpCompress.Common +{ + [Flags] + public enum Options + { + /// + /// No options specified + /// + None = 0, + + /// + /// SharpCompress will keep the supplied streams open + /// + KeepStreamsOpen = 1, + + /// + /// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file) + /// + LookForHeader = 2, + } } \ No newline at end of file diff --git a/SharpCompress/Common/PasswordProtectedException.cs b/src/SharpCompress/Common/PasswordProtectedException.cs similarity index 95% rename from SharpCompress/Common/PasswordProtectedException.cs rename to src/SharpCompress/Common/PasswordProtectedException.cs index cfd3a809..58dc7660 100644 --- a/SharpCompress/Common/PasswordProtectedException.cs +++ b/src/SharpCompress/Common/PasswordProtectedException.cs @@ -1,17 +1,17 @@ -using System; - -namespace SharpCompress.Common -{ - public class PasswordProtectedException : ExtractionException - { - public PasswordProtectedException(string message) - : base(message) - { - } - - public PasswordProtectedException(string message, Exception inner) - : base(message, inner) - { - } - } +using System; + +namespace SharpCompress.Common +{ + public class PasswordProtectedException : ExtractionException + { + public PasswordProtectedException(string message) + : base(message) + { + } + + public PasswordProtectedException(string message, Exception inner) + : base(message, inner) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/AVHeader.cs b/src/SharpCompress/Common/Rar/Headers/AVHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/AVHeader.cs rename to src/SharpCompress/Common/Rar/Headers/AVHeader.cs index d3ff7580..acb878ba 100644 --- a/SharpCompress/Common/Rar/Headers/AVHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/AVHeader.cs @@ -1,20 +1,20 @@ -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class SignHeader : RarHeader - { - protected override void ReadFromReader(MarkingBinaryReader reader) - { - CreationTime = reader.ReadInt32(); - ArcNameSize = reader.ReadInt16(); - UserNameSize = reader.ReadInt16(); - } - - internal int CreationTime { get; private set; } - - internal short ArcNameSize { get; private set; } - - internal short UserNameSize { get; private set; } - } +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class SignHeader : RarHeader + { + protected override void ReadFromReader(MarkingBinaryReader reader) + { + CreationTime = reader.ReadInt32(); + ArcNameSize = reader.ReadInt16(); + UserNameSize = reader.ReadInt16(); + } + + internal int CreationTime { get; private set; } + + internal short ArcNameSize { get; private set; } + + internal short UserNameSize { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/ArchiveHeader.cs rename to src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs index 7c79f072..2de02de0 100644 --- a/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs @@ -1,36 +1,36 @@ -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class ArchiveHeader : RarHeader - { - internal const short mainHeaderSizeWithEnc = 7; - internal const short mainHeaderSize = 6; - - protected override void ReadFromReader(MarkingBinaryReader reader) - { - HighPosAv = reader.ReadInt16(); - PosAv = reader.ReadInt32(); - if (ArchiveHeaderFlags.HasFlag(ArchiveFlags.ENCRYPTVER)) - { - EncryptionVersion = reader.ReadByte(); - } - } - - internal ArchiveFlags ArchiveHeaderFlags - { - get { return (ArchiveFlags) base.Flags; } - } - - internal short HighPosAv { get; private set; } - - internal int PosAv { get; private set; } - - internal byte EncryptionVersion { get; private set; } - - public bool HasPassword - { - get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); } - } - } +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class ArchiveHeader : RarHeader + { + internal const short mainHeaderSizeWithEnc = 7; + internal const short mainHeaderSize = 6; + + protected override void ReadFromReader(MarkingBinaryReader reader) + { + HighPosAv = reader.ReadInt16(); + PosAv = reader.ReadInt32(); + if (ArchiveHeaderFlags.HasFlag(ArchiveFlags.ENCRYPTVER)) + { + EncryptionVersion = reader.ReadByte(); + } + } + + internal ArchiveFlags ArchiveHeaderFlags + { + get { return (ArchiveFlags) base.Flags; } + } + + internal short HighPosAv { get; private set; } + + internal int PosAv { get; private set; } + + internal byte EncryptionVersion { get; private set; } + + public bool HasPassword + { + get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/CommentHeader.cs b/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/CommentHeader.cs rename to src/SharpCompress/Common/Rar/Headers/CommentHeader.cs index b170e6e4..c9943bde 100644 --- a/SharpCompress/Common/Rar/Headers/CommentHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs @@ -1,22 +1,22 @@ -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class CommentHeader : RarHeader - { - protected override void ReadFromReader(MarkingBinaryReader reader) - { - UnpSize = reader.ReadInt16(); - UnpVersion = reader.ReadByte(); - UnpMethod = reader.ReadByte(); - CommCRC = reader.ReadInt16(); - } - - internal short UnpSize { get; private set; } - - internal byte UnpVersion { get; private set; } - - internal byte UnpMethod { get; private set; } - internal short CommCRC { get; private set; } - } +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class CommentHeader : RarHeader + { + protected override void ReadFromReader(MarkingBinaryReader reader) + { + UnpSize = reader.ReadInt16(); + UnpVersion = reader.ReadByte(); + UnpMethod = reader.ReadByte(); + CommCRC = reader.ReadInt16(); + } + + internal short UnpSize { get; private set; } + + internal byte UnpVersion { get; private set; } + + internal byte UnpMethod { get; private set; } + internal short CommCRC { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs rename to src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs index 7ae9c06e..95bc6f07 100644 --- a/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs @@ -1,28 +1,28 @@ -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class EndArchiveHeader : RarHeader - { - protected override void ReadFromReader(MarkingBinaryReader reader) - { - if (EndArchiveFlags.HasFlag(EndArchiveFlags.EARC_DATACRC)) - { - ArchiveCRC = reader.ReadInt32(); - } - if (EndArchiveFlags.HasFlag(EndArchiveFlags.EARC_VOLNUMBER)) - { - VolumeNumber = reader.ReadInt16(); - } - } - - internal EndArchiveFlags EndArchiveFlags - { - get { return (EndArchiveFlags) base.Flags; } - } - - internal int? ArchiveCRC { get; private set; } - - internal short? VolumeNumber { get; private set; } - } +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class EndArchiveHeader : RarHeader + { + protected override void ReadFromReader(MarkingBinaryReader reader) + { + if (EndArchiveFlags.HasFlag(EndArchiveFlags.EARC_DATACRC)) + { + ArchiveCRC = reader.ReadInt32(); + } + if (EndArchiveFlags.HasFlag(EndArchiveFlags.EARC_VOLNUMBER)) + { + VolumeNumber = reader.ReadInt16(); + } + } + + internal EndArchiveFlags EndArchiveFlags + { + get { return (EndArchiveFlags) base.Flags; } + } + + internal int? ArchiveCRC { get; private set; } + + internal short? VolumeNumber { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs similarity index 97% rename from SharpCompress/Common/Rar/Headers/FileHeader.cs rename to src/SharpCompress/Common/Rar/Headers/FileHeader.cs index 9276d48a..c76c005d 100644 --- a/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -1,233 +1,233 @@ -using System; -using System.IO; -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class FileHeader : RarHeader - { - private const byte SALT_SIZE = 8; - - private const byte NEWLHD_SIZE = 32; - - protected override void ReadFromReader(MarkingBinaryReader reader) - { - uint lowUncompressedSize = reader.ReadUInt32(); - - HostOS = (HostOS)reader.ReadByte(); - - FileCRC = reader.ReadUInt32(); - - FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadInt32()); - - RarVersion = reader.ReadByte(); - PackingMethod = reader.ReadByte(); - - short nameSize = reader.ReadInt16(); - - FileAttributes = reader.ReadInt32(); - - uint highCompressedSize = 0; - uint highUncompressedkSize = 0; - if (FileFlags.HasFlag(FileFlags.LARGE)) - { - highCompressedSize = reader.ReadUInt32(); - highUncompressedkSize = reader.ReadUInt32(); - } - else - { - if (lowUncompressedSize == 0xffffffff) - { - lowUncompressedSize = 0xffffffff; - highUncompressedkSize = int.MaxValue; - } - } - CompressedSize = UInt32To64(highCompressedSize, AdditionalSize); - UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize); - - nameSize = nameSize > 4 * 1024 ? (short)(4 * 1024) : nameSize; - - byte[] fileNameBytes = reader.ReadBytes(nameSize); - - switch (HeaderType) - { - case HeaderType.FileHeader: - { - if (FileFlags.HasFlag(FileFlags.UNICODE)) - { - int length = 0; - while (length < fileNameBytes.Length - && fileNameBytes[length] != 0) - { - length++; - } - if (length != nameSize) - { - length++; - FileName = FileNameDecoder.Decode(fileNameBytes, length); - } - else - { - FileName = DecodeDefault(fileNameBytes); - } - } - else - { - FileName = DecodeDefault(fileNameBytes); - } - FileName = ConvertPath(FileName, HostOS); - } - break; - case HeaderType.NewSubHeader: - { - int datasize = HeaderSize - NEWLHD_SIZE - nameSize; - if (FileFlags.HasFlag(FileFlags.SALT)) - { - datasize -= SALT_SIZE; - } - if (datasize > 0) - { - SubData = reader.ReadBytes(datasize); - } - - if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) - { - RecoverySectors = SubData[8] + (SubData[9] << 8) - + (SubData[10] << 16) + (SubData[11] << 24); - } - } - break; - } - - if (FileFlags.HasFlag(FileFlags.SALT)) - { - Salt = reader.ReadBytes(SALT_SIZE); - } - if (FileFlags.HasFlag(FileFlags.EXTTIME)) - { - // verify that the end of the header hasn't been reached before reading the Extended Time. - // some tools incorrectly omit Extended Time despite specifying FileFlags.EXTTIME, which most parsers tolerate. - if (ReadBytes + reader.CurrentReadByteCount <= HeaderSize - 2) - { - ushort extendedFlags = reader.ReadUInt16(); - FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0); - FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1); - FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2); - FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3); - } - } - } - - //only the full .net framework will do other code pages than unicode/utf8 - private string DecodeDefault(byte[] bytes) - { - return ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length); - } - - private long UInt32To64(uint x, uint y) - { - long l = x; - l <<= 32; - return l + y; - } - - private static DateTime? ProcessExtendedTime(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader, - int i) - { - uint rmode = (uint)extendedFlags >> (3 - i) * 4; - if ((rmode & 8) == 0) - { - return null; - } - if (i != 0) - { - uint DosTime = reader.ReadUInt32(); - time = Utility.DosDateToDateTime(DosTime); - } - if ((rmode & 4) == 0) - { - time = time.Value.AddSeconds(1); - } - uint nanosecondHundreds = 0; - int count = (int)rmode & 3; - for (int j = 0; j < count; j++) - { - byte b = reader.ReadByte(); - nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8)); - } - //10^-7 to 10^-3 - return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4)); - } - - private static string ConvertPath(string path, HostOS os) - { -#if DOTNET51 - return path.Replace('\\', '/'); -#else - switch (os) - { - case HostOS.MacOS: - case HostOS.Unix: - { - if (Path.DirectorySeparatorChar == '\\') - { - return path.Replace('/', '\\'); - } - } - break; - default: - { - if (Path.DirectorySeparatorChar == '/') - { - return path.Replace('\\', '/'); - } - } - break; - } - return path; -#endif - } - - internal long DataStartPosition { get; set; } - internal HostOS HostOS { get; private set; } - - internal uint FileCRC { get; private set; } - - internal DateTime? FileLastModifiedTime { get; private set; } - - internal DateTime? FileCreatedTime { get; private set; } - - internal DateTime? FileLastAccessedTime { get; private set; } - - internal DateTime? FileArchivedTime { get; private set; } - - internal byte RarVersion { get; private set; } - - internal byte PackingMethod { get; private set; } - - internal int FileAttributes { get; private set; } - - internal FileFlags FileFlags - { - get { return (FileFlags)base.Flags; } - } - - internal long CompressedSize { get; private set; } - internal long UncompressedSize { get; private set; } - - internal string FileName { get; private set; } - - internal byte[] SubData { get; private set; } - - internal int RecoverySectors { get; private set; } - - internal byte[] Salt { get; private set; } - - public override string ToString() - { - return FileName; - } - - public Stream PackedStream { get; set; } - } +using System; +using System.IO; +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class FileHeader : RarHeader + { + private const byte SALT_SIZE = 8; + + private const byte NEWLHD_SIZE = 32; + + protected override void ReadFromReader(MarkingBinaryReader reader) + { + uint lowUncompressedSize = reader.ReadUInt32(); + + HostOS = (HostOS)reader.ReadByte(); + + FileCRC = reader.ReadUInt32(); + + FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadInt32()); + + RarVersion = reader.ReadByte(); + PackingMethod = reader.ReadByte(); + + short nameSize = reader.ReadInt16(); + + FileAttributes = reader.ReadInt32(); + + uint highCompressedSize = 0; + uint highUncompressedkSize = 0; + if (FileFlags.HasFlag(FileFlags.LARGE)) + { + highCompressedSize = reader.ReadUInt32(); + highUncompressedkSize = reader.ReadUInt32(); + } + else + { + if (lowUncompressedSize == 0xffffffff) + { + lowUncompressedSize = 0xffffffff; + highUncompressedkSize = int.MaxValue; + } + } + CompressedSize = UInt32To64(highCompressedSize, AdditionalSize); + UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize); + + nameSize = nameSize > 4 * 1024 ? (short)(4 * 1024) : nameSize; + + byte[] fileNameBytes = reader.ReadBytes(nameSize); + + switch (HeaderType) + { + case HeaderType.FileHeader: + { + if (FileFlags.HasFlag(FileFlags.UNICODE)) + { + int length = 0; + while (length < fileNameBytes.Length + && fileNameBytes[length] != 0) + { + length++; + } + if (length != nameSize) + { + length++; + FileName = FileNameDecoder.Decode(fileNameBytes, length); + } + else + { + FileName = DecodeDefault(fileNameBytes); + } + } + else + { + FileName = DecodeDefault(fileNameBytes); + } + FileName = ConvertPath(FileName, HostOS); + } + break; + case HeaderType.NewSubHeader: + { + int datasize = HeaderSize - NEWLHD_SIZE - nameSize; + if (FileFlags.HasFlag(FileFlags.SALT)) + { + datasize -= SALT_SIZE; + } + if (datasize > 0) + { + SubData = reader.ReadBytes(datasize); + } + + if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) + { + RecoverySectors = SubData[8] + (SubData[9] << 8) + + (SubData[10] << 16) + (SubData[11] << 24); + } + } + break; + } + + if (FileFlags.HasFlag(FileFlags.SALT)) + { + Salt = reader.ReadBytes(SALT_SIZE); + } + if (FileFlags.HasFlag(FileFlags.EXTTIME)) + { + // verify that the end of the header hasn't been reached before reading the Extended Time. + // some tools incorrectly omit Extended Time despite specifying FileFlags.EXTTIME, which most parsers tolerate. + if (ReadBytes + reader.CurrentReadByteCount <= HeaderSize - 2) + { + ushort extendedFlags = reader.ReadUInt16(); + FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0); + FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1); + FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2); + FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3); + } + } + } + + //only the full .net framework will do other code pages than unicode/utf8 + private string DecodeDefault(byte[] bytes) + { + return ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length); + } + + private long UInt32To64(uint x, uint y) + { + long l = x; + l <<= 32; + return l + y; + } + + private static DateTime? ProcessExtendedTime(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader, + int i) + { + uint rmode = (uint)extendedFlags >> (3 - i) * 4; + if ((rmode & 8) == 0) + { + return null; + } + if (i != 0) + { + uint DosTime = reader.ReadUInt32(); + time = Utility.DosDateToDateTime(DosTime); + } + if ((rmode & 4) == 0) + { + time = time.Value.AddSeconds(1); + } + uint nanosecondHundreds = 0; + int count = (int)rmode & 3; + for (int j = 0; j < count; j++) + { + byte b = reader.ReadByte(); + nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8)); + } + //10^-7 to 10^-3 + return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4)); + } + + private static string ConvertPath(string path, HostOS os) + { +#if DOTNET51 + return path.Replace('\\', '/'); +#else + switch (os) + { + case HostOS.MacOS: + case HostOS.Unix: + { + if (Path.DirectorySeparatorChar == '\\') + { + return path.Replace('/', '\\'); + } + } + break; + default: + { + if (Path.DirectorySeparatorChar == '/') + { + return path.Replace('\\', '/'); + } + } + break; + } + return path; +#endif + } + + internal long DataStartPosition { get; set; } + internal HostOS HostOS { get; private set; } + + internal uint FileCRC { get; private set; } + + internal DateTime? FileLastModifiedTime { get; private set; } + + internal DateTime? FileCreatedTime { get; private set; } + + internal DateTime? FileLastAccessedTime { get; private set; } + + internal DateTime? FileArchivedTime { get; private set; } + + internal byte RarVersion { get; private set; } + + internal byte PackingMethod { get; private set; } + + internal int FileAttributes { get; private set; } + + internal FileFlags FileFlags + { + get { return (FileFlags)base.Flags; } + } + + internal long CompressedSize { get; private set; } + internal long UncompressedSize { get; private set; } + + internal string FileName { get; private set; } + + internal byte[] SubData { get; private set; } + + internal int RecoverySectors { get; private set; } + + internal byte[] Salt { get; private set; } + + public override string ToString() + { + return FileName; + } + + public Stream PackedStream { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs similarity index 97% rename from SharpCompress/Common/Rar/Headers/FileNameDecoder.cs rename to src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs index 97d6644a..a9cb6ebc 100644 --- a/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs @@ -1,78 +1,78 @@ -using System.Text; - -namespace SharpCompress.Common.Rar.Headers -{ - /// - /// This is for the crazy Rar encoding that I don't understand - /// - internal static class FileNameDecoder - { - internal static int GetChar(byte[] name, int pos) - { - return name[pos] & 0xff; - } - - internal static string Decode(byte[] name, int encPos) - { - int decPos = 0; - int flags = 0; - int flagBits = 0; - - int low = 0; - int high = 0; - int highByte = GetChar(name, encPos++); - StringBuilder buf = new StringBuilder(); - while (encPos < name.Length) - { - if (flagBits == 0) - { - flags = GetChar(name, encPos++); - flagBits = 8; - } - switch (flags >> 6) - { - case 0: - buf.Append((char) (GetChar(name, encPos++))); - ++decPos; - break; - - case 1: - buf.Append((char) (GetChar(name, encPos++) + (highByte << 8))); - ++decPos; - break; - - case 2: - low = GetChar(name, encPos); - high = GetChar(name, encPos + 1); - buf.Append((char) ((high << 8) + low)); - ++decPos; - encPos += 2; - break; - - case 3: - int length = GetChar(name, encPos++); - if ((length & 0x80) != 0) - { - int correction = GetChar(name, encPos++); - for (length = (length & 0x7f) + 2; length > 0 && decPos < name.Length; length--, decPos++) - { - low = (GetChar(name, decPos) + correction) & 0xff; - buf.Append((char) ((highByte << 8) + low)); - } - } - else - { - for (length += 2; length > 0 && decPos < name.Length; length--, decPos++) - { - buf.Append((char) (GetChar(name, decPos))); - } - } - break; - } - flags = (flags << 2) & 0xff; - flagBits -= 2; - } - return buf.ToString(); - } - } +using System.Text; + +namespace SharpCompress.Common.Rar.Headers +{ + /// + /// This is for the crazy Rar encoding that I don't understand + /// + internal static class FileNameDecoder + { + internal static int GetChar(byte[] name, int pos) + { + return name[pos] & 0xff; + } + + internal static string Decode(byte[] name, int encPos) + { + int decPos = 0; + int flags = 0; + int flagBits = 0; + + int low = 0; + int high = 0; + int highByte = GetChar(name, encPos++); + StringBuilder buf = new StringBuilder(); + while (encPos < name.Length) + { + if (flagBits == 0) + { + flags = GetChar(name, encPos++); + flagBits = 8; + } + switch (flags >> 6) + { + case 0: + buf.Append((char) (GetChar(name, encPos++))); + ++decPos; + break; + + case 1: + buf.Append((char) (GetChar(name, encPos++) + (highByte << 8))); + ++decPos; + break; + + case 2: + low = GetChar(name, encPos); + high = GetChar(name, encPos + 1); + buf.Append((char) ((high << 8) + low)); + ++decPos; + encPos += 2; + break; + + case 3: + int length = GetChar(name, encPos++); + if ((length & 0x80) != 0) + { + int correction = GetChar(name, encPos++); + for (length = (length & 0x7f) + 2; length > 0 && decPos < name.Length; length--, decPos++) + { + low = (GetChar(name, decPos) + correction) & 0xff; + buf.Append((char) ((highByte << 8) + low)); + } + } + else + { + for (length += 2; length > 0 && decPos < name.Length; length--, decPos++) + { + buf.Append((char) (GetChar(name, decPos))); + } + } + break; + } + flags = (flags << 2) & 0xff; + flagBits -= 2; + } + return buf.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs similarity index 95% rename from SharpCompress/Common/Rar/Headers/Flags.cs rename to src/SharpCompress/Common/Rar/Headers/Flags.cs index 477a096d..421e983a 100644 --- a/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -1,85 +1,85 @@ -using System; - -namespace SharpCompress.Common.Rar.Headers -{ - internal enum HeaderType - { - MarkHeader = 0x72, - ArchiveHeader = 0x73, - FileHeader = 0x74, - CommHeader = 0x75, - AvHeader = 0x76, - SubHeader = 0x77, - ProtectHeader = 0x78, - SignHeader = 0x79, - NewSubHeader = 0x7a, - EndArchiveHeader = 0x7b, - } - - internal enum HeaderFlags : short - { - LONG_BLOCK = -0x8000, - } - - [Flags] - internal enum ArchiveFlags - { - VOLUME = 0x0001, - COMMENT = 0x0002, - LOCK = 0x0004, - SOLID = 0x0008, - NEWNUMBERING = 0x0010, - AV = 0x0020, - PROTECT = 0x0040, - PASSWORD = 0x0080, - FIRSTVOLUME = 0x0100, - ENCRYPTVER = 0x0200, - } - - internal enum HostOS - { - MSDOS = 0, - OS2 = 1, - Win32 = 2, - Unix = 3, - MacOS = 4, - BeOS = 5 - } - - [Flags] - internal enum FileFlags : ushort - { - SPLIT_BEFORE = 0x0001, - SPLIT_AFTER = 0x0002, - PASSWORD = 0x0004, - COMMENT = 0x0008, - SOLID = 0x0010, - - WINDOWMASK = 0x00e0, - WINDOW64 = 0x0000, - WINDOW128 = 0x0020, - WINDOW256 = 0x0040, - WINDOW512 = 0x0060, - WINDOW1024 = 0x0080, - WINDOW2048 = 0x00a0, - WINDOW4096 = 0x00c0, - DIRECTORY = 0x00e0, - - LARGE = 0x0100, - UNICODE = 0x0200, - SALT = 0x0400, - VERSION = 0x0800, - EXTTIME = 0x1000, - EXTFLAGS = 0x2000, - } - - - [Flags] - internal enum EndArchiveFlags - { - EARC_NEXT_VOLUME = 0x0001, - EARC_DATACRC = 0x0002, - EARC_REVSPACE = 0x0004, - EARC_VOLNUMBER = 0x0008, - } +using System; + +namespace SharpCompress.Common.Rar.Headers +{ + internal enum HeaderType + { + MarkHeader = 0x72, + ArchiveHeader = 0x73, + FileHeader = 0x74, + CommHeader = 0x75, + AvHeader = 0x76, + SubHeader = 0x77, + ProtectHeader = 0x78, + SignHeader = 0x79, + NewSubHeader = 0x7a, + EndArchiveHeader = 0x7b, + } + + internal enum HeaderFlags : short + { + LONG_BLOCK = -0x8000, + } + + [Flags] + internal enum ArchiveFlags + { + VOLUME = 0x0001, + COMMENT = 0x0002, + LOCK = 0x0004, + SOLID = 0x0008, + NEWNUMBERING = 0x0010, + AV = 0x0020, + PROTECT = 0x0040, + PASSWORD = 0x0080, + FIRSTVOLUME = 0x0100, + ENCRYPTVER = 0x0200, + } + + internal enum HostOS + { + MSDOS = 0, + OS2 = 1, + Win32 = 2, + Unix = 3, + MacOS = 4, + BeOS = 5 + } + + [Flags] + internal enum FileFlags : ushort + { + SPLIT_BEFORE = 0x0001, + SPLIT_AFTER = 0x0002, + PASSWORD = 0x0004, + COMMENT = 0x0008, + SOLID = 0x0010, + + WINDOWMASK = 0x00e0, + WINDOW64 = 0x0000, + WINDOW128 = 0x0020, + WINDOW256 = 0x0040, + WINDOW512 = 0x0060, + WINDOW1024 = 0x0080, + WINDOW2048 = 0x00a0, + WINDOW4096 = 0x00c0, + DIRECTORY = 0x00e0, + + LARGE = 0x0100, + UNICODE = 0x0200, + SALT = 0x0400, + VERSION = 0x0800, + EXTTIME = 0x1000, + EXTFLAGS = 0x2000, + } + + + [Flags] + internal enum EndArchiveFlags + { + EARC_NEXT_VOLUME = 0x0001, + EARC_DATACRC = 0x0002, + EARC_REVSPACE = 0x0004, + EARC_VOLNUMBER = 0x0008, + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/MarkHeader.cs b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/MarkHeader.cs rename to src/SharpCompress/Common/Rar/Headers/MarkHeader.cs index 41214b46..c8290bdb 100644 --- a/SharpCompress/Common/Rar/Headers/MarkHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs @@ -1,59 +1,59 @@ -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class MarkHeader : RarHeader - { - protected override void ReadFromReader(MarkingBinaryReader reader) - { - } - - internal bool IsValid() - { - if (!(HeadCRC == 0x6152)) - { - return false; - } - if (!(HeaderType == HeaderType.MarkHeader)) - { - return false; - } - if (!(Flags == 0x1a21)) - { - return false; - } - if (!(HeaderSize == BaseBlockSize)) - { - return false; - } - return true; - } - - internal bool IsSignature() - { - bool valid = false; - /*byte[] d = new byte[BaseBlock.BaseBlockSize]; - BinaryWriter writer = new BinaryWriter(); - writer.Write(HeadCRC); - writer.Write((byte)HeaderType); - writer.Write(flags); - writer.Write(HeaderSize); - writer.Flush - - if (d[0] == 0x52) { - if (d[1]==0x45 && d[2]==0x7e && d[3]==0x5e) { - oldFormat=true; - valid=true; - } - else if (d[1]==0x61 && d[2]==0x72 && d[3]==0x21 && d[4]==0x1a && - d[5]==0x07 && d[6]==0x00) { - oldFormat=false; - valid=true; - } - }*/ - return valid; - } - - internal bool OldFormat { get; private set; } - } +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class MarkHeader : RarHeader + { + protected override void ReadFromReader(MarkingBinaryReader reader) + { + } + + internal bool IsValid() + { + if (!(HeadCRC == 0x6152)) + { + return false; + } + if (!(HeaderType == HeaderType.MarkHeader)) + { + return false; + } + if (!(Flags == 0x1a21)) + { + return false; + } + if (!(HeaderSize == BaseBlockSize)) + { + return false; + } + return true; + } + + internal bool IsSignature() + { + bool valid = false; + /*byte[] d = new byte[BaseBlock.BaseBlockSize]; + BinaryWriter writer = new BinaryWriter(); + writer.Write(HeadCRC); + writer.Write((byte)HeaderType); + writer.Write(flags); + writer.Write(HeaderSize); + writer.Flush + + if (d[0] == 0x52) { + if (d[1]==0x45 && d[2]==0x7e && d[3]==0x5e) { + oldFormat=true; + valid=true; + } + else if (d[1]==0x61 && d[2]==0x72 && d[3]==0x21 && d[4]==0x1a && + d[5]==0x07 && d[6]==0x00) { + oldFormat=false; + valid=true; + } + }*/ + return valid; + } + + internal bool OldFormat { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/NewSubHeader.cs b/src/SharpCompress/Common/Rar/Headers/NewSubHeader.cs similarity index 97% rename from SharpCompress/Common/Rar/Headers/NewSubHeader.cs rename to src/SharpCompress/Common/Rar/Headers/NewSubHeader.cs index 23bf6247..e259e837 100644 --- a/SharpCompress/Common/Rar/Headers/NewSubHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/NewSubHeader.cs @@ -1,59 +1,59 @@ -using System; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class NewSubHeaderType : IEquatable - { - internal static readonly NewSubHeaderType SUBHEAD_TYPE_CMT = new NewSubHeaderType('C', 'M', 'T'); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_ACL = new NewSubHeaderType(new byte[]{'A','C','L'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_STREAM = new NewSubHeaderType(new byte[]{'S','T','M'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_UOWNER = new NewSubHeaderType(new byte[]{'U','O','W'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_AV = new NewSubHeaderType(new byte[]{'A','V'}); - - internal static readonly NewSubHeaderType SUBHEAD_TYPE_RR = new NewSubHeaderType('R', 'R'); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_OS2EA = new NewSubHeaderType(new byte[]{'E','A','2'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new NewSubHeaderType(new byte[]{'E','A','B','E'}); - - private byte[] bytes; - - private NewSubHeaderType(params char[] chars) - { - bytes = new byte[chars.Length]; - for (int i = 0; i < chars.Length; ++i) - { - bytes[i] = (byte) chars[i]; - } - } - - internal bool Equals(byte[] bytes) - { - if (this.bytes.Length != bytes.Length) - { - return false; - } - for (int i = 0; i < bytes.Length; ++i) - { - if (this.bytes[i] != bytes[i]) - { - return false; - } - } - return true; - } - - #region IEquatable Members - - public bool Equals(NewSubHeaderType other) - { - return Equals(other.bytes); - } - - #endregion - } +using System; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class NewSubHeaderType : IEquatable + { + internal static readonly NewSubHeaderType SUBHEAD_TYPE_CMT = new NewSubHeaderType('C', 'M', 'T'); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_ACL = new NewSubHeaderType(new byte[]{'A','C','L'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_STREAM = new NewSubHeaderType(new byte[]{'S','T','M'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_UOWNER = new NewSubHeaderType(new byte[]{'U','O','W'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_AV = new NewSubHeaderType(new byte[]{'A','V'}); + + internal static readonly NewSubHeaderType SUBHEAD_TYPE_RR = new NewSubHeaderType('R', 'R'); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_OS2EA = new NewSubHeaderType(new byte[]{'E','A','2'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new NewSubHeaderType(new byte[]{'E','A','B','E'}); + + private byte[] bytes; + + private NewSubHeaderType(params char[] chars) + { + bytes = new byte[chars.Length]; + for (int i = 0; i < chars.Length; ++i) + { + bytes[i] = (byte) chars[i]; + } + } + + internal bool Equals(byte[] bytes) + { + if (this.bytes.Length != bytes.Length) + { + return false; + } + for (int i = 0; i < bytes.Length; ++i) + { + if (this.bytes[i] != bytes[i]) + { + return false; + } + } + return true; + } + + #region IEquatable Members + + public bool Equals(NewSubHeaderType other) + { + return Equals(other.bytes); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/ProtectHeader.cs b/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs similarity index 100% rename from SharpCompress/Common/Rar/Headers/ProtectHeader.cs rename to src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs diff --git a/SharpCompress/Common/Rar/Headers/RarHeader.cs b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/RarHeader.cs rename to src/SharpCompress/Common/Rar/Headers/RarHeader.cs index 65803cd1..8e3b60f5 100644 --- a/SharpCompress/Common/Rar/Headers/RarHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs @@ -1,95 +1,95 @@ -using System.IO; -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class RarHeader - { - internal const short BaseBlockSize = 7; - internal const short LONG_BLOCK = -0x8000; - - private void FillBase(RarHeader baseHeader) - { - HeadCRC = baseHeader.HeadCRC; - HeaderType = baseHeader.HeaderType; - Flags = baseHeader.Flags; - HeaderSize = baseHeader.HeaderSize; - AdditionalSize = baseHeader.AdditionalSize; - ReadBytes = baseHeader.ReadBytes; - } - - internal static RarHeader Create(MarkingBinaryReader reader) - { - try - { - RarHeader header = new RarHeader(); - - reader.Mark(); - header.ReadFromReader(reader); - header.ReadBytes += reader.CurrentReadByteCount; - - return header; - } - catch (EndOfStreamException) - { - return null; - } - } - protected virtual void ReadFromReader(MarkingBinaryReader reader) - { - HeadCRC = reader.ReadInt16(); - HeaderType = (HeaderType)(reader.ReadByte() & 0xff); - Flags = reader.ReadInt16(); - HeaderSize = reader.ReadInt16(); - if (FlagUtility.HasFlag(Flags, LONG_BLOCK)) - { - AdditionalSize = reader.ReadUInt32(); - } - } - - internal T PromoteHeader(MarkingBinaryReader reader) - where T : RarHeader, new() - { - T header = new T(); - header.FillBase(this); - - reader.Mark(); - header.ReadFromReader(reader); - header.ReadBytes += reader.CurrentReadByteCount; - - int headerSizeDiff = header.HeaderSize - (int)header.ReadBytes; - - if (headerSizeDiff > 0) - { - reader.ReadBytes(headerSizeDiff); - } - - return header; - } - - protected virtual void PostReadingBytes(MarkingBinaryReader reader) - { - } - - /// - /// This is the number of bytes read when reading the header - /// - protected long ReadBytes { get; private set; } - - protected short HeadCRC { get; private set; } - - internal HeaderType HeaderType { get; private set; } - - /// - /// Untyped flags. These should be typed when Promoting to another header - /// - protected short Flags { get; private set; } - - protected short HeaderSize { get; private set; } - - /// - /// This additional size of the header could be file data - /// - protected uint AdditionalSize { get; private set; } - } +using System.IO; +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class RarHeader + { + internal const short BaseBlockSize = 7; + internal const short LONG_BLOCK = -0x8000; + + private void FillBase(RarHeader baseHeader) + { + HeadCRC = baseHeader.HeadCRC; + HeaderType = baseHeader.HeaderType; + Flags = baseHeader.Flags; + HeaderSize = baseHeader.HeaderSize; + AdditionalSize = baseHeader.AdditionalSize; + ReadBytes = baseHeader.ReadBytes; + } + + internal static RarHeader Create(MarkingBinaryReader reader) + { + try + { + RarHeader header = new RarHeader(); + + reader.Mark(); + header.ReadFromReader(reader); + header.ReadBytes += reader.CurrentReadByteCount; + + return header; + } + catch (EndOfStreamException) + { + return null; + } + } + protected virtual void ReadFromReader(MarkingBinaryReader reader) + { + HeadCRC = reader.ReadInt16(); + HeaderType = (HeaderType)(reader.ReadByte() & 0xff); + Flags = reader.ReadInt16(); + HeaderSize = reader.ReadInt16(); + if (FlagUtility.HasFlag(Flags, LONG_BLOCK)) + { + AdditionalSize = reader.ReadUInt32(); + } + } + + internal T PromoteHeader(MarkingBinaryReader reader) + where T : RarHeader, new() + { + T header = new T(); + header.FillBase(this); + + reader.Mark(); + header.ReadFromReader(reader); + header.ReadBytes += reader.CurrentReadByteCount; + + int headerSizeDiff = header.HeaderSize - (int)header.ReadBytes; + + if (headerSizeDiff > 0) + { + reader.ReadBytes(headerSizeDiff); + } + + return header; + } + + protected virtual void PostReadingBytes(MarkingBinaryReader reader) + { + } + + /// + /// This is the number of bytes read when reading the header + /// + protected long ReadBytes { get; private set; } + + protected short HeadCRC { get; private set; } + + internal HeaderType HeaderType { get; private set; } + + /// + /// Untyped flags. These should be typed when Promoting to another header + /// + protected short Flags { get; private set; } + + protected short HeaderSize { get; private set; } + + /// + /// This additional size of the header could be file data + /// + protected uint AdditionalSize { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs similarity index 97% rename from SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs rename to src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 555447ab..ed803e82 100644 --- a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -1,243 +1,243 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class RarHeaderFactory - { - private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136 - - internal RarHeaderFactory(StreamingMode mode, Options options, string password = null) - { - StreamingMode = mode; - Options = options; - Password = password; - } - - private Options Options { get; set; } - public string Password { get; private set; } - internal StreamingMode StreamingMode { get; private set; } - internal bool IsEncrypted { get; private set; } - - internal IEnumerable ReadHeaders(Stream stream) - { - if (Options.HasFlag(Options.LookForHeader)) - { - stream = CheckSFX(stream); - } - - RarHeader header; - while ((header = ReadNextHeader(stream)) != null) - { - yield return header; - if (header.HeaderType == HeaderType.EndArchiveHeader) - { - yield break; // the end? - } - } - } - - private Stream CheckSFX(Stream stream) - { - RewindableStream rewindableStream = GetRewindableStream(stream); - stream = rewindableStream; - BinaryReader reader = new BinaryReader(rewindableStream); - try - { - int count = 0; - while (true) - { - byte firstByte = reader.ReadByte(); - if (firstByte == 0x52) - { - MemoryStream buffer = new MemoryStream(); - byte[] nextThreeBytes = reader.ReadBytes(3); - if ((nextThreeBytes[0] == 0x45) - && (nextThreeBytes[1] == 0x7E) - && (nextThreeBytes[2] == 0x5E)) - { - //old format and isvalid - buffer.WriteByte(0x52); - buffer.Write(nextThreeBytes, 0, 3); - rewindableStream.Rewind(buffer); - break; - } - byte[] secondThreeBytes = reader.ReadBytes(3); - if ((nextThreeBytes[0] == 0x61) - && (nextThreeBytes[1] == 0x72) - && (nextThreeBytes[2] == 0x21) - && (secondThreeBytes[0] == 0x1A) - && (secondThreeBytes[1] == 0x07) - && (secondThreeBytes[2] == 0x00)) - { - //new format and isvalid - buffer.WriteByte(0x52); - buffer.Write(nextThreeBytes, 0, 3); - buffer.Write(secondThreeBytes, 0, 3); - rewindableStream.Rewind(buffer); - break; - } - buffer.Write(nextThreeBytes, 0, 3); - buffer.Write(secondThreeBytes, 0, 3); - rewindableStream.Rewind(buffer); - } - if (count > MAX_SFX_SIZE) - { - break; - } - } - } - catch (Exception e) - { - if (!Options.HasFlag(Options.KeepStreamsOpen)) - { -#if NET35 - reader.Close(); -#else - reader.Dispose(); -#endif - } - throw new InvalidFormatException("Error trying to read rar signature.", e); - } - return stream; - } - - private RewindableStream GetRewindableStream(Stream stream) - { - RewindableStream rewindableStream = stream as RewindableStream; - if (rewindableStream == null) - { - rewindableStream = new RewindableStream(stream); - } - return rewindableStream; - } - - - private RarHeader ReadNextHeader(Stream stream) - { - var reader = new RarCryptoBinaryReader(stream, Password); - - if (IsEncrypted) - { - if (Password == null) - { - throw new CryptographicException("Encrypted Rar archive has no password specified."); - } - reader.SkipQueue(); - byte[] salt = reader.ReadBytes(8); - reader.InitializeAes(salt); - } - - RarHeader header = RarHeader.Create(reader); - if (header == null) - { - return null; - } - switch (header.HeaderType) - { - case HeaderType.ArchiveHeader: - { - var ah = header.PromoteHeader(reader); - IsEncrypted = ah.HasPassword; - return ah; - } - case HeaderType.MarkHeader: - { - return header.PromoteHeader(reader); - } - - case HeaderType.ProtectHeader: - { - ProtectHeader ph = header.PromoteHeader(reader); - - // skip the recovery record data, we do not use it. - switch (StreamingMode) - { - case StreamingMode.Seekable: - { - reader.BaseStream.Position += ph.DataSize; - } - break; - case StreamingMode.Streaming: - { - reader.BaseStream.Skip(ph.DataSize); - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - - return ph; - } - - case HeaderType.NewSubHeader: - { - FileHeader fh = header.PromoteHeader(reader); - switch (StreamingMode) - { - case StreamingMode.Seekable: - { - fh.DataStartPosition = reader.BaseStream.Position; - reader.BaseStream.Position += fh.CompressedSize; - } - break; - case StreamingMode.Streaming: - { - //skip the data because it's useless? - reader.BaseStream.Skip(fh.CompressedSize); - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - return fh; - } - case HeaderType.FileHeader: - { - FileHeader fh = header.PromoteHeader(reader); - switch (StreamingMode) - { - case StreamingMode.Seekable: - { - fh.DataStartPosition = reader.BaseStream.Position; - reader.BaseStream.Position += fh.CompressedSize; - } - break; - case StreamingMode.Streaming: - { - var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize); - if (fh.Salt == null) - { - fh.PackedStream = ms; - } - else - { - fh.PackedStream = new RarCryptoWrapper(ms, Password, fh.Salt); - } - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - return fh; - } - case HeaderType.EndArchiveHeader: - { - return header.PromoteHeader(reader); - } - default: - { - throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType.ToString()); - } - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class RarHeaderFactory + { + private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136 + + internal RarHeaderFactory(StreamingMode mode, Options options, string password = null) + { + StreamingMode = mode; + Options = options; + Password = password; + } + + private Options Options { get; set; } + public string Password { get; private set; } + internal StreamingMode StreamingMode { get; private set; } + internal bool IsEncrypted { get; private set; } + + internal IEnumerable ReadHeaders(Stream stream) + { + if (Options.HasFlag(Options.LookForHeader)) + { + stream = CheckSFX(stream); + } + + RarHeader header; + while ((header = ReadNextHeader(stream)) != null) + { + yield return header; + if (header.HeaderType == HeaderType.EndArchiveHeader) + { + yield break; // the end? + } + } + } + + private Stream CheckSFX(Stream stream) + { + RewindableStream rewindableStream = GetRewindableStream(stream); + stream = rewindableStream; + BinaryReader reader = new BinaryReader(rewindableStream); + try + { + int count = 0; + while (true) + { + byte firstByte = reader.ReadByte(); + if (firstByte == 0x52) + { + MemoryStream buffer = new MemoryStream(); + byte[] nextThreeBytes = reader.ReadBytes(3); + if ((nextThreeBytes[0] == 0x45) + && (nextThreeBytes[1] == 0x7E) + && (nextThreeBytes[2] == 0x5E)) + { + //old format and isvalid + buffer.WriteByte(0x52); + buffer.Write(nextThreeBytes, 0, 3); + rewindableStream.Rewind(buffer); + break; + } + byte[] secondThreeBytes = reader.ReadBytes(3); + if ((nextThreeBytes[0] == 0x61) + && (nextThreeBytes[1] == 0x72) + && (nextThreeBytes[2] == 0x21) + && (secondThreeBytes[0] == 0x1A) + && (secondThreeBytes[1] == 0x07) + && (secondThreeBytes[2] == 0x00)) + { + //new format and isvalid + buffer.WriteByte(0x52); + buffer.Write(nextThreeBytes, 0, 3); + buffer.Write(secondThreeBytes, 0, 3); + rewindableStream.Rewind(buffer); + break; + } + buffer.Write(nextThreeBytes, 0, 3); + buffer.Write(secondThreeBytes, 0, 3); + rewindableStream.Rewind(buffer); + } + if (count > MAX_SFX_SIZE) + { + break; + } + } + } + catch (Exception e) + { + if (!Options.HasFlag(Options.KeepStreamsOpen)) + { +#if NET35 + reader.Close(); +#else + reader.Dispose(); +#endif + } + throw new InvalidFormatException("Error trying to read rar signature.", e); + } + return stream; + } + + private RewindableStream GetRewindableStream(Stream stream) + { + RewindableStream rewindableStream = stream as RewindableStream; + if (rewindableStream == null) + { + rewindableStream = new RewindableStream(stream); + } + return rewindableStream; + } + + + private RarHeader ReadNextHeader(Stream stream) + { + var reader = new RarCryptoBinaryReader(stream, Password); + + if (IsEncrypted) + { + if (Password == null) + { + throw new CryptographicException("Encrypted Rar archive has no password specified."); + } + reader.SkipQueue(); + byte[] salt = reader.ReadBytes(8); + reader.InitializeAes(salt); + } + + RarHeader header = RarHeader.Create(reader); + if (header == null) + { + return null; + } + switch (header.HeaderType) + { + case HeaderType.ArchiveHeader: + { + var ah = header.PromoteHeader(reader); + IsEncrypted = ah.HasPassword; + return ah; + } + case HeaderType.MarkHeader: + { + return header.PromoteHeader(reader); + } + + case HeaderType.ProtectHeader: + { + ProtectHeader ph = header.PromoteHeader(reader); + + // skip the recovery record data, we do not use it. + switch (StreamingMode) + { + case StreamingMode.Seekable: + { + reader.BaseStream.Position += ph.DataSize; + } + break; + case StreamingMode.Streaming: + { + reader.BaseStream.Skip(ph.DataSize); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + + return ph; + } + + case HeaderType.NewSubHeader: + { + FileHeader fh = header.PromoteHeader(reader); + switch (StreamingMode) + { + case StreamingMode.Seekable: + { + fh.DataStartPosition = reader.BaseStream.Position; + reader.BaseStream.Position += fh.CompressedSize; + } + break; + case StreamingMode.Streaming: + { + //skip the data because it's useless? + reader.BaseStream.Skip(fh.CompressedSize); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + return fh; + } + case HeaderType.FileHeader: + { + FileHeader fh = header.PromoteHeader(reader); + switch (StreamingMode) + { + case StreamingMode.Seekable: + { + fh.DataStartPosition = reader.BaseStream.Position; + reader.BaseStream.Position += fh.CompressedSize; + } + break; + case StreamingMode.Streaming: + { + var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize); + if (fh.Salt == null) + { + fh.PackedStream = ms; + } + else + { + fh.PackedStream = new RarCryptoWrapper(ms, Password, fh.Salt); + } + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + return fh; + } + case HeaderType.EndArchiveHeader: + { + return header.PromoteHeader(reader); + } + default: + { + throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType.ToString()); + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/SignHeader.cs b/src/SharpCompress/Common/Rar/Headers/SignHeader.cs similarity index 96% rename from SharpCompress/Common/Rar/Headers/SignHeader.cs rename to src/SharpCompress/Common/Rar/Headers/SignHeader.cs index 8c0482c1..708241d8 100644 --- a/SharpCompress/Common/Rar/Headers/SignHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/SignHeader.cs @@ -1,23 +1,23 @@ -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar.Headers -{ - internal class AVHeader : RarHeader - { - protected override void ReadFromReader(MarkingBinaryReader reader) - { - UnpackVersion = reader.ReadByte(); - Method = reader.ReadByte(); - AVVersion = reader.ReadByte(); - AVInfoCRC = reader.ReadInt32(); - } - - internal int AVInfoCRC { get; private set; } - - internal byte UnpackVersion { get; private set; } - - internal byte Method { get; private set; } - - internal byte AVVersion { get; private set; } - } +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar.Headers +{ + internal class AVHeader : RarHeader + { + protected override void ReadFromReader(MarkingBinaryReader reader) + { + UnpackVersion = reader.ReadByte(); + Method = reader.ReadByte(); + AVVersion = reader.ReadByte(); + AVInfoCRC = reader.ReadInt32(); + } + + internal int AVInfoCRC { get; private set; } + + internal byte UnpackVersion { get; private set; } + + internal byte Method { get; private set; } + + internal byte AVVersion { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs similarity index 96% rename from SharpCompress/Common/Rar/RarCryptoBinaryReader.cs rename to src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs index a235f95a..952c015a 100644 --- a/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs @@ -1,81 +1,81 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar -{ - internal class RarCryptoBinaryReader : MarkingBinaryReader - { - private RarRijndael rijndael; - private byte[] salt; - private readonly string password; - private readonly Queue data = new Queue(); - - public RarCryptoBinaryReader(Stream stream, string password ) - : base(stream) - { - this.password = password; - } - - protected bool UseEncryption - { - get { return salt != null; } - } - - internal void InitializeAes(byte[] salt) - { - this.salt = salt; - rijndael = RarRijndael.InitializeFrom(password, salt); - } - - public override byte[] ReadBytes(int count) - { - if (UseEncryption) - { - return ReadAndDecryptBytes(count); - } - return base.ReadBytes(count); - } - - private byte[] ReadAndDecryptBytes(int count) - { - int queueSize = data.Count; - int sizeToRead = count - queueSize; - - if (sizeToRead > 0) - { - int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); - for (int i = 0; i < alignedSize / 16; i++) - { - //long ax = System.currentTimeMillis(); - byte[] cipherText = base.ReadBytes(16); - var readBytes = rijndael.ProcessBlock(cipherText); - foreach (var readByte in readBytes) - data.Enqueue(readByte); - - } - - } - - var decryptedBytes = new byte[count]; - - for (int i = 0; i < count; i++) - { - decryptedBytes[i] = data.Dequeue(); - } - return decryptedBytes; - } - - public void ClearQueue() - { - data.Clear(); - } - - public void SkipQueue() - { - var position = BaseStream.Position; - BaseStream.Position = position + data.Count; - ClearQueue(); - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar +{ + internal class RarCryptoBinaryReader : MarkingBinaryReader + { + private RarRijndael rijndael; + private byte[] salt; + private readonly string password; + private readonly Queue data = new Queue(); + + public RarCryptoBinaryReader(Stream stream, string password ) + : base(stream) + { + this.password = password; + } + + protected bool UseEncryption + { + get { return salt != null; } + } + + internal void InitializeAes(byte[] salt) + { + this.salt = salt; + rijndael = RarRijndael.InitializeFrom(password, salt); + } + + public override byte[] ReadBytes(int count) + { + if (UseEncryption) + { + return ReadAndDecryptBytes(count); + } + return base.ReadBytes(count); + } + + private byte[] ReadAndDecryptBytes(int count) + { + int queueSize = data.Count; + int sizeToRead = count - queueSize; + + if (sizeToRead > 0) + { + int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); + for (int i = 0; i < alignedSize / 16; i++) + { + //long ax = System.currentTimeMillis(); + byte[] cipherText = base.ReadBytes(16); + var readBytes = rijndael.ProcessBlock(cipherText); + foreach (var readByte in readBytes) + data.Enqueue(readByte); + + } + + } + + var decryptedBytes = new byte[count]; + + for (int i = 0; i < count; i++) + { + decryptedBytes[i] = data.Dequeue(); + } + return decryptedBytes; + } + + public void ClearQueue() + { + data.Clear(); + } + + public void SkipQueue() + { + var position = BaseStream.Position; + BaseStream.Position = position + data.Count; + ClearQueue(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarCryptoWrapper.cs b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs similarity index 96% rename from SharpCompress/Common/Rar/RarCryptoWrapper.cs rename to src/SharpCompress/Common/Rar/RarCryptoWrapper.cs index e7a1b858..af3b9d9b 100644 --- a/SharpCompress/Common/Rar/RarCryptoWrapper.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs @@ -1,108 +1,108 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace SharpCompress.Common.Rar -{ - internal class RarCryptoWrapper : Stream - { - private readonly Stream actualStream; - private readonly byte[] salt; - private RarRijndael rijndael; - private readonly Queue data = new Queue(); - - public RarCryptoWrapper(Stream actualStream, string password, byte[] salt) - { - this.actualStream = actualStream; - this.salt = salt; - rijndael = RarRijndael.InitializeFrom(password, salt); - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (salt == null) - { - return actualStream.Read(buffer, offset, count); - } - return ReadAndDecrypt(buffer, offset, count); - } - - public int ReadAndDecrypt(byte[] buffer, int offset, int count) - { - int queueSize = data.Count; - int sizeToRead = count - queueSize; - - if (sizeToRead > 0) - { - int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); - for (int i = 0; i < alignedSize / 16; i++) - { - //long ax = System.currentTimeMillis(); - byte[] cipherText = new byte[RarRijndael.CRYPTO_BLOCK_SIZE]; - actualStream.Read(cipherText, 0, RarRijndael.CRYPTO_BLOCK_SIZE); - - var readBytes = rijndael.ProcessBlock(cipherText); - foreach (var readByte in readBytes) - data.Enqueue(readByte); - - } - - for (int i = 0; i < count; i++) - buffer[offset + i] = data.Dequeue(); - } - return count; - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position { get; set; } - - protected override void Dispose(bool disposing) - { - if (rijndael != null) - { - rijndael.Dispose(); - rijndael = null; - } - base.Dispose(disposing); - } - } +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress.Common.Rar +{ + internal class RarCryptoWrapper : Stream + { + private readonly Stream actualStream; + private readonly byte[] salt; + private RarRijndael rijndael; + private readonly Queue data = new Queue(); + + public RarCryptoWrapper(Stream actualStream, string password, byte[] salt) + { + this.actualStream = actualStream; + this.salt = salt; + rijndael = RarRijndael.InitializeFrom(password, salt); + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (salt == null) + { + return actualStream.Read(buffer, offset, count); + } + return ReadAndDecrypt(buffer, offset, count); + } + + public int ReadAndDecrypt(byte[] buffer, int offset, int count) + { + int queueSize = data.Count; + int sizeToRead = count - queueSize; + + if (sizeToRead > 0) + { + int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); + for (int i = 0; i < alignedSize / 16; i++) + { + //long ax = System.currentTimeMillis(); + byte[] cipherText = new byte[RarRijndael.CRYPTO_BLOCK_SIZE]; + actualStream.Read(cipherText, 0, RarRijndael.CRYPTO_BLOCK_SIZE); + + var readBytes = rijndael.ProcessBlock(cipherText); + foreach (var readByte in readBytes) + data.Enqueue(readByte); + + } + + for (int i = 0; i < count; i++) + buffer[offset + i] = data.Dequeue(); + } + return count; + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position { get; set; } + + protected override void Dispose(bool disposing) + { + if (rijndael != null) + { + rijndael.Dispose(); + rijndael = null; + } + base.Dispose(disposing); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs similarity index 96% rename from SharpCompress/Common/Rar/RarEntry.cs rename to src/SharpCompress/Common/Rar/RarEntry.cs index be584ea9..dc898517 100644 --- a/SharpCompress/Common/Rar/RarEntry.cs +++ b/src/SharpCompress/Common/Rar/RarEntry.cs @@ -1,85 +1,85 @@ -using System; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Common.Rar -{ - public abstract class RarEntry : Entry - { - internal abstract FileHeader FileHeader { get; } - - /// - /// The File's 32 bit CRC Hash - /// - public override long Crc - { - get { return FileHeader.FileCRC; } - } - - /// - /// The path of the file internal to the Rar Archive. - /// - public override string Key - { - get { return FileHeader.FileName; } - } - - /// - /// The entry last modified time in the archive, if recorded - /// - public override DateTime? LastModifiedTime - { - get { return FileHeader.FileLastModifiedTime; } - } - - /// - /// The entry create time in the archive, if recorded - /// - public override DateTime? CreatedTime - { - get { return FileHeader.FileCreatedTime; } - } - - /// - /// The entry last accessed time in the archive, if recorded - /// - public override DateTime? LastAccessedTime - { - get { return FileHeader.FileLastAccessedTime; } - } - - /// - /// The entry time whend archived, if recorded - /// - public override DateTime? ArchivedTime - { - get { return FileHeader.FileArchivedTime; } - } - - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public override bool IsEncrypted - { - get { return FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD); } - } - - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public override bool IsDirectory - { - get { return FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY); } - } - - public override bool IsSplit - { - get { return FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER); } - } - - public override string ToString() - { - return string.Format("Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", - Key, CompressedSize, Size, Crc); - } - } +using System; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Common.Rar +{ + public abstract class RarEntry : Entry + { + internal abstract FileHeader FileHeader { get; } + + /// + /// The File's 32 bit CRC Hash + /// + public override long Crc + { + get { return FileHeader.FileCRC; } + } + + /// + /// The path of the file internal to the Rar Archive. + /// + public override string Key + { + get { return FileHeader.FileName; } + } + + /// + /// The entry last modified time in the archive, if recorded + /// + public override DateTime? LastModifiedTime + { + get { return FileHeader.FileLastModifiedTime; } + } + + /// + /// The entry create time in the archive, if recorded + /// + public override DateTime? CreatedTime + { + get { return FileHeader.FileCreatedTime; } + } + + /// + /// The entry last accessed time in the archive, if recorded + /// + public override DateTime? LastAccessedTime + { + get { return FileHeader.FileLastAccessedTime; } + } + + /// + /// The entry time whend archived, if recorded + /// + public override DateTime? ArchivedTime + { + get { return FileHeader.FileArchivedTime; } + } + + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public override bool IsEncrypted + { + get { return FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD); } + } + + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public override bool IsDirectory + { + get { return FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY); } + } + + public override bool IsSplit + { + get { return FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER); } + } + + public override string ToString() + { + return string.Format("Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", + Key, CompressedSize, Size, Crc); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarFilePart.cs b/src/SharpCompress/Common/Rar/RarFilePart.cs similarity index 96% rename from SharpCompress/Common/Rar/RarFilePart.cs rename to src/SharpCompress/Common/Rar/RarFilePart.cs index a6ba8ec7..c9d00dc0 100644 --- a/SharpCompress/Common/Rar/RarFilePart.cs +++ b/src/SharpCompress/Common/Rar/RarFilePart.cs @@ -1,26 +1,26 @@ -using System.IO; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Common.Rar -{ - /// - /// This represents a single file part that exists in a rar volume. A compressed file is one or many file parts that are spread across one or may rar parts. - /// - internal abstract class RarFilePart : FilePart - { - internal RarFilePart(MarkHeader mh, FileHeader fh) - { - MarkHeader = mh; - FileHeader = fh; - } - - internal MarkHeader MarkHeader { get; private set; } - - internal FileHeader FileHeader { get; private set; } - - internal override Stream GetRawStream() - { - return null; - } - } +using System.IO; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Common.Rar +{ + /// + /// This represents a single file part that exists in a rar volume. A compressed file is one or many file parts that are spread across one or may rar parts. + /// + internal abstract class RarFilePart : FilePart + { + internal RarFilePart(MarkHeader mh, FileHeader fh) + { + MarkHeader = mh; + FileHeader = fh; + } + + internal MarkHeader MarkHeader { get; private set; } + + internal FileHeader FileHeader { get; private set; } + + internal override Stream GetRawStream() + { + return null; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarRijndael.cs b/src/SharpCompress/Common/Rar/RarRijndael.cs similarity index 97% rename from SharpCompress/Common/Rar/RarRijndael.cs rename to src/SharpCompress/Common/Rar/RarRijndael.cs index 12d339b7..a2806a12 100644 --- a/SharpCompress/Common/Rar/RarRijndael.cs +++ b/src/SharpCompress/Common/Rar/RarRijndael.cs @@ -1,116 +1,116 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; - -namespace SharpCompress.Common.Rar -{ - internal class RarRijndael : IDisposable - { - internal const int CRYPTO_BLOCK_SIZE = 16; - - private readonly string password; - private readonly byte[] salt; - private byte[] aesInitializationVector; - private RijndaelEngine rijndael; - - private RarRijndael(string password, byte[] salt) - { - this.password = password; - this.salt = salt; - } - - private byte[] ComputeHash(byte[] input) - { - var sha = new Sha1Digest(); - sha.BlockUpdate(input, 0, input.Length); - byte[] result = new byte[sha.GetDigestSize()]; - sha.DoFinal(result, 0); - return result; - } - - private void Initialize() - { - - rijndael = new RijndaelEngine(); - aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE]; - int rawLength = 2*password.Length; - byte[] rawPassword = new byte[rawLength + 8]; - byte[] passwordBytes = Encoding.UTF8.GetBytes(password); - for (int i = 0; i < password.Length; i++) - { - rawPassword[i*2] = passwordBytes[i]; - rawPassword[i*2 + 1] = 0; - } - for (int i = 0; i < salt.Length; i++) - { - rawPassword[i + rawLength] = salt[i]; - } - - - const int noOfRounds = (1 << 18); - IList bytes = new List(); - byte[] digest; - - //TODO slow code below, find ways to optimize - for (int i = 0; i < noOfRounds; i++) - { - bytes.AddRange(rawPassword); - - bytes.AddRange(new[] - { - (byte) i, (byte) (i >> 8), (byte) (i >> CRYPTO_BLOCK_SIZE) - }); - if (i%(noOfRounds/CRYPTO_BLOCK_SIZE) == 0) - { - digest = ComputeHash(bytes.ToArray()); - aesInitializationVector[i/(noOfRounds/CRYPTO_BLOCK_SIZE)] = digest[19]; - } - } - - digest = ComputeHash(bytes.ToArray()); - //slow code ends - - byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE]; - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - aesKey[i*4 + j] = (byte) - (((digest[i*4]*0x1000000) & 0xff000000 | - (uint) ((digest[i*4 + 1]*0x10000) & 0xff0000) | - (uint) ((digest[i*4 + 2]*0x100) & 0xff00) | - (uint) (digest[i*4 + 3] & 0xff)) >> (j*8)); - - - rijndael.Init(false, new KeyParameter(aesKey)); - - } - - public static RarRijndael InitializeFrom(string password, byte[] salt) - { - var rijndael = new RarRijndael(password, salt); - rijndael.Initialize(); - return rijndael; - } - - public byte[] ProcessBlock(byte[] cipherText) - { - var plainText = new byte[CRYPTO_BLOCK_SIZE]; - var decryptedBytes = new List(); - rijndael.ProcessBlock(cipherText, 0, plainText, 0); - - for (int j = 0; j < plainText.Length; j++) - decryptedBytes.Add((byte) (plainText[j] ^ aesInitializationVector[j%16])); //32:114, 33:101 - - for (int j = 0; j < aesInitializationVector.Length; j++) - aesInitializationVector[j] = cipherText[j]; - return decryptedBytes.ToArray(); - } - - public void Dispose() - { - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; + +namespace SharpCompress.Common.Rar +{ + internal class RarRijndael : IDisposable + { + internal const int CRYPTO_BLOCK_SIZE = 16; + + private readonly string password; + private readonly byte[] salt; + private byte[] aesInitializationVector; + private RijndaelEngine rijndael; + + private RarRijndael(string password, byte[] salt) + { + this.password = password; + this.salt = salt; + } + + private byte[] ComputeHash(byte[] input) + { + var sha = new Sha1Digest(); + sha.BlockUpdate(input, 0, input.Length); + byte[] result = new byte[sha.GetDigestSize()]; + sha.DoFinal(result, 0); + return result; + } + + private void Initialize() + { + + rijndael = new RijndaelEngine(); + aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE]; + int rawLength = 2*password.Length; + byte[] rawPassword = new byte[rawLength + 8]; + byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + for (int i = 0; i < password.Length; i++) + { + rawPassword[i*2] = passwordBytes[i]; + rawPassword[i*2 + 1] = 0; + } + for (int i = 0; i < salt.Length; i++) + { + rawPassword[i + rawLength] = salt[i]; + } + + + const int noOfRounds = (1 << 18); + IList bytes = new List(); + byte[] digest; + + //TODO slow code below, find ways to optimize + for (int i = 0; i < noOfRounds; i++) + { + bytes.AddRange(rawPassword); + + bytes.AddRange(new[] + { + (byte) i, (byte) (i >> 8), (byte) (i >> CRYPTO_BLOCK_SIZE) + }); + if (i%(noOfRounds/CRYPTO_BLOCK_SIZE) == 0) + { + digest = ComputeHash(bytes.ToArray()); + aesInitializationVector[i/(noOfRounds/CRYPTO_BLOCK_SIZE)] = digest[19]; + } + } + + digest = ComputeHash(bytes.ToArray()); + //slow code ends + + byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE]; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + aesKey[i*4 + j] = (byte) + (((digest[i*4]*0x1000000) & 0xff000000 | + (uint) ((digest[i*4 + 1]*0x10000) & 0xff0000) | + (uint) ((digest[i*4 + 2]*0x100) & 0xff00) | + (uint) (digest[i*4 + 3] & 0xff)) >> (j*8)); + + + rijndael.Init(false, new KeyParameter(aesKey)); + + } + + public static RarRijndael InitializeFrom(string password, byte[] salt) + { + var rijndael = new RarRijndael(password, salt); + rijndael.Initialize(); + return rijndael; + } + + public byte[] ProcessBlock(byte[] cipherText) + { + var plainText = new byte[CRYPTO_BLOCK_SIZE]; + var decryptedBytes = new List(); + rijndael.ProcessBlock(cipherText, 0, plainText, 0); + + for (int j = 0; j < plainText.Length; j++) + decryptedBytes.Add((byte) (plainText[j] ^ aesInitializationVector[j%16])); //32:114, 33:101 + + for (int j = 0; j < aesInitializationVector.Length; j++) + aesInitializationVector[j] = cipherText[j]; + return decryptedBytes.ToArray(); + } + + public void Dispose() + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarVolume.cs b/src/SharpCompress/Common/Rar/RarVolume.cs similarity index 97% rename from SharpCompress/Common/Rar/RarVolume.cs rename to src/SharpCompress/Common/Rar/RarVolume.cs index e8f2ee8b..b1db9469 100644 --- a/SharpCompress/Common/Rar/RarVolume.cs +++ b/src/SharpCompress/Common/Rar/RarVolume.cs @@ -1,117 +1,117 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Common.Rar -{ - /// - /// A RarArchiveVolume is a single rar file that may or may not be a split RarArchive. A Rar Archive is one to many Rar Parts - /// - public abstract class RarVolume : Volume - { - private readonly RarHeaderFactory headerFactory; - - internal RarVolume(StreamingMode mode, Stream stream, string password, Options options) - : base(stream, options) - { - headerFactory = new RarHeaderFactory(mode, options, password); - Password = password; - } - - internal string Password { get; private set; } - - internal StreamingMode Mode - { - get { return headerFactory.StreamingMode; } - } - - internal abstract IEnumerable ReadFileParts(); - - internal abstract RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader); - - internal IEnumerable GetVolumeFileParts() - { - MarkHeader previousMarkHeader = null; - foreach (RarHeader header in headerFactory.ReadHeaders(this.Stream)) - { - switch (header.HeaderType) - { - case HeaderType.ArchiveHeader: - { - ArchiveHeader = header as ArchiveHeader; - } - break; - case HeaderType.MarkHeader: - { - previousMarkHeader = header as MarkHeader; - } - break; - case HeaderType.FileHeader: - { - FileHeader fh = header as FileHeader; - RarFilePart fp = CreateFilePart(fh, previousMarkHeader); - yield return fp; - } - break; - } - } - } - - internal ArchiveHeader ArchiveHeader { get; private set; } - - private void EnsureArchiveHeaderLoaded() - { - if (ArchiveHeader == null) - { - if (Mode == StreamingMode.Streaming) - { - throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read."); - } - //we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream - GetVolumeFileParts().First(); - Stream.Position = 0; - } - } - - /// - /// RarArchive is the first volume of a multi-part archive. - /// Only Rar 3.0 format and higher - /// - public override bool IsFirstVolume - { - get - { - EnsureArchiveHeaderLoaded(); - return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.FIRSTVOLUME); - } - } - - /// - /// RarArchive is part of a multi-part archive. - /// - public override bool IsMultiVolume - { - get - { - EnsureArchiveHeaderLoaded(); - return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME); - } - } - - /// - /// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). - /// Currently, SharpCompress cannot decompress SOLID archives. - /// - public bool IsSolidArchive - { - get - { - EnsureArchiveHeaderLoaded(); - return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.SOLID); - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Rar +{ + /// + /// A RarArchiveVolume is a single rar file that may or may not be a split RarArchive. A Rar Archive is one to many Rar Parts + /// + public abstract class RarVolume : Volume + { + private readonly RarHeaderFactory headerFactory; + + internal RarVolume(StreamingMode mode, Stream stream, string password, Options options) + : base(stream, options) + { + headerFactory = new RarHeaderFactory(mode, options, password); + Password = password; + } + + internal string Password { get; private set; } + + internal StreamingMode Mode + { + get { return headerFactory.StreamingMode; } + } + + internal abstract IEnumerable ReadFileParts(); + + internal abstract RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader); + + internal IEnumerable GetVolumeFileParts() + { + MarkHeader previousMarkHeader = null; + foreach (RarHeader header in headerFactory.ReadHeaders(this.Stream)) + { + switch (header.HeaderType) + { + case HeaderType.ArchiveHeader: + { + ArchiveHeader = header as ArchiveHeader; + } + break; + case HeaderType.MarkHeader: + { + previousMarkHeader = header as MarkHeader; + } + break; + case HeaderType.FileHeader: + { + FileHeader fh = header as FileHeader; + RarFilePart fp = CreateFilePart(fh, previousMarkHeader); + yield return fp; + } + break; + } + } + } + + internal ArchiveHeader ArchiveHeader { get; private set; } + + private void EnsureArchiveHeaderLoaded() + { + if (ArchiveHeader == null) + { + if (Mode == StreamingMode.Streaming) + { + throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read."); + } + //we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream + GetVolumeFileParts().First(); + Stream.Position = 0; + } + } + + /// + /// RarArchive is the first volume of a multi-part archive. + /// Only Rar 3.0 format and higher + /// + public override bool IsFirstVolume + { + get + { + EnsureArchiveHeaderLoaded(); + return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.FIRSTVOLUME); + } + } + + /// + /// RarArchive is part of a multi-part archive. + /// + public override bool IsMultiVolume + { + get + { + EnsureArchiveHeaderLoaded(); + return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME); + } + } + + /// + /// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). + /// Currently, SharpCompress cannot decompress SOLID archives. + /// + public bool IsSolidArchive + { + get + { + EnsureArchiveHeaderLoaded(); + return ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.SOLID); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/ReaderExtractionEventArgs.cs b/src/SharpCompress/Common/ReaderExtractionEventArgs.cs similarity index 95% rename from SharpCompress/Common/ReaderExtractionEventArgs.cs rename to src/SharpCompress/Common/ReaderExtractionEventArgs.cs index 2dc33e6e..d4db5e41 100644 --- a/SharpCompress/Common/ReaderExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ReaderExtractionEventArgs.cs @@ -1,13 +1,13 @@ -using System; - -namespace SharpCompress.Common -{ - public class ReaderExtractionEventArgs : EventArgs - { - internal ReaderExtractionEventArgs(T entry) - { - Item = entry; - } - public T Item { get; private set; } - } -} +using System; + +namespace SharpCompress.Common +{ + public class ReaderExtractionEventArgs : EventArgs + { + internal ReaderExtractionEventArgs(T entry) + { + Item = entry; + } + public T Item { get; private set; } + } +} diff --git a/SharpCompress/Common/SevenZip/ArchiveDatabase.cs b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs similarity index 96% rename from SharpCompress/Common/SevenZip/ArchiveDatabase.cs rename to src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs index bee1e177..88d090fa 100644 --- a/SharpCompress/Common/SevenZip/ArchiveDatabase.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs @@ -1,161 +1,161 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Compressor.LZMA; -using SharpCompress.Compressor.LZMA.Utilites; - -namespace SharpCompress.Common.SevenZip -{ - internal class ArchiveDatabase - { - internal byte MajorVersion; - internal byte MinorVersion; - internal long StartPositionAfterHeader; - internal long DataStartPosition; - - internal List PackSizes = new List(); - internal List PackCRCs = new List(); - internal List Folders = new List(); - internal List NumUnpackStreamsVector; - internal List Files = new List(); - - internal List PackStreamStartPositions = new List(); - internal List FolderStartFileIndex = new List(); - internal List FileIndexToFolderIndexMap = new List(); - - internal void Clear() - { - PackSizes.Clear(); - PackCRCs.Clear(); - Folders.Clear(); - NumUnpackStreamsVector = null; - Files.Clear(); - - PackStreamStartPositions.Clear(); - FolderStartFileIndex.Clear(); - FileIndexToFolderIndexMap.Clear(); - } - - internal bool IsEmpty() - { - return PackSizes.Count == 0 - && PackCRCs.Count == 0 - && Folders.Count == 0 - && NumUnpackStreamsVector.Count == 0 - && Files.Count == 0; - } - - private void FillStartPos() - { - PackStreamStartPositions.Clear(); - - long startPos = 0; - for (int i = 0; i < PackSizes.Count; i++) - { - PackStreamStartPositions.Add(startPos); - startPos += PackSizes[i]; - } - } - - private void FillFolderStartFileIndex() - { - FolderStartFileIndex.Clear(); - FileIndexToFolderIndexMap.Clear(); - - int folderIndex = 0; - int indexInFolder = 0; - for (int i = 0; i < Files.Count; i++) - { - CFileItem file = Files[i]; - - bool emptyStream = !file.HasStream; - - if (emptyStream && indexInFolder == 0) - { - FileIndexToFolderIndexMap.Add(-1); - continue; - } - - if (indexInFolder == 0) - { - // v3.13 incorrectly worked with empty folders - // v4.07: Loop for skipping empty folders - for (; ; ) - { - if (folderIndex >= Folders.Count) - throw new InvalidOperationException(); - - 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; - } - } - } - - public void Fill() - { - FillStartPos(); - FillFolderStartFileIndex(); - } - - internal long GetFolderStreamPos(CFolder folder, int indexInFolder) - { - int index = folder.FirstPackStreamId + indexInFolder; - return DataStartPosition + PackStreamStartPositions[index]; - } - - internal long GetFolderFullPackSize(int folderIndex) - { - int packStreamIndex = Folders[folderIndex].FirstPackStreamId; - CFolder folder = Folders[folderIndex]; - - long size = 0; - for (int i = 0; i < folder.PackStreams.Count; i++) - size += PackSizes[packStreamIndex + i]; - - return size; - } - - internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw) - { - int packStreamIndex = folder.FirstPackStreamId; - long folderStartPackPos = GetFolderStreamPos(folder, 0); - List packSizes = new List(); - for (int j = 0; j < folder.PackStreams.Count; j++) - packSizes.Add(PackSizes[packStreamIndex + j]); - - return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw); - } - - private long GetFolderPackStreamSize(int folderIndex, int streamIndex) - { - return PackSizes[Folders[folderIndex].FirstPackStreamId + streamIndex]; - } - - private long GetFilePackSize(int fileIndex) - { - int folderIndex = FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex != -1) - if (FolderStartFileIndex[folderIndex] == fileIndex) - return GetFolderFullPackSize(folderIndex); - return 0; - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Compressor.LZMA; +using SharpCompress.Compressor.LZMA.Utilites; + +namespace SharpCompress.Common.SevenZip +{ + internal class ArchiveDatabase + { + internal byte MajorVersion; + internal byte MinorVersion; + internal long StartPositionAfterHeader; + internal long DataStartPosition; + + internal List PackSizes = new List(); + internal List PackCRCs = new List(); + internal List Folders = new List(); + internal List NumUnpackStreamsVector; + internal List Files = new List(); + + internal List PackStreamStartPositions = new List(); + internal List FolderStartFileIndex = new List(); + internal List FileIndexToFolderIndexMap = new List(); + + internal void Clear() + { + PackSizes.Clear(); + PackCRCs.Clear(); + Folders.Clear(); + NumUnpackStreamsVector = null; + Files.Clear(); + + PackStreamStartPositions.Clear(); + FolderStartFileIndex.Clear(); + FileIndexToFolderIndexMap.Clear(); + } + + internal bool IsEmpty() + { + return PackSizes.Count == 0 + && PackCRCs.Count == 0 + && Folders.Count == 0 + && NumUnpackStreamsVector.Count == 0 + && Files.Count == 0; + } + + private void FillStartPos() + { + PackStreamStartPositions.Clear(); + + long startPos = 0; + for (int i = 0; i < PackSizes.Count; i++) + { + PackStreamStartPositions.Add(startPos); + startPos += PackSizes[i]; + } + } + + private void FillFolderStartFileIndex() + { + FolderStartFileIndex.Clear(); + FileIndexToFolderIndexMap.Clear(); + + int folderIndex = 0; + int indexInFolder = 0; + for (int i = 0; i < Files.Count; i++) + { + CFileItem file = Files[i]; + + bool emptyStream = !file.HasStream; + + if (emptyStream && indexInFolder == 0) + { + FileIndexToFolderIndexMap.Add(-1); + continue; + } + + if (indexInFolder == 0) + { + // v3.13 incorrectly worked with empty folders + // v4.07: Loop for skipping empty folders + for (; ; ) + { + if (folderIndex >= Folders.Count) + throw new InvalidOperationException(); + + 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; + } + } + } + + public void Fill() + { + FillStartPos(); + FillFolderStartFileIndex(); + } + + internal long GetFolderStreamPos(CFolder folder, int indexInFolder) + { + int index = folder.FirstPackStreamId + indexInFolder; + return DataStartPosition + PackStreamStartPositions[index]; + } + + internal long GetFolderFullPackSize(int folderIndex) + { + int packStreamIndex = Folders[folderIndex].FirstPackStreamId; + CFolder folder = Folders[folderIndex]; + + long size = 0; + for (int i = 0; i < folder.PackStreams.Count; i++) + size += PackSizes[packStreamIndex + i]; + + return size; + } + + internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw) + { + int packStreamIndex = folder.FirstPackStreamId; + long folderStartPackPos = GetFolderStreamPos(folder, 0); + List packSizes = new List(); + for (int j = 0; j < folder.PackStreams.Count; j++) + packSizes.Add(PackSizes[packStreamIndex + j]); + + return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw); + } + + private long GetFolderPackStreamSize(int folderIndex, int streamIndex) + { + return PackSizes[Folders[folderIndex].FirstPackStreamId + streamIndex]; + } + + private long GetFilePackSize(int fileIndex) + { + int folderIndex = FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex != -1) + if (FolderStartFileIndex[folderIndex] == fileIndex) + return GetFolderFullPackSize(folderIndex); + return 0; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs similarity index 97% rename from SharpCompress/Common/SevenZip/ArchiveReader.cs rename to src/SharpCompress/Common/SevenZip/ArchiveReader.cs index 31455ca3..588b8e96 100644 --- a/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -1,1453 +1,1453 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Compressor.LZMA; -using SharpCompress.Compressor.LZMA.Utilites; -using SharpCompress.IO; - -namespace SharpCompress.Common.SevenZip -{ - internal class ArchiveReader - { - internal Stream _stream; - internal Stack _readerStack = new Stack(); - internal DataReader _currentReader; - internal long _streamOrigin; - internal long _streamEnding; - internal byte[] _header; - - private Dictionary _cachedStreams = new Dictionary(); - - internal void AddByteStream(byte[] buffer, int offset, int length) - { - _readerStack.Push(_currentReader); - _currentReader = new DataReader(buffer, offset, length); - } - - internal void DeleteByteStream() - { - _currentReader = _readerStack.Pop(); - } - - #region Private Methods - Data Reader - - internal Byte ReadByte() - { - return _currentReader.ReadByte(); - } - - private void ReadBytes(byte[] buffer, int offset, int length) - { - _currentReader.ReadBytes(buffer, offset, length); - } - - private ulong ReadNumber() - { - return _currentReader.ReadNumber(); - } - - internal int ReadNum() - { - return _currentReader.ReadNum(); - } - - private uint ReadUInt32() - { - return _currentReader.ReadUInt32(); - } - - private ulong ReadUInt64() - { - return _currentReader.ReadUInt64(); - } - - private BlockType? ReadId() - { - ulong id = _currentReader.ReadNumber(); - if (id > 25) - return null; -#if DEBUG - Log.WriteLine("ReadId: {0}", (BlockType)id); -#endif - return (BlockType)id; - } - - private void SkipData(long size) - { - _currentReader.SkipData(size); - } - - private void SkipData() - { - _currentReader.SkipData(); - } - - private void WaitAttribute(BlockType attribute) - { - for (; ; ) - { - BlockType? type = ReadId(); - if (type == attribute) - return; - if (type == BlockType.End) - throw new InvalidOperationException(); - SkipData(); - } - } - - private void ReadArchiveProperties() - { - while (ReadId() != BlockType.End) - SkipData(); - } - - #endregion - - #region Private Methods - Reader Utilities - - private BitVector ReadBitVector(int length) - { - var bits = new BitVector(length); - - byte data = 0; - byte mask = 0; - - for (int i = 0; i < length; i++) - { - if (mask == 0) - { - data = ReadByte(); - mask = 0x80; - } - - if ((data & mask) != 0) - bits.SetBit(i); - - mask >>= 1; - } - - return bits; - } - - private BitVector ReadOptionalBitVector(int length) - { - byte allTrue = ReadByte(); - if (allTrue != 0) - return new BitVector(length, true); - - return ReadBitVector(length); - } - - private void ReadNumberVector(List dataVector, int numFiles, Action action) - { - var defined = ReadOptionalBitVector(numFiles); - - using (CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - - for (int i = 0; i < numFiles; i++) - { - if (defined[i]) - action(i, checked((long)ReadUInt64())); - else - action(i, null); - } - } - } - - private DateTime TranslateTime(long time) - { - // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) - return DateTime.FromFileTimeUtc(time).ToLocalTime(); - } - - private DateTime? TranslateTime(long? time) - { - if (time.HasValue) - return TranslateTime(time.Value); - else - return null; - } - - private void ReadDateTimeVector(List dataVector, int numFiles, Action action) - { - ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value))); - } - - private void ReadAttributeVector(List dataVector, int numFiles, Action action) - { - BitVector boolVector = ReadOptionalBitVector(numFiles); - using (var streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - for (int i = 0; i < numFiles; i++) - { - if (boolVector[i]) - action(i, ReadUInt32()); - else - action(i, null); - } - } - } - - #endregion - - #region Private Methods - - private void GetNextFolderItem(CFolder folder) - { -#if DEBUG - Log.WriteLine("-- GetNextFolderItem --"); - Log.PushIndent(); -#endif - try - { - int numCoders = ReadNum(); -#if DEBUG - Log.WriteLine("NumCoders: " + numCoders); -#endif - folder.Coders = new List(numCoders); - int numInStreams = 0; - int numOutStreams = 0; - for (int i = 0; i < numCoders; i++) - { -#if DEBUG - Log.WriteLine("-- Coder --"); - Log.PushIndent(); -#endif - try - { - CCoderInfo coder = new CCoderInfo(); - folder.Coders.Add(coder); - - byte mainByte = ReadByte(); - int idSize = (mainByte & 0xF); - byte[] longID = new byte[idSize]; - ReadBytes(longID, 0, idSize); -#if DEBUG - Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray())); -#endif - if (idSize > 8) - throw new NotSupportedException(); - ulong id = 0; - for (int j = 0; j < idSize; j++) - id |= (ulong)longID[idSize - 1 - j] << (8 * j); - coder.MethodId = new CMethodId(id); - - if ((mainByte & 0x10) != 0) - { - coder.NumInStreams = ReadNum(); - coder.NumOutStreams = ReadNum(); -#if DEBUG - Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")"); -#endif - } - else - { -#if DEBUG - Log.WriteLine("Simple Stream (In: 1 - Out: 1)"); -#endif - coder.NumInStreams = 1; - coder.NumOutStreams = 1; - } - - if ((mainByte & 0x20) != 0) - { - int propsSize = ReadNum(); - coder.Props = new byte[propsSize]; - ReadBytes(coder.Props, 0, propsSize); -#if DEBUG - Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray())); -#endif - } - - if ((mainByte & 0x80) != 0) - throw new NotSupportedException(); - - numInStreams += coder.NumInStreams; - numOutStreams += coder.NumOutStreams; - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - int numBindPairs = numOutStreams - 1; - folder.BindPairs = new List(numBindPairs); -#if DEBUG - Log.WriteLine("BindPairs: " + numBindPairs); - Log.PushIndent(); -#endif - for (int i = 0; i < numBindPairs; i++) - { - CBindPair bp = new CBindPair(); - bp.InIndex = ReadNum(); - bp.OutIndex = ReadNum(); - folder.BindPairs.Add(bp); -#if DEBUG - Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex); -#endif - } -#if DEBUG - Log.PopIndent(); -#endif - - if (numInStreams < numBindPairs) - throw new NotSupportedException(); - - int numPackStreams = numInStreams - numBindPairs; - //folder.PackStreams.Reserve(numPackStreams); - if (numPackStreams == 1) - { - for (int i = 0; i < numInStreams; i++) - { - if (folder.FindBindPairForInStream(i) < 0) - { -#if DEBUG - Log.WriteLine("Single PackStream: #" + i); -#endif - folder.PackStreams.Add(i); - break; - } - } - - if (folder.PackStreams.Count != 1) - throw new NotSupportedException(); - } - else - { -#if DEBUG - Log.WriteLine("Multiple PackStreams ..."); - Log.PushIndent(); -#endif - for (int i = 0; i < numPackStreams; i++) - { - var num = ReadNum(); -#if DEBUG - Log.WriteLine("#" + i + " - " + num); -#endif - folder.PackStreams.Add(num); - } -#if DEBUG - Log.PopIndent(); -#endif - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private List ReadHashDigests(int count) - { -#if DEBUG - Log.Write("ReadHashDigests:"); -#endif - - var defined = ReadOptionalBitVector(count); - var digests = new List(count); - for (int i = 0; i < count; i++) - { - if (defined[i]) - { - uint crc = ReadUInt32(); -#if DEBUG - Log.Write(" " + crc.ToString("x8")); -#endif - digests.Add(crc); - } - else - { -#if DEBUG - Log.Write(" ########"); -#endif - digests.Add(null); - } - } -#if DEBUG - - Log.WriteLine(); -#endif - return digests; - } - - private void ReadPackInfo(out long dataOffset, out List packSizes, out List packCRCs) - { -#if DEBUG - Log.WriteLine("-- ReadPackInfo --"); - Log.PushIndent(); -#endif - try - { - packCRCs = null; - - dataOffset = checked((long)ReadNumber()); -#if DEBUG - Log.WriteLine("DataOffset: " + dataOffset); -#endif - - int numPackStreams = ReadNum(); -#if DEBUG - Log.WriteLine("NumPackStreams: " + numPackStreams); -#endif - - WaitAttribute(BlockType.Size); - packSizes = new List(numPackStreams); -#if DEBUG - Log.Write("Sizes:"); -#endif - for (int i = 0; i < numPackStreams; i++) - { - var size = checked((long)ReadNumber()); -#if DEBUG - Log.Write(" " + size); -#endif - packSizes.Add(size); - } -#if DEBUG - Log.WriteLine(); -#endif - - BlockType? type; - for (; ; ) - { - type = ReadId(); - if (type == BlockType.End) - break; - if (type == BlockType.CRC) - { - packCRCs = ReadHashDigests(numPackStreams); - continue; - } - SkipData(); - } - - if (packCRCs == null) - { - packCRCs = new List(numPackStreams); - for (int i = 0; i < numPackStreams; i++) - packCRCs.Add(null); - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadUnpackInfo(List dataVector, out List folders) - { -#if DEBUG - Log.WriteLine("-- ReadUnpackInfo --"); - Log.PushIndent(); -#endif - try - { - WaitAttribute(BlockType.Folder); - int numFolders = ReadNum(); -#if DEBUG - Log.WriteLine("NumFolders: {0}", numFolders); -#endif - - using (CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - //folders.Clear(); - //folders.Reserve(numFolders); - folders = new List(numFolders); - int index = 0; - for (int i = 0; i < numFolders; i++) - { - var f = new CFolder { FirstPackStreamId = index }; - folders.Add(f); - GetNextFolderItem(f); - index += f.PackStreams.Count; - } - } - - WaitAttribute(BlockType.CodersUnpackSize); -#if DEBUG - Log.WriteLine("UnpackSizes:"); -#endif - for (int i = 0; i < numFolders; i++) - { - CFolder folder = folders[i]; -#if DEBUG - Log.Write(" #" + i + ":"); -#endif - int numOutStreams = folder.GetNumOutStreams(); - for (int j = 0; j < numOutStreams; j++) - { - long size = checked((long)ReadNumber()); -#if DEBUG - Log.Write(" " + size); -#endif - folder.UnpackSizes.Add(size); - } -#if DEBUG - Log.WriteLine(); -#endif - } - - for (; ; ) - { - BlockType? type = ReadId(); - if (type == BlockType.End) - return; - - if (type == BlockType.CRC) - { - List crcs = ReadHashDigests(numFolders); - for (int i = 0; i < numFolders; i++) - folders[i].UnpackCRC = crcs[i]; - continue; - } - - SkipData(); - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadSubStreamsInfo(List folders, out List numUnpackStreamsInFolders, - out List unpackSizes, out List digests) - { -#if DEBUG - Log.WriteLine("-- ReadSubStreamsInfo --"); - Log.PushIndent(); -#endif - try - { - numUnpackStreamsInFolders = null; - - BlockType? type; - for (; ; ) - { - type = ReadId(); - if (type == BlockType.NumUnpackStream) - { - numUnpackStreamsInFolders = new List(folders.Count); -#if DEBUG - Log.Write("NumUnpackStreams:"); -#endif - for (int i = 0; i < folders.Count; i++) - { - var num = ReadNum(); -#if DEBUG - Log.Write(" " + num); -#endif - numUnpackStreamsInFolders.Add(num); - } -#if DEBUG - Log.WriteLine(); -#endif - continue; - } - if (type == BlockType.CRC || type == BlockType.Size) - break; - if (type == BlockType.End) - break; - SkipData(); - } - - if (numUnpackStreamsInFolders == null) - { - numUnpackStreamsInFolders = new List(folders.Count); - for (int i = 0; i < folders.Count; i++) - numUnpackStreamsInFolders.Add(1); - } - - unpackSizes = new List(folders.Count); - for (int i = 0; i < numUnpackStreamsInFolders.Count; i++) - { - // v3.13 incorrectly worked with empty folders - // v4.07: we check that folder is empty - int numSubstreams = numUnpackStreamsInFolders[i]; - if (numSubstreams == 0) - continue; -#if DEBUG - Log.Write("#{0} StreamSizes:", i); -#endif - long sum = 0; - for (int j = 1; j < numSubstreams; j++) - { - if (type == BlockType.Size) - { - long size = checked((long)ReadNumber()); -#if DEBUG - Log.Write(" " + size); -#endif - unpackSizes.Add(size); - sum += size; - } - } - unpackSizes.Add(folders[i].GetUnpackSize() - sum); -#if DEBUG - Log.WriteLine(" - rest: " + unpackSizes.Last()); -#endif - } - if (type == BlockType.Size) - type = ReadId(); - - int numDigests = 0; - int numDigestsTotal = 0; - for (int i = 0; i < folders.Count; i++) - { - int numSubstreams = numUnpackStreamsInFolders[i]; - if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) - numDigests += numSubstreams; - numDigestsTotal += numSubstreams; - } - - digests = null; - - for (; ; ) - { - if (type == BlockType.CRC) - { - digests = new List(numDigestsTotal); - - List digests2 = ReadHashDigests(numDigests); - - int digestIndex = 0; - for (int i = 0; i < folders.Count; i++) - { - int numSubstreams = numUnpackStreamsInFolders[i]; - CFolder folder = folders[i]; - if (numSubstreams == 1 && folder.UnpackCRCDefined) - { - digests.Add(folder.UnpackCRC.Value); - } - else - { - for (int j = 0; j < numSubstreams; j++, digestIndex++) - digests.Add(digests2[digestIndex]); - } - } - - if (digestIndex != numDigests || numDigestsTotal != digests.Count) - System.Diagnostics.Debugger.Break(); - } - else if (type == BlockType.End) - { - if (digests == null) - { - digests = new List(numDigestsTotal); - for (int i = 0; i < numDigestsTotal; i++) - digests.Add(null); - } - return; - } - else - { - SkipData(); - } - - type = ReadId(); - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadStreamsInfo( - List dataVector, - out long dataOffset, - out List packSizes, - out List packCRCs, - out List folders, - out List numUnpackStreamsInFolders, - out List unpackSizes, - out List digests) - { -#if DEBUG - Log.WriteLine("-- ReadStreamsInfo --"); - Log.PushIndent(); -#endif - try - { - dataOffset = long.MinValue; - packSizes = null; - packCRCs = null; - folders = null; - numUnpackStreamsInFolders = null; - unpackSizes = null; - digests = null; - - for (; ; ) - { - switch (ReadId()) - { - case BlockType.End: - return; - case BlockType.PackInfo: - ReadPackInfo(out dataOffset, out packSizes, out packCRCs); - break; - case BlockType.UnpackInfo: - ReadUnpackInfo(dataVector, out folders); - break; - case BlockType.SubStreamsInfo: - ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests); - break; - default: - throw new InvalidOperationException(); - } - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) - { -#if DEBUG - Log.WriteLine("-- ReadAndDecodePackedStreams --"); - Log.PushIndent(); -#endif - try - { - long dataStartPos; - List packSizes; - List packCRCs; - List folders; - List numUnpackStreamsInFolders; - List unpackSizes; - List digests; - - ReadStreamsInfo(null, - out dataStartPos, - out packSizes, - out packCRCs, - out folders, - out numUnpackStreamsInFolders, - out unpackSizes, - out digests); - - dataStartPos += baseOffset; - - var dataVector = new List(folders.Count); - int packIndex = 0; - foreach (var folder in folders) - { - long oldDataStartPos = dataStartPos; - long[] myPackSizes = new long[folder.PackStreams.Count]; - for (int i = 0; i < myPackSizes.Length; i++) - { - long packSize = packSizes[packIndex + i]; - myPackSizes[i] = packSize; - dataStartPos += packSize; - } - - var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes, - folder, pass); - - int unpackSize = checked((int)folder.GetUnpackSize()); - byte[] data = new byte[unpackSize]; - outStream.ReadExact(data, 0, data.Length); - if (outStream.ReadByte() >= 0) - throw new InvalidOperationException("Decoded stream is longer than expected."); - dataVector.Add(data); - - if (folder.UnpackCRCDefined) - if (CRC.Finish(CRC.Update(CRC.kInitCRC, data, 0, unpackSize)) != folder.UnpackCRC) - throw new InvalidOperationException("Decoded stream does not match expected CRC."); - } - return dataVector; - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) - { -#if DEBUG - Log.WriteLine("-- ReadHeader --"); - Log.PushIndent(); -#endif - try - { - BlockType? type = ReadId(); - - if (type == BlockType.ArchiveProperties) - { - ReadArchiveProperties(); - type = ReadId(); - } - - List dataVector = null; - if (type == BlockType.AdditionalStreamsInfo) - { - dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, getTextPassword); - type = ReadId(); - } - - List unpackSizes; - List digests; - - if (type == BlockType.MainStreamsInfo) - { - ReadStreamsInfo(dataVector, - out db.DataStartPosition, - out db.PackSizes, - out db.PackCRCs, - out db.Folders, - out db.NumUnpackStreamsVector, - out unpackSizes, - out digests); - - db.DataStartPosition += db.StartPositionAfterHeader; - type = ReadId(); - } - else - { - unpackSizes = new List(db.Folders.Count); - digests = new List(db.Folders.Count); - db.NumUnpackStreamsVector = new List(db.Folders.Count); - for (int i = 0; i < db.Folders.Count; i++) - { - var folder = db.Folders[i]; - unpackSizes.Add(folder.GetUnpackSize()); - digests.Add(folder.UnpackCRC); - db.NumUnpackStreamsVector.Add(1); - } - } - - db.Files.Clear(); - - if (type == BlockType.End) - return; - - if (type != BlockType.FilesInfo) - throw new InvalidOperationException(); - - int numFiles = ReadNum(); -#if DEBUG - Log.WriteLine("NumFiles: " + numFiles); -#endif - db.Files = new List(numFiles); - for (int i = 0; i < numFiles; i++) - db.Files.Add(new CFileItem()); - - BitVector emptyStreamVector = new BitVector(numFiles); - BitVector emptyFileVector = null; - BitVector antiFileVector = null; - int numEmptyStreams = 0; - - for (; ; ) - { - type = ReadId(); - if (type == BlockType.End) - break; - - long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative - int oldPos = _currentReader.Offset; - switch (type) - { - case BlockType.Name: - using (var streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); -#if DEBUG - Log.Write("FileNames:"); -#endif - for (int i = 0; i < db.Files.Count; i++) - { - db.Files[i].Name = _currentReader.ReadString(); -#if DEBUG - Log.Write(" " + db.Files[i].Name); -#endif - } -#if DEBUG - Log.WriteLine(); -#endif - } - break; - case BlockType.WinAttributes: -#if DEBUG - Log.Write("WinAttributes:"); -#endif - ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr) - { - db.Files[i].Attrib = attr; -#if DEBUG - Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")); -#endif - }); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.EmptyStream: - emptyStreamVector = ReadBitVector(numFiles); -#if DEBUG - - Log.Write("EmptyStream: "); -#endif - for (int i = 0; i < emptyStreamVector.Length; i++) - { - if (emptyStreamVector[i]) - { -#if DEBUG - Log.Write("x"); -#endif - numEmptyStreams++; - } - else - { -#if DEBUG - Log.Write("."); -#endif - } - } -#if DEBUG - Log.WriteLine(); -#endif - - emptyFileVector = new BitVector(numEmptyStreams); - antiFileVector = new BitVector(numEmptyStreams); - break; - case BlockType.EmptyFile: - emptyFileVector = ReadBitVector(numEmptyStreams); -#if DEBUG - Log.Write("EmptyFile: "); - for (int i = 0; i < numEmptyStreams; i++) - Log.Write(emptyFileVector[i] ? "x" : "."); - Log.WriteLine(); -#endif - break; - case BlockType.Anti: - antiFileVector = ReadBitVector(numEmptyStreams); -#if DEBUG - Log.Write("Anti: "); - for (int i = 0; i < numEmptyStreams; i++) - Log.Write(antiFileVector[i] ? "x" : "."); - Log.WriteLine(); -#endif - break; - case BlockType.StartPos: -#if DEBUG - Log.Write("StartPos:"); -#endif - ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos) - { - db.Files[i].StartPos = startPos; -#if DEBUG - Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")); -#endif - }); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.CTime: -#if DEBUG - Log.Write("CTime:"); -#endif - ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) - { - db.Files[i].CTime = time; -#if DEBUG - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); -#endif - }); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.ATime: -#if DEBUG - Log.Write("ATime:"); -#endif - ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) - { - db.Files[i].ATime = time; -#if DEBUG - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); -#endif - }); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.MTime: -#if DEBUG - Log.Write("MTime:"); -#endif - ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) - { - db.Files[i].MTime = time; -#if DEBUG - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); -#endif - }); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.Dummy: -#if DEBUG - Log.Write("Dummy: " + size); -#endif - for (long j = 0; j < size; j++) - if (ReadByte() != 0) - throw new InvalidOperationException(); - break; - default: - SkipData(size); - break; - } - - // since 0.3 record sizes must be correct - bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2); - if (checkRecordsSize && _currentReader.Offset - oldPos != size) - throw new InvalidOperationException(); - } - - int emptyFileIndex = 0; - int sizeIndex = 0; - for (int i = 0; i < numFiles; i++) - { - CFileItem file = db.Files[i]; - file.HasStream = !emptyStreamVector[i]; - if (file.HasStream) - { - file.IsDir = false; - file.IsAnti = false; - file.Size = unpackSizes[sizeIndex]; - file.Crc = digests[sizeIndex]; - sizeIndex++; - } - else - { - file.IsDir = !emptyFileVector[emptyFileIndex]; - file.IsAnti = antiFileVector[emptyFileIndex]; - emptyFileIndex++; - file.Size = 0; - file.Crc = null; - } - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - #endregion - - #region Public Methods - - public void Open(Stream stream) - { - Close(); - - _streamOrigin = stream.Position; - _streamEnding = stream.Length; - - // TODO: Check Signature! - _header = new byte[0x20]; - for (int offset = 0; offset < 0x20; ) - { - int delta = stream.Read(_header, offset, 0x20 - offset); - if (delta == 0) - throw new EndOfStreamException(); - offset += delta; - } - - _stream = stream; - } - - public void Close() - { - if (_stream != null) - _stream.Dispose(); - - foreach (var stream in _cachedStreams.Values) - stream.Dispose(); - - _cachedStreams.Clear(); - } - - public ArchiveDatabase ReadDatabase(IPasswordProvider pass) - { - var db = new ArchiveDatabase(); - db.Clear(); - - db.MajorVersion = _header[6]; - db.MinorVersion = _header[7]; - - if (db.MajorVersion != 0) - throw new InvalidOperationException(); - - uint crcFromArchive = DataReader.Get32(_header, 8); - long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); - long nextHeaderSize = (long)DataReader.Get64(_header, 0x14); - uint nextHeaderCrc = DataReader.Get32(_header, 0x1C); - - uint crc = CRC.kInitCRC; - crc = CRC.Update(crc, nextHeaderOffset); - crc = CRC.Update(crc, nextHeaderSize); - crc = CRC.Update(crc, nextHeaderCrc); - crc = CRC.Finish(crc); - - if (crc != crcFromArchive) - throw new InvalidOperationException(); - - db.StartPositionAfterHeader = _streamOrigin + 0x20; - - // empty header is ok - if (nextHeaderSize == 0) - { - db.Fill(); - return db; - } - - - if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue) - throw new InvalidOperationException(); - - if (nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader) - throw new IndexOutOfRangeException(); - - _stream.Seek(nextHeaderOffset, SeekOrigin.Current); - - byte[] header = new byte[nextHeaderSize]; - _stream.ReadExact(header, 0, header.Length); - - if (CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc) - throw new InvalidOperationException(); - - using (CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, header); - - BlockType? type = ReadId(); - if (type != BlockType.Header) - { - if (type != BlockType.EncodedHeader) - throw new InvalidOperationException(); - - var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass); - - // compressed header without content is odd but ok - if (dataVector.Count == 0) - { - db.Fill(); - return db; - } - - if (dataVector.Count != 1) - throw new InvalidOperationException(); - - streamSwitch.Set(this, dataVector[0]); - - if (ReadId() != BlockType.Header) - throw new InvalidOperationException(); - } - - ReadHeader(db, pass); - } - db.Fill(); - return db; - } - - internal class CExtractFolderInfo - { - internal int FileIndex; - internal int FolderIndex; - internal List ExtractStatuses = new List(); - - internal CExtractFolderInfo(int fileIndex, int folderIndex) - { - FileIndex = fileIndex; - FolderIndex = folderIndex; - if (fileIndex != -1) - ExtractStatuses.Add(true); - } - } - - private class FolderUnpackStream : Stream - { - private ArchiveDatabase _db; - private int _otherIndex; - private int _startIndex; - private List _extractStatuses; - - public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) - { - this._db = db; - this._otherIndex = p; - this._startIndex = startIndex; - this._extractStatuses = list; - } - - #region Stream - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - private Stream _stream; - private long _rem; - private int _currentIndex; - - private void ProcessEmptyFiles() - { - while (_currentIndex < _extractStatuses.Count && _db.Files[_startIndex + _currentIndex].Size == 0) - { - OpenFile(); - _stream.Dispose(); - _stream = null; - _currentIndex++; - } - } - - private void OpenFile() - { - bool skip = !_extractStatuses[_currentIndex]; - int index = _startIndex + _currentIndex; - int realIndex = _otherIndex + index; - //string filename = @"D:\_testdump\" + _db.Files[index].Name; - //Directory.CreateDirectory(Path.GetDirectoryName(filename)); - //_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete); -#if DEBUG - Log.WriteLine(_db.Files[index].Name); -#endif - if (_db.Files[index].CrcDefined) - _stream = new CrcCheckStream(_db.Files[index].Crc.Value); - else - _stream = new MemoryStream(); - _rem = _db.Files[index].Size; - } - - public override void Write(byte[] buffer, int offset, int count) - { - while (count != 0) - { - if (_stream != null) - { - int write = count; - if (write > _rem) - write = (int)_rem; - _stream.Write(buffer, offset, write); - count -= write; - _rem -= write; - offset += write; - if (_rem == 0) - { - _stream.Dispose(); - _stream = null; - _currentIndex++; - ProcessEmptyFiles(); - } - } - else - { - ProcessEmptyFiles(); - if (_currentIndex == _extractStatuses.Count) - { - // we support partial extracting - System.Diagnostics.Debugger.Break(); - throw new NotSupportedException(); - } - OpenFile(); - } - } - } - - #endregion - } - - private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw) - { - Stream s; - if (!_cachedStreams.TryGetValue(folderIndex, out s)) - { - CFolder folderInfo = _db.Folders[folderIndex]; - int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; - long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); - List packSizes = new List(); - for (int j = 0; j < folderInfo.PackStreams.Count; j++) - packSizes.Add(_db.PackSizes[packStreamIndex + j]); - - s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, - pw); - _cachedStreams.Add(folderIndex, s); - } - return s; - } - - public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw) - { - int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex]; - int firstFileIndex = _db.FolderStartFileIndex[folderIndex]; - if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) - throw new InvalidOperationException(); - - int skipCount = fileIndex - firstFileIndex; - long skipSize = 0; - for (int i = 0; i < skipCount; i++) - skipSize += _db.Files[firstFileIndex + i].Size; - - Stream s = GetCachedDecoderStream(_db, folderIndex, pw); - s.Position = skipSize; - return new ReadOnlySubStream(s, _db.Files[fileIndex].Size); - } - - public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw) - { - int numItems; - bool allFilesMode = (indices == null); - if (allFilesMode) - numItems = _db.Files.Count; - else - numItems = indices.Length; - - if (numItems == 0) - return; - - List extractFolderInfoVector = new List(); - for (int i = 0; i < numItems; i++) - { - int fileIndex = allFilesMode ? i : indices[i]; - - int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex == -1) - { - extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); - continue; - } - - if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex) - extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); - - CExtractFolderInfo efi = extractFolderInfoVector.Last(); - - int startIndex = _db.FolderStartFileIndex[folderIndex]; - for (int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++) - efi.ExtractStatuses.Add(index == fileIndex - startIndex); - } - - foreach (CExtractFolderInfo efi in extractFolderInfoVector) - { - int startIndex; - if (efi.FileIndex != -1) - startIndex = efi.FileIndex; - else - startIndex = _db.FolderStartFileIndex[efi.FolderIndex]; - - var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses); - - if (efi.FileIndex != -1) - continue; - - int folderIndex = efi.FolderIndex; - CFolder folderInfo = _db.Folders[folderIndex]; - - int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; - long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); - - List packSizes = new List(); - for (int j = 0; j < folderInfo.PackStreams.Count; j++) - packSizes.Add(_db.PackSizes[packStreamIndex + j]); - - // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? - - Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), - folderInfo, pw); - byte[] buffer = new byte[4 << 10]; - for (; ; ) - { - int processed = s.Read(buffer, 0, buffer.Length); - if (processed == 0) - break; - outStream.Write(buffer, 0, processed); - } - } - } - - public IEnumerable GetFiles(ArchiveDatabase db) - { - return db.Files; - } - - public int GetFileIndex(ArchiveDatabase db, CFileItem item) - { - return db.Files.IndexOf(item); - } - - #endregion - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Compressor.LZMA; +using SharpCompress.Compressor.LZMA.Utilites; +using SharpCompress.IO; + +namespace SharpCompress.Common.SevenZip +{ + internal class ArchiveReader + { + internal Stream _stream; + internal Stack _readerStack = new Stack(); + internal DataReader _currentReader; + internal long _streamOrigin; + internal long _streamEnding; + internal byte[] _header; + + private Dictionary _cachedStreams = new Dictionary(); + + internal void AddByteStream(byte[] buffer, int offset, int length) + { + _readerStack.Push(_currentReader); + _currentReader = new DataReader(buffer, offset, length); + } + + internal void DeleteByteStream() + { + _currentReader = _readerStack.Pop(); + } + + #region Private Methods - Data Reader + + internal Byte ReadByte() + { + return _currentReader.ReadByte(); + } + + private void ReadBytes(byte[] buffer, int offset, int length) + { + _currentReader.ReadBytes(buffer, offset, length); + } + + private ulong ReadNumber() + { + return _currentReader.ReadNumber(); + } + + internal int ReadNum() + { + return _currentReader.ReadNum(); + } + + private uint ReadUInt32() + { + return _currentReader.ReadUInt32(); + } + + private ulong ReadUInt64() + { + return _currentReader.ReadUInt64(); + } + + private BlockType? ReadId() + { + ulong id = _currentReader.ReadNumber(); + if (id > 25) + return null; +#if DEBUG + Log.WriteLine("ReadId: {0}", (BlockType)id); +#endif + return (BlockType)id; + } + + private void SkipData(long size) + { + _currentReader.SkipData(size); + } + + private void SkipData() + { + _currentReader.SkipData(); + } + + private void WaitAttribute(BlockType attribute) + { + for (; ; ) + { + BlockType? type = ReadId(); + if (type == attribute) + return; + if (type == BlockType.End) + throw new InvalidOperationException(); + SkipData(); + } + } + + private void ReadArchiveProperties() + { + while (ReadId() != BlockType.End) + SkipData(); + } + + #endregion + + #region Private Methods - Reader Utilities + + private BitVector ReadBitVector(int length) + { + var bits = new BitVector(length); + + byte data = 0; + byte mask = 0; + + for (int i = 0; i < length; i++) + { + if (mask == 0) + { + data = ReadByte(); + mask = 0x80; + } + + if ((data & mask) != 0) + bits.SetBit(i); + + mask >>= 1; + } + + return bits; + } + + private BitVector ReadOptionalBitVector(int length) + { + byte allTrue = ReadByte(); + if (allTrue != 0) + return new BitVector(length, true); + + return ReadBitVector(length); + } + + private void ReadNumberVector(List dataVector, int numFiles, Action action) + { + var defined = ReadOptionalBitVector(numFiles); + + using (CStreamSwitch streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); + + for (int i = 0; i < numFiles; i++) + { + if (defined[i]) + action(i, checked((long)ReadUInt64())); + else + action(i, null); + } + } + } + + private DateTime TranslateTime(long time) + { + // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) + return DateTime.FromFileTimeUtc(time).ToLocalTime(); + } + + private DateTime? TranslateTime(long? time) + { + if (time.HasValue) + return TranslateTime(time.Value); + else + return null; + } + + private void ReadDateTimeVector(List dataVector, int numFiles, Action action) + { + ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value))); + } + + private void ReadAttributeVector(List dataVector, int numFiles, Action action) + { + BitVector boolVector = ReadOptionalBitVector(numFiles); + using (var streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); + for (int i = 0; i < numFiles; i++) + { + if (boolVector[i]) + action(i, ReadUInt32()); + else + action(i, null); + } + } + } + + #endregion + + #region Private Methods + + private void GetNextFolderItem(CFolder folder) + { +#if DEBUG + Log.WriteLine("-- GetNextFolderItem --"); + Log.PushIndent(); +#endif + try + { + int numCoders = ReadNum(); +#if DEBUG + Log.WriteLine("NumCoders: " + numCoders); +#endif + folder.Coders = new List(numCoders); + int numInStreams = 0; + int numOutStreams = 0; + for (int i = 0; i < numCoders; i++) + { +#if DEBUG + Log.WriteLine("-- Coder --"); + Log.PushIndent(); +#endif + try + { + CCoderInfo coder = new CCoderInfo(); + folder.Coders.Add(coder); + + byte mainByte = ReadByte(); + int idSize = (mainByte & 0xF); + byte[] longID = new byte[idSize]; + ReadBytes(longID, 0, idSize); +#if DEBUG + Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray())); +#endif + if (idSize > 8) + throw new NotSupportedException(); + ulong id = 0; + for (int j = 0; j < idSize; j++) + id |= (ulong)longID[idSize - 1 - j] << (8 * j); + coder.MethodId = new CMethodId(id); + + if ((mainByte & 0x10) != 0) + { + coder.NumInStreams = ReadNum(); + coder.NumOutStreams = ReadNum(); +#if DEBUG + Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")"); +#endif + } + else + { +#if DEBUG + Log.WriteLine("Simple Stream (In: 1 - Out: 1)"); +#endif + coder.NumInStreams = 1; + coder.NumOutStreams = 1; + } + + if ((mainByte & 0x20) != 0) + { + int propsSize = ReadNum(); + coder.Props = new byte[propsSize]; + ReadBytes(coder.Props, 0, propsSize); +#if DEBUG + Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray())); +#endif + } + + if ((mainByte & 0x80) != 0) + throw new NotSupportedException(); + + numInStreams += coder.NumInStreams; + numOutStreams += coder.NumOutStreams; + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + int numBindPairs = numOutStreams - 1; + folder.BindPairs = new List(numBindPairs); +#if DEBUG + Log.WriteLine("BindPairs: " + numBindPairs); + Log.PushIndent(); +#endif + for (int i = 0; i < numBindPairs; i++) + { + CBindPair bp = new CBindPair(); + bp.InIndex = ReadNum(); + bp.OutIndex = ReadNum(); + folder.BindPairs.Add(bp); +#if DEBUG + Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex); +#endif + } +#if DEBUG + Log.PopIndent(); +#endif + + if (numInStreams < numBindPairs) + throw new NotSupportedException(); + + int numPackStreams = numInStreams - numBindPairs; + //folder.PackStreams.Reserve(numPackStreams); + if (numPackStreams == 1) + { + for (int i = 0; i < numInStreams; i++) + { + if (folder.FindBindPairForInStream(i) < 0) + { +#if DEBUG + Log.WriteLine("Single PackStream: #" + i); +#endif + folder.PackStreams.Add(i); + break; + } + } + + if (folder.PackStreams.Count != 1) + throw new NotSupportedException(); + } + else + { +#if DEBUG + Log.WriteLine("Multiple PackStreams ..."); + Log.PushIndent(); +#endif + for (int i = 0; i < numPackStreams; i++) + { + var num = ReadNum(); +#if DEBUG + Log.WriteLine("#" + i + " - " + num); +#endif + folder.PackStreams.Add(num); + } +#if DEBUG + Log.PopIndent(); +#endif + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private List ReadHashDigests(int count) + { +#if DEBUG + Log.Write("ReadHashDigests:"); +#endif + + var defined = ReadOptionalBitVector(count); + var digests = new List(count); + for (int i = 0; i < count; i++) + { + if (defined[i]) + { + uint crc = ReadUInt32(); +#if DEBUG + Log.Write(" " + crc.ToString("x8")); +#endif + digests.Add(crc); + } + else + { +#if DEBUG + Log.Write(" ########"); +#endif + digests.Add(null); + } + } +#if DEBUG + + Log.WriteLine(); +#endif + return digests; + } + + private void ReadPackInfo(out long dataOffset, out List packSizes, out List packCRCs) + { +#if DEBUG + Log.WriteLine("-- ReadPackInfo --"); + Log.PushIndent(); +#endif + try + { + packCRCs = null; + + dataOffset = checked((long)ReadNumber()); +#if DEBUG + Log.WriteLine("DataOffset: " + dataOffset); +#endif + + int numPackStreams = ReadNum(); +#if DEBUG + Log.WriteLine("NumPackStreams: " + numPackStreams); +#endif + + WaitAttribute(BlockType.Size); + packSizes = new List(numPackStreams); +#if DEBUG + Log.Write("Sizes:"); +#endif + for (int i = 0; i < numPackStreams; i++) + { + var size = checked((long)ReadNumber()); +#if DEBUG + Log.Write(" " + size); +#endif + packSizes.Add(size); + } +#if DEBUG + Log.WriteLine(); +#endif + + BlockType? type; + for (; ; ) + { + type = ReadId(); + if (type == BlockType.End) + break; + if (type == BlockType.CRC) + { + packCRCs = ReadHashDigests(numPackStreams); + continue; + } + SkipData(); + } + + if (packCRCs == null) + { + packCRCs = new List(numPackStreams); + for (int i = 0; i < numPackStreams; i++) + packCRCs.Add(null); + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private void ReadUnpackInfo(List dataVector, out List folders) + { +#if DEBUG + Log.WriteLine("-- ReadUnpackInfo --"); + Log.PushIndent(); +#endif + try + { + WaitAttribute(BlockType.Folder); + int numFolders = ReadNum(); +#if DEBUG + Log.WriteLine("NumFolders: {0}", numFolders); +#endif + + using (CStreamSwitch streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); + //folders.Clear(); + //folders.Reserve(numFolders); + folders = new List(numFolders); + int index = 0; + for (int i = 0; i < numFolders; i++) + { + var f = new CFolder { FirstPackStreamId = index }; + folders.Add(f); + GetNextFolderItem(f); + index += f.PackStreams.Count; + } + } + + WaitAttribute(BlockType.CodersUnpackSize); +#if DEBUG + Log.WriteLine("UnpackSizes:"); +#endif + for (int i = 0; i < numFolders; i++) + { + CFolder folder = folders[i]; +#if DEBUG + Log.Write(" #" + i + ":"); +#endif + int numOutStreams = folder.GetNumOutStreams(); + for (int j = 0; j < numOutStreams; j++) + { + long size = checked((long)ReadNumber()); +#if DEBUG + Log.Write(" " + size); +#endif + folder.UnpackSizes.Add(size); + } +#if DEBUG + Log.WriteLine(); +#endif + } + + for (; ; ) + { + BlockType? type = ReadId(); + if (type == BlockType.End) + return; + + if (type == BlockType.CRC) + { + List crcs = ReadHashDigests(numFolders); + for (int i = 0; i < numFolders; i++) + folders[i].UnpackCRC = crcs[i]; + continue; + } + + SkipData(); + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private void ReadSubStreamsInfo(List folders, out List numUnpackStreamsInFolders, + out List unpackSizes, out List digests) + { +#if DEBUG + Log.WriteLine("-- ReadSubStreamsInfo --"); + Log.PushIndent(); +#endif + try + { + numUnpackStreamsInFolders = null; + + BlockType? type; + for (; ; ) + { + type = ReadId(); + if (type == BlockType.NumUnpackStream) + { + numUnpackStreamsInFolders = new List(folders.Count); +#if DEBUG + Log.Write("NumUnpackStreams:"); +#endif + for (int i = 0; i < folders.Count; i++) + { + var num = ReadNum(); +#if DEBUG + Log.Write(" " + num); +#endif + numUnpackStreamsInFolders.Add(num); + } +#if DEBUG + Log.WriteLine(); +#endif + continue; + } + if (type == BlockType.CRC || type == BlockType.Size) + break; + if (type == BlockType.End) + break; + SkipData(); + } + + if (numUnpackStreamsInFolders == null) + { + numUnpackStreamsInFolders = new List(folders.Count); + for (int i = 0; i < folders.Count; i++) + numUnpackStreamsInFolders.Add(1); + } + + unpackSizes = new List(folders.Count); + for (int i = 0; i < numUnpackStreamsInFolders.Count; i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + int numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams == 0) + continue; +#if DEBUG + Log.Write("#{0} StreamSizes:", i); +#endif + long sum = 0; + for (int j = 1; j < numSubstreams; j++) + { + if (type == BlockType.Size) + { + long size = checked((long)ReadNumber()); +#if DEBUG + Log.Write(" " + size); +#endif + unpackSizes.Add(size); + sum += size; + } + } + unpackSizes.Add(folders[i].GetUnpackSize() - sum); +#if DEBUG + Log.WriteLine(" - rest: " + unpackSizes.Last()); +#endif + } + if (type == BlockType.Size) + type = ReadId(); + + int numDigests = 0; + int numDigestsTotal = 0; + for (int i = 0; i < folders.Count; i++) + { + int numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) + numDigests += numSubstreams; + numDigestsTotal += numSubstreams; + } + + digests = null; + + for (; ; ) + { + if (type == BlockType.CRC) + { + digests = new List(numDigestsTotal); + + List digests2 = ReadHashDigests(numDigests); + + int digestIndex = 0; + for (int i = 0; i < folders.Count; i++) + { + int numSubstreams = numUnpackStreamsInFolders[i]; + CFolder folder = folders[i]; + if (numSubstreams == 1 && folder.UnpackCRCDefined) + { + digests.Add(folder.UnpackCRC.Value); + } + else + { + for (int j = 0; j < numSubstreams; j++, digestIndex++) + digests.Add(digests2[digestIndex]); + } + } + + if (digestIndex != numDigests || numDigestsTotal != digests.Count) + System.Diagnostics.Debugger.Break(); + } + else if (type == BlockType.End) + { + if (digests == null) + { + digests = new List(numDigestsTotal); + for (int i = 0; i < numDigestsTotal; i++) + digests.Add(null); + } + return; + } + else + { + SkipData(); + } + + type = ReadId(); + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private void ReadStreamsInfo( + List dataVector, + out long dataOffset, + out List packSizes, + out List packCRCs, + out List folders, + out List numUnpackStreamsInFolders, + out List unpackSizes, + out List digests) + { +#if DEBUG + Log.WriteLine("-- ReadStreamsInfo --"); + Log.PushIndent(); +#endif + try + { + dataOffset = long.MinValue; + packSizes = null; + packCRCs = null; + folders = null; + numUnpackStreamsInFolders = null; + unpackSizes = null; + digests = null; + + for (; ; ) + { + switch (ReadId()) + { + case BlockType.End: + return; + case BlockType.PackInfo: + ReadPackInfo(out dataOffset, out packSizes, out packCRCs); + break; + case BlockType.UnpackInfo: + ReadUnpackInfo(dataVector, out folders); + break; + case BlockType.SubStreamsInfo: + ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests); + break; + default: + throw new InvalidOperationException(); + } + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) + { +#if DEBUG + Log.WriteLine("-- ReadAndDecodePackedStreams --"); + Log.PushIndent(); +#endif + try + { + long dataStartPos; + List packSizes; + List packCRCs; + List folders; + List numUnpackStreamsInFolders; + List unpackSizes; + List digests; + + ReadStreamsInfo(null, + out dataStartPos, + out packSizes, + out packCRCs, + out folders, + out numUnpackStreamsInFolders, + out unpackSizes, + out digests); + + dataStartPos += baseOffset; + + var dataVector = new List(folders.Count); + int packIndex = 0; + foreach (var folder in folders) + { + long oldDataStartPos = dataStartPos; + long[] myPackSizes = new long[folder.PackStreams.Count]; + for (int i = 0; i < myPackSizes.Length; i++) + { + long packSize = packSizes[packIndex + i]; + myPackSizes[i] = packSize; + dataStartPos += packSize; + } + + var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes, + folder, pass); + + int unpackSize = checked((int)folder.GetUnpackSize()); + byte[] data = new byte[unpackSize]; + outStream.ReadExact(data, 0, data.Length); + if (outStream.ReadByte() >= 0) + throw new InvalidOperationException("Decoded stream is longer than expected."); + dataVector.Add(data); + + if (folder.UnpackCRCDefined) + if (CRC.Finish(CRC.Update(CRC.kInitCRC, data, 0, unpackSize)) != folder.UnpackCRC) + throw new InvalidOperationException("Decoded stream does not match expected CRC."); + } + return dataVector; + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) + { +#if DEBUG + Log.WriteLine("-- ReadHeader --"); + Log.PushIndent(); +#endif + try + { + BlockType? type = ReadId(); + + if (type == BlockType.ArchiveProperties) + { + ReadArchiveProperties(); + type = ReadId(); + } + + List dataVector = null; + if (type == BlockType.AdditionalStreamsInfo) + { + dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, getTextPassword); + type = ReadId(); + } + + List unpackSizes; + List digests; + + if (type == BlockType.MainStreamsInfo) + { + ReadStreamsInfo(dataVector, + out db.DataStartPosition, + out db.PackSizes, + out db.PackCRCs, + out db.Folders, + out db.NumUnpackStreamsVector, + out unpackSizes, + out digests); + + db.DataStartPosition += db.StartPositionAfterHeader; + type = ReadId(); + } + else + { + unpackSizes = new List(db.Folders.Count); + digests = new List(db.Folders.Count); + db.NumUnpackStreamsVector = new List(db.Folders.Count); + for (int i = 0; i < db.Folders.Count; i++) + { + var folder = db.Folders[i]; + unpackSizes.Add(folder.GetUnpackSize()); + digests.Add(folder.UnpackCRC); + db.NumUnpackStreamsVector.Add(1); + } + } + + db.Files.Clear(); + + if (type == BlockType.End) + return; + + if (type != BlockType.FilesInfo) + throw new InvalidOperationException(); + + int numFiles = ReadNum(); +#if DEBUG + Log.WriteLine("NumFiles: " + numFiles); +#endif + db.Files = new List(numFiles); + for (int i = 0; i < numFiles; i++) + db.Files.Add(new CFileItem()); + + BitVector emptyStreamVector = new BitVector(numFiles); + BitVector emptyFileVector = null; + BitVector antiFileVector = null; + int numEmptyStreams = 0; + + for (; ; ) + { + type = ReadId(); + if (type == BlockType.End) + break; + + long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative + int oldPos = _currentReader.Offset; + switch (type) + { + case BlockType.Name: + using (var streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); +#if DEBUG + Log.Write("FileNames:"); +#endif + for (int i = 0; i < db.Files.Count; i++) + { + db.Files[i].Name = _currentReader.ReadString(); +#if DEBUG + Log.Write(" " + db.Files[i].Name); +#endif + } +#if DEBUG + Log.WriteLine(); +#endif + } + break; + case BlockType.WinAttributes: +#if DEBUG + Log.Write("WinAttributes:"); +#endif + ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr) + { + db.Files[i].Attrib = attr; +#if DEBUG + Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")); +#endif + }); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.EmptyStream: + emptyStreamVector = ReadBitVector(numFiles); +#if DEBUG + + Log.Write("EmptyStream: "); +#endif + for (int i = 0; i < emptyStreamVector.Length; i++) + { + if (emptyStreamVector[i]) + { +#if DEBUG + Log.Write("x"); +#endif + numEmptyStreams++; + } + else + { +#if DEBUG + Log.Write("."); +#endif + } + } +#if DEBUG + Log.WriteLine(); +#endif + + emptyFileVector = new BitVector(numEmptyStreams); + antiFileVector = new BitVector(numEmptyStreams); + break; + case BlockType.EmptyFile: + emptyFileVector = ReadBitVector(numEmptyStreams); +#if DEBUG + Log.Write("EmptyFile: "); + for (int i = 0; i < numEmptyStreams; i++) + Log.Write(emptyFileVector[i] ? "x" : "."); + Log.WriteLine(); +#endif + break; + case BlockType.Anti: + antiFileVector = ReadBitVector(numEmptyStreams); +#if DEBUG + Log.Write("Anti: "); + for (int i = 0; i < numEmptyStreams; i++) + Log.Write(antiFileVector[i] ? "x" : "."); + Log.WriteLine(); +#endif + break; + case BlockType.StartPos: +#if DEBUG + Log.Write("StartPos:"); +#endif + ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos) + { + db.Files[i].StartPos = startPos; +#if DEBUG + Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")); +#endif + }); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.CTime: +#if DEBUG + Log.Write("CTime:"); +#endif + ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) + { + db.Files[i].CTime = time; +#if DEBUG + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); +#endif + }); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.ATime: +#if DEBUG + Log.Write("ATime:"); +#endif + ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) + { + db.Files[i].ATime = time; +#if DEBUG + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); +#endif + }); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.MTime: +#if DEBUG + Log.Write("MTime:"); +#endif + ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time) + { + db.Files[i].MTime = time; +#if DEBUG + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); +#endif + }); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.Dummy: +#if DEBUG + Log.Write("Dummy: " + size); +#endif + for (long j = 0; j < size; j++) + if (ReadByte() != 0) + throw new InvalidOperationException(); + break; + default: + SkipData(size); + break; + } + + // since 0.3 record sizes must be correct + bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2); + if (checkRecordsSize && _currentReader.Offset - oldPos != size) + throw new InvalidOperationException(); + } + + int emptyFileIndex = 0; + int sizeIndex = 0; + for (int i = 0; i < numFiles; i++) + { + CFileItem file = db.Files[i]; + file.HasStream = !emptyStreamVector[i]; + if (file.HasStream) + { + file.IsDir = false; + file.IsAnti = false; + file.Size = unpackSizes[sizeIndex]; + file.Crc = digests[sizeIndex]; + sizeIndex++; + } + else + { + file.IsDir = !emptyFileVector[emptyFileIndex]; + file.IsAnti = antiFileVector[emptyFileIndex]; + emptyFileIndex++; + file.Size = 0; + file.Crc = null; + } + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + #endregion + + #region Public Methods + + public void Open(Stream stream) + { + Close(); + + _streamOrigin = stream.Position; + _streamEnding = stream.Length; + + // TODO: Check Signature! + _header = new byte[0x20]; + for (int offset = 0; offset < 0x20; ) + { + int delta = stream.Read(_header, offset, 0x20 - offset); + if (delta == 0) + throw new EndOfStreamException(); + offset += delta; + } + + _stream = stream; + } + + public void Close() + { + if (_stream != null) + _stream.Dispose(); + + foreach (var stream in _cachedStreams.Values) + stream.Dispose(); + + _cachedStreams.Clear(); + } + + public ArchiveDatabase ReadDatabase(IPasswordProvider pass) + { + var db = new ArchiveDatabase(); + db.Clear(); + + db.MajorVersion = _header[6]; + db.MinorVersion = _header[7]; + + if (db.MajorVersion != 0) + throw new InvalidOperationException(); + + uint crcFromArchive = DataReader.Get32(_header, 8); + long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); + long nextHeaderSize = (long)DataReader.Get64(_header, 0x14); + uint nextHeaderCrc = DataReader.Get32(_header, 0x1C); + + uint crc = CRC.kInitCRC; + crc = CRC.Update(crc, nextHeaderOffset); + crc = CRC.Update(crc, nextHeaderSize); + crc = CRC.Update(crc, nextHeaderCrc); + crc = CRC.Finish(crc); + + if (crc != crcFromArchive) + throw new InvalidOperationException(); + + db.StartPositionAfterHeader = _streamOrigin + 0x20; + + // empty header is ok + if (nextHeaderSize == 0) + { + db.Fill(); + return db; + } + + + if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue) + throw new InvalidOperationException(); + + if (nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader) + throw new IndexOutOfRangeException(); + + _stream.Seek(nextHeaderOffset, SeekOrigin.Current); + + byte[] header = new byte[nextHeaderSize]; + _stream.ReadExact(header, 0, header.Length); + + if (CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc) + throw new InvalidOperationException(); + + using (CStreamSwitch streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, header); + + BlockType? type = ReadId(); + if (type != BlockType.Header) + { + if (type != BlockType.EncodedHeader) + throw new InvalidOperationException(); + + var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass); + + // compressed header without content is odd but ok + if (dataVector.Count == 0) + { + db.Fill(); + return db; + } + + if (dataVector.Count != 1) + throw new InvalidOperationException(); + + streamSwitch.Set(this, dataVector[0]); + + if (ReadId() != BlockType.Header) + throw new InvalidOperationException(); + } + + ReadHeader(db, pass); + } + db.Fill(); + return db; + } + + internal class CExtractFolderInfo + { + internal int FileIndex; + internal int FolderIndex; + internal List ExtractStatuses = new List(); + + internal CExtractFolderInfo(int fileIndex, int folderIndex) + { + FileIndex = fileIndex; + FolderIndex = folderIndex; + if (fileIndex != -1) + ExtractStatuses.Add(true); + } + } + + private class FolderUnpackStream : Stream + { + private ArchiveDatabase _db; + private int _otherIndex; + private int _startIndex; + private List _extractStatuses; + + public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) + { + this._db = db; + this._otherIndex = p; + this._startIndex = startIndex; + this._extractStatuses = list; + } + + #region Stream + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + private Stream _stream; + private long _rem; + private int _currentIndex; + + private void ProcessEmptyFiles() + { + while (_currentIndex < _extractStatuses.Count && _db.Files[_startIndex + _currentIndex].Size == 0) + { + OpenFile(); + _stream.Dispose(); + _stream = null; + _currentIndex++; + } + } + + private void OpenFile() + { + bool skip = !_extractStatuses[_currentIndex]; + int index = _startIndex + _currentIndex; + int realIndex = _otherIndex + index; + //string filename = @"D:\_testdump\" + _db.Files[index].Name; + //Directory.CreateDirectory(Path.GetDirectoryName(filename)); + //_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete); +#if DEBUG + Log.WriteLine(_db.Files[index].Name); +#endif + if (_db.Files[index].CrcDefined) + _stream = new CrcCheckStream(_db.Files[index].Crc.Value); + else + _stream = new MemoryStream(); + _rem = _db.Files[index].Size; + } + + public override void Write(byte[] buffer, int offset, int count) + { + while (count != 0) + { + if (_stream != null) + { + int write = count; + if (write > _rem) + write = (int)_rem; + _stream.Write(buffer, offset, write); + count -= write; + _rem -= write; + offset += write; + if (_rem == 0) + { + _stream.Dispose(); + _stream = null; + _currentIndex++; + ProcessEmptyFiles(); + } + } + else + { + ProcessEmptyFiles(); + if (_currentIndex == _extractStatuses.Count) + { + // we support partial extracting + System.Diagnostics.Debugger.Break(); + throw new NotSupportedException(); + } + OpenFile(); + } + } + } + + #endregion + } + + private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw) + { + Stream s; + if (!_cachedStreams.TryGetValue(folderIndex, out s)) + { + CFolder folderInfo = _db.Folders[folderIndex]; + int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; + long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); + List packSizes = new List(); + for (int j = 0; j < folderInfo.PackStreams.Count; j++) + packSizes.Add(_db.PackSizes[packStreamIndex + j]); + + s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo, + pw); + _cachedStreams.Add(folderIndex, s); + } + return s; + } + + public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw) + { + int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; + int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex]; + int firstFileIndex = _db.FolderStartFileIndex[folderIndex]; + if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) + throw new InvalidOperationException(); + + int skipCount = fileIndex - firstFileIndex; + long skipSize = 0; + for (int i = 0; i < skipCount; i++) + skipSize += _db.Files[firstFileIndex + i].Size; + + Stream s = GetCachedDecoderStream(_db, folderIndex, pw); + s.Position = skipSize; + return new ReadOnlySubStream(s, _db.Files[fileIndex].Size); + } + + public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw) + { + int numItems; + bool allFilesMode = (indices == null); + if (allFilesMode) + numItems = _db.Files.Count; + else + numItems = indices.Length; + + if (numItems == 0) + return; + + List extractFolderInfoVector = new List(); + for (int i = 0; i < numItems; i++) + { + int fileIndex = allFilesMode ? i : indices[i]; + + int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex == -1) + { + extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); + continue; + } + + if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex) + extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); + + CExtractFolderInfo efi = extractFolderInfoVector.Last(); + + int startIndex = _db.FolderStartFileIndex[folderIndex]; + for (int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++) + efi.ExtractStatuses.Add(index == fileIndex - startIndex); + } + + foreach (CExtractFolderInfo efi in extractFolderInfoVector) + { + int startIndex; + if (efi.FileIndex != -1) + startIndex = efi.FileIndex; + else + startIndex = _db.FolderStartFileIndex[efi.FolderIndex]; + + var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses); + + if (efi.FileIndex != -1) + continue; + + int folderIndex = efi.FolderIndex; + CFolder folderInfo = _db.Folders[folderIndex]; + + int packStreamIndex = _db.Folders[folderIndex].FirstPackStreamId; + long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0); + + List packSizes = new List(); + for (int j = 0; j < folderInfo.PackStreams.Count; j++) + packSizes.Add(_db.PackSizes[packStreamIndex + j]); + + // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? + + Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), + folderInfo, pw); + byte[] buffer = new byte[4 << 10]; + for (; ; ) + { + int processed = s.Read(buffer, 0, buffer.Length); + if (processed == 0) + break; + outStream.Write(buffer, 0, processed); + } + } + } + + public IEnumerable GetFiles(ArchiveDatabase db) + { + return db.Files; + } + + public int GetFileIndex(ArchiveDatabase db, CFileItem item) + { + return db.Files.IndexOf(item); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CBindPair.cs b/src/SharpCompress/Common/SevenZip/CBindPair.cs similarity index 95% rename from SharpCompress/Common/SevenZip/CBindPair.cs rename to src/SharpCompress/Common/SevenZip/CBindPair.cs index 6956ef6f..ca52cdbe 100644 --- a/SharpCompress/Common/SevenZip/CBindPair.cs +++ b/src/SharpCompress/Common/SevenZip/CBindPair.cs @@ -1,8 +1,8 @@ -namespace SharpCompress.Common.SevenZip -{ - internal class CBindPair - { - internal int InIndex; - internal int OutIndex; - } +namespace SharpCompress.Common.SevenZip +{ + internal class CBindPair + { + internal int InIndex; + internal int OutIndex; + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CCoderInfo.cs b/src/SharpCompress/Common/SevenZip/CCoderInfo.cs similarity index 96% rename from SharpCompress/Common/SevenZip/CCoderInfo.cs rename to src/SharpCompress/Common/SevenZip/CCoderInfo.cs index abe11ae4..75ae4781 100644 --- a/SharpCompress/Common/SevenZip/CCoderInfo.cs +++ b/src/SharpCompress/Common/SevenZip/CCoderInfo.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Common.SevenZip -{ - internal class CCoderInfo - { - internal CMethodId MethodId; - internal byte[] Props; - internal int NumInStreams; - internal int NumOutStreams; - } +namespace SharpCompress.Common.SevenZip +{ + internal class CCoderInfo + { + internal CMethodId MethodId; + internal byte[] Props; + internal int NumInStreams; + internal int NumOutStreams; + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CFileItem.cs b/src/SharpCompress/Common/SevenZip/CFileItem.cs similarity index 96% rename from SharpCompress/Common/SevenZip/CFileItem.cs rename to src/SharpCompress/Common/SevenZip/CFileItem.cs index 92d72354..8c19d984 100644 --- a/SharpCompress/Common/SevenZip/CFileItem.cs +++ b/src/SharpCompress/Common/SevenZip/CFileItem.cs @@ -1,42 +1,42 @@ -using System; - -namespace SharpCompress.Common.SevenZip -{ - internal class CFileItem - { - public long Size { get; internal set; } - public uint? Attrib { get; internal set; } - public uint? Crc { get; internal set; } - public string Name { get; internal set; } - - public bool HasStream { get; internal set; } - public bool IsDir { get; internal set; } - - public bool CrcDefined - { - get { return Crc != null; } - } - - public bool AttribDefined - { - get { return Attrib != null; } - } - - public void SetAttrib(uint attrib) - { - this.Attrib = attrib; - } - - public DateTime? CTime { get; internal set; } - public DateTime? ATime { get; internal set; } - public DateTime? MTime { get; internal set; } - - public long? StartPos { get; internal set; } - public bool IsAnti { get; internal set; } - - internal CFileItem() - { - HasStream = true; - } - } +using System; + +namespace SharpCompress.Common.SevenZip +{ + internal class CFileItem + { + public long Size { get; internal set; } + public uint? Attrib { get; internal set; } + public uint? Crc { get; internal set; } + public string Name { get; internal set; } + + public bool HasStream { get; internal set; } + public bool IsDir { get; internal set; } + + public bool CrcDefined + { + get { return Crc != null; } + } + + public bool AttribDefined + { + get { return Attrib != null; } + } + + public void SetAttrib(uint attrib) + { + this.Attrib = attrib; + } + + public DateTime? CTime { get; internal set; } + public DateTime? ATime { get; internal set; } + public DateTime? MTime { get; internal set; } + + public long? StartPos { get; internal set; } + public bool IsAnti { get; internal set; } + + internal CFileItem() + { + HasStream = true; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CFolder.cs b/src/SharpCompress/Common/SevenZip/CFolder.cs similarity index 96% rename from SharpCompress/Common/SevenZip/CFolder.cs rename to src/SharpCompress/Common/SevenZip/CFolder.cs index c83bc4df..de0a19e7 100644 --- a/SharpCompress/Common/SevenZip/CFolder.cs +++ b/src/SharpCompress/Common/SevenZip/CFolder.cs @@ -1,139 +1,139 @@ -using System; -using System.Collections.Generic; -using SharpCompress.Compressor.LZMA; - -namespace SharpCompress.Common.SevenZip -{ - internal class CFolder - { - internal List Coders = new List(); - internal List BindPairs = new List(); - internal List PackStreams = new List(); - internal int FirstPackStreamId; - internal List UnpackSizes = new List(); - internal uint? UnpackCRC; - - internal bool UnpackCRCDefined - { - get { return UnpackCRC != null; } - } - - public long GetUnpackSize() - { - if (UnpackSizes.Count == 0) - return 0; - - for (int i = UnpackSizes.Count - 1; i >= 0; i--) - if (FindBindPairForOutStream(i) < 0) - return UnpackSizes[i]; - - throw new Exception(); - } - - public int GetNumOutStreams() - { - int count = 0; - for (int i = 0; i < Coders.Count; i++) - count += Coders[i].NumOutStreams; - - return count; - } - - public int FindBindPairForInStream(int inStreamIndex) - { - for (int i = 0; i < BindPairs.Count; i++) - if (BindPairs[i].InIndex == inStreamIndex) - return i; - - return -1; - } - - public int FindBindPairForOutStream(int outStreamIndex) - { - for (int i = 0; i < BindPairs.Count; i++) - if (BindPairs[i].OutIndex == outStreamIndex) - return i; - - return -1; - } - - public int FindPackStreamArrayIndex(int inStreamIndex) - { - for (int i = 0; i < PackStreams.Count; i++) - if (PackStreams[i] == inStreamIndex) - return i; - - return -1; - } - - public bool IsEncrypted() - { - for (int i = Coders.Count - 1; i >= 0; i--) - if (Coders[i].MethodId == CMethodId.kAES) - return true; - - return false; - } - - public bool CheckStructure() - { - const int kNumCodersMax = 32; // don't change it - const int kMaskSize = 32; // it must be >= kNumCodersMax - const int kNumBindsMax = 32; - - if (Coders.Count > kNumCodersMax || BindPairs.Count > kNumBindsMax) - return false; - - { - var v = new BitVector(BindPairs.Count + PackStreams.Count); - - for (int i = 0; i < BindPairs.Count; i++) - if (v.GetAndSet(BindPairs[i].InIndex)) - return false; - - for (int i = 0; i < PackStreams.Count; i++) - if (v.GetAndSet(PackStreams[i])) - return false; - } - - { - var v = new BitVector(UnpackSizes.Count); - for (int i = 0; i < BindPairs.Count; i++) - if (v.GetAndSet(BindPairs[i].OutIndex)) - return false; - } - - uint[] mask = new uint[kMaskSize]; - - { - List inStreamToCoder = new List(); - List outStreamToCoder = new List(); - for (int i = 0; i < Coders.Count; i++) - { - CCoderInfo coder = Coders[i]; - for (int j = 0; j < coder.NumInStreams; j++) - inStreamToCoder.Add(i); - for (int j = 0; j < coder.NumOutStreams; j++) - outStreamToCoder.Add(i); - } - - for (int i = 0; i < BindPairs.Count; i++) - { - CBindPair bp = BindPairs[i]; - mask[inStreamToCoder[bp.InIndex]] |= (1u << outStreamToCoder[bp.OutIndex]); - } - } - - for (int i = 0; i < kMaskSize; i++) - for (int j = 0; j < kMaskSize; j++) - if (((1u << j) & mask[i]) != 0) - mask[i] |= mask[j]; - - for (int i = 0; i < kMaskSize; i++) - if (((1u << i) & mask[i]) != 0) - return false; - - return true; - } - } +using System; +using System.Collections.Generic; +using SharpCompress.Compressor.LZMA; + +namespace SharpCompress.Common.SevenZip +{ + internal class CFolder + { + internal List Coders = new List(); + internal List BindPairs = new List(); + internal List PackStreams = new List(); + internal int FirstPackStreamId; + internal List UnpackSizes = new List(); + internal uint? UnpackCRC; + + internal bool UnpackCRCDefined + { + get { return UnpackCRC != null; } + } + + public long GetUnpackSize() + { + if (UnpackSizes.Count == 0) + return 0; + + for (int i = UnpackSizes.Count - 1; i >= 0; i--) + if (FindBindPairForOutStream(i) < 0) + return UnpackSizes[i]; + + throw new Exception(); + } + + public int GetNumOutStreams() + { + int count = 0; + for (int i = 0; i < Coders.Count; i++) + count += Coders[i].NumOutStreams; + + return count; + } + + public int FindBindPairForInStream(int inStreamIndex) + { + for (int i = 0; i < BindPairs.Count; i++) + if (BindPairs[i].InIndex == inStreamIndex) + return i; + + return -1; + } + + public int FindBindPairForOutStream(int outStreamIndex) + { + for (int i = 0; i < BindPairs.Count; i++) + if (BindPairs[i].OutIndex == outStreamIndex) + return i; + + return -1; + } + + public int FindPackStreamArrayIndex(int inStreamIndex) + { + for (int i = 0; i < PackStreams.Count; i++) + if (PackStreams[i] == inStreamIndex) + return i; + + return -1; + } + + public bool IsEncrypted() + { + for (int i = Coders.Count - 1; i >= 0; i--) + if (Coders[i].MethodId == CMethodId.kAES) + return true; + + return false; + } + + public bool CheckStructure() + { + const int kNumCodersMax = 32; // don't change it + const int kMaskSize = 32; // it must be >= kNumCodersMax + const int kNumBindsMax = 32; + + if (Coders.Count > kNumCodersMax || BindPairs.Count > kNumBindsMax) + return false; + + { + var v = new BitVector(BindPairs.Count + PackStreams.Count); + + for (int i = 0; i < BindPairs.Count; i++) + if (v.GetAndSet(BindPairs[i].InIndex)) + return false; + + for (int i = 0; i < PackStreams.Count; i++) + if (v.GetAndSet(PackStreams[i])) + return false; + } + + { + var v = new BitVector(UnpackSizes.Count); + for (int i = 0; i < BindPairs.Count; i++) + if (v.GetAndSet(BindPairs[i].OutIndex)) + return false; + } + + uint[] mask = new uint[kMaskSize]; + + { + List inStreamToCoder = new List(); + List outStreamToCoder = new List(); + for (int i = 0; i < Coders.Count; i++) + { + CCoderInfo coder = Coders[i]; + for (int j = 0; j < coder.NumInStreams; j++) + inStreamToCoder.Add(i); + for (int j = 0; j < coder.NumOutStreams; j++) + outStreamToCoder.Add(i); + } + + for (int i = 0; i < BindPairs.Count; i++) + { + CBindPair bp = BindPairs[i]; + mask[inStreamToCoder[bp.InIndex]] |= (1u << outStreamToCoder[bp.OutIndex]); + } + } + + for (int i = 0; i < kMaskSize; i++) + for (int j = 0; j < kMaskSize; j++) + if (((1u << j) & mask[i]) != 0) + mask[i] |= mask[j]; + + for (int i = 0; i < kMaskSize; i++) + if (((1u << i) & mask[i]) != 0) + return false; + + return true; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CMethodId.cs b/src/SharpCompress/Common/SevenZip/CMethodId.cs similarity index 96% rename from SharpCompress/Common/SevenZip/CMethodId.cs rename to src/SharpCompress/Common/SevenZip/CMethodId.cs index ebf1b52a..ecc40aaf 100644 --- a/SharpCompress/Common/SevenZip/CMethodId.cs +++ b/src/SharpCompress/Common/SevenZip/CMethodId.cs @@ -1,55 +1,55 @@ -namespace SharpCompress.Common.SevenZip -{ - internal struct CMethodId - { - public const ulong kCopyId = 0; - public const ulong kLzmaId = 0x030101; - public const ulong kLzma2Id = 0x21; - public const ulong kAESId = 0x06F10701; - - public static readonly CMethodId kCopy = new CMethodId(kCopyId); - public static readonly CMethodId kLzma = new CMethodId(kLzmaId); - public static readonly CMethodId kLzma2 = new CMethodId(kLzma2Id); - public static readonly CMethodId kAES = new CMethodId(kAESId); - - public readonly ulong Id; - - public CMethodId(ulong id) - { - this.Id = id; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } - - public override bool Equals(object obj) - { - return obj is CMethodId && (CMethodId) obj == this; - } - - public bool Equals(CMethodId other) - { - return Id == other.Id; - } - - public static bool operator ==(CMethodId left, CMethodId right) - { - return left.Id == right.Id; - } - - public static bool operator !=(CMethodId left, CMethodId right) - { - return left.Id != right.Id; - } - - public int GetLength() - { - int bytes = 0; - for (ulong value = Id; value != 0; value >>= 8) - bytes++; - return bytes; - } - } +namespace SharpCompress.Common.SevenZip +{ + internal struct CMethodId + { + public const ulong kCopyId = 0; + public const ulong kLzmaId = 0x030101; + public const ulong kLzma2Id = 0x21; + public const ulong kAESId = 0x06F10701; + + public static readonly CMethodId kCopy = new CMethodId(kCopyId); + public static readonly CMethodId kLzma = new CMethodId(kLzmaId); + public static readonly CMethodId kLzma2 = new CMethodId(kLzma2Id); + public static readonly CMethodId kAES = new CMethodId(kAESId); + + public readonly ulong Id; + + public CMethodId(ulong id) + { + this.Id = id; + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + public override bool Equals(object obj) + { + return obj is CMethodId && (CMethodId) obj == this; + } + + public bool Equals(CMethodId other) + { + return Id == other.Id; + } + + public static bool operator ==(CMethodId left, CMethodId right) + { + return left.Id == right.Id; + } + + public static bool operator !=(CMethodId left, CMethodId right) + { + return left.Id != right.Id; + } + + public int GetLength() + { + int bytes = 0; + for (ulong value = Id; value != 0; value >>= 8) + bytes++; + return bytes; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/CStreamSwitch.cs b/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs similarity index 96% rename from SharpCompress/Common/SevenZip/CStreamSwitch.cs rename to src/SharpCompress/Common/SevenZip/CStreamSwitch.cs index eacfc26b..ca054db1 100644 --- a/SharpCompress/Common/SevenZip/CStreamSwitch.cs +++ b/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs @@ -1,68 +1,68 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Compressor.LZMA; - -namespace SharpCompress.Common.SevenZip -{ - internal struct CStreamSwitch : IDisposable - { - private ArchiveReader _archive; - private bool _needRemove; - private bool _active; - - public void Dispose() - { - if (_active) - { - _active = false; -#if DEBUG - Log.WriteLine("[end of switch]"); -#endif - } - - if (_needRemove) - { - _needRemove = false; - _archive.DeleteByteStream(); - } - } - - public void Set(ArchiveReader archive, byte[] dataVector) - { - Dispose(); - _archive = archive; - _archive.AddByteStream(dataVector, 0, dataVector.Length); - _needRemove = true; - _active = true; - } - - public void Set(ArchiveReader archive, List dataVector) - { - Dispose(); - _active = true; - - byte external = archive.ReadByte(); - if (external != 0) - { - int dataIndex = archive.ReadNum(); - if (dataIndex < 0 || dataIndex >= dataVector.Count) - throw new InvalidOperationException(); - -#if DEBUG - Log.WriteLine("[switch to stream {0}]", dataIndex); -#endif - _archive = archive; - _archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length); - _needRemove = true; - _active = true; - } - else - { -#if DEBUG - Log.WriteLine("[inline data]"); -#endif - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Compressor.LZMA; + +namespace SharpCompress.Common.SevenZip +{ + internal struct CStreamSwitch : IDisposable + { + private ArchiveReader _archive; + private bool _needRemove; + private bool _active; + + public void Dispose() + { + if (_active) + { + _active = false; +#if DEBUG + Log.WriteLine("[end of switch]"); +#endif + } + + if (_needRemove) + { + _needRemove = false; + _archive.DeleteByteStream(); + } + } + + public void Set(ArchiveReader archive, byte[] dataVector) + { + Dispose(); + _archive = archive; + _archive.AddByteStream(dataVector, 0, dataVector.Length); + _needRemove = true; + _active = true; + } + + public void Set(ArchiveReader archive, List dataVector) + { + Dispose(); + _active = true; + + byte external = archive.ReadByte(); + if (external != 0) + { + int dataIndex = archive.ReadNum(); + if (dataIndex < 0 || dataIndex >= dataVector.Count) + throw new InvalidOperationException(); + +#if DEBUG + Log.WriteLine("[switch to stream {0}]", dataIndex); +#endif + _archive = archive; + _archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length); + _needRemove = true; + _active = true; + } + else + { +#if DEBUG + Log.WriteLine("[inline data]"); +#endif + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/DataReader.cs b/src/SharpCompress/Common/SevenZip/DataReader.cs similarity index 96% rename from SharpCompress/Common/SevenZip/DataReader.cs rename to src/SharpCompress/Common/SevenZip/DataReader.cs index 2b6f27cd..e0140f46 100644 --- a/SharpCompress/Common/SevenZip/DataReader.cs +++ b/src/SharpCompress/Common/SevenZip/DataReader.cs @@ -1,170 +1,170 @@ -using System; -using System.IO; -using System.Text; -using SharpCompress.Compressor.LZMA; - -namespace SharpCompress.Common.SevenZip -{ - internal class DataReader - { - #region Static Methods - - public static uint Get32(byte[] buffer, int offset) - { - return (uint) buffer[offset] - + ((uint) buffer[offset + 1] << 8) - + ((uint) buffer[offset + 2] << 16) - + ((uint) buffer[offset + 3] << 24); - } - - public static ulong Get64(byte[] buffer, int offset) - { - return (ulong) buffer[offset] - + ((ulong) buffer[offset + 1] << 8) - + ((ulong) buffer[offset + 2] << 16) - + ((ulong) buffer[offset + 3] << 24) - + ((ulong) buffer[offset + 4] << 32) - + ((ulong) buffer[offset + 5] << 40) - + ((ulong) buffer[offset + 6] << 48) - + ((ulong) buffer[offset + 7] << 56); - } - - #endregion - - #region Variables - - private byte[] _buffer; - private int _origin; - private int _offset; - private int _ending; - - #endregion - - #region Public Methods - - public DataReader(byte[] buffer, int offset, int length) - { - _buffer = buffer; - _origin = offset; - _offset = offset; - _ending = offset + length; - } - - public int Offset - { - get { return _offset; } - } - - public Byte ReadByte() - { - if (_offset >= _ending) - throw new EndOfStreamException(); - - return _buffer[_offset++]; - } - - public void ReadBytes(byte[] buffer, int offset, int length) - { - if (length > _ending - _offset) - throw new EndOfStreamException(); - - while (length-- > 0) - buffer[offset++] = _buffer[_offset++]; - } - - public void SkipData(long size) - { - if (size > _ending - _offset) - throw new EndOfStreamException(); - - _offset += (int) size; -#if DEBUG - Log.WriteLine("SkipData {0}", size); -#endif - } - - public void SkipData() - { - SkipData(checked((long) ReadNumber())); - } - - public ulong ReadNumber() - { - if (_offset >= _ending) - throw new EndOfStreamException(); - - byte firstByte = _buffer[_offset++]; - byte mask = 0x80; - ulong value = 0; - - for (int i = 0; i < 8; i++) - { - if ((firstByte & mask) == 0) - { - ulong highPart = firstByte & (mask - 1u); - value += highPart << (i*8); - return value; - } - - if (_offset >= _ending) - throw new EndOfStreamException(); - - value |= (ulong) _buffer[_offset++] << (8*i); - mask >>= 1; - } - - return value; - } - - public int ReadNum() - { - ulong value = ReadNumber(); - if (value > Int32.MaxValue) - throw new NotSupportedException(); - - return (int) value; - } - - public uint ReadUInt32() - { - if (_offset + 4 > _ending) - throw new EndOfStreamException(); - - uint res = Get32(_buffer, _offset); - _offset += 4; - return res; - } - - public ulong ReadUInt64() - { - if (_offset + 8 > _ending) - throw new EndOfStreamException(); - - ulong res = Get64(_buffer, _offset); - _offset += 8; - return res; - } - - public string ReadString() - { - int ending = _offset; - - for (;;) - { - if (ending + 2 > _ending) - throw new EndOfStreamException(); - - if (_buffer[ending] == 0 && _buffer[ending + 1] == 0) - break; - - ending += 2; - } - - string str = Encoding.Unicode.GetString(_buffer, _offset, ending - _offset); - _offset = ending + 2; - return str; - } - - #endregion - } +using System; +using System.IO; +using System.Text; +using SharpCompress.Compressor.LZMA; + +namespace SharpCompress.Common.SevenZip +{ + internal class DataReader + { + #region Static Methods + + public static uint Get32(byte[] buffer, int offset) + { + return (uint) buffer[offset] + + ((uint) buffer[offset + 1] << 8) + + ((uint) buffer[offset + 2] << 16) + + ((uint) buffer[offset + 3] << 24); + } + + public static ulong Get64(byte[] buffer, int offset) + { + return (ulong) buffer[offset] + + ((ulong) buffer[offset + 1] << 8) + + ((ulong) buffer[offset + 2] << 16) + + ((ulong) buffer[offset + 3] << 24) + + ((ulong) buffer[offset + 4] << 32) + + ((ulong) buffer[offset + 5] << 40) + + ((ulong) buffer[offset + 6] << 48) + + ((ulong) buffer[offset + 7] << 56); + } + + #endregion + + #region Variables + + private byte[] _buffer; + private int _origin; + private int _offset; + private int _ending; + + #endregion + + #region Public Methods + + public DataReader(byte[] buffer, int offset, int length) + { + _buffer = buffer; + _origin = offset; + _offset = offset; + _ending = offset + length; + } + + public int Offset + { + get { return _offset; } + } + + public Byte ReadByte() + { + if (_offset >= _ending) + throw new EndOfStreamException(); + + return _buffer[_offset++]; + } + + public void ReadBytes(byte[] buffer, int offset, int length) + { + if (length > _ending - _offset) + throw new EndOfStreamException(); + + while (length-- > 0) + buffer[offset++] = _buffer[_offset++]; + } + + public void SkipData(long size) + { + if (size > _ending - _offset) + throw new EndOfStreamException(); + + _offset += (int) size; +#if DEBUG + Log.WriteLine("SkipData {0}", size); +#endif + } + + public void SkipData() + { + SkipData(checked((long) ReadNumber())); + } + + public ulong ReadNumber() + { + if (_offset >= _ending) + throw new EndOfStreamException(); + + byte firstByte = _buffer[_offset++]; + byte mask = 0x80; + ulong value = 0; + + for (int i = 0; i < 8; i++) + { + if ((firstByte & mask) == 0) + { + ulong highPart = firstByte & (mask - 1u); + value += highPart << (i*8); + return value; + } + + if (_offset >= _ending) + throw new EndOfStreamException(); + + value |= (ulong) _buffer[_offset++] << (8*i); + mask >>= 1; + } + + return value; + } + + public int ReadNum() + { + ulong value = ReadNumber(); + if (value > Int32.MaxValue) + throw new NotSupportedException(); + + return (int) value; + } + + public uint ReadUInt32() + { + if (_offset + 4 > _ending) + throw new EndOfStreamException(); + + uint res = Get32(_buffer, _offset); + _offset += 4; + return res; + } + + public ulong ReadUInt64() + { + if (_offset + 8 > _ending) + throw new EndOfStreamException(); + + ulong res = Get64(_buffer, _offset); + _offset += 8; + return res; + } + + public string ReadString() + { + int ending = _offset; + + for (;;) + { + if (ending + 2 > _ending) + throw new EndOfStreamException(); + + if (_buffer[ending] == 0 && _buffer[ending + 1] == 0) + break; + + ending += 2; + } + + string str = Encoding.Unicode.GetString(_buffer, _offset, ending - _offset); + _offset = ending + 2; + return str; + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/SevenZipEntry.cs b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs similarity index 95% rename from SharpCompress/Common/SevenZip/SevenZipEntry.cs rename to src/SharpCompress/Common/SevenZip/SevenZipEntry.cs index 63620d3e..c832c7b0 100644 --- a/SharpCompress/Common/SevenZip/SevenZipEntry.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs @@ -1,85 +1,85 @@ -using System; -using System.Collections.Generic; - -namespace SharpCompress.Common.SevenZip -{ - public class SevenZipEntry : Entry - { - internal SevenZipEntry(SevenZipFilePart filePart) - { - this.FilePart = filePart; - } - - internal SevenZipFilePart FilePart { get; private set; } - - public override CompressionType CompressionType - { - get { return FilePart.CompressionType; } - } - - public override long Crc - { - get { return FilePart.Header.Crc ?? 0; } - } - - public override string Key - { - get { return FilePart.Header.Name; } - } - - public override long CompressedSize - { - get { return 0; } - } - - public override long Size - { - get { return (long) FilePart.Header.Size; } - } - - public override DateTime? LastModifiedTime - { - get { return FilePart.Header.MTime; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return false; } - } - - public override bool IsDirectory - { - get { return FilePart.Header.IsDir; } - } - - public override bool IsSplit - { - get { return false; } - } - - public override int? Attrib - { - get { return (int) FilePart.Header.Attrib; } - } - - internal override IEnumerable Parts - { - get { return FilePart.AsEnumerable(); } - } - } +using System; +using System.Collections.Generic; + +namespace SharpCompress.Common.SevenZip +{ + public class SevenZipEntry : Entry + { + internal SevenZipEntry(SevenZipFilePart filePart) + { + this.FilePart = filePart; + } + + internal SevenZipFilePart FilePart { get; private set; } + + public override CompressionType CompressionType + { + get { return FilePart.CompressionType; } + } + + public override long Crc + { + get { return FilePart.Header.Crc ?? 0; } + } + + public override string Key + { + get { return FilePart.Header.Name; } + } + + public override long CompressedSize + { + get { return 0; } + } + + public override long Size + { + get { return (long) FilePart.Header.Size; } + } + + public override DateTime? LastModifiedTime + { + get { return FilePart.Header.MTime; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return false; } + } + + public override bool IsDirectory + { + get { return FilePart.Header.IsDir; } + } + + public override bool IsSplit + { + get { return false; } + } + + public override int? Attrib + { + get { return (int) FilePart.Header.Attrib; } + } + + internal override IEnumerable Parts + { + get { return FilePart.AsEnumerable(); } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs similarity index 96% rename from SharpCompress/Common/SevenZip/SevenZipFilePart.cs rename to src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs index 215ba10c..ed403687 100644 --- a/SharpCompress/Common/SevenZip/SevenZipFilePart.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs @@ -1,109 +1,109 @@ -using System; -using System.IO; -using System.Linq; -using SharpCompress.IO; - -namespace SharpCompress.Common.SevenZip -{ - internal class SevenZipFilePart : FilePart - { - private CompressionType? type; - private Stream stream; - private ArchiveDatabase database; - - internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry) - { - this.stream = stream; - this.database = database; - Index = index; - Header = fileEntry; - if (Header.HasStream) - { - Folder = database.Folders[database.FileIndexToFolderIndexMap[index]]; - } - } - - internal Stream BaseStream { get; private set; } - internal CFileItem Header { get; private set; } - internal CFolder Folder { get; private set; } - internal int Index { get; private set; } - - internal override string FilePartName - { - get { return Header.Name; } - } - - internal override Stream GetRawStream() - { - return null; - } - - internal override Stream GetCompressedStream() - { - if (!Header.HasStream) - { - return null; - } - var folderStream = database.GetFolderStream(stream, Folder, null); - - int firstFileIndex = database.FolderStartFileIndex[database.Folders.IndexOf(Folder)]; - int skipCount = Index - firstFileIndex; - long skipSize = 0; - for (int i = 0; i < skipCount; i++) - { - skipSize += database.Files[firstFileIndex + i].Size; - } - if (skipSize > 0) - { - folderStream.Skip(skipSize); - } - return new ReadOnlySubStream(folderStream, Header.Size); - } - - public CompressionType CompressionType - { - get - { - if (type == null) - { - type = GetCompression(); - } - return type.Value; - } - } - - //copied from DecoderRegistry - private const uint k_Copy = 0x0; - private const uint k_Delta = 3; - private const uint k_LZMA2 = 0x21; - private const uint k_LZMA = 0x030101; - private const uint k_PPMD = 0x030401; - private const uint k_BCJ = 0x03030103; - private const uint k_BCJ2 = 0x0303011B; - private const uint k_Deflate = 0x040108; - private const uint k_BZip2 = 0x040202; - - internal CompressionType GetCompression() - { - var coder = Folder.Coders.First(); - switch (coder.MethodId.Id) - { - case k_LZMA: - case k_LZMA2: - { - return CompressionType.LZMA; - } - case k_PPMD: - { - return CompressionType.PPMd; - } - case k_BZip2: - { - return CompressionType.BZip2; - } - default: - throw new NotImplementedException(); - } - } - } +using System; +using System.IO; +using System.Linq; +using SharpCompress.IO; + +namespace SharpCompress.Common.SevenZip +{ + internal class SevenZipFilePart : FilePart + { + private CompressionType? type; + private Stream stream; + private ArchiveDatabase database; + + internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry) + { + this.stream = stream; + this.database = database; + Index = index; + Header = fileEntry; + if (Header.HasStream) + { + Folder = database.Folders[database.FileIndexToFolderIndexMap[index]]; + } + } + + internal Stream BaseStream { get; private set; } + internal CFileItem Header { get; private set; } + internal CFolder Folder { get; private set; } + internal int Index { get; private set; } + + internal override string FilePartName + { + get { return Header.Name; } + } + + internal override Stream GetRawStream() + { + return null; + } + + internal override Stream GetCompressedStream() + { + if (!Header.HasStream) + { + return null; + } + var folderStream = database.GetFolderStream(stream, Folder, null); + + int firstFileIndex = database.FolderStartFileIndex[database.Folders.IndexOf(Folder)]; + int skipCount = Index - firstFileIndex; + long skipSize = 0; + for (int i = 0; i < skipCount; i++) + { + skipSize += database.Files[firstFileIndex + i].Size; + } + if (skipSize > 0) + { + folderStream.Skip(skipSize); + } + return new ReadOnlySubStream(folderStream, Header.Size); + } + + public CompressionType CompressionType + { + get + { + if (type == null) + { + type = GetCompression(); + } + return type.Value; + } + } + + //copied from DecoderRegistry + private const uint k_Copy = 0x0; + private const uint k_Delta = 3; + private const uint k_LZMA2 = 0x21; + private const uint k_LZMA = 0x030101; + private const uint k_PPMD = 0x030401; + private const uint k_BCJ = 0x03030103; + private const uint k_BCJ2 = 0x0303011B; + private const uint k_Deflate = 0x040108; + private const uint k_BZip2 = 0x040202; + + internal CompressionType GetCompression() + { + var coder = Folder.Coders.First(); + switch (coder.MethodId.Id) + { + case k_LZMA: + case k_LZMA2: + { + return CompressionType.LZMA; + } + case k_PPMD: + { + return CompressionType.PPMd; + } + case k_BZip2: + { + return CompressionType.BZip2; + } + default: + throw new NotImplementedException(); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/SevenZip/SevenZipVolume.cs b/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs similarity index 95% rename from SharpCompress/Common/SevenZip/SevenZipVolume.cs rename to src/SharpCompress/Common/SevenZip/SevenZipVolume.cs index c5d5f9dd..9b2a849a 100644 --- a/SharpCompress/Common/SevenZip/SevenZipVolume.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs @@ -1,12 +1,12 @@ -using System.IO; - -namespace SharpCompress.Common.SevenZip -{ - public class SevenZipVolume : Volume - { - public SevenZipVolume(Stream stream, Options options) - : base(stream, options) - { - } - } +using System.IO; + +namespace SharpCompress.Common.SevenZip +{ + public class SevenZipVolume : Volume + { + public SevenZipVolume(Stream stream, Options options) + : base(stream, options) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Tar/Headers/EntryType.cs b/src/SharpCompress/Common/Tar/Headers/EntryType.cs similarity index 100% rename from SharpCompress/Common/Tar/Headers/EntryType.cs rename to src/SharpCompress/Common/Tar/Headers/EntryType.cs diff --git a/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs similarity index 97% rename from SharpCompress/Common/Tar/Headers/TarHeader.cs rename to src/SharpCompress/Common/Tar/Headers/TarHeader.cs index dbbc0fe5..0dd0c352 100644 --- a/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -1,223 +1,223 @@ -using System; -using System.IO; -using System.Text; - -namespace SharpCompress.Common.Tar.Headers -{ - internal class TarHeader - { - internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - internal string Name { get; set; } - //internal int Mode { get; set; } - //internal int UserId { get; set; } - //internal string UserName { get; set; } - //internal int GroupId { get; set; } - //internal string GroupName { get; set; } - internal long Size { get; set; } - internal DateTime LastModifiedTime { get; set; } - internal EntryType EntryType { get; set; } - internal Stream PackedStream { get; set; } - - internal void Write(Stream output) - { - byte[] buffer = new byte[512]; - - WriteOctalBytes(511, buffer, 100, 8); // file mode - WriteOctalBytes(0, buffer, 108, 8); // owner ID - WriteOctalBytes(0, buffer, 116, 8); // group ID - - //Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257); - if (Name.Length > 100) - { - // Set mock filename and filetype to indicate the next block is the actual name of the file - WriteStringBytes("././@LongLink", buffer, 0, 100); - buffer[156] = (byte)EntryType.LongName; - WriteOctalBytes(Name.Length + 1, buffer, 124, 12); - } - else - { - WriteStringBytes(Name, buffer, 0, 100); - WriteOctalBytes(Size, buffer, 124, 12); - var time = (long)(LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds; - WriteOctalBytes(time, buffer, 136, 12); - buffer[156] = (byte)EntryType; - - if (Size >= 0x1FFFFFFFF) - { - byte[] bytes = BitConverter.GetBytes(Utility.HostToNetworkOrder(Size)); - var bytes12 = new byte[12]; - bytes.CopyTo(bytes12, 12 - bytes.Length); - bytes12[0] |= 0x80; - bytes12.CopyTo(buffer, 124); - } - } - - int crc = RecalculateChecksum(buffer); - WriteOctalBytes(crc, buffer, 148, 8); - - output.Write(buffer, 0, buffer.Length); - - if (Name.Length > 100) - { - WriteLongFilenameHeader(output); - Name = Name.Substring(0, 100); - Write(output); - } - } - private void WriteLongFilenameHeader(Stream output) - { - byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name); - output.Write(nameBytes, 0, nameBytes.Length); - - // pad to multiple of 512 bytes, and make sure a terminating null is added - int numPaddingBytes = 512 - (nameBytes.Length % 512); - if (numPaddingBytes == 0) - numPaddingBytes = 512; - output.Write(new byte[numPaddingBytes], 0, numPaddingBytes); - } - - internal bool Read(BinaryReader reader) - { - byte[] buffer = reader.ReadBytes(512); - if (buffer.Length == 0) - { - return false; - } - if (buffer.Length < 512) - { - throw new InvalidOperationException(); - } - Name = ArchiveEncoding.Default.GetString(buffer, 0, 100).TrimNulls(); - - //Mode = ReadASCIIInt32Base8(buffer, 100, 7); - //UserId = ReadASCIIInt32Base8(buffer, 108, 7); - //GroupId = ReadASCIIInt32Base8(buffer, 116, 7); - EntryType = (EntryType) buffer[156]; - if ((buffer[124] & 0x80) == 0x80) // if size in binary - { - long sizeBigEndian = BitConverter.ToInt64(buffer, 0x80); - Size = Utility.NetworkToHostOrder(sizeBigEndian); - } - else - { - Size = ReadASCIIInt64Base8(buffer, 124, 11); - } - long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11); - LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime(); - - - Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls(); - - if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic)) - { - string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157); - namePrefix = namePrefix.TrimNulls(); - if (!string.IsNullOrEmpty(namePrefix)) - { - Name = namePrefix + "/" + Name; - } - } - if (EntryType != EntryType.LongName && Name.Length == 0) - { - return false; - } - return true; - } - - private static void WriteStringBytes(string name, byte[] buffer, int offset, int length) - { - int i; - - for (i = 0; i < length - 1 && i < name.Length; ++i) - { - buffer[offset + i] = (byte) name[i]; - } - - for (; i < length; ++i) - { - buffer[offset + i] = 0; - } - } - - private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length) - { - string val = Convert.ToString(value, 8); - int shift = length - val.Length - 1; - for (int i = 0; i < shift; i++) - { - buffer[offset + i] = (byte) ' '; - } - for (int i = 0; i < val.Length; i++) - { - buffer[offset + i + shift] = (byte) val[i]; - } - } - - private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count) - { - string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); - if (string.IsNullOrEmpty(s)) - { - return 0; - } - return Convert.ToInt32(s, 8); - } - - private static long ReadASCIIInt64Base8(byte[] buffer, int offset, int count) - { - string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); - if (string.IsNullOrEmpty(s)) - { - return 0; - } - return Convert.ToInt64(s, 8); - } - - private static long ReadASCIIInt64(byte[] buffer, int offset, int count) - { - string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); - if (string.IsNullOrEmpty(s)) - { - return 0; - } - return Convert.ToInt64(s); - } - - internal static int RecalculateChecksum(byte[] buf) - { - // Set default value for checksum. That is 8 spaces. - Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148); - - // Calculate checksum - int headerChecksum = 0; - foreach (byte b in buf) - { - headerChecksum += b; - } - return headerChecksum; - } - - internal static int RecalculateAltChecksum(byte[] buf) - { - Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148); - int headerChecksum = 0; - foreach (byte b in buf) - { - if ((b & 0x80) == 0x80) - { - headerChecksum -= b ^ 0x80; - } - else - { - headerChecksum += b; - } - } - return headerChecksum; - } - - public long? DataStartPosition { get; set; } - - public string Magic { get; set; } - } +using System; +using System.IO; +using System.Text; + +namespace SharpCompress.Common.Tar.Headers +{ + internal class TarHeader + { + internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + internal string Name { get; set; } + //internal int Mode { get; set; } + //internal int UserId { get; set; } + //internal string UserName { get; set; } + //internal int GroupId { get; set; } + //internal string GroupName { get; set; } + internal long Size { get; set; } + internal DateTime LastModifiedTime { get; set; } + internal EntryType EntryType { get; set; } + internal Stream PackedStream { get; set; } + + internal void Write(Stream output) + { + byte[] buffer = new byte[512]; + + WriteOctalBytes(511, buffer, 100, 8); // file mode + WriteOctalBytes(0, buffer, 108, 8); // owner ID + WriteOctalBytes(0, buffer, 116, 8); // group ID + + //Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257); + if (Name.Length > 100) + { + // Set mock filename and filetype to indicate the next block is the actual name of the file + WriteStringBytes("././@LongLink", buffer, 0, 100); + buffer[156] = (byte)EntryType.LongName; + WriteOctalBytes(Name.Length + 1, buffer, 124, 12); + } + else + { + WriteStringBytes(Name, buffer, 0, 100); + WriteOctalBytes(Size, buffer, 124, 12); + var time = (long)(LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds; + WriteOctalBytes(time, buffer, 136, 12); + buffer[156] = (byte)EntryType; + + if (Size >= 0x1FFFFFFFF) + { + byte[] bytes = BitConverter.GetBytes(Utility.HostToNetworkOrder(Size)); + var bytes12 = new byte[12]; + bytes.CopyTo(bytes12, 12 - bytes.Length); + bytes12[0] |= 0x80; + bytes12.CopyTo(buffer, 124); + } + } + + int crc = RecalculateChecksum(buffer); + WriteOctalBytes(crc, buffer, 148, 8); + + output.Write(buffer, 0, buffer.Length); + + if (Name.Length > 100) + { + WriteLongFilenameHeader(output); + Name = Name.Substring(0, 100); + Write(output); + } + } + private void WriteLongFilenameHeader(Stream output) + { + byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name); + output.Write(nameBytes, 0, nameBytes.Length); + + // pad to multiple of 512 bytes, and make sure a terminating null is added + int numPaddingBytes = 512 - (nameBytes.Length % 512); + if (numPaddingBytes == 0) + numPaddingBytes = 512; + output.Write(new byte[numPaddingBytes], 0, numPaddingBytes); + } + + internal bool Read(BinaryReader reader) + { + byte[] buffer = reader.ReadBytes(512); + if (buffer.Length == 0) + { + return false; + } + if (buffer.Length < 512) + { + throw new InvalidOperationException(); + } + Name = ArchiveEncoding.Default.GetString(buffer, 0, 100).TrimNulls(); + + //Mode = ReadASCIIInt32Base8(buffer, 100, 7); + //UserId = ReadASCIIInt32Base8(buffer, 108, 7); + //GroupId = ReadASCIIInt32Base8(buffer, 116, 7); + EntryType = (EntryType) buffer[156]; + if ((buffer[124] & 0x80) == 0x80) // if size in binary + { + long sizeBigEndian = BitConverter.ToInt64(buffer, 0x80); + Size = Utility.NetworkToHostOrder(sizeBigEndian); + } + else + { + Size = ReadASCIIInt64Base8(buffer, 124, 11); + } + long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11); + LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime(); + + + Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls(); + + if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic)) + { + string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157); + namePrefix = namePrefix.TrimNulls(); + if (!string.IsNullOrEmpty(namePrefix)) + { + Name = namePrefix + "/" + Name; + } + } + if (EntryType != EntryType.LongName && Name.Length == 0) + { + return false; + } + return true; + } + + private static void WriteStringBytes(string name, byte[] buffer, int offset, int length) + { + int i; + + for (i = 0; i < length - 1 && i < name.Length; ++i) + { + buffer[offset + i] = (byte) name[i]; + } + + for (; i < length; ++i) + { + buffer[offset + i] = 0; + } + } + + private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length) + { + string val = Convert.ToString(value, 8); + int shift = length - val.Length - 1; + for (int i = 0; i < shift; i++) + { + buffer[offset + i] = (byte) ' '; + } + for (int i = 0; i < val.Length; i++) + { + buffer[offset + i + shift] = (byte) val[i]; + } + } + + private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count) + { + string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); + if (string.IsNullOrEmpty(s)) + { + return 0; + } + return Convert.ToInt32(s, 8); + } + + private static long ReadASCIIInt64Base8(byte[] buffer, int offset, int count) + { + string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); + if (string.IsNullOrEmpty(s)) + { + return 0; + } + return Convert.ToInt64(s, 8); + } + + private static long ReadASCIIInt64(byte[] buffer, int offset, int count) + { + string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); + if (string.IsNullOrEmpty(s)) + { + return 0; + } + return Convert.ToInt64(s); + } + + internal static int RecalculateChecksum(byte[] buf) + { + // Set default value for checksum. That is 8 spaces. + Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148); + + // Calculate checksum + int headerChecksum = 0; + foreach (byte b in buf) + { + headerChecksum += b; + } + return headerChecksum; + } + + internal static int RecalculateAltChecksum(byte[] buf) + { + Encoding.UTF8.GetBytes(" ").CopyTo(buf, 148); + int headerChecksum = 0; + foreach (byte b in buf) + { + if ((b & 0x80) == 0x80) + { + headerChecksum -= b ^ 0x80; + } + else + { + headerChecksum += b; + } + } + return headerChecksum; + } + + public long? DataStartPosition { get; set; } + + public string Magic { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Tar/TarEntry.cs b/src/SharpCompress/Common/Tar/TarEntry.cs similarity index 96% rename from SharpCompress/Common/Tar/TarEntry.cs rename to src/SharpCompress/Common/Tar/TarEntry.cs index 88b56fca..a9c1f1c2 100644 --- a/SharpCompress/Common/Tar/TarEntry.cs +++ b/src/SharpCompress/Common/Tar/TarEntry.cs @@ -1,104 +1,104 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Common.Tar -{ - public class TarEntry : Entry - { - private readonly TarFilePart filePart; - private readonly CompressionType type; - - internal TarEntry(TarFilePart filePart, CompressionType type) - { - this.filePart = filePart; - this.type = type; - } - - public override CompressionType CompressionType - { - get { return type; } - } - - public override long Crc - { - get { return 0; } - } - - public override string Key - { - get { return filePart.Header.Name; } - } - - public override long CompressedSize - { - get { return filePart.Header.Size; } - } - - public override long Size - { - get { return filePart.Header.Size; } - } - - public override DateTime? LastModifiedTime - { - get { return filePart.Header.LastModifiedTime; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return false; } - } - - public override bool IsDirectory - { - get { return filePart.Header.EntryType == EntryType.Directory; } - } - - public override bool IsSplit - { - get { return false; } - } - - internal override IEnumerable Parts - { - get { return filePart.AsEnumerable(); } - } - - internal static IEnumerable GetEntries(StreamingMode mode, Stream stream, - CompressionType compressionType) - { - foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream)) - { - if (h != null) - { - if (mode == StreamingMode.Seekable) - { - yield return new TarEntry(new TarFilePart(h, stream), compressionType); - } - else - { - yield return new TarEntry(new TarFilePart(h, null), compressionType); - } - } - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Tar +{ + public class TarEntry : Entry + { + private readonly TarFilePart filePart; + private readonly CompressionType type; + + internal TarEntry(TarFilePart filePart, CompressionType type) + { + this.filePart = filePart; + this.type = type; + } + + public override CompressionType CompressionType + { + get { return type; } + } + + public override long Crc + { + get { return 0; } + } + + public override string Key + { + get { return filePart.Header.Name; } + } + + public override long CompressedSize + { + get { return filePart.Header.Size; } + } + + public override long Size + { + get { return filePart.Header.Size; } + } + + public override DateTime? LastModifiedTime + { + get { return filePart.Header.LastModifiedTime; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return false; } + } + + public override bool IsDirectory + { + get { return filePart.Header.EntryType == EntryType.Directory; } + } + + public override bool IsSplit + { + get { return false; } + } + + internal override IEnumerable Parts + { + get { return filePart.AsEnumerable(); } + } + + internal static IEnumerable GetEntries(StreamingMode mode, Stream stream, + CompressionType compressionType) + { + foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream)) + { + if (h != null) + { + if (mode == StreamingMode.Seekable) + { + yield return new TarEntry(new TarFilePart(h, stream), compressionType); + } + else + { + yield return new TarEntry(new TarFilePart(h, null), compressionType); + } + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Tar/TarFilePart.cs b/src/SharpCompress/Common/Tar/TarFilePart.cs similarity index 96% rename from SharpCompress/Common/Tar/TarFilePart.cs rename to src/SharpCompress/Common/Tar/TarFilePart.cs index ae170dfc..766c87b8 100644 --- a/SharpCompress/Common/Tar/TarFilePart.cs +++ b/src/SharpCompress/Common/Tar/TarFilePart.cs @@ -1,39 +1,39 @@ -using System.IO; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Common.Tar -{ - internal class TarFilePart : FilePart - { - private readonly Stream seekableStream; - - internal TarFilePart(TarHeader header, Stream seekableStream) - { - this.seekableStream = seekableStream; - Header = header; - } - - internal TarHeader Header { get; private set; } - - internal override string FilePartName - { - get { return Header.Name; } - } - - internal override Stream GetCompressedStream() - { - if (seekableStream != null) - { - seekableStream.Position = Header.DataStartPosition.Value; - return new ReadOnlySubStream(seekableStream, Header.Size); - } - return Header.PackedStream; - } - - internal override Stream GetRawStream() - { - return null; - } - } +using System.IO; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Tar +{ + internal class TarFilePart : FilePart + { + private readonly Stream seekableStream; + + internal TarFilePart(TarHeader header, Stream seekableStream) + { + this.seekableStream = seekableStream; + Header = header; + } + + internal TarHeader Header { get; private set; } + + internal override string FilePartName + { + get { return Header.Name; } + } + + internal override Stream GetCompressedStream() + { + if (seekableStream != null) + { + seekableStream.Position = Header.DataStartPosition.Value; + return new ReadOnlySubStream(seekableStream, Header.Size); + } + return Header.PackedStream; + } + + internal override Stream GetRawStream() + { + return null; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Tar/TarHeaderFactory.cs b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs similarity index 97% rename from SharpCompress/Common/Tar/TarHeaderFactory.cs rename to src/SharpCompress/Common/Tar/TarHeaderFactory.cs index f084849e..32787c8b 100644 --- a/SharpCompress/Common/Tar/TarHeaderFactory.cs +++ b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs @@ -1,61 +1,61 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Common.Tar -{ - internal static class TarHeaderFactory - { - internal static IEnumerable ReadHeader(StreamingMode mode, Stream stream) - { - while (true) - { - TarHeader header = null; - try - { - BinaryReader reader = new BinaryReader(stream); - header = new TarHeader(); - if (!header.Read(reader)) - { - yield break; - } - switch (mode) - { - case StreamingMode.Seekable: - { - header.DataStartPosition = reader.BaseStream.Position; - //skip to nearest 512 - reader.BaseStream.Position += PadTo512(header.Size); - } - break; - case StreamingMode.Streaming: - { - header.PackedStream = new TarReadOnlySubStream(stream, header.Size); - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - } - catch - { - header = null; - } - yield return header; - } - } - - private static long PadTo512(long size) - { - int zeros = (int) (size%512); - if (zeros == 0) - { - return size; - } - return 512 - zeros + size; - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Tar +{ + internal static class TarHeaderFactory + { + internal static IEnumerable ReadHeader(StreamingMode mode, Stream stream) + { + while (true) + { + TarHeader header = null; + try + { + BinaryReader reader = new BinaryReader(stream); + header = new TarHeader(); + if (!header.Read(reader)) + { + yield break; + } + switch (mode) + { + case StreamingMode.Seekable: + { + header.DataStartPosition = reader.BaseStream.Position; + //skip to nearest 512 + reader.BaseStream.Position += PadTo512(header.Size); + } + break; + case StreamingMode.Streaming: + { + header.PackedStream = new TarReadOnlySubStream(stream, header.Size); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + } + catch + { + header = null; + } + yield return header; + } + } + + private static long PadTo512(long size) + { + int zeros = (int) (size%512); + if (zeros == 0) + { + return size; + } + return 512 - zeros + size; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Tar/TarReadOnlySubStream.cs b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs similarity index 96% rename from SharpCompress/Common/Tar/TarReadOnlySubStream.cs rename to src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs index 5ed5ffa0..a62abe39 100644 --- a/SharpCompress/Common/Tar/TarReadOnlySubStream.cs +++ b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs @@ -1,105 +1,105 @@ -using System.IO; - -namespace SharpCompress.Common.Tar -{ - internal class TarReadOnlySubStream : Stream - { - private bool isDisposed; - private long amountRead; - - public TarReadOnlySubStream(Stream stream, long bytesToRead) - { - Stream = stream; - BytesLeftToRead = bytesToRead; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - long skipBytes = amountRead % 512; - if (skipBytes == 0) - { - return; - } - skipBytes = 512 - skipBytes; - if (skipBytes == 0) - { - return; - } - var buffer = new byte[skipBytes]; - Stream.ReadFully(buffer); - } - } - - private long BytesLeftToRead { get; set; } - - public Stream Stream { get; private set; } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new System.NotSupportedException(); - } - - public override long Length - { - get { throw new System.NotSupportedException(); } - } - - public override long Position - { - get { throw new System.NotSupportedException(); } - set { throw new System.NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (BytesLeftToRead < count) - { - count = (int)BytesLeftToRead; - } - int read = Stream.Read(buffer, offset, count); - if (read > 0) - { - BytesLeftToRead -= read; - amountRead += read; - } - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new System.NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new System.NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new System.NotSupportedException(); - } - } +using System.IO; + +namespace SharpCompress.Common.Tar +{ + internal class TarReadOnlySubStream : Stream + { + private bool isDisposed; + private long amountRead; + + public TarReadOnlySubStream(Stream stream, long bytesToRead) + { + Stream = stream; + BytesLeftToRead = bytesToRead; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + if (disposing) + { + long skipBytes = amountRead % 512; + if (skipBytes == 0) + { + return; + } + skipBytes = 512 - skipBytes; + if (skipBytes == 0) + { + return; + } + var buffer = new byte[skipBytes]; + Stream.ReadFully(buffer); + } + } + + private long BytesLeftToRead { get; set; } + + public Stream Stream { get; private set; } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new System.NotSupportedException(); + } + + public override long Length + { + get { throw new System.NotSupportedException(); } + } + + public override long Position + { + get { throw new System.NotSupportedException(); } + set { throw new System.NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (BytesLeftToRead < count) + { + count = (int)BytesLeftToRead; + } + int read = Stream.Read(buffer, offset, count); + if (read > 0) + { + BytesLeftToRead -= read; + amountRead += read; + } + return read; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new System.NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new System.NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new System.NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Tar/TarVolume.cs b/src/SharpCompress/Common/Tar/TarVolume.cs similarity index 95% rename from SharpCompress/Common/Tar/TarVolume.cs rename to src/SharpCompress/Common/Tar/TarVolume.cs index f70da6d0..5e445683 100644 --- a/SharpCompress/Common/Tar/TarVolume.cs +++ b/src/SharpCompress/Common/Tar/TarVolume.cs @@ -1,12 +1,12 @@ -using System.IO; - -namespace SharpCompress.Common.Tar -{ - public class TarVolume : Volume - { - public TarVolume(Stream stream, Options options) - : base(stream, options) - { - } - } +using System.IO; + +namespace SharpCompress.Common.Tar +{ + public class TarVolume : Volume + { + public TarVolume(Stream stream, Options options) + : base(stream, options) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Volume.cs b/src/SharpCompress/Common/Volume.cs similarity index 96% rename from SharpCompress/Common/Volume.cs rename to src/SharpCompress/Common/Volume.cs index 5f12cc9e..42c2c3d6 100644 --- a/SharpCompress/Common/Volume.cs +++ b/src/SharpCompress/Common/Volume.cs @@ -1,51 +1,51 @@ -using System.IO; -using SharpCompress.IO; - -namespace SharpCompress.Common -{ - public abstract class Volume : IVolume - { - private readonly Stream actualStream; - - internal Volume(Stream stream, Options options) - { - actualStream = stream; - Options = options; - } - - internal Stream Stream - { - get { return new NonDisposingStream(actualStream); } - } - - internal Options Options { get; private set; } - - /// - /// RarArchive is the first volume of a multi-part archive. - /// Only Rar 3.0 format and higher - /// - public virtual bool IsFirstVolume - { - get { return true; } - } - - /// - /// RarArchive is part of a multi-part archive. - /// - public virtual bool IsMultiVolume - { - get { return true; } - } - - private bool disposed; - - public void Dispose() - { - if (!Options.HasFlag(Options.KeepStreamsOpen) && !disposed) - { - actualStream.Dispose(); - disposed = true; - } - } - } +using System.IO; +using SharpCompress.IO; + +namespace SharpCompress.Common +{ + public abstract class Volume : IVolume + { + private readonly Stream actualStream; + + internal Volume(Stream stream, Options options) + { + actualStream = stream; + Options = options; + } + + internal Stream Stream + { + get { return new NonDisposingStream(actualStream); } + } + + internal Options Options { get; private set; } + + /// + /// RarArchive is the first volume of a multi-part archive. + /// Only Rar 3.0 format and higher + /// + public virtual bool IsFirstVolume + { + get { return true; } + } + + /// + /// RarArchive is part of a multi-part archive. + /// + public virtual bool IsMultiVolume + { + get { return true; } + } + + private bool disposed; + + public void Dispose() + { + if (!Options.HasFlag(Options.KeepStreamsOpen) && !disposed) + { + actualStream.Dispose(); + disposed = true; + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs similarity index 97% rename from SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs rename to src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs index a27778e1..ef133fbd 100644 --- a/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs @@ -1,52 +1,52 @@ -using System.IO; - -namespace SharpCompress.Common.Zip.Headers -{ - internal class DirectoryEndHeader : ZipHeader - { - public DirectoryEndHeader() - : base(ZipHeaderType.DirectoryEnd) - { - } - - internal override void Read(BinaryReader reader) - { - VolumeNumber = reader.ReadUInt16(); - FirstVolumeWithDirectory = reader.ReadUInt16(); - TotalNumberOfEntriesInDisk = reader.ReadUInt16(); - TotalNumberOfEntries = reader.ReadUInt16(); - DirectorySize = reader.ReadUInt32(); - DirectoryStartOffsetRelativeToDisk = reader.ReadUInt32(); - CommentLength = reader.ReadUInt16(); - Comment = reader.ReadBytes(CommentLength); - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(VolumeNumber); - writer.Write(FirstVolumeWithDirectory); - writer.Write(TotalNumberOfEntriesInDisk); - writer.Write(TotalNumberOfEntries); - writer.Write(DirectorySize); - writer.Write(DirectoryStartOffsetRelativeToDisk); - writer.Write(CommentLength); - writer.Write(Comment); - } - - public ushort VolumeNumber { get; private set; } - - public ushort FirstVolumeWithDirectory { get; private set; } - - public ushort TotalNumberOfEntriesInDisk { get; private set; } - - public uint DirectorySize { get; private set; } - - public uint DirectoryStartOffsetRelativeToDisk { get; private set; } - - public ushort CommentLength { get; private set; } - - public byte[] Comment { get; private set; } - - public ushort TotalNumberOfEntries { get; private set; } - } +using System.IO; + +namespace SharpCompress.Common.Zip.Headers +{ + internal class DirectoryEndHeader : ZipHeader + { + public DirectoryEndHeader() + : base(ZipHeaderType.DirectoryEnd) + { + } + + internal override void Read(BinaryReader reader) + { + VolumeNumber = reader.ReadUInt16(); + FirstVolumeWithDirectory = reader.ReadUInt16(); + TotalNumberOfEntriesInDisk = reader.ReadUInt16(); + TotalNumberOfEntries = reader.ReadUInt16(); + DirectorySize = reader.ReadUInt32(); + DirectoryStartOffsetRelativeToDisk = reader.ReadUInt32(); + CommentLength = reader.ReadUInt16(); + Comment = reader.ReadBytes(CommentLength); + } + + internal override void Write(BinaryWriter writer) + { + writer.Write(VolumeNumber); + writer.Write(FirstVolumeWithDirectory); + writer.Write(TotalNumberOfEntriesInDisk); + writer.Write(TotalNumberOfEntries); + writer.Write(DirectorySize); + writer.Write(DirectoryStartOffsetRelativeToDisk); + writer.Write(CommentLength); + writer.Write(Comment); + } + + public ushort VolumeNumber { get; private set; } + + public ushort FirstVolumeWithDirectory { get; private set; } + + public ushort TotalNumberOfEntriesInDisk { get; private set; } + + public uint DirectorySize { get; private set; } + + public uint DirectoryStartOffsetRelativeToDisk { get; private set; } + + public ushort CommentLength { get; private set; } + + public byte[] Comment { get; private set; } + + public ushort TotalNumberOfEntries { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs similarity index 97% rename from SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs rename to src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs index cce5acc9..755c9ae0 100644 --- a/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs @@ -1,88 +1,88 @@ -using System.IO; -using System.Linq; - -namespace SharpCompress.Common.Zip.Headers -{ - internal class DirectoryEntryHeader : ZipFileEntry - { - public DirectoryEntryHeader() - : base(ZipHeaderType.DirectoryEntry) - { - } - - internal override void Read(BinaryReader reader) - { - Version = reader.ReadUInt16(); - VersionNeededToExtract = reader.ReadUInt16(); - Flags = (HeaderFlags) reader.ReadUInt16(); - CompressionMethod = (ZipCompressionMethod) reader.ReadUInt16(); - LastModifiedTime = reader.ReadUInt16(); - LastModifiedDate = reader.ReadUInt16(); - Crc = reader.ReadUInt32(); - CompressedSize = reader.ReadUInt32(); - UncompressedSize = reader.ReadUInt32(); - ushort nameLength = reader.ReadUInt16(); - ushort extraLength = reader.ReadUInt16(); - ushort commentLength = reader.ReadUInt16(); - DiskNumberStart = reader.ReadUInt16(); - InternalFileAttributes = reader.ReadUInt16(); - ExternalFileAttributes = reader.ReadUInt32(); - RelativeOffsetOfEntryHeader = reader.ReadUInt32(); - - byte[] name = reader.ReadBytes(nameLength); - Name = DecodeString(name); - byte[] extra = reader.ReadBytes(extraLength); - byte[] comment = reader.ReadBytes(commentLength); - Comment = DecodeString(comment); - LoadExtra(extra); - - var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField); - if (unicodePathExtra != null) - { - Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; - } - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Version); - writer.Write(VersionNeededToExtract); - writer.Write((ushort) Flags); - writer.Write((ushort) CompressionMethod); - writer.Write(LastModifiedTime); - writer.Write(LastModifiedDate); - writer.Write(Crc); - writer.Write(CompressedSize); - writer.Write(UncompressedSize); - - byte[] nameBytes = EncodeString(Name); - writer.Write((ushort) nameBytes.Length); - //writer.Write((ushort)Extra.Length); - writer.Write((ushort) 0); - writer.Write((ushort) Comment.Length); - - writer.Write(DiskNumberStart); - writer.Write(InternalFileAttributes); - writer.Write(ExternalFileAttributes); - writer.Write(RelativeOffsetOfEntryHeader); - - writer.Write(nameBytes); - // writer.Write(Extra); - writer.Write(Comment); - } - - internal ushort Version { get; private set; } - - public ushort VersionNeededToExtract { get; set; } - - public uint RelativeOffsetOfEntryHeader { get; set; } - - public uint ExternalFileAttributes { get; set; } - - public ushort InternalFileAttributes { get; set; } - - public ushort DiskNumberStart { get; set; } - - public string Comment { get; private set; } - } +using System.IO; +using System.Linq; + +namespace SharpCompress.Common.Zip.Headers +{ + internal class DirectoryEntryHeader : ZipFileEntry + { + public DirectoryEntryHeader() + : base(ZipHeaderType.DirectoryEntry) + { + } + + internal override void Read(BinaryReader reader) + { + Version = reader.ReadUInt16(); + VersionNeededToExtract = reader.ReadUInt16(); + Flags = (HeaderFlags) reader.ReadUInt16(); + CompressionMethod = (ZipCompressionMethod) reader.ReadUInt16(); + LastModifiedTime = reader.ReadUInt16(); + LastModifiedDate = reader.ReadUInt16(); + Crc = reader.ReadUInt32(); + CompressedSize = reader.ReadUInt32(); + UncompressedSize = reader.ReadUInt32(); + ushort nameLength = reader.ReadUInt16(); + ushort extraLength = reader.ReadUInt16(); + ushort commentLength = reader.ReadUInt16(); + DiskNumberStart = reader.ReadUInt16(); + InternalFileAttributes = reader.ReadUInt16(); + ExternalFileAttributes = reader.ReadUInt32(); + RelativeOffsetOfEntryHeader = reader.ReadUInt32(); + + byte[] name = reader.ReadBytes(nameLength); + Name = DecodeString(name); + byte[] extra = reader.ReadBytes(extraLength); + byte[] comment = reader.ReadBytes(commentLength); + Comment = DecodeString(comment); + LoadExtra(extra); + + var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField); + if (unicodePathExtra != null) + { + Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; + } + } + + internal override void Write(BinaryWriter writer) + { + writer.Write(Version); + writer.Write(VersionNeededToExtract); + writer.Write((ushort) Flags); + writer.Write((ushort) CompressionMethod); + writer.Write(LastModifiedTime); + writer.Write(LastModifiedDate); + writer.Write(Crc); + writer.Write(CompressedSize); + writer.Write(UncompressedSize); + + byte[] nameBytes = EncodeString(Name); + writer.Write((ushort) nameBytes.Length); + //writer.Write((ushort)Extra.Length); + writer.Write((ushort) 0); + writer.Write((ushort) Comment.Length); + + writer.Write(DiskNumberStart); + writer.Write(InternalFileAttributes); + writer.Write(ExternalFileAttributes); + writer.Write(RelativeOffsetOfEntryHeader); + + writer.Write(nameBytes); + // writer.Write(Extra); + writer.Write(Comment); + } + + internal ushort Version { get; private set; } + + public ushort VersionNeededToExtract { get; set; } + + public uint RelativeOffsetOfEntryHeader { get; set; } + + public uint ExternalFileAttributes { get; set; } + + public ushort InternalFileAttributes { get; set; } + + public ushort DiskNumberStart { get; set; } + + public string Comment { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/HeaderFlags.cs b/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs similarity index 95% rename from SharpCompress/Common/Zip/Headers/HeaderFlags.cs rename to src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs index 40562a74..b5415463 100644 --- a/SharpCompress/Common/Zip/Headers/HeaderFlags.cs +++ b/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs @@ -1,15 +1,15 @@ -using System; - -namespace SharpCompress.Common.Zip.Headers -{ - [Flags] - internal enum HeaderFlags : ushort - { - Encrypted = 1, // http://www.pkware.com/documents/casestudies/APPNOTE.TXT - Bit1 = 2, - Bit2 = 4, - UsePostDataDescriptor = 8, - EnhancedDeflate = 16, - UTF8 = 2048 - } +using System; + +namespace SharpCompress.Common.Zip.Headers +{ + [Flags] + internal enum HeaderFlags : ushort + { + Encrypted = 1, // http://www.pkware.com/documents/casestudies/APPNOTE.TXT + Bit1 = 2, + Bit2 = 4, + UsePostDataDescriptor = 8, + EnhancedDeflate = 16, + UTF8 = 2048 + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs b/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs similarity index 95% rename from SharpCompress/Common/Zip/Headers/IgnoreHeader.cs rename to src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs index 679b1048..5aa8e353 100644 --- a/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs @@ -1,22 +1,22 @@ -using System; -using System.IO; - -namespace SharpCompress.Common.Zip.Headers -{ - internal class IgnoreHeader : ZipHeader - { - public IgnoreHeader(ZipHeaderType type) - : base(type) - { - } - - internal override void Read(BinaryReader reader) - { - } - - internal override void Write(BinaryWriter writer) - { - throw new NotImplementedException(); - } - } +using System; +using System.IO; + +namespace SharpCompress.Common.Zip.Headers +{ + internal class IgnoreHeader : ZipHeader + { + public IgnoreHeader(ZipHeaderType type) + : base(type) + { + } + + internal override void Read(BinaryReader reader) + { + } + + internal override void Write(BinaryWriter writer) + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs similarity index 97% rename from SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs rename to src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs index 0146c89e..73b2df15 100644 --- a/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs @@ -1,61 +1,61 @@ -using System.IO; -using System.Linq; - -namespace SharpCompress.Common.Zip.Headers -{ - internal class LocalEntryHeader : ZipFileEntry - { - public LocalEntryHeader() - : base(ZipHeaderType.LocalEntry) - { - } - - internal override void Read(BinaryReader reader) - { - Version = reader.ReadUInt16(); - Flags = (HeaderFlags) reader.ReadUInt16(); - CompressionMethod = (ZipCompressionMethod) reader.ReadUInt16(); - LastModifiedTime = reader.ReadUInt16(); - LastModifiedDate = reader.ReadUInt16(); - Crc = reader.ReadUInt32(); - CompressedSize = reader.ReadUInt32(); - UncompressedSize = reader.ReadUInt32(); - ushort nameLength = reader.ReadUInt16(); - ushort extraLength = reader.ReadUInt16(); - byte[] name = reader.ReadBytes(nameLength); - byte[] extra = reader.ReadBytes(extraLength); - Name = DecodeString(name); - LoadExtra(extra); - - var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField); - if (unicodePathExtra!=null) - { - Name = ((ExtraUnicodePathExtraField) unicodePathExtra).UnicodeName; - } - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Version); - writer.Write((ushort) Flags); - writer.Write((ushort) CompressionMethod); - writer.Write(LastModifiedTime); - writer.Write(LastModifiedDate); - writer.Write(Crc); - writer.Write(CompressedSize); - writer.Write(UncompressedSize); - - byte[] nameBytes = EncodeString(Name); - - writer.Write((ushort) nameBytes.Length); - writer.Write((ushort) 0); - //if (Extra != null) - //{ - // writer.Write(Extra); - //} - writer.Write(nameBytes); - } - - internal ushort Version { get; private set; } - } +using System.IO; +using System.Linq; + +namespace SharpCompress.Common.Zip.Headers +{ + internal class LocalEntryHeader : ZipFileEntry + { + public LocalEntryHeader() + : base(ZipHeaderType.LocalEntry) + { + } + + internal override void Read(BinaryReader reader) + { + Version = reader.ReadUInt16(); + Flags = (HeaderFlags) reader.ReadUInt16(); + CompressionMethod = (ZipCompressionMethod) reader.ReadUInt16(); + LastModifiedTime = reader.ReadUInt16(); + LastModifiedDate = reader.ReadUInt16(); + Crc = reader.ReadUInt32(); + CompressedSize = reader.ReadUInt32(); + UncompressedSize = reader.ReadUInt32(); + ushort nameLength = reader.ReadUInt16(); + ushort extraLength = reader.ReadUInt16(); + byte[] name = reader.ReadBytes(nameLength); + byte[] extra = reader.ReadBytes(extraLength); + Name = DecodeString(name); + LoadExtra(extra); + + var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField); + if (unicodePathExtra!=null) + { + Name = ((ExtraUnicodePathExtraField) unicodePathExtra).UnicodeName; + } + } + + internal override void Write(BinaryWriter writer) + { + writer.Write(Version); + writer.Write((ushort) Flags); + writer.Write((ushort) CompressionMethod); + writer.Write(LastModifiedTime); + writer.Write(LastModifiedDate); + writer.Write(Crc); + writer.Write(CompressedSize); + writer.Write(UncompressedSize); + + byte[] nameBytes = EncodeString(Name); + + writer.Write((ushort) nameBytes.Length); + writer.Write((ushort) 0); + //if (Extra != null) + //{ + // writer.Write(Extra); + //} + writer.Write(nameBytes); + } + + internal ushort Version { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs similarity index 96% rename from SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs rename to src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs index d7741001..f7a98861 100644 --- a/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs @@ -1,75 +1,75 @@ -using System; -using System.Text; - -namespace SharpCompress.Common.Zip.Headers -{ - internal enum ExtraDataType : ushort - { - WinZipAes = 0x9901, - - NotImplementedExtraData = 0xFFFF, - // Third Party Mappings - // -Info-ZIP Unicode Path Extra Field - UnicodePathExtraField = 0x7075 - } - - internal class ExtraData - { - internal ExtraDataType Type { get; set; } - internal ushort Length { get; set; } - internal byte[] DataBytes { get; set; } - } - - internal class ExtraUnicodePathExtraField : ExtraData - { - internal byte Version - { - get { return this.DataBytes[0]; } - } - - internal byte[] NameCRC32 - { - get - { - var crc = new byte[4]; - Buffer.BlockCopy(this.DataBytes, 1, crc, 0, 4); - return crc; - } - } - - internal string UnicodeName - { - get - { - // PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes) - var length = this.Length - 5; - var nameStr = Encoding.UTF8.GetString(this.DataBytes, 5, length); - return nameStr; - } - } - } - - internal static class LocalEntryHeaderExtraFactory - { - internal static ExtraData Create(ExtraDataType type,ushort length, byte[] extraData) - { - switch (type) - { - case ExtraDataType.UnicodePathExtraField: - return new ExtraUnicodePathExtraField() - { - Type = type, - Length = length, - DataBytes = extraData - }; - default: - return new ExtraData - { - Type = type, - Length = length, - DataBytes = extraData - }; - } - } - } -} +using System; +using System.Text; + +namespace SharpCompress.Common.Zip.Headers +{ + internal enum ExtraDataType : ushort + { + WinZipAes = 0x9901, + + NotImplementedExtraData = 0xFFFF, + // Third Party Mappings + // -Info-ZIP Unicode Path Extra Field + UnicodePathExtraField = 0x7075 + } + + internal class ExtraData + { + internal ExtraDataType Type { get; set; } + internal ushort Length { get; set; } + internal byte[] DataBytes { get; set; } + } + + internal class ExtraUnicodePathExtraField : ExtraData + { + internal byte Version + { + get { return this.DataBytes[0]; } + } + + internal byte[] NameCRC32 + { + get + { + var crc = new byte[4]; + Buffer.BlockCopy(this.DataBytes, 1, crc, 0, 4); + return crc; + } + } + + internal string UnicodeName + { + get + { + // PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes) + var length = this.Length - 5; + var nameStr = Encoding.UTF8.GetString(this.DataBytes, 5, length); + return nameStr; + } + } + } + + internal static class LocalEntryHeaderExtraFactory + { + internal static ExtraData Create(ExtraDataType type,ushort length, byte[] extraData) + { + switch (type) + { + case ExtraDataType.UnicodePathExtraField: + return new ExtraUnicodePathExtraField() + { + Type = type, + Length = length, + DataBytes = extraData + }; + default: + return new ExtraData + { + Type = type, + Length = length, + DataBytes = extraData + }; + } + } + } +} diff --git a/SharpCompress/Common/Zip/Headers/SplitHeader.cs b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs similarity index 95% rename from SharpCompress/Common/Zip/Headers/SplitHeader.cs rename to src/SharpCompress/Common/Zip/Headers/SplitHeader.cs index 82bb8f6c..8dbb4c61 100644 --- a/SharpCompress/Common/Zip/Headers/SplitHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs @@ -1,22 +1,22 @@ -using System; - -namespace SharpCompress.Common.Zip.Headers -{ - internal class SplitHeader : ZipHeader - { - public SplitHeader() - : base(ZipHeaderType.Split) - { - } - - internal override void Read(System.IO.BinaryReader reader) - { - throw new NotImplementedException(); - } - - internal override void Write(System.IO.BinaryWriter writer) - { - throw new NotImplementedException(); - } - } +using System; + +namespace SharpCompress.Common.Zip.Headers +{ + internal class SplitHeader : ZipHeader + { + public SplitHeader() + : base(ZipHeaderType.Split) + { + } + + internal override void Read(System.IO.BinaryReader reader) + { + throw new NotImplementedException(); + } + + internal override void Write(System.IO.BinaryWriter writer) + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs similarity index 96% rename from SharpCompress/Common/Zip/Headers/ZipFileEntry.cs rename to src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs index e0c079e7..42b49734 100644 --- a/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs @@ -1,88 +1,88 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace SharpCompress.Common.Zip.Headers -{ - internal abstract class ZipFileEntry : ZipHeader - { - protected ZipFileEntry(ZipHeaderType type) - : base(type) - { - Extra = new List(); - } - - internal bool IsDirectory - { - get { return Name.EndsWith("/"); } - } - - protected string DecodeString(byte[] str) - { - if (FlagUtility.HasFlag(Flags, HeaderFlags.UTF8)) - { - return Encoding.UTF8.GetString(str, 0, str.Length); - } - - return ArchiveEncoding.Default.GetString(str, 0, str.Length); - } - - protected byte[] EncodeString(string str) - { - if (FlagUtility.HasFlag(Flags, HeaderFlags.UTF8)) - { - return Encoding.UTF8.GetBytes(str); - } - return ArchiveEncoding.Default.GetBytes(str); - } - - internal Stream PackedStream { get; set; } - - internal string Name { get; set; } - - internal HeaderFlags Flags { get; set; } - - internal ZipCompressionMethod CompressionMethod { get; set; } - - internal uint CompressedSize { get; set; } - - internal long? DataStartPosition { get; set; } - - internal uint UncompressedSize { get; set; } - - internal List Extra { get; set; } - - internal PkwareTraditionalEncryptionData PkwareTraditionalEncryptionData { get; set; } -#if !DOTNET51 - internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; } -#endif - - internal ushort LastModifiedDate { get; set; } - - internal ushort LastModifiedTime { get; set; } - - internal uint Crc { get; set; } - - protected void LoadExtra(byte[] extra) - { - for (int i = 0; i < extra.Length-4;) - { - ExtraDataType type = (ExtraDataType) BitConverter.ToUInt16(extra, i); - if (!Enum.IsDefined(typeof (ExtraDataType), type)) - { - type = ExtraDataType.NotImplementedExtraData; - } - - ushort length = BitConverter.ToUInt16(extra, i + 2); - byte[] data = new byte[length]; - Buffer.BlockCopy(extra, i + 4, data, 0, length); - Extra.Add(LocalEntryHeaderExtraFactory.Create(type,length,data)); - - i += length + 4; - } - } - - internal ZipFilePart Part { get; set; } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace SharpCompress.Common.Zip.Headers +{ + internal abstract class ZipFileEntry : ZipHeader + { + protected ZipFileEntry(ZipHeaderType type) + : base(type) + { + Extra = new List(); + } + + internal bool IsDirectory + { + get { return Name.EndsWith("/"); } + } + + protected string DecodeString(byte[] str) + { + if (FlagUtility.HasFlag(Flags, HeaderFlags.UTF8)) + { + return Encoding.UTF8.GetString(str, 0, str.Length); + } + + return ArchiveEncoding.Default.GetString(str, 0, str.Length); + } + + protected byte[] EncodeString(string str) + { + if (FlagUtility.HasFlag(Flags, HeaderFlags.UTF8)) + { + return Encoding.UTF8.GetBytes(str); + } + return ArchiveEncoding.Default.GetBytes(str); + } + + internal Stream PackedStream { get; set; } + + internal string Name { get; set; } + + internal HeaderFlags Flags { get; set; } + + internal ZipCompressionMethod CompressionMethod { get; set; } + + internal uint CompressedSize { get; set; } + + internal long? DataStartPosition { get; set; } + + internal uint UncompressedSize { get; set; } + + internal List Extra { get; set; } + + internal PkwareTraditionalEncryptionData PkwareTraditionalEncryptionData { get; set; } +#if !DOTNET51 + internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; } +#endif + + internal ushort LastModifiedDate { get; set; } + + internal ushort LastModifiedTime { get; set; } + + internal uint Crc { get; set; } + + protected void LoadExtra(byte[] extra) + { + for (int i = 0; i < extra.Length-4;) + { + ExtraDataType type = (ExtraDataType) BitConverter.ToUInt16(extra, i); + if (!Enum.IsDefined(typeof (ExtraDataType), type)) + { + type = ExtraDataType.NotImplementedExtraData; + } + + ushort length = BitConverter.ToUInt16(extra, i + 2); + byte[] data = new byte[length]; + Buffer.BlockCopy(extra, i + 4, data, 0, length); + Extra.Add(LocalEntryHeaderExtraFactory.Create(type,length,data)); + + i += length + 4; + } + } + + internal ZipFilePart Part { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/ZipHeader.cs b/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs similarity index 95% rename from SharpCompress/Common/Zip/Headers/ZipHeader.cs rename to src/SharpCompress/Common/Zip/Headers/ZipHeader.cs index e8114b96..ba71778b 100644 --- a/SharpCompress/Common/Zip/Headers/ZipHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs @@ -1,21 +1,21 @@ -using System.IO; - -namespace SharpCompress.Common.Zip.Headers -{ - internal abstract class ZipHeader - { - protected ZipHeader(ZipHeaderType type) - { - ZipHeaderType = type; - HasData = true; - } - - internal ZipHeaderType ZipHeaderType { get; private set; } - - internal abstract void Read(BinaryReader reader); - - internal abstract void Write(BinaryWriter writer); - - internal bool HasData { get; set; } - } +using System.IO; + +namespace SharpCompress.Common.Zip.Headers +{ + internal abstract class ZipHeader + { + protected ZipHeader(ZipHeaderType type) + { + ZipHeaderType = type; + HasData = true; + } + + internal ZipHeaderType ZipHeaderType { get; private set; } + + internal abstract void Read(BinaryReader reader); + + internal abstract void Write(BinaryWriter writer); + + internal bool HasData { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs b/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs similarity index 95% rename from SharpCompress/Common/Zip/Headers/ZipHeaderType.cs rename to src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs index de823d10..45570381 100644 --- a/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs @@ -1,11 +1,11 @@ -namespace SharpCompress.Common.Zip.Headers -{ - internal enum ZipHeaderType - { - Ignore, - LocalEntry, - DirectoryEntry, - DirectoryEnd, - Split, - } +namespace SharpCompress.Common.Zip.Headers +{ + internal enum ZipHeaderType + { + Ignore, + LocalEntry, + DirectoryEntry, + DirectoryEnd, + Split, + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs similarity index 96% rename from SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs rename to src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs index cd82c329..97ac7ed4 100644 --- a/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs @@ -1,120 +1,120 @@ -using System; -using System.IO; - -namespace SharpCompress.Common.Zip -{ - internal enum CryptoMode - { - Encrypt, - Decrypt - } - - - internal class PkwareTraditionalCryptoStream : Stream - { - private readonly PkwareTraditionalEncryptionData encryptor; - private readonly CryptoMode mode; - private readonly Stream stream; - private bool isDisposed; - - public PkwareTraditionalCryptoStream(Stream stream, PkwareTraditionalEncryptionData encryptor, CryptoMode mode) - { - this.encryptor = encryptor; - this.stream = stream; - this.mode = mode; - } - - - public override bool CanRead - { - get { return (mode == CryptoMode.Decrypt); } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return (mode == CryptoMode.Encrypt); } - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (mode == CryptoMode.Encrypt) - throw new NotSupportedException("This stream does not encrypt via Read()"); - - if (buffer == null) - throw new ArgumentNullException("buffer"); - - byte[] temp = new byte[count]; - int readBytes = stream.Read(temp, 0, count); - byte[] decrypted = encryptor.Decrypt(temp, readBytes); - Buffer.BlockCopy(decrypted, 0, buffer, offset, readBytes); - return readBytes; - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (mode == CryptoMode.Decrypt) - throw new NotSupportedException("This stream does not Decrypt via Write()"); - - if (count == 0) - { - return; - } - - byte[] plaintext = null; - if (offset != 0) - { - plaintext = new byte[count]; - Buffer.BlockCopy(buffer, offset, plaintext, 0, count); - } - else - { - plaintext = buffer; - } - - byte[] encrypted = encryptor.Encrypt(plaintext, count); - stream.Write(encrypted, 0, encrypted.Length); - } - - public override void Flush() - { - //throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - stream.Dispose(); - } - } +using System; +using System.IO; + +namespace SharpCompress.Common.Zip +{ + internal enum CryptoMode + { + Encrypt, + Decrypt + } + + + internal class PkwareTraditionalCryptoStream : Stream + { + private readonly PkwareTraditionalEncryptionData encryptor; + private readonly CryptoMode mode; + private readonly Stream stream; + private bool isDisposed; + + public PkwareTraditionalCryptoStream(Stream stream, PkwareTraditionalEncryptionData encryptor, CryptoMode mode) + { + this.encryptor = encryptor; + this.stream = stream; + this.mode = mode; + } + + + public override bool CanRead + { + get { return (mode == CryptoMode.Decrypt); } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return (mode == CryptoMode.Encrypt); } + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (mode == CryptoMode.Encrypt) + throw new NotSupportedException("This stream does not encrypt via Read()"); + + if (buffer == null) + throw new ArgumentNullException("buffer"); + + byte[] temp = new byte[count]; + int readBytes = stream.Read(temp, 0, count); + byte[] decrypted = encryptor.Decrypt(temp, readBytes); + Buffer.BlockCopy(decrypted, 0, buffer, offset, readBytes); + return readBytes; + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (mode == CryptoMode.Decrypt) + throw new NotSupportedException("This stream does not Decrypt via Write()"); + + if (count == 0) + { + return; + } + + byte[] plaintext = null; + if (offset != 0) + { + plaintext = new byte[count]; + Buffer.BlockCopy(buffer, offset, plaintext, 0, count); + } + else + { + plaintext = buffer; + } + + byte[] encrypted = encryptor.Encrypt(plaintext, count); + stream.Write(encrypted, 0, encrypted.Length); + } + + public override void Flush() + { + //throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + stream.Dispose(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs similarity index 97% rename from SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs rename to src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs index f3b11d02..313bb64a 100644 --- a/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs @@ -1,108 +1,108 @@ -using System; -using System.Text; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.Compressor.Deflate; - -namespace SharpCompress.Common.Zip -{ - internal class PkwareTraditionalEncryptionData - { - private static readonly CRC32 crc32 = new CRC32(); - private readonly UInt32[] _Keys = {0x12345678, 0x23456789, 0x34567890}; - - private PkwareTraditionalEncryptionData(string password) - { - Initialize(password); - } - - private byte MagicByte - { - get - { - ushort t = (ushort) ((ushort) (_Keys[2] & 0xFFFF) | 2); - return (byte) ((t*(t ^ 1)) >> 8); - } - } - - public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header, - byte[] encryptionHeader) - { - var encryptor = new PkwareTraditionalEncryptionData(password); - byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length); - if (plainTextHeader[11] != (byte) ((header.Crc >> 24) & 0xff)) - { - if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor)) - { - throw new CryptographicException("The password did not match."); - } - if (plainTextHeader[11] != (byte) ((header.LastModifiedTime >> 8) & 0xff)) - { - throw new CryptographicException("The password did not match."); - } - } - return encryptor; - } - - - public byte[] Decrypt(byte[] cipherText, int length) - { - if (length > cipherText.Length) - throw new ArgumentOutOfRangeException("length", - "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array."); - - var plainText = new byte[length]; - for (int i = 0; i < length; i++) - { - var C = (byte) (cipherText[i] ^ MagicByte); - UpdateKeys(C); - plainText[i] = C; - } - return plainText; - } - - public byte[] Encrypt(byte[] plainText, int length) - { - if (plainText == null) - throw new ArgumentNullException("plaintext"); - - if (length > plainText.Length) - throw new ArgumentOutOfRangeException("length", - "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array."); - - var cipherText = new byte[length]; - for (int i = 0; i < length; i++) - { - byte C = plainText[i]; - cipherText[i] = (byte) (plainText[i] ^ MagicByte); - UpdateKeys(C); - } - return cipherText; - } - - private void Initialize(string password) - { - byte[] p = StringToByteArray(password); - for (int i = 0; i < password.Length; i++) - UpdateKeys(p[i]); - } - - internal static byte[] StringToByteArray(string value, Encoding encoding) - { - byte[] a = encoding.GetBytes(value); - return a; - } - - internal static byte[] StringToByteArray(string value) - { - return StringToByteArray(value, ArchiveEncoding.Password); - } - - private void UpdateKeys(byte byteValue) - { - _Keys[0] = (UInt32) crc32.ComputeCrc32((int) _Keys[0], byteValue); - _Keys[1] = _Keys[1] + (byte) _Keys[0]; - _Keys[1] = _Keys[1]*0x08088405 + 1; - _Keys[2] = (UInt32) crc32.ComputeCrc32((int) _Keys[2], (byte) (_Keys[1] >> 24)); - } - } +using System; +using System.Text; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.Compressor.Deflate; + +namespace SharpCompress.Common.Zip +{ + internal class PkwareTraditionalEncryptionData + { + private static readonly CRC32 crc32 = new CRC32(); + private readonly UInt32[] _Keys = {0x12345678, 0x23456789, 0x34567890}; + + private PkwareTraditionalEncryptionData(string password) + { + Initialize(password); + } + + private byte MagicByte + { + get + { + ushort t = (ushort) ((ushort) (_Keys[2] & 0xFFFF) | 2); + return (byte) ((t*(t ^ 1)) >> 8); + } + } + + public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header, + byte[] encryptionHeader) + { + var encryptor = new PkwareTraditionalEncryptionData(password); + byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length); + if (plainTextHeader[11] != (byte) ((header.Crc >> 24) & 0xff)) + { + if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor)) + { + throw new CryptographicException("The password did not match."); + } + if (plainTextHeader[11] != (byte) ((header.LastModifiedTime >> 8) & 0xff)) + { + throw new CryptographicException("The password did not match."); + } + } + return encryptor; + } + + + public byte[] Decrypt(byte[] cipherText, int length) + { + if (length > cipherText.Length) + throw new ArgumentOutOfRangeException("length", + "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array."); + + var plainText = new byte[length]; + for (int i = 0; i < length; i++) + { + var C = (byte) (cipherText[i] ^ MagicByte); + UpdateKeys(C); + plainText[i] = C; + } + return plainText; + } + + public byte[] Encrypt(byte[] plainText, int length) + { + if (plainText == null) + throw new ArgumentNullException("plaintext"); + + if (length > plainText.Length) + throw new ArgumentOutOfRangeException("length", + "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array."); + + var cipherText = new byte[length]; + for (int i = 0; i < length; i++) + { + byte C = plainText[i]; + cipherText[i] = (byte) (plainText[i] ^ MagicByte); + UpdateKeys(C); + } + return cipherText; + } + + private void Initialize(string password) + { + byte[] p = StringToByteArray(password); + for (int i = 0; i < password.Length; i++) + UpdateKeys(p[i]); + } + + internal static byte[] StringToByteArray(string value, Encoding encoding) + { + byte[] a = encoding.GetBytes(value); + return a; + } + + internal static byte[] StringToByteArray(string value) + { + return StringToByteArray(value, ArchiveEncoding.Password); + } + + private void UpdateKeys(byte byteValue) + { + _Keys[0] = (UInt32) crc32.ComputeCrc32((int) _Keys[0], byteValue); + _Keys[1] = _Keys[1] + (byte) _Keys[0]; + _Keys[1] = _Keys[1]*0x08088405 + 1; + _Keys[2] = (UInt32) crc32.ComputeCrc32((int) _Keys[2], (byte) (_Keys[1] >> 24)); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/SeekableZipFilePart.cs b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs similarity index 96% rename from SharpCompress/Common/Zip/SeekableZipFilePart.cs rename to src/SharpCompress/Common/Zip/SeekableZipFilePart.cs index f507c113..dc4fc61d 100644 --- a/SharpCompress/Common/Zip/SeekableZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs @@ -1,45 +1,45 @@ -using System.IO; -using SharpCompress.Common.Zip.Headers; - -namespace SharpCompress.Common.Zip -{ - internal class SeekableZipFilePart : ZipFilePart - { - private bool isLocalHeaderLoaded; - private readonly SeekableZipHeaderFactory headerFactory; - - internal SeekableZipFilePart(SeekableZipHeaderFactory headerFactory, DirectoryEntryHeader header, Stream stream) - : base(header, stream) - { - this.headerFactory = headerFactory; - } - - internal override Stream GetCompressedStream() - { - if (!isLocalHeaderLoaded) - { - LoadLocalHeader(); - isLocalHeaderLoaded = true; - } - return base.GetCompressedStream(); - } - - internal string Comment - { - get { return (Header as DirectoryEntryHeader).Comment; } - } - - private void LoadLocalHeader() - { - bool hasData = Header.HasData; - Header = headerFactory.GetLocalHeader(BaseStream, Header as DirectoryEntryHeader); - Header.HasData = hasData; - } - - protected override Stream CreateBaseStream() - { - BaseStream.Position = Header.DataStartPosition.Value; - return BaseStream; - } - } +using System.IO; +using SharpCompress.Common.Zip.Headers; + +namespace SharpCompress.Common.Zip +{ + internal class SeekableZipFilePart : ZipFilePart + { + private bool isLocalHeaderLoaded; + private readonly SeekableZipHeaderFactory headerFactory; + + internal SeekableZipFilePart(SeekableZipHeaderFactory headerFactory, DirectoryEntryHeader header, Stream stream) + : base(header, stream) + { + this.headerFactory = headerFactory; + } + + internal override Stream GetCompressedStream() + { + if (!isLocalHeaderLoaded) + { + LoadLocalHeader(); + isLocalHeaderLoaded = true; + } + return base.GetCompressedStream(); + } + + internal string Comment + { + get { return (Header as DirectoryEntryHeader).Comment; } + } + + private void LoadLocalHeader() + { + bool hasData = Header.HasData; + Header = headerFactory.GetLocalHeader(BaseStream, Header as DirectoryEntryHeader); + Header.HasData = hasData; + } + + protected override Stream CreateBaseStream() + { + BaseStream.Position = Header.DataStartPosition.Value; + return BaseStream; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs similarity index 97% rename from SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs rename to src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs index 61c96393..98eb9f43 100644 --- a/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs @@ -1,77 +1,77 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Common.Zip -{ - internal class SeekableZipHeaderFactory : ZipHeaderFactory - { - private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096; - - internal SeekableZipHeaderFactory(string password) - : base(StreamingMode.Seekable, password) - { - } - - internal IEnumerable ReadSeekableHeader(Stream stream) - { - long offset = 0; - uint signature; - BinaryReader reader = new BinaryReader(stream); - - int iterationCount = 0; - do - { - if ((stream.Length + offset) - 4 < 0) - { - throw new ArchiveException("Failed to locate the Zip Header"); - } - stream.Seek(offset - 4, SeekOrigin.End); - signature = reader.ReadUInt32(); - offset--; - iterationCount++; - if (iterationCount > MAX_ITERATIONS_FOR_DIRECTORY_HEADER) - { - throw new ArchiveException( - "Could not find Zip file Directory at the end of the file. File may be corrupted."); - } - } while (signature != DIRECTORY_END_HEADER_BYTES); - - var entry = new DirectoryEndHeader(); - entry.Read(reader); - stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); - - DirectoryEntryHeader directoryEntryHeader = null; - long position = stream.Position; - while (true) - { - stream.Position = position; - signature = reader.ReadUInt32(); - directoryEntryHeader = ReadHeader(signature, reader) as DirectoryEntryHeader; - position = stream.Position; - if (directoryEntryHeader == null) - { - yield break; - } - //entry could be zero bytes so we need to know that. - directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0; - yield return directoryEntryHeader; - } - } - - internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader) - { - stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin); - BinaryReader reader = new BinaryReader(stream); - uint signature = reader.ReadUInt32(); - var localEntryHeader = ReadHeader(signature, reader) as LocalEntryHeader; - if (localEntryHeader == null) - { - throw new InvalidOperationException(); - } - return localEntryHeader; - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Zip +{ + internal class SeekableZipHeaderFactory : ZipHeaderFactory + { + private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096; + + internal SeekableZipHeaderFactory(string password) + : base(StreamingMode.Seekable, password) + { + } + + internal IEnumerable ReadSeekableHeader(Stream stream) + { + long offset = 0; + uint signature; + BinaryReader reader = new BinaryReader(stream); + + int iterationCount = 0; + do + { + if ((stream.Length + offset) - 4 < 0) + { + throw new ArchiveException("Failed to locate the Zip Header"); + } + stream.Seek(offset - 4, SeekOrigin.End); + signature = reader.ReadUInt32(); + offset--; + iterationCount++; + if (iterationCount > MAX_ITERATIONS_FOR_DIRECTORY_HEADER) + { + throw new ArchiveException( + "Could not find Zip file Directory at the end of the file. File may be corrupted."); + } + } while (signature != DIRECTORY_END_HEADER_BYTES); + + var entry = new DirectoryEndHeader(); + entry.Read(reader); + stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); + + DirectoryEntryHeader directoryEntryHeader = null; + long position = stream.Position; + while (true) + { + stream.Position = position; + signature = reader.ReadUInt32(); + directoryEntryHeader = ReadHeader(signature, reader) as DirectoryEntryHeader; + position = stream.Position; + if (directoryEntryHeader == null) + { + yield break; + } + //entry could be zero bytes so we need to know that. + directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0; + yield return directoryEntryHeader; + } + } + + internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader) + { + stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin); + BinaryReader reader = new BinaryReader(stream); + uint signature = reader.ReadUInt32(); + var localEntryHeader = ReadHeader(signature, reader) as LocalEntryHeader; + if (localEntryHeader == null) + { + throw new InvalidOperationException(); + } + return localEntryHeader; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs similarity index 96% rename from SharpCompress/Common/Zip/StreamingZipFilePart.cs rename to src/SharpCompress/Common/Zip/StreamingZipFilePart.cs index 82a0b43a..6dcdd34d 100644 --- a/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -1,61 +1,61 @@ -using System.IO; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.Compressor.Deflate; -using SharpCompress.IO; - -namespace SharpCompress.Common.Zip -{ - internal class StreamingZipFilePart : ZipFilePart - { - private Stream decompressionStream; - - internal StreamingZipFilePart(ZipFileEntry header, Stream stream) - : base(header, stream) - { - } - - protected override Stream CreateBaseStream() - { - return Header.PackedStream; - } - - internal override Stream GetCompressedStream() - { - if (!Header.HasData) - { - return Stream.Null; - } - decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream())); - if (LeaveStreamOpen) - { - return new NonDisposingStream(decompressionStream); - } - return decompressionStream; - } - - internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStream) - { - if (Header.IsDirectory) - { - return new BinaryReader(rewindableStream); - } - if (Header.HasData) - { - if (decompressionStream == null) - { - decompressionStream = GetCompressedStream(); - } - decompressionStream.SkipAll(); - - DeflateStream deflateStream = decompressionStream as DeflateStream; - if (deflateStream != null) - { - rewindableStream.Rewind(deflateStream.InputBuffer); - } - } - var reader = new BinaryReader(rewindableStream); - decompressionStream = null; - return reader; - } - } +using System.IO; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.Compressor.Deflate; +using SharpCompress.IO; + +namespace SharpCompress.Common.Zip +{ + internal class StreamingZipFilePart : ZipFilePart + { + private Stream decompressionStream; + + internal StreamingZipFilePart(ZipFileEntry header, Stream stream) + : base(header, stream) + { + } + + protected override Stream CreateBaseStream() + { + return Header.PackedStream; + } + + internal override Stream GetCompressedStream() + { + if (!Header.HasData) + { + return Stream.Null; + } + decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream())); + if (LeaveStreamOpen) + { + return new NonDisposingStream(decompressionStream); + } + return decompressionStream; + } + + internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStream) + { + if (Header.IsDirectory) + { + return new BinaryReader(rewindableStream); + } + if (Header.HasData) + { + if (decompressionStream == null) + { + decompressionStream = GetCompressedStream(); + } + decompressionStream.SkipAll(); + + DeflateStream deflateStream = decompressionStream as DeflateStream; + if (deflateStream != null) + { + rewindableStream.Rewind(deflateStream.InputBuffer); + } + } + var reader = new BinaryReader(rewindableStream); + decompressionStream = null; + return reader; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs similarity index 97% rename from SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs rename to src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 6bcffa1d..7e736cef 100644 --- a/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -1,65 +1,65 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Common.Zip -{ - internal class StreamingZipHeaderFactory : ZipHeaderFactory - { - internal StreamingZipHeaderFactory(string password) - : base(StreamingMode.Streaming, password) - { - } - - internal IEnumerable ReadStreamHeader(Stream stream) - { - RewindableStream rewindableStream; - if (stream is RewindableStream) - { - rewindableStream = stream as RewindableStream; - } - else - { - rewindableStream = new RewindableStream(stream); - } - while (true) - { - ZipHeader header = null; - BinaryReader reader = new BinaryReader(rewindableStream); - if (lastEntryHeader != null && - FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) - { - reader = (lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream); - long pos = rewindableStream.Position; - uint crc = reader.ReadUInt32(); - if (crc == POST_DATA_DESCRIPTOR) - { - crc = reader.ReadUInt32(); - } - lastEntryHeader.Crc = crc; - lastEntryHeader.CompressedSize = reader.ReadUInt32(); - lastEntryHeader.UncompressedSize = reader.ReadUInt32(); - lastEntryHeader.DataStartPosition = pos - lastEntryHeader.CompressedSize; - } - lastEntryHeader = null; - uint headerBytes = reader.ReadUInt32(); - header = ReadHeader(headerBytes, reader); - - //entry could be zero bytes so we need to know that. - if (header.ZipHeaderType == ZipHeaderType.LocalEntry) - { - bool isRecording = rewindableStream.IsRecording; - if (!isRecording) - { - rewindableStream.StartRecording(); - } - uint nextHeaderBytes = reader.ReadUInt32(); - header.HasData = !IsHeader(nextHeaderBytes); - rewindableStream.Rewind(!isRecording); - } - yield return header; - } - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Common.Zip +{ + internal class StreamingZipHeaderFactory : ZipHeaderFactory + { + internal StreamingZipHeaderFactory(string password) + : base(StreamingMode.Streaming, password) + { + } + + internal IEnumerable ReadStreamHeader(Stream stream) + { + RewindableStream rewindableStream; + if (stream is RewindableStream) + { + rewindableStream = stream as RewindableStream; + } + else + { + rewindableStream = new RewindableStream(stream); + } + while (true) + { + ZipHeader header = null; + BinaryReader reader = new BinaryReader(rewindableStream); + if (lastEntryHeader != null && + FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) + { + reader = (lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream); + long pos = rewindableStream.Position; + uint crc = reader.ReadUInt32(); + if (crc == POST_DATA_DESCRIPTOR) + { + crc = reader.ReadUInt32(); + } + lastEntryHeader.Crc = crc; + lastEntryHeader.CompressedSize = reader.ReadUInt32(); + lastEntryHeader.UncompressedSize = reader.ReadUInt32(); + lastEntryHeader.DataStartPosition = pos - lastEntryHeader.CompressedSize; + } + lastEntryHeader = null; + uint headerBytes = reader.ReadUInt32(); + header = ReadHeader(headerBytes, reader); + + //entry could be zero bytes so we need to know that. + if (header.ZipHeaderType == ZipHeaderType.LocalEntry) + { + bool isRecording = rewindableStream.IsRecording; + if (!isRecording) + { + rewindableStream.StartRecording(); + } + uint nextHeaderBytes = reader.ReadUInt32(); + header.HasData = !IsHeader(nextHeaderBytes); + rewindableStream.Rewind(!isRecording); + } + yield return header; + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs similarity index 96% rename from SharpCompress/Common/Zip/WinzipAesCryptoStream.cs rename to src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs index c14216e6..bdad6cf7 100644 --- a/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs @@ -1,188 +1,188 @@ -using System; -using System.IO; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; - -namespace SharpCompress.Common.Zip -{ - internal class WinzipAesCryptoStream : Stream - { - private const int BLOCK_SIZE_IN_BYTES = 16; - private readonly IBufferedCipher rijndael; - private readonly byte[] counter = new byte[BLOCK_SIZE_IN_BYTES]; - private readonly Stream stream; - private int nonce = 1; - private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES]; - private bool isFinalBlock; - private long totalBytesLeftToRead; - private bool isDisposed; - - internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length) - { - this.stream = stream; - totalBytesLeftToRead = length; - - rijndael = CreateRijndael(winzipAesEncryptionData); - } - - private IBufferedCipher CreateRijndael(WinzipAesEncryptionData winzipAesEncryptionData) - { - var blockCipher = new BufferedBlockCipher(new RijndaelEngine()); - var param = new KeyParameter(winzipAesEncryptionData.KeyBytes); - blockCipher.Init(true, param); - return blockCipher; - } - - public override bool CanRead - { - get - { - return true; - } - } - - public override bool CanSeek - { - get - { - return false; - } - } - - public override bool CanWrite - { - get - { - return false; - } - } - - public override long Length - { - get - { - throw new NotImplementedException(); - } - } - - public override long Position - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - //read out last 10 auth bytes - var ten = new byte[10]; - stream.Read(ten, 0, 10); - stream.Dispose(); - } - } - - public override void Flush() - { - throw new NotImplementedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (totalBytesLeftToRead == 0) - { - return 0; - } - int bytesToRead = count; - if (count > totalBytesLeftToRead) - { - bytesToRead = (int)totalBytesLeftToRead; - } - int read = stream.Read(buffer, offset, bytesToRead); - totalBytesLeftToRead = read; - - ReadTransformBlocks(buffer, offset, read); - - return read; - } - - private int ReadTransformOneBlock(byte[] buffer, int offset, int last) - { - if (isFinalBlock) - { - throw new InvalidOperationException(); - } - - int bytesRemaining = last - offset; - int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES) - ? BLOCK_SIZE_IN_BYTES - : bytesRemaining; - - // update the counter - Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4); - - // Determine if this is the final block - if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0)) - { - counterOut = rijndael.DoFinal(counter, 0, BLOCK_SIZE_IN_BYTES); - - isFinalBlock = true; - } - else - { - rijndael.ProcessBytes(counter, 0, BLOCK_SIZE_IN_BYTES, counterOut, 0); - } - XorInPlace(buffer, offset, bytesToRead); - return bytesToRead; - } - - - private void XorInPlace(byte[] buffer, int offset, int count) - { - for (int i = 0; i < count; i++) - { - buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]); - } - } - - private void ReadTransformBlocks(byte[] buffer, int offset, int count) - { - int posn = offset; - int last = count + offset; - - while (posn < buffer.Length && posn < last) - { - int n = ReadTransformOneBlock(buffer, posn, last); - posn += n; - } - } - - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - } +using System; +using System.IO; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; + +namespace SharpCompress.Common.Zip +{ + internal class WinzipAesCryptoStream : Stream + { + private const int BLOCK_SIZE_IN_BYTES = 16; + private readonly IBufferedCipher rijndael; + private readonly byte[] counter = new byte[BLOCK_SIZE_IN_BYTES]; + private readonly Stream stream; + private int nonce = 1; + private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES]; + private bool isFinalBlock; + private long totalBytesLeftToRead; + private bool isDisposed; + + internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length) + { + this.stream = stream; + totalBytesLeftToRead = length; + + rijndael = CreateRijndael(winzipAesEncryptionData); + } + + private IBufferedCipher CreateRijndael(WinzipAesEncryptionData winzipAesEncryptionData) + { + var blockCipher = new BufferedBlockCipher(new RijndaelEngine()); + var param = new KeyParameter(winzipAesEncryptionData.KeyBytes); + blockCipher.Init(true, param); + return blockCipher; + } + + public override bool CanRead + { + get + { + return true; + } + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanWrite + { + get + { + return false; + } + } + + public override long Length + { + get + { + throw new NotImplementedException(); + } + } + + public override long Position + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + if (disposing) + { + //read out last 10 auth bytes + var ten = new byte[10]; + stream.Read(ten, 0, 10); + stream.Dispose(); + } + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (totalBytesLeftToRead == 0) + { + return 0; + } + int bytesToRead = count; + if (count > totalBytesLeftToRead) + { + bytesToRead = (int)totalBytesLeftToRead; + } + int read = stream.Read(buffer, offset, bytesToRead); + totalBytesLeftToRead = read; + + ReadTransformBlocks(buffer, offset, read); + + return read; + } + + private int ReadTransformOneBlock(byte[] buffer, int offset, int last) + { + if (isFinalBlock) + { + throw new InvalidOperationException(); + } + + int bytesRemaining = last - offset; + int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES) + ? BLOCK_SIZE_IN_BYTES + : bytesRemaining; + + // update the counter + Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4); + + // Determine if this is the final block + if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0)) + { + counterOut = rijndael.DoFinal(counter, 0, BLOCK_SIZE_IN_BYTES); + + isFinalBlock = true; + } + else + { + rijndael.ProcessBytes(counter, 0, BLOCK_SIZE_IN_BYTES, counterOut, 0); + } + XorInPlace(buffer, offset, bytesToRead); + return bytesToRead; + } + + + private void XorInPlace(byte[] buffer, int offset, int count) + { + for (int i = 0; i < count; i++) + { + buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]); + } + } + + private void ReadTransformBlocks(byte[] buffer, int offset, int count) + { + int posn = offset; + int last = count + offset; + + while (posn < buffer.Length && posn < last) + { + int n = ReadTransformOneBlock(buffer, posn, last); + posn += n; + } + } + + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs similarity index 96% rename from SharpCompress/Common/Zip/WinzipAesEncryptionData.cs rename to src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index 204ddfcb..8f906d3d 100644 --- a/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -1,75 +1,75 @@ -using System; -using System.Text; -using SharpCompress.Crypto; - -namespace SharpCompress.Common.Zip -{ - internal class WinzipAesEncryptionData - { - private const int RFC2898_ITERATIONS = 1000; - - private byte[] salt; - private WinzipAesKeySize keySize; - private byte[] passwordVerifyValue; - private string password; - - private byte[] generatedVerifyValue; - - internal WinzipAesEncryptionData(WinzipAesKeySize keySize, byte[] salt, byte[] passwordVerifyValue, - string password) - { - this.keySize = keySize; - this.salt = salt; - this.passwordVerifyValue = passwordVerifyValue; - this.password = password; - Initialize(); - } - - internal byte[] IvBytes -{ - get; set; -} - internal byte[] KeyBytes -{ - get; set; -} - - private int KeySizeInBytes - { - get { return KeyLengthInBytes(keySize); -} - } - - internal static int KeyLengthInBytes(WinzipAesKeySize keySize) - { - switch (keySize) - { - case WinzipAesKeySize.KeySize128: - return 16; - case WinzipAesKeySize.KeySize192: - return 24; - case WinzipAesKeySize.KeySize256: - return 32; - } - throw new InvalidOperationException(); - } - - private void Initialize() - { - var utf8 = new UTF8Encoding(false); - var paramz = new PBKDF2(utf8.GetBytes(password), salt, RFC2898_ITERATIONS); - KeyBytes = paramz.GetBytes(KeySizeInBytes); - IvBytes = paramz.GetBytes(KeySizeInBytes); - generatedVerifyValue = paramz.GetBytes(2); - - - short verify = BitConverter.ToInt16(passwordVerifyValue, 0); - if (password != null) - { - short generated = BitConverter.ToInt16(generatedVerifyValue, 0); - if (verify != generated) - throw new InvalidFormatException("bad password"); - } - } - } -} +using System; +using System.Text; +using SharpCompress.Crypto; + +namespace SharpCompress.Common.Zip +{ + internal class WinzipAesEncryptionData + { + private const int RFC2898_ITERATIONS = 1000; + + private byte[] salt; + private WinzipAesKeySize keySize; + private byte[] passwordVerifyValue; + private string password; + + private byte[] generatedVerifyValue; + + internal WinzipAesEncryptionData(WinzipAesKeySize keySize, byte[] salt, byte[] passwordVerifyValue, + string password) + { + this.keySize = keySize; + this.salt = salt; + this.passwordVerifyValue = passwordVerifyValue; + this.password = password; + Initialize(); + } + + internal byte[] IvBytes +{ + get; set; +} + internal byte[] KeyBytes +{ + get; set; +} + + private int KeySizeInBytes + { + get { return KeyLengthInBytes(keySize); +} + } + + internal static int KeyLengthInBytes(WinzipAesKeySize keySize) + { + switch (keySize) + { + case WinzipAesKeySize.KeySize128: + return 16; + case WinzipAesKeySize.KeySize192: + return 24; + case WinzipAesKeySize.KeySize256: + return 32; + } + throw new InvalidOperationException(); + } + + private void Initialize() + { + var utf8 = new UTF8Encoding(false); + var paramz = new PBKDF2(utf8.GetBytes(password), salt, RFC2898_ITERATIONS); + KeyBytes = paramz.GetBytes(KeySizeInBytes); + IvBytes = paramz.GetBytes(KeySizeInBytes); + generatedVerifyValue = paramz.GetBytes(2); + + + short verify = BitConverter.ToInt16(passwordVerifyValue, 0); + if (password != null) + { + short generated = BitConverter.ToInt16(generatedVerifyValue, 0); + if (verify != generated) + throw new InvalidFormatException("bad password"); + } + } + } +} diff --git a/SharpCompress/Common/Zip/WinzipAesKeySize.cs b/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs similarity index 95% rename from SharpCompress/Common/Zip/WinzipAesKeySize.cs rename to src/SharpCompress/Common/Zip/WinzipAesKeySize.cs index c5c55d30..7df0cb6f 100644 --- a/SharpCompress/Common/Zip/WinzipAesKeySize.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs @@ -1,9 +1,9 @@ -namespace SharpCompress.Common.Zip -{ - internal enum WinzipAesKeySize - { - KeySize128 = 1, - KeySize192 = 2, - KeySize256 = 3, - } +namespace SharpCompress.Common.Zip +{ + internal enum WinzipAesKeySize + { + KeySize128 = 1, + KeySize192 = 2, + KeySize256 = 3, + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/ZipCompressionMethod.cs b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs similarity index 95% rename from SharpCompress/Common/Zip/ZipCompressionMethod.cs rename to src/SharpCompress/Common/Zip/ZipCompressionMethod.cs index 887418cf..bf7df040 100644 --- a/SharpCompress/Common/Zip/ZipCompressionMethod.cs +++ b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs @@ -1,13 +1,13 @@ -namespace SharpCompress.Common.Zip -{ - internal enum ZipCompressionMethod - { - None = 0, - Deflate = 8, - Deflate64 = 9, - BZip2 = 12, - LZMA = 14, - PPMd = 98, - WinzipAes = 0x63 //http://www.winzip.com/aes_info.htm - } +namespace SharpCompress.Common.Zip +{ + internal enum ZipCompressionMethod + { + None = 0, + Deflate = 8, + Deflate64 = 9, + BZip2 = 12, + LZMA = 14, + PPMd = 98, + WinzipAes = 0x63 //http://www.winzip.com/aes_info.htm + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/ZipEntry.cs b/src/SharpCompress/Common/Zip/ZipEntry.cs similarity index 96% rename from SharpCompress/Common/Zip/ZipEntry.cs rename to src/SharpCompress/Common/Zip/ZipEntry.cs index 1c8593e0..7b962ace 100644 --- a/SharpCompress/Common/Zip/ZipEntry.cs +++ b/src/SharpCompress/Common/Zip/ZipEntry.cs @@ -1,116 +1,116 @@ -using System; -using System.Collections.Generic; -using SharpCompress.Common.Zip.Headers; - -namespace SharpCompress.Common.Zip -{ - public class ZipEntry : Entry - { - private readonly ZipFilePart filePart; - private readonly DateTime? lastModifiedTime; - - internal ZipEntry(ZipFilePart filePart) - { - if (filePart != null) - { - this.filePart = filePart; - lastModifiedTime = Utility.DosDateToDateTime(filePart.Header.LastModifiedDate, - filePart.Header.LastModifiedTime); - } - } - - public override CompressionType CompressionType - { - get - { - switch (filePart.Header.CompressionMethod) - { - case ZipCompressionMethod.BZip2: - { - return CompressionType.BZip2; - } - case ZipCompressionMethod.Deflate: - { - return CompressionType.Deflate; - } - case ZipCompressionMethod.LZMA: - { - return CompressionType.LZMA; - } - case ZipCompressionMethod.PPMd: - { - return CompressionType.PPMd; - } - case ZipCompressionMethod.None: - { - return CompressionType.None; - } - default: - { - return CompressionType.Unknown; - } - } - } - } - - public override long Crc - { - get { return filePart.Header.Crc; } - } - - public override string Key - { - get { return filePart.Header.Name; } - } - - public override long CompressedSize - { - get { return filePart.Header.CompressedSize; } - } - - public override long Size - { - get { return filePart.Header.UncompressedSize; } - } - - public override DateTime? LastModifiedTime - { - get { return lastModifiedTime; } - } - - public override DateTime? CreatedTime - { - get { return null; } - } - - public override DateTime? LastAccessedTime - { - get { return null; } - } - - public override DateTime? ArchivedTime - { - get { return null; } - } - - public override bool IsEncrypted - { - get { return FlagUtility.HasFlag(filePart.Header.Flags, HeaderFlags.Encrypted); } - } - - public override bool IsDirectory - { - get { return filePart.Header.IsDirectory; } - } - - public override bool IsSplit - { - get { return false; } - } - - internal override IEnumerable Parts - { - get { return filePart.AsEnumerable(); } - } - } +using System; +using System.Collections.Generic; +using SharpCompress.Common.Zip.Headers; + +namespace SharpCompress.Common.Zip +{ + public class ZipEntry : Entry + { + private readonly ZipFilePart filePart; + private readonly DateTime? lastModifiedTime; + + internal ZipEntry(ZipFilePart filePart) + { + if (filePart != null) + { + this.filePart = filePart; + lastModifiedTime = Utility.DosDateToDateTime(filePart.Header.LastModifiedDate, + filePart.Header.LastModifiedTime); + } + } + + public override CompressionType CompressionType + { + get + { + switch (filePart.Header.CompressionMethod) + { + case ZipCompressionMethod.BZip2: + { + return CompressionType.BZip2; + } + case ZipCompressionMethod.Deflate: + { + return CompressionType.Deflate; + } + case ZipCompressionMethod.LZMA: + { + return CompressionType.LZMA; + } + case ZipCompressionMethod.PPMd: + { + return CompressionType.PPMd; + } + case ZipCompressionMethod.None: + { + return CompressionType.None; + } + default: + { + return CompressionType.Unknown; + } + } + } + } + + public override long Crc + { + get { return filePart.Header.Crc; } + } + + public override string Key + { + get { return filePart.Header.Name; } + } + + public override long CompressedSize + { + get { return filePart.Header.CompressedSize; } + } + + public override long Size + { + get { return filePart.Header.UncompressedSize; } + } + + public override DateTime? LastModifiedTime + { + get { return lastModifiedTime; } + } + + public override DateTime? CreatedTime + { + get { return null; } + } + + public override DateTime? LastAccessedTime + { + get { return null; } + } + + public override DateTime? ArchivedTime + { + get { return null; } + } + + public override bool IsEncrypted + { + get { return FlagUtility.HasFlag(filePart.Header.Flags, HeaderFlags.Encrypted); } + } + + public override bool IsDirectory + { + get { return filePart.Header.IsDirectory; } + } + + public override bool IsSplit + { + get { return false; } + } + + internal override IEnumerable Parts + { + get { return filePart.AsEnumerable(); } + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs similarity index 97% rename from SharpCompress/Common/Zip/ZipFilePart.cs rename to src/SharpCompress/Common/Zip/ZipFilePart.cs index 8371a5a3..cc73e1d5 100644 --- a/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs @@ -1,169 +1,169 @@ -using System; -using System.IO; -using System.Linq; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.Compressor; -using SharpCompress.Compressor.BZip2; -using SharpCompress.Compressor.Deflate; -using SharpCompress.Compressor.LZMA; -using SharpCompress.Compressor.PPMd; -using SharpCompress.IO; - -namespace SharpCompress.Common.Zip -{ - internal abstract class ZipFilePart : FilePart - { - internal ZipFilePart(ZipFileEntry header, Stream stream) - { - Header = header; - header.Part = this; - this.BaseStream = stream; - } - - internal Stream BaseStream { get; private set; } - internal ZipFileEntry Header { get; set; } - - - internal override string FilePartName - { - get { return Header.Name; } - } - - internal override Stream GetCompressedStream() - { - if (!Header.HasData) - { - return Stream.Null; - } - Stream decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream())); - if (LeaveStreamOpen) - { - return new NonDisposingStream(decompressionStream); - } - return decompressionStream; - } - - internal override Stream GetRawStream() - { - if (!Header.HasData) - { - return Stream.Null; - } - return CreateBaseStream(); - } - - protected abstract Stream CreateBaseStream(); - - protected bool LeaveStreamOpen - { - get { return FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor); } - } - - protected Stream CreateDecompressionStream(Stream stream) - { - switch (Header.CompressionMethod) - { - case ZipCompressionMethod.None: - { - return stream; - } - case ZipCompressionMethod.Deflate: - { - return new DeflateStream(stream, CompressionMode.Decompress); - } - case ZipCompressionMethod.BZip2: - { - return new BZip2Stream(stream, CompressionMode.Decompress); - } - case ZipCompressionMethod.LZMA: - { - if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) - { - throw new NotSupportedException("LZMA with pkware encryption."); - } - var reader = new BinaryReader(stream); - reader.ReadUInt16(); //LZMA version - var props = new byte[reader.ReadUInt16()]; - reader.Read(props, 0, props.Length); - return new LzmaStream(props, stream, - Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, - FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) - ? -1 - : (long)Header.UncompressedSize); - } - case ZipCompressionMethod.PPMd: - { - var props = new byte[2]; - stream.Read(props, 0, props.Length); - return new PpmdStream(new PpmdProperties(props), stream, false); - } - case ZipCompressionMethod.WinzipAes: - { - ExtraData data = Header.Extra.Where(x => x.Type == ExtraDataType.WinZipAes).SingleOrDefault(); - if (data == null) - { - throw new InvalidFormatException("No Winzip AES extra data found."); - } - if (data.Length != 7) - { - throw new InvalidFormatException("Winzip data length is not 7."); - } - ushort method = BitConverter.ToUInt16(data.DataBytes, 0); - - if (method != 0x01 && method != 0x02) - { - throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); - } - - ushort vendorId = BitConverter.ToUInt16(data.DataBytes, 2); - if (vendorId != 0x4541) - { - throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); - } - Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5); - return CreateDecompressionStream(stream); - } - default: - { - throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); - } - } - } - - protected Stream GetCryptoStream(Stream plainStream) - { - if ((Header.CompressedSize == 0) -#if !DOTNET51 - && ((Header.PkwareTraditionalEncryptionData != null) - || (Header.WinzipAesEncryptionData != null))) -#else - && (Header.PkwareTraditionalEncryptionData != null)) -#endif - { - throw new NotSupportedException("Cannot encrypt file with unknown size at start."); - } - if ((Header.CompressedSize == 0) - && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)) - { - plainStream = new NonDisposingStream(plainStream); //make sure AES doesn't close - } - else - { - plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close - } - if (Header.PkwareTraditionalEncryptionData != null) - { - return new PkwareTraditionalCryptoStream(plainStream, Header.PkwareTraditionalEncryptionData, - CryptoMode.Decrypt); - } -#if !DOTNET51 - if (Header.WinzipAesEncryptionData != null) - { - //only read 10 less because the last ten are auth bytes - return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10); - } -#endif - return plainStream; - } - } +using System; +using System.IO; +using System.Linq; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.Compressor; +using SharpCompress.Compressor.BZip2; +using SharpCompress.Compressor.Deflate; +using SharpCompress.Compressor.LZMA; +using SharpCompress.Compressor.PPMd; +using SharpCompress.IO; + +namespace SharpCompress.Common.Zip +{ + internal abstract class ZipFilePart : FilePart + { + internal ZipFilePart(ZipFileEntry header, Stream stream) + { + Header = header; + header.Part = this; + this.BaseStream = stream; + } + + internal Stream BaseStream { get; private set; } + internal ZipFileEntry Header { get; set; } + + + internal override string FilePartName + { + get { return Header.Name; } + } + + internal override Stream GetCompressedStream() + { + if (!Header.HasData) + { + return Stream.Null; + } + Stream decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream())); + if (LeaveStreamOpen) + { + return new NonDisposingStream(decompressionStream); + } + return decompressionStream; + } + + internal override Stream GetRawStream() + { + if (!Header.HasData) + { + return Stream.Null; + } + return CreateBaseStream(); + } + + protected abstract Stream CreateBaseStream(); + + protected bool LeaveStreamOpen + { + get { return FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor); } + } + + protected Stream CreateDecompressionStream(Stream stream) + { + switch (Header.CompressionMethod) + { + case ZipCompressionMethod.None: + { + return stream; + } + case ZipCompressionMethod.Deflate: + { + return new DeflateStream(stream, CompressionMode.Decompress); + } + case ZipCompressionMethod.BZip2: + { + return new BZip2Stream(stream, CompressionMode.Decompress); + } + case ZipCompressionMethod.LZMA: + { + if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) + { + throw new NotSupportedException("LZMA with pkware encryption."); + } + var reader = new BinaryReader(stream); + reader.ReadUInt16(); //LZMA version + var props = new byte[reader.ReadUInt16()]; + reader.Read(props, 0, props.Length); + return new LzmaStream(props, stream, + Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, + FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) + ? -1 + : (long)Header.UncompressedSize); + } + case ZipCompressionMethod.PPMd: + { + var props = new byte[2]; + stream.Read(props, 0, props.Length); + return new PpmdStream(new PpmdProperties(props), stream, false); + } + case ZipCompressionMethod.WinzipAes: + { + ExtraData data = Header.Extra.Where(x => x.Type == ExtraDataType.WinZipAes).SingleOrDefault(); + if (data == null) + { + throw new InvalidFormatException("No Winzip AES extra data found."); + } + if (data.Length != 7) + { + throw new InvalidFormatException("Winzip data length is not 7."); + } + ushort method = BitConverter.ToUInt16(data.DataBytes, 0); + + if (method != 0x01 && method != 0x02) + { + throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); + } + + ushort vendorId = BitConverter.ToUInt16(data.DataBytes, 2); + if (vendorId != 0x4541) + { + throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); + } + Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5); + return CreateDecompressionStream(stream); + } + default: + { + throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); + } + } + } + + protected Stream GetCryptoStream(Stream plainStream) + { + if ((Header.CompressedSize == 0) +#if !DOTNET51 + && ((Header.PkwareTraditionalEncryptionData != null) + || (Header.WinzipAesEncryptionData != null))) +#else + && (Header.PkwareTraditionalEncryptionData != null)) +#endif + { + throw new NotSupportedException("Cannot encrypt file with unknown size at start."); + } + if ((Header.CompressedSize == 0) + && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)) + { + plainStream = new NonDisposingStream(plainStream); //make sure AES doesn't close + } + else + { + plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close + } + if (Header.PkwareTraditionalEncryptionData != null) + { + return new PkwareTraditionalCryptoStream(plainStream, Header.PkwareTraditionalEncryptionData, + CryptoMode.Decrypt); + } +#if !DOTNET51 + if (Header.WinzipAesEncryptionData != null) + { + //only read 10 less because the last ten are auth bytes + return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10); + } +#endif + return plainStream; + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/ZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs similarity index 97% rename from SharpCompress/Common/Zip/ZipHeaderFactory.cs rename to src/SharpCompress/Common/Zip/ZipHeaderFactory.cs index 9473504c..dce9bab4 100644 --- a/SharpCompress/Common/Zip/ZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs @@ -1,184 +1,184 @@ -using System; -using System.IO; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.IO; -using System.Linq; - -namespace SharpCompress.Common.Zip -{ - internal class ZipHeaderFactory - { - internal const uint ENTRY_HEADER_BYTES = 0x04034b50; - internal const uint POST_DATA_DESCRIPTOR = 0x08074b50; - internal const uint DIRECTORY_START_HEADER_BYTES = 0x02014b50; - internal const uint DIRECTORY_END_HEADER_BYTES = 0x06054b50; - internal const uint DIGITAL_SIGNATURE = 0x05054b50; - internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 0x30304b50; - - private const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50; - private const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50; - - - protected LocalEntryHeader lastEntryHeader; - private string password; - private StreamingMode mode; - - protected ZipHeaderFactory(StreamingMode mode, string password) - { - this.mode = mode; - this.password = password; - } - - protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader) - { - switch (headerBytes) - { - case ENTRY_HEADER_BYTES: - { - var entryHeader = new LocalEntryHeader(); - entryHeader.Read(reader); - LoadHeader(entryHeader, reader.BaseStream); - - lastEntryHeader = entryHeader; - return entryHeader; - } - case DIRECTORY_START_HEADER_BYTES: - { - var entry = new DirectoryEntryHeader(); - entry.Read(reader); - return entry; - } - case POST_DATA_DESCRIPTOR: - { - if (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) - { - lastEntryHeader.Crc = reader.ReadUInt32(); - lastEntryHeader.CompressedSize = reader.ReadUInt32(); - lastEntryHeader.UncompressedSize = reader.ReadUInt32(); - } - else - { - reader.ReadUInt32(); - reader.ReadUInt32(); - reader.ReadUInt32(); - } - return null; - } - case DIGITAL_SIGNATURE: - return null; - case DIRECTORY_END_HEADER_BYTES: - { - var entry = new DirectoryEndHeader(); - entry.Read(reader); - return entry; - } - case SPLIT_ARCHIVE_HEADER_BYTES: - { - return new SplitHeader(); - } - case ZIP64_END_OF_CENTRAL_DIRECTORY: - case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: - { - var entry = new IgnoreHeader(ZipHeaderType.Ignore); - entry.Read(reader); - return entry; - } - default: - throw new NotSupportedException("Unknown header: " + headerBytes); - } - } - - internal static bool IsHeader(uint headerBytes) - { - switch (headerBytes) - { - case ENTRY_HEADER_BYTES: - case DIRECTORY_START_HEADER_BYTES: - case POST_DATA_DESCRIPTOR: - case DIGITAL_SIGNATURE: - case DIRECTORY_END_HEADER_BYTES: - case SPLIT_ARCHIVE_HEADER_BYTES: - case ZIP64_END_OF_CENTRAL_DIRECTORY: - case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: - return true; - default: - return false; - } - } - - private void LoadHeader(ZipFileEntry entryHeader, Stream stream) - { - if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) - { - if (!entryHeader.IsDirectory && - entryHeader.CompressedSize == 0 && - FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) - { - throw new NotSupportedException( - "SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); - } - if (password == null) - { - throw new CryptographicException("No password supplied for encrypted zip."); - } - if (entryHeader.CompressionMethod != ZipCompressionMethod.WinzipAes) - { - byte[] buffer = new byte[12]; - stream.Read(buffer, 0, 12); - entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(password, - entryHeader, - buffer); - entryHeader.CompressedSize -= 12; - } - else - { -#if DOTNET51 - throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7."); -#else - - var data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); - WinzipAesKeySize keySize = (WinzipAesKeySize) data.DataBytes[4]; - - byte[] salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize)/2]; - byte[] passwordVerifyValue = new byte[2]; - stream.Read(salt, 0, salt.Length); - stream.Read(passwordVerifyValue, 0, 2); - entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, - password); - entryHeader.CompressedSize -= (uint) (salt.Length + 2); - -#endif - } - } - if (entryHeader.IsDirectory) - { - return; - } - //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) - //{ - // entryHeader.PackedStream = new ReadOnlySubStream(stream); - //} - //else - //{ - switch (mode) - { - case StreamingMode.Seekable: - { - entryHeader.DataStartPosition = stream.Position; - stream.Position += entryHeader.CompressedSize; - } - break; - case StreamingMode.Streaming: - { - entryHeader.PackedStream = stream; - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - //} - } - } +using System; +using System.IO; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.IO; +using System.Linq; + +namespace SharpCompress.Common.Zip +{ + internal class ZipHeaderFactory + { + internal const uint ENTRY_HEADER_BYTES = 0x04034b50; + internal const uint POST_DATA_DESCRIPTOR = 0x08074b50; + internal const uint DIRECTORY_START_HEADER_BYTES = 0x02014b50; + internal const uint DIRECTORY_END_HEADER_BYTES = 0x06054b50; + internal const uint DIGITAL_SIGNATURE = 0x05054b50; + internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 0x30304b50; + + private const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50; + private const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50; + + + protected LocalEntryHeader lastEntryHeader; + private string password; + private StreamingMode mode; + + protected ZipHeaderFactory(StreamingMode mode, string password) + { + this.mode = mode; + this.password = password; + } + + protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader) + { + switch (headerBytes) + { + case ENTRY_HEADER_BYTES: + { + var entryHeader = new LocalEntryHeader(); + entryHeader.Read(reader); + LoadHeader(entryHeader, reader.BaseStream); + + lastEntryHeader = entryHeader; + return entryHeader; + } + case DIRECTORY_START_HEADER_BYTES: + { + var entry = new DirectoryEntryHeader(); + entry.Read(reader); + return entry; + } + case POST_DATA_DESCRIPTOR: + { + if (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) + { + lastEntryHeader.Crc = reader.ReadUInt32(); + lastEntryHeader.CompressedSize = reader.ReadUInt32(); + lastEntryHeader.UncompressedSize = reader.ReadUInt32(); + } + else + { + reader.ReadUInt32(); + reader.ReadUInt32(); + reader.ReadUInt32(); + } + return null; + } + case DIGITAL_SIGNATURE: + return null; + case DIRECTORY_END_HEADER_BYTES: + { + var entry = new DirectoryEndHeader(); + entry.Read(reader); + return entry; + } + case SPLIT_ARCHIVE_HEADER_BYTES: + { + return new SplitHeader(); + } + case ZIP64_END_OF_CENTRAL_DIRECTORY: + case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: + { + var entry = new IgnoreHeader(ZipHeaderType.Ignore); + entry.Read(reader); + return entry; + } + default: + throw new NotSupportedException("Unknown header: " + headerBytes); + } + } + + internal static bool IsHeader(uint headerBytes) + { + switch (headerBytes) + { + case ENTRY_HEADER_BYTES: + case DIRECTORY_START_HEADER_BYTES: + case POST_DATA_DESCRIPTOR: + case DIGITAL_SIGNATURE: + case DIRECTORY_END_HEADER_BYTES: + case SPLIT_ARCHIVE_HEADER_BYTES: + case ZIP64_END_OF_CENTRAL_DIRECTORY: + case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: + return true; + default: + return false; + } + } + + private void LoadHeader(ZipFileEntry entryHeader, Stream stream) + { + if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) + { + if (!entryHeader.IsDirectory && + entryHeader.CompressedSize == 0 && + FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) + { + throw new NotSupportedException( + "SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); + } + if (password == null) + { + throw new CryptographicException("No password supplied for encrypted zip."); + } + if (entryHeader.CompressionMethod != ZipCompressionMethod.WinzipAes) + { + byte[] buffer = new byte[12]; + stream.Read(buffer, 0, 12); + entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(password, + entryHeader, + buffer); + entryHeader.CompressedSize -= 12; + } + else + { +#if DOTNET51 + throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7."); +#else + + var data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); + WinzipAesKeySize keySize = (WinzipAesKeySize) data.DataBytes[4]; + + byte[] salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize)/2]; + byte[] passwordVerifyValue = new byte[2]; + stream.Read(salt, 0, salt.Length); + stream.Read(passwordVerifyValue, 0, 2); + entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, + password); + entryHeader.CompressedSize -= (uint) (salt.Length + 2); + +#endif + } + } + if (entryHeader.IsDirectory) + { + return; + } + //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) + //{ + // entryHeader.PackedStream = new ReadOnlySubStream(stream); + //} + //else + //{ + switch (mode) + { + case StreamingMode.Seekable: + { + entryHeader.DataStartPosition = stream.Position; + stream.Position += entryHeader.CompressedSize; + } + break; + case StreamingMode.Streaming: + { + entryHeader.PackedStream = stream; + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + //} + } + } } \ No newline at end of file diff --git a/SharpCompress/Common/Zip/ZipVolume.cs b/src/SharpCompress/Common/Zip/ZipVolume.cs similarity index 95% rename from SharpCompress/Common/Zip/ZipVolume.cs rename to src/SharpCompress/Common/Zip/ZipVolume.cs index 1f3fdd97..92ee8910 100644 --- a/SharpCompress/Common/Zip/ZipVolume.cs +++ b/src/SharpCompress/Common/Zip/ZipVolume.cs @@ -1,14 +1,14 @@ -using System.IO; - -namespace SharpCompress.Common.Zip -{ - public class ZipVolume : Volume - { - public ZipVolume(Stream stream, Options options) - : base(stream, options) - { - } - - public string Comment { get; internal set; } - } +using System.IO; + +namespace SharpCompress.Common.Zip +{ + public class ZipVolume : Volume + { + public ZipVolume(Stream stream, Options options) + : base(stream, options) + { + } + + public string Comment { get; internal set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/BZip2/BZip2Constants.cs b/src/SharpCompress/Compressor/BZip2/BZip2Constants.cs similarity index 98% rename from SharpCompress/Compressor/BZip2/BZip2Constants.cs rename to src/SharpCompress/Compressor/BZip2/BZip2Constants.cs index 4ba2887a..8d445fa2 100644 --- a/SharpCompress/Compressor/BZip2/BZip2Constants.cs +++ b/src/SharpCompress/Compressor/BZip2/BZip2Constants.cs @@ -1,101 +1,101 @@ -/* - * Copyright 2001,2004-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package is based on the work done by Keiron Liddle, Aftex Software - * to whom the Ant project is very grateful for his - * great code. - */ - -namespace SharpCompress.Compressor.BZip2 -{ - /** - * Base class for both the compress and decompress classes. - * Holds common arrays, and static data. - * - * @author Keiron Liddle - */ - - internal class BZip2Constants - { - public const int baseBlockSize = 100000; - public const int MAX_ALPHA_SIZE = 258; - public const int MAX_CODE_LEN = 23; - public const int RUNA = 0; - public const int RUNB = 1; - public const int N_GROUPS = 6; - public const int G_SIZE = 50; - public const int N_ITERS = 4; - public const int MAX_SELECTORS = (2 + (900000/G_SIZE)); - public const int NUM_OVERSHOOT_BYTES = 20; - - public static int[] rNums = - { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 - }; - } +/* + * Copyright 2001,2004-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace SharpCompress.Compressor.BZip2 +{ + /** + * Base class for both the compress and decompress classes. + * Holds common arrays, and static data. + * + * @author Keiron Liddle + */ + + internal class BZip2Constants + { + public const int baseBlockSize = 100000; + public const int MAX_ALPHA_SIZE = 258; + public const int MAX_CODE_LEN = 23; + public const int RUNA = 0; + public const int RUNB = 1; + public const int N_GROUPS = 6; + public const int G_SIZE = 50; + public const int N_ITERS = 4; + public const int MAX_SELECTORS = (2 + (900000/G_SIZE)); + public const int NUM_OVERSHOOT_BYTES = 20; + + public static int[] rNums = + { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 + }; + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressor/BZip2/BZip2Stream.cs similarity index 96% rename from SharpCompress/Compressor/BZip2/BZip2Stream.cs rename to src/SharpCompress/Compressor/BZip2/BZip2Stream.cs index e56d1d80..369e7e90 100644 --- a/SharpCompress/Compressor/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressor/BZip2/BZip2Stream.cs @@ -1,113 +1,113 @@ -using System.IO; - -namespace SharpCompress.Compressor.BZip2 -{ - public class BZip2Stream : Stream - { - private readonly Stream stream; - private bool isDisposed; - - /// - /// Create a BZip2Stream - /// - /// The stream to read from - /// Compression Mode - /// Leave the underlying stream open when disposed. - /// Should the BZip2 stream continue to decompress the stream when the End Marker is found. - public BZip2Stream(Stream stream, CompressionMode compressionMode, bool leaveOpen = false, - bool decompressContacted = false) - { - Mode = compressionMode; - if (Mode == CompressionMode.Compress) - { - this.stream = new CBZip2OutputStream(stream, leaveOpen); - } - else - { - this.stream = new CBZip2InputStream(stream, decompressContacted, leaveOpen); - } - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - stream.Dispose(); - } - } - - public CompressionMode Mode { get; private set; } - - public override bool CanRead - { - get { return stream.CanRead; } - } - - public override bool CanSeek - { - get { return stream.CanSeek; } - } - - public override bool CanWrite - { - get { return stream.CanWrite; } - } - - public override void Flush() - { - stream.Flush(); - } - - public override long Length - { - get { return stream.Length; } - } - - public override long Position - { - get { return stream.Position; } - set { stream.Position = value; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - stream.Write(buffer, offset, count); - } - - /// - /// Consumes two bytes to test if there is a BZip2 header - /// - /// - /// - public static bool IsBZip2(Stream stream) - { - BinaryReader br = new BinaryReader(stream); - byte[] chars = br.ReadBytes(2); - if (chars.Length < 2 || chars[0] != 'B' || chars[1] != 'Z') - { - return false; - } - return true; - } - } +using System.IO; + +namespace SharpCompress.Compressor.BZip2 +{ + public class BZip2Stream : Stream + { + private readonly Stream stream; + private bool isDisposed; + + /// + /// Create a BZip2Stream + /// + /// The stream to read from + /// Compression Mode + /// Leave the underlying stream open when disposed. + /// Should the BZip2 stream continue to decompress the stream when the End Marker is found. + public BZip2Stream(Stream stream, CompressionMode compressionMode, bool leaveOpen = false, + bool decompressContacted = false) + { + Mode = compressionMode; + if (Mode == CompressionMode.Compress) + { + this.stream = new CBZip2OutputStream(stream, leaveOpen); + } + else + { + this.stream = new CBZip2InputStream(stream, decompressContacted, leaveOpen); + } + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + if (disposing) + { + stream.Dispose(); + } + } + + public CompressionMode Mode { get; private set; } + + public override bool CanRead + { + get { return stream.CanRead; } + } + + public override bool CanSeek + { + get { return stream.CanSeek; } + } + + public override bool CanWrite + { + get { return stream.CanWrite; } + } + + public override void Flush() + { + stream.Flush(); + } + + public override long Length + { + get { return stream.Length; } + } + + public override long Position + { + get { return stream.Position; } + set { stream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return stream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + stream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + stream.Write(buffer, offset, count); + } + + /// + /// Consumes two bytes to test if there is a BZip2 header + /// + /// + /// + public static bool IsBZip2(Stream stream) + { + BinaryReader br = new BinaryReader(stream); + byte[] chars = br.ReadBytes(2); + if (chars.Length < 2 || chars[0] != 'B' || chars[1] != 'Z') + { + return false; + } + return true; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressor/BZip2/CBZip2InputStream.cs similarity index 96% rename from SharpCompress/Compressor/BZip2/CBZip2InputStream.cs rename to src/SharpCompress/Compressor/BZip2/CBZip2InputStream.cs index d3d363f4..4e82ee65 100644 --- a/SharpCompress/Compressor/BZip2/CBZip2InputStream.cs +++ b/src/SharpCompress/Compressor/BZip2/CBZip2InputStream.cs @@ -1,1119 +1,1119 @@ -using System.IO; - -/* - * Copyright 2001,2004-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package is based on the work done by Keiron Liddle, Aftex Software - * to whom the Ant project is very grateful for his - * great code. - */ - -namespace SharpCompress.Compressor.BZip2 -{ - /** - * An input stream that decompresses from the BZip2 format (with the file - * header chars) to be read as any other stream. - * - * @author Keiron Liddle - * - * NB: note this class has been modified to read the leading BZ from the - * start of the BZIP2 stream to make it compatible with other PGP programs. - */ - - internal class CBZip2InputStream : Stream - { - private static void Cadvise() - { - //System.out.Println("CRC Error"); - //throw new CCoruptionError(); - } - - private static void BadBGLengths() - { - Cadvise(); - } - - private static void BitStreamEOF() - { - Cadvise(); - } - - private static void CompressedStreamEOF() - { - Cadvise(); - } - - private void MakeMaps() - { - int i; - nInUse = 0; - for (i = 0; i < 256; i++) - { - if (inUse[i]) - { - seqToUnseq[nInUse] = (char)i; - unseqToSeq[i] = (char)nInUse; - nInUse++; - } - } - } - - /* - index of the last char in the block, so - the block size == last + 1. - */ - private int last; - - /* - index in zptr[] of original string after sorting. - */ - private int origPtr; - - /* - always: in the range 0 .. 9. - The current block size is 100000 * this number. - */ - private int blockSize100k; - - private bool blockRandomised; - - private int bsBuff; - private int bsLive; - private CRC mCrc = new CRC(); - - private bool[] inUse = new bool[256]; - private int nInUse; - - private char[] seqToUnseq = new char[256]; - private char[] unseqToSeq = new char[256]; - - private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; - private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; - - private int[] tt; - private char[] ll8; - - /* - freq table collected to save a pass over the data - during decompression. - */ - private int[] unzftab = new int[256]; - - private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - private int[] minLens = new int[BZip2Constants.N_GROUPS]; - - private Stream bsStream; - private bool leaveOpen; - - private bool streamEnd = false; - - private int currentChar = -1; - - private const int START_BLOCK_STATE = 1; - private const int RAND_PART_A_STATE = 2; - private const int RAND_PART_B_STATE = 3; - private const int RAND_PART_C_STATE = 4; - private const int NO_RAND_PART_A_STATE = 5; - private const int NO_RAND_PART_B_STATE = 6; - private const int NO_RAND_PART_C_STATE = 7; - - private int currentState = START_BLOCK_STATE; - - private int storedBlockCRC, storedCombinedCRC; - private int computedBlockCRC, computedCombinedCRC; - private bool decompressConcatenated; - - private int i2, count, chPrev, ch2; - private int i, tPos; - private int rNToGo = 0; - private int rTPos = 0; - private int j2; - private char z; - private bool isDisposed; - - public CBZip2InputStream(Stream zStream, bool decompressConcatenated, bool leaveOpen) - { - this.decompressConcatenated = decompressConcatenated; - ll8 = null; - tt = null; - BsSetStream(zStream, leaveOpen); - Initialize(true); - InitBlock(); - SetupBlock(); - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - if (bsStream != null) - { - bsStream.Dispose(); - } - } - - internal static int[][] InitIntArray(int n1, int n2) - { - int[][] a = new int[n1][]; - for (int k = 0; k < n1; ++k) - { - a[k] = new int[n2]; - } - return a; - } - - internal static char[][] InitCharArray(int n1, int n2) - { - char[][] a = new char[n1][]; - for (int k = 0; k < n1; ++k) - { - a[k] = new char[n2]; - } - return a; - } - - public override int ReadByte() - { - if (streamEnd) - { - return -1; - } - else - { - int retChar = currentChar; - switch (currentState) - { - case START_BLOCK_STATE: - break; - case RAND_PART_A_STATE: - break; - case RAND_PART_B_STATE: - SetupRandPartB(); - break; - case RAND_PART_C_STATE: - SetupRandPartC(); - break; - case NO_RAND_PART_A_STATE: - break; - case NO_RAND_PART_B_STATE: - SetupNoRandPartB(); - break; - case NO_RAND_PART_C_STATE: - SetupNoRandPartC(); - break; - default: - break; - } - return retChar; - } - } - - private bool Initialize(bool isFirstStream) - { - int magic0 = bsStream.ReadByte(); - int magic1 = bsStream.ReadByte(); - int magic2 = bsStream.ReadByte(); - if (magic0 == -1 && !isFirstStream) - { - return false; - } - if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') - { - throw new IOException("Not a BZIP2 marked stream"); - } - int magic3 = bsStream.ReadByte(); - if (magic3 < '1' || magic3 > '9') - { - BsFinishedWithStream(); - streamEnd = true; - return false; - } - - SetDecompressStructureSizes(magic3 - '0'); - this.bsLive = 0; - computedCombinedCRC = 0; - return true; - } - - private void InitBlock() - { - char magic1, magic2, magic3, magic4; - char magic5, magic6; - - while (true) - { - magic1 = BsGetUChar(); - magic2 = BsGetUChar(); - magic3 = BsGetUChar(); - magic4 = BsGetUChar(); - magic5 = BsGetUChar(); - magic6 = BsGetUChar(); - if (magic1 != 0x17 || magic2 != 0x72 || magic3 != 0x45 - || magic4 != 0x38 || magic5 != 0x50 || magic6 != 0x90) - { - break; - } - - if (Complete()) - return; - } - - if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 - || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) - { - BadBlockHeader(); - streamEnd = true; - return; - } - - storedBlockCRC = BsGetInt32(); - - if (BsR(1) == 1) - { - blockRandomised = true; - } - else - { - blockRandomised = false; - } - - // currBlockNo++; - GetAndMoveToFrontDecode(); - - mCrc.InitialiseCRC(); - currentState = START_BLOCK_STATE; - } - - private void EndBlock() - { - computedBlockCRC = mCrc.GetFinalCRC(); - /* A bad CRC is considered a fatal error. */ - if (storedBlockCRC != computedBlockCRC) - { - CrcError(); - } - - computedCombinedCRC = (computedCombinedCRC << 1) - | (int)(((uint)computedCombinedCRC) >> 31); - computedCombinedCRC ^= computedBlockCRC; - } - - private bool Complete() - { - storedCombinedCRC = BsGetInt32(); - if (storedCombinedCRC != computedCombinedCRC) - { - CrcError(); - } - - bool complete = !decompressConcatenated || !Initialize(false); - if (complete) - { - BsFinishedWithStream(); - streamEnd = true; - } - - // Look for the next .bz2 stream if decompressing - // concatenated files. - return complete; - } - - private static void BlockOverrun() - { - Cadvise(); - } - - private static void BadBlockHeader() - { - Cadvise(); - } - - private static void CrcError() - { - Cadvise(); - } - - private void BsFinishedWithStream() - { - try - { - if (this.bsStream != null) - { - if (!leaveOpen) - this.bsStream.Dispose(); - this.bsStream = null; - } - } - catch - { - //ignore - } - } - - private void BsSetStream(Stream f, bool leaveOpen) - { - bsStream = f; - bsLive = 0; - bsBuff = 0; - this.leaveOpen = leaveOpen; - } - - private int BsR(int n) - { - int v; - while (bsLive < n) - { - int zzi; - int thech = '\0'; - try - { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - if (thech == '\uffff') - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - - v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); - bsLive -= n; - return v; - } - - private char BsGetUChar() - { - return (char)BsR(8); - } - - private int BsGetint() - { - int u = 0; - u = (u << 8) | BsR(8); - u = (u << 8) | BsR(8); - u = (u << 8) | BsR(8); - u = (u << 8) | BsR(8); - return u; - } - - private int BsGetIntVS(int numBits) - { - return (int)BsR(numBits); - } - - private int BsGetInt32() - { - return (int)BsGetint(); - } - - private void HbCreateDecodeTables(int[] limit, int[] basev, - int[] perm, char[] length, - int minLen, int maxLen, int alphaSize) - { - int pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - { - for (j = 0; j < alphaSize; j++) - { - if (length[j] == i) - { - perm[pp] = j; - pp++; - } - } - } - - for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) - { - basev[i] = 0; - } - for (i = 0; i < alphaSize; i++) - { - basev[length[i] + 1]++; - } - - for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) - { - basev[i] += basev[i - 1]; - } - - for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) - { - limit[i] = 0; - } - vec = 0; - - for (i = minLen; i <= maxLen; i++) - { - vec += (basev[i + 1] - basev[i]); - limit[i] = vec - 1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - { - basev[i] = ((limit[i - 1] + 1) << 1) - basev[i]; - } - } - - private void RecvDecodingTables() - { - char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - int i, j, t, nGroups, nSelectors, alphaSize; - int minLen, maxLen; - bool[] inUse16 = new bool[16]; - - /* Receive the mapping table */ - for (i = 0; i < 16; i++) - { - if (BsR(1) == 1) - { - inUse16[i] = true; - } - else - { - inUse16[i] = false; - } - } - - for (i = 0; i < 256; i++) - { - inUse[i] = false; - } - - for (i = 0; i < 16; i++) - { - if (inUse16[i]) - { - for (j = 0; j < 16; j++) - { - if (BsR(1) == 1) - { - inUse[i * 16 + j] = true; - } - } - } - } - - MakeMaps(); - alphaSize = nInUse + 2; - - /* Now the selectors */ - nGroups = BsR(3); - nSelectors = BsR(15); - for (i = 0; i < nSelectors; i++) - { - j = 0; - while (BsR(1) == 1) - { - j++; - } - selectorMtf[i] = (char)j; - } - - /* Undo the MTF values for the selectors. */ - { - char[] pos = new char[BZip2Constants.N_GROUPS]; - char tmp, v; - for (v = '\0'; v < nGroups; v++) - { - pos[v] = v; - } - - for (i = 0; i < nSelectors; i++) - { - v = selectorMtf[i]; - tmp = pos[v]; - while (v > 0) - { - pos[v] = pos[v - 1]; - v--; - } - pos[0] = tmp; - selector[i] = tmp; - } - } - - /* Now the coding tables */ - for (t = 0; t < nGroups; t++) - { - int curr = BsR(5); - for (i = 0; i < alphaSize; i++) - { - while (BsR(1) == 1) - { - if (BsR(1) == 0) - { - curr++; - } - else - { - curr--; - } - } - len[t][i] = (char)curr; - } - } - - /* Create the Huffman decoding tables */ - for (t = 0; t < nGroups; t++) - { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) - { - if (len[t][i] > maxLen) - { - maxLen = len[t][i]; - } - if (len[t][i] < minLen) - { - minLen = len[t][i]; - } - } - HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen, - maxLen, alphaSize); - minLens[t] = minLen; - } - } - - private void GetAndMoveToFrontDecode() - { - char[] yy = new char[256]; - int i, j, nextSym, limitLast; - int EOB, groupNo, groupPos; - - limitLast = BZip2Constants.baseBlockSize * blockSize100k; - origPtr = BsGetIntVS(24); - - RecvDecodingTables(); - EOB = nInUse + 1; - groupNo = -1; - groupPos = 0; - - /* - Setting up the unzftab entries here is not strictly - necessary, but it does save having to do it later - in a separate pass, and so saves a block's worth of - cache misses. - */ - for (i = 0; i <= 255; i++) - { - unzftab[i] = 0; - } - - for (i = 0; i <= 255; i++) - { - yy[i] = (char)i; - } - - last = -1; - - { - int zt, zn, zvec, zj; - if (groupPos == 0) - { - groupNo++; - groupPos = BZip2Constants.G_SIZE; - } - groupPos--; - zt = selector[groupNo]; - zn = minLens[zt]; - zvec = BsR(zn); - while (zvec > limit[zt][zn]) - { - zn++; - { - { - while (bsLive < 1) - { - int zzi; - char thech = '\0'; - try - { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - if (thech == '\uffff') - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - } - zj = (bsBuff >> (bsLive - 1)) & 1; - bsLive--; - } - zvec = (zvec << 1) | zj; - } - nextSym = perm[zt][zvec - basev[zt][zn]]; - } - - while (true) - { - if (nextSym == EOB) - { - break; - } - - if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) - { - char ch; - int s = -1; - int N = 1; - do - { - if (nextSym == BZip2Constants.RUNA) - { - s = s + (0 + 1) * N; - } - else if (nextSym == BZip2Constants.RUNB) - { - s = s + (1 + 1) * N; - } - N = N * 2; - { - int zt, zn, zvec, zj; - if (groupPos == 0) - { - groupNo++; - groupPos = BZip2Constants.G_SIZE; - } - groupPos--; - zt = selector[groupNo]; - zn = minLens[zt]; - zvec = BsR(zn); - while (zvec > limit[zt][zn]) - { - zn++; - { - { - while (bsLive < 1) - { - int zzi; - char thech = '\0'; - try - { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - if (thech == '\uffff') - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - } - zj = (bsBuff >> (bsLive - 1)) & 1; - bsLive--; - } - zvec = (zvec << 1) | zj; - } - nextSym = perm[zt][zvec - basev[zt][zn]]; - } - } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); - - s++; - ch = seqToUnseq[yy[0]]; - unzftab[ch] += s; - - while (s > 0) - { - last++; - ll8[last] = ch; - s--; - } - - if (last >= limitLast) - { - BlockOverrun(); - } - continue; - } - else - { - char tmp; - last++; - if (last >= limitLast) - { - BlockOverrun(); - } - - tmp = yy[nextSym - 1]; - unzftab[seqToUnseq[tmp]]++; - ll8[last] = seqToUnseq[tmp]; - - /* - This loop is hammered during decompression, - hence the unrolling. - - for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; - */ - - j = nextSym - 1; - for (; j > 3; j -= 4) - { - yy[j] = yy[j - 1]; - yy[j - 1] = yy[j - 2]; - yy[j - 2] = yy[j - 3]; - yy[j - 3] = yy[j - 4]; - } - for (; j > 0; j--) - { - yy[j] = yy[j - 1]; - } - - yy[0] = tmp; - { - int zt, zn, zvec, zj; - if (groupPos == 0) - { - groupNo++; - groupPos = BZip2Constants.G_SIZE; - } - groupPos--; - zt = selector[groupNo]; - zn = minLens[zt]; - zvec = BsR(zn); - while (zvec > limit[zt][zn]) - { - zn++; - { - { - while (bsLive < 1) - { - int zzi; - char thech = '\0'; - try - { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - } - zj = (bsBuff >> (bsLive - 1)) & 1; - bsLive--; - } - zvec = (zvec << 1) | zj; - } - nextSym = perm[zt][zvec - basev[zt][zn]]; - } - continue; - } - } - } - - private void SetupBlock() - { - int[] cftab = new int[257]; - char ch; - - cftab[0] = 0; - for (i = 1; i <= 256; i++) - { - cftab[i] = unzftab[i - 1]; - } - for (i = 1; i <= 256; i++) - { - cftab[i] += cftab[i - 1]; - } - - for (i = 0; i <= last; i++) - { - ch = (char)ll8[i]; - tt[cftab[ch]] = i; - cftab[ch]++; - } - cftab = null; - - tPos = tt[origPtr]; - - count = 0; - i2 = 0; - ch2 = 256; /* not a char and not EOF */ - - if (blockRandomised) - { - rNToGo = 0; - rTPos = 0; - SetupRandPartA(); - } - else - { - SetupNoRandPartA(); - } - } - - private void SetupRandPartA() - { - if (i2 <= last) - { - chPrev = ch2; - ch2 = ll8[tPos]; - tPos = tt[tPos]; - if (rNToGo == 0) - { - rNToGo = BZip2Constants.rNums[rTPos]; - rTPos++; - if (rTPos == 512) - { - rTPos = 0; - } - } - rNToGo--; - ch2 ^= (int)((rNToGo == 1) ? 1 : 0); - i2++; - - currentChar = ch2; - currentState = RAND_PART_B_STATE; - mCrc.UpdateCRC(ch2); - } - else - { - EndBlock(); - InitBlock(); - SetupBlock(); - } - } - - private void SetupNoRandPartA() - { - if (i2 <= last) - { - chPrev = ch2; - ch2 = ll8[tPos]; - tPos = tt[tPos]; - i2++; - - currentChar = ch2; - currentState = NO_RAND_PART_B_STATE; - mCrc.UpdateCRC(ch2); - } - else - { - EndBlock(); - InitBlock(); - SetupBlock(); - } - } - - private void SetupRandPartB() - { - if (ch2 != chPrev) - { - currentState = RAND_PART_A_STATE; - count = 1; - SetupRandPartA(); - } - else - { - count++; - if (count >= 4) - { - z = ll8[tPos]; - tPos = tt[tPos]; - if (rNToGo == 0) - { - rNToGo = BZip2Constants.rNums[rTPos]; - rTPos++; - if (rTPos == 512) - { - rTPos = 0; - } - } - rNToGo--; - z ^= (char)((rNToGo == 1) ? 1 : 0); - j2 = 0; - currentState = RAND_PART_C_STATE; - SetupRandPartC(); - } - else - { - currentState = RAND_PART_A_STATE; - SetupRandPartA(); - } - } - } - - private void SetupRandPartC() - { - if (j2 < (int)z) - { - currentChar = ch2; - mCrc.UpdateCRC(ch2); - j2++; - } - else - { - currentState = RAND_PART_A_STATE; - i2++; - count = 0; - SetupRandPartA(); - } - } - - private void SetupNoRandPartB() - { - if (ch2 != chPrev) - { - currentState = NO_RAND_PART_A_STATE; - count = 1; - SetupNoRandPartA(); - } - else - { - count++; - if (count >= 4) - { - z = ll8[tPos]; - tPos = tt[tPos]; - currentState = NO_RAND_PART_C_STATE; - j2 = 0; - SetupNoRandPartC(); - } - else - { - currentState = NO_RAND_PART_A_STATE; - SetupNoRandPartA(); - } - } - } - - private void SetupNoRandPartC() - { - if (j2 < (int)z) - { - currentChar = ch2; - mCrc.UpdateCRC(ch2); - j2++; - } - else - { - currentState = NO_RAND_PART_A_STATE; - i2++; - count = 0; - SetupNoRandPartA(); - } - } - - private void SetDecompressStructureSizes(int newSize100k) - { - if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k - && blockSize100k <= 9)) - { - // throw new IOException("Invalid block size"); - } - - blockSize100k = newSize100k; - - if (newSize100k == 0) - { - return; - } - - int n = BZip2Constants.baseBlockSize * newSize100k; - ll8 = new char[n]; - tt = new int[n]; - } - - public override void Flush() - { - } - - public override int Read(byte[] buffer, int offset, int count) - { - int c = -1; - int k; - for (k = 0; k < count; ++k) - { - c = ReadByte(); - if (c == -1) - break; - buffer[k + offset] = (byte)c; - } - return k; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return 0; - } - - public override void SetLength(long value) - { - } - - public override void Write(byte[] buffer, int offset, int count) - { - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override long Length - { - get { return 0; } - } - - public override long Position - { - get { return 0; } - set { } - } - } +using System.IO; + +/* + * Copyright 2001,2004-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace SharpCompress.Compressor.BZip2 +{ + /** + * An input stream that decompresses from the BZip2 format (with the file + * header chars) to be read as any other stream. + * + * @author Keiron Liddle + * + * NB: note this class has been modified to read the leading BZ from the + * start of the BZIP2 stream to make it compatible with other PGP programs. + */ + + internal class CBZip2InputStream : Stream + { + private static void Cadvise() + { + //System.out.Println("CRC Error"); + //throw new CCoruptionError(); + } + + private static void BadBGLengths() + { + Cadvise(); + } + + private static void BitStreamEOF() + { + Cadvise(); + } + + private static void CompressedStreamEOF() + { + Cadvise(); + } + + private void MakeMaps() + { + int i; + nInUse = 0; + for (i = 0; i < 256; i++) + { + if (inUse[i]) + { + seqToUnseq[nInUse] = (char)i; + unseqToSeq[i] = (char)nInUse; + nInUse++; + } + } + } + + /* + index of the last char in the block, so + the block size == last + 1. + */ + private int last; + + /* + index in zptr[] of original string after sorting. + */ + private int origPtr; + + /* + always: in the range 0 .. 9. + The current block size is 100000 * this number. + */ + private int blockSize100k; + + private bool blockRandomised; + + private int bsBuff; + private int bsLive; + private CRC mCrc = new CRC(); + + private bool[] inUse = new bool[256]; + private int nInUse; + + private char[] seqToUnseq = new char[256]; + private char[] unseqToSeq = new char[256]; + + private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; + private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; + + private int[] tt; + private char[] ll8; + + /* + freq table collected to save a pass over the data + during decompression. + */ + private int[] unzftab = new int[256]; + + private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private int[] minLens = new int[BZip2Constants.N_GROUPS]; + + private Stream bsStream; + private bool leaveOpen; + + private bool streamEnd = false; + + private int currentChar = -1; + + private const int START_BLOCK_STATE = 1; + private const int RAND_PART_A_STATE = 2; + private const int RAND_PART_B_STATE = 3; + private const int RAND_PART_C_STATE = 4; + private const int NO_RAND_PART_A_STATE = 5; + private const int NO_RAND_PART_B_STATE = 6; + private const int NO_RAND_PART_C_STATE = 7; + + private int currentState = START_BLOCK_STATE; + + private int storedBlockCRC, storedCombinedCRC; + private int computedBlockCRC, computedCombinedCRC; + private bool decompressConcatenated; + + private int i2, count, chPrev, ch2; + private int i, tPos; + private int rNToGo = 0; + private int rTPos = 0; + private int j2; + private char z; + private bool isDisposed; + + public CBZip2InputStream(Stream zStream, bool decompressConcatenated, bool leaveOpen) + { + this.decompressConcatenated = decompressConcatenated; + ll8 = null; + tt = null; + BsSetStream(zStream, leaveOpen); + Initialize(true); + InitBlock(); + SetupBlock(); + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + if (bsStream != null) + { + bsStream.Dispose(); + } + } + + internal static int[][] InitIntArray(int n1, int n2) + { + int[][] a = new int[n1][]; + for (int k = 0; k < n1; ++k) + { + a[k] = new int[n2]; + } + return a; + } + + internal static char[][] InitCharArray(int n1, int n2) + { + char[][] a = new char[n1][]; + for (int k = 0; k < n1; ++k) + { + a[k] = new char[n2]; + } + return a; + } + + public override int ReadByte() + { + if (streamEnd) + { + return -1; + } + else + { + int retChar = currentChar; + switch (currentState) + { + case START_BLOCK_STATE: + break; + case RAND_PART_A_STATE: + break; + case RAND_PART_B_STATE: + SetupRandPartB(); + break; + case RAND_PART_C_STATE: + SetupRandPartC(); + break; + case NO_RAND_PART_A_STATE: + break; + case NO_RAND_PART_B_STATE: + SetupNoRandPartB(); + break; + case NO_RAND_PART_C_STATE: + SetupNoRandPartC(); + break; + default: + break; + } + return retChar; + } + } + + private bool Initialize(bool isFirstStream) + { + int magic0 = bsStream.ReadByte(); + int magic1 = bsStream.ReadByte(); + int magic2 = bsStream.ReadByte(); + if (magic0 == -1 && !isFirstStream) + { + return false; + } + if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') + { + throw new IOException("Not a BZIP2 marked stream"); + } + int magic3 = bsStream.ReadByte(); + if (magic3 < '1' || magic3 > '9') + { + BsFinishedWithStream(); + streamEnd = true; + return false; + } + + SetDecompressStructureSizes(magic3 - '0'); + this.bsLive = 0; + computedCombinedCRC = 0; + return true; + } + + private void InitBlock() + { + char magic1, magic2, magic3, magic4; + char magic5, magic6; + + while (true) + { + magic1 = BsGetUChar(); + magic2 = BsGetUChar(); + magic3 = BsGetUChar(); + magic4 = BsGetUChar(); + magic5 = BsGetUChar(); + magic6 = BsGetUChar(); + if (magic1 != 0x17 || magic2 != 0x72 || magic3 != 0x45 + || magic4 != 0x38 || magic5 != 0x50 || magic6 != 0x90) + { + break; + } + + if (Complete()) + return; + } + + if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 + || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) + { + BadBlockHeader(); + streamEnd = true; + return; + } + + storedBlockCRC = BsGetInt32(); + + if (BsR(1) == 1) + { + blockRandomised = true; + } + else + { + blockRandomised = false; + } + + // currBlockNo++; + GetAndMoveToFrontDecode(); + + mCrc.InitialiseCRC(); + currentState = START_BLOCK_STATE; + } + + private void EndBlock() + { + computedBlockCRC = mCrc.GetFinalCRC(); + /* A bad CRC is considered a fatal error. */ + if (storedBlockCRC != computedBlockCRC) + { + CrcError(); + } + + computedCombinedCRC = (computedCombinedCRC << 1) + | (int)(((uint)computedCombinedCRC) >> 31); + computedCombinedCRC ^= computedBlockCRC; + } + + private bool Complete() + { + storedCombinedCRC = BsGetInt32(); + if (storedCombinedCRC != computedCombinedCRC) + { + CrcError(); + } + + bool complete = !decompressConcatenated || !Initialize(false); + if (complete) + { + BsFinishedWithStream(); + streamEnd = true; + } + + // Look for the next .bz2 stream if decompressing + // concatenated files. + return complete; + } + + private static void BlockOverrun() + { + Cadvise(); + } + + private static void BadBlockHeader() + { + Cadvise(); + } + + private static void CrcError() + { + Cadvise(); + } + + private void BsFinishedWithStream() + { + try + { + if (this.bsStream != null) + { + if (!leaveOpen) + this.bsStream.Dispose(); + this.bsStream = null; + } + } + catch + { + //ignore + } + } + + private void BsSetStream(Stream f, bool leaveOpen) + { + bsStream = f; + bsLive = 0; + bsBuff = 0; + this.leaveOpen = leaveOpen; + } + + private int BsR(int n) + { + int v; + while (bsLive < n) + { + int zzi; + int thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + if (thech == '\uffff') + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + + v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); + bsLive -= n; + return v; + } + + private char BsGetUChar() + { + return (char)BsR(8); + } + + private int BsGetint() + { + int u = 0; + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + return u; + } + + private int BsGetIntVS(int numBits) + { + return (int)BsR(numBits); + } + + private int BsGetInt32() + { + return (int)BsGetint(); + } + + private void HbCreateDecodeTables(int[] limit, int[] basev, + int[] perm, char[] length, + int minLen, int maxLen, int alphaSize) + { + int pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + { + for (j = 0; j < alphaSize; j++) + { + if (length[j] == i) + { + perm[pp] = j; + pp++; + } + } + } + + for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) + { + basev[i] = 0; + } + for (i = 0; i < alphaSize; i++) + { + basev[length[i] + 1]++; + } + + for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) + { + basev[i] += basev[i - 1]; + } + + for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) + { + limit[i] = 0; + } + vec = 0; + + for (i = minLen; i <= maxLen; i++) + { + vec += (basev[i + 1] - basev[i]); + limit[i] = vec - 1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + { + basev[i] = ((limit[i - 1] + 1) << 1) - basev[i]; + } + } + + private void RecvDecodingTables() + { + char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int i, j, t, nGroups, nSelectors, alphaSize; + int minLen, maxLen; + bool[] inUse16 = new bool[16]; + + /* Receive the mapping table */ + for (i = 0; i < 16; i++) + { + if (BsR(1) == 1) + { + inUse16[i] = true; + } + else + { + inUse16[i] = false; + } + } + + for (i = 0; i < 256; i++) + { + inUse[i] = false; + } + + for (i = 0; i < 16; i++) + { + if (inUse16[i]) + { + for (j = 0; j < 16; j++) + { + if (BsR(1) == 1) + { + inUse[i * 16 + j] = true; + } + } + } + } + + MakeMaps(); + alphaSize = nInUse + 2; + + /* Now the selectors */ + nGroups = BsR(3); + nSelectors = BsR(15); + for (i = 0; i < nSelectors; i++) + { + j = 0; + while (BsR(1) == 1) + { + j++; + } + selectorMtf[i] = (char)j; + } + + /* Undo the MTF values for the selectors. */ + { + char[] pos = new char[BZip2Constants.N_GROUPS]; + char tmp, v; + for (v = '\0'; v < nGroups; v++) + { + pos[v] = v; + } + + for (i = 0; i < nSelectors; i++) + { + v = selectorMtf[i]; + tmp = pos[v]; + while (v > 0) + { + pos[v] = pos[v - 1]; + v--; + } + pos[0] = tmp; + selector[i] = tmp; + } + } + + /* Now the coding tables */ + for (t = 0; t < nGroups; t++) + { + int curr = BsR(5); + for (i = 0; i < alphaSize; i++) + { + while (BsR(1) == 1) + { + if (BsR(1) == 0) + { + curr++; + } + else + { + curr--; + } + } + len[t][i] = (char)curr; + } + } + + /* Create the Huffman decoding tables */ + for (t = 0; t < nGroups; t++) + { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) + { + if (len[t][i] > maxLen) + { + maxLen = len[t][i]; + } + if (len[t][i] < minLen) + { + minLen = len[t][i]; + } + } + HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen, + maxLen, alphaSize); + minLens[t] = minLen; + } + } + + private void GetAndMoveToFrontDecode() + { + char[] yy = new char[256]; + int i, j, nextSym, limitLast; + int EOB, groupNo, groupPos; + + limitLast = BZip2Constants.baseBlockSize * blockSize100k; + origPtr = BsGetIntVS(24); + + RecvDecodingTables(); + EOB = nInUse + 1; + groupNo = -1; + groupPos = 0; + + /* + Setting up the unzftab entries here is not strictly + necessary, but it does save having to do it later + in a separate pass, and so saves a block's worth of + cache misses. + */ + for (i = 0; i <= 255; i++) + { + unzftab[i] = 0; + } + + for (i = 0; i <= 255; i++) + { + yy[i] = (char)i; + } + + last = -1; + + { + int zt, zn, zvec, zj; + if (groupPos == 0) + { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) + { + zn++; + { + { + while (bsLive < 1) + { + int zzi; + char thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + if (thech == '\uffff') + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + + while (true) + { + if (nextSym == EOB) + { + break; + } + + if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) + { + char ch; + int s = -1; + int N = 1; + do + { + if (nextSym == BZip2Constants.RUNA) + { + s = s + (0 + 1) * N; + } + else if (nextSym == BZip2Constants.RUNB) + { + s = s + (1 + 1) * N; + } + N = N * 2; + { + int zt, zn, zvec, zj; + if (groupPos == 0) + { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) + { + zn++; + { + { + while (bsLive < 1) + { + int zzi; + char thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + if (thech == '\uffff') + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); + + s++; + ch = seqToUnseq[yy[0]]; + unzftab[ch] += s; + + while (s > 0) + { + last++; + ll8[last] = ch; + s--; + } + + if (last >= limitLast) + { + BlockOverrun(); + } + continue; + } + else + { + char tmp; + last++; + if (last >= limitLast) + { + BlockOverrun(); + } + + tmp = yy[nextSym - 1]; + unzftab[seqToUnseq[tmp]]++; + ll8[last] = seqToUnseq[tmp]; + + /* + This loop is hammered during decompression, + hence the unrolling. + + for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; + */ + + j = nextSym - 1; + for (; j > 3; j -= 4) + { + yy[j] = yy[j - 1]; + yy[j - 1] = yy[j - 2]; + yy[j - 2] = yy[j - 3]; + yy[j - 3] = yy[j - 4]; + } + for (; j > 0; j--) + { + yy[j] = yy[j - 1]; + } + + yy[0] = tmp; + { + int zt, zn, zvec, zj; + if (groupPos == 0) + { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) + { + zn++; + { + { + while (bsLive < 1) + { + int zzi; + char thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + continue; + } + } + } + + private void SetupBlock() + { + int[] cftab = new int[257]; + char ch; + + cftab[0] = 0; + for (i = 1; i <= 256; i++) + { + cftab[i] = unzftab[i - 1]; + } + for (i = 1; i <= 256; i++) + { + cftab[i] += cftab[i - 1]; + } + + for (i = 0; i <= last; i++) + { + ch = (char)ll8[i]; + tt[cftab[ch]] = i; + cftab[ch]++; + } + cftab = null; + + tPos = tt[origPtr]; + + count = 0; + i2 = 0; + ch2 = 256; /* not a char and not EOF */ + + if (blockRandomised) + { + rNToGo = 0; + rTPos = 0; + SetupRandPartA(); + } + else + { + SetupNoRandPartA(); + } + } + + private void SetupRandPartA() + { + if (i2 <= last) + { + chPrev = ch2; + ch2 = ll8[tPos]; + tPos = tt[tPos]; + if (rNToGo == 0) + { + rNToGo = BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) + { + rTPos = 0; + } + } + rNToGo--; + ch2 ^= (int)((rNToGo == 1) ? 1 : 0); + i2++; + + currentChar = ch2; + currentState = RAND_PART_B_STATE; + mCrc.UpdateCRC(ch2); + } + else + { + EndBlock(); + InitBlock(); + SetupBlock(); + } + } + + private void SetupNoRandPartA() + { + if (i2 <= last) + { + chPrev = ch2; + ch2 = ll8[tPos]; + tPos = tt[tPos]; + i2++; + + currentChar = ch2; + currentState = NO_RAND_PART_B_STATE; + mCrc.UpdateCRC(ch2); + } + else + { + EndBlock(); + InitBlock(); + SetupBlock(); + } + } + + private void SetupRandPartB() + { + if (ch2 != chPrev) + { + currentState = RAND_PART_A_STATE; + count = 1; + SetupRandPartA(); + } + else + { + count++; + if (count >= 4) + { + z = ll8[tPos]; + tPos = tt[tPos]; + if (rNToGo == 0) + { + rNToGo = BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) + { + rTPos = 0; + } + } + rNToGo--; + z ^= (char)((rNToGo == 1) ? 1 : 0); + j2 = 0; + currentState = RAND_PART_C_STATE; + SetupRandPartC(); + } + else + { + currentState = RAND_PART_A_STATE; + SetupRandPartA(); + } + } + } + + private void SetupRandPartC() + { + if (j2 < (int)z) + { + currentChar = ch2; + mCrc.UpdateCRC(ch2); + j2++; + } + else + { + currentState = RAND_PART_A_STATE; + i2++; + count = 0; + SetupRandPartA(); + } + } + + private void SetupNoRandPartB() + { + if (ch2 != chPrev) + { + currentState = NO_RAND_PART_A_STATE; + count = 1; + SetupNoRandPartA(); + } + else + { + count++; + if (count >= 4) + { + z = ll8[tPos]; + tPos = tt[tPos]; + currentState = NO_RAND_PART_C_STATE; + j2 = 0; + SetupNoRandPartC(); + } + else + { + currentState = NO_RAND_PART_A_STATE; + SetupNoRandPartA(); + } + } + } + + private void SetupNoRandPartC() + { + if (j2 < (int)z) + { + currentChar = ch2; + mCrc.UpdateCRC(ch2); + j2++; + } + else + { + currentState = NO_RAND_PART_A_STATE; + i2++; + count = 0; + SetupNoRandPartA(); + } + } + + private void SetDecompressStructureSizes(int newSize100k) + { + if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k + && blockSize100k <= 9)) + { + // throw new IOException("Invalid block size"); + } + + blockSize100k = newSize100k; + + if (newSize100k == 0) + { + return; + } + + int n = BZip2Constants.baseBlockSize * newSize100k; + ll8 = new char[n]; + tt = new int[n]; + } + + public override void Flush() + { + } + + public override int Read(byte[] buffer, int offset, int count) + { + int c = -1; + int k; + for (k = 0; k < count; ++k) + { + c = ReadByte(); + if (c == -1) + break; + buffer[k + offset] = (byte)c; + } + return k; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + + public override void SetLength(long value) + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override long Length + { + get { return 0; } + } + + public override long Position + { + get { return 0; } + set { } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressor/BZip2/CBZip2OutputStream.cs similarity index 96% rename from SharpCompress/Compressor/BZip2/CBZip2OutputStream.cs rename to src/SharpCompress/Compressor/BZip2/CBZip2OutputStream.cs index 02faf223..7addf723 100644 --- a/SharpCompress/Compressor/BZip2/CBZip2OutputStream.cs +++ b/src/SharpCompress/Compressor/BZip2/CBZip2OutputStream.cs @@ -1,1981 +1,1981 @@ -using System.IO; - -/* - * Copyright 2001,2004-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package is based on the work done by Keiron Liddle, Aftex Software - * to whom the Ant project is very grateful for his - * great code. - */ - -namespace SharpCompress.Compressor.BZip2 -{ - /** - * An output stream that compresses into the BZip2 format (with the file - * header chars) into another stream. - * - * @author Keiron Liddle - * - * TODO: Update to BZip2 1.0.1 - * NB: note this class has been modified to add a leading BZ to the - * start of the BZIP2 stream to make it compatible with other PGP programs. - */ - - internal class CBZip2OutputStream : Stream - { - protected const int SETMASK = (1 << 21); - protected const int CLEARMASK = (~SETMASK); - protected const int GREATER_ICOST = 15; - protected const int LESSER_ICOST = 0; - protected const int SMALL_THRESH = 20; - protected const int DEPTH_THRESH = 10; - - /* - If you are ever unlucky/improbable enough - to get a stack overflow whilst sorting, - increase the following constant and try - again. In practice I have never seen the - stack go above 27 elems, so the following - limit seems very generous. - */ - protected const int QSORT_STACK_SIZE = 1000; - private bool finished; - - private static void Panic() - { - //System.out.Println("panic"); - //throw new CError(); - } - - private void MakeMaps() - { - int i; - nInUse = 0; - for (i = 0; i < 256; i++) - { - if (inUse[i]) - { - seqToUnseq[nInUse] = (char) i; - unseqToSeq[i] = (char) nInUse; - nInUse++; - } - } - } - - protected static void HbMakeCodeLengths(char[] len, int[] freq, - int alphaSize, int maxLen) - { - /* - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - */ - int nNodes, nHeap, n1, n2, i, j, k; - bool tooLong; - - int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2]; - int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE*2]; - int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE*2]; - - for (i = 0; i < alphaSize; i++) - { - weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - } - - while (true) - { - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) - { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - { - int zz, tmp; - zz = nHeap; - tmp = heap[zz]; - while (weight[tmp] < weight[heap[zz >> 1]]) - { - heap[zz] = heap[zz >> 1]; - zz >>= 1; - } - heap[zz] = tmp; - } - } - if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) - { - Panic(); - } - - while (nHeap > 1) - { - n1 = heap[1]; - heap[1] = heap[nHeap]; - nHeap--; - { - int zz = 0, yy = 0, tmp = 0; - zz = 1; - tmp = heap[zz]; - while (true) - { - yy = zz << 1; - if (yy > nHeap) - { - break; - } - if (yy < nHeap - && weight[heap[yy + 1]] < weight[heap[yy]]) - { - yy++; - } - if (weight[tmp] < weight[heap[yy]]) - { - break; - } - heap[zz] = heap[yy]; - zz = yy; - } - heap[zz] = tmp; - } - n2 = heap[1]; - heap[1] = heap[nHeap]; - nHeap--; - { - int zz = 0, yy = 0, tmp = 0; - zz = 1; - tmp = heap[zz]; - while (true) - { - yy = zz << 1; - if (yy > nHeap) - { - break; - } - if (yy < nHeap - && weight[heap[yy + 1]] < weight[heap[yy]]) - { - yy++; - } - if (weight[tmp] < weight[heap[yy]]) - { - break; - } - heap[zz] = heap[yy]; - zz = yy; - } - heap[zz] = tmp; - } - nNodes++; - parent[n1] = parent[n2] = nNodes; - - weight[nNodes] = (int) ((uint) ((weight[n1] & 0xffffff00) - + (weight[n2] & 0xffffff00)) - | (uint) (1 + (((weight[n1] & 0x000000ff) > - (weight[n2] & 0x000000ff)) - ? (weight[n1] & 0x000000ff) - : (weight[n2] & 0x000000ff)))); - - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - { - int zz = 0, tmp = 0; - zz = nHeap; - tmp = heap[zz]; - while (weight[tmp] < weight[heap[zz >> 1]]) - { - heap[zz] = heap[zz >> 1]; - zz >>= 1; - } - heap[zz] = tmp; - } - } - if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE*2))) - { - Panic(); - } - - tooLong = false; - for (i = 1; i <= alphaSize; i++) - { - j = 0; - k = i; - while (parent[k] >= 0) - { - k = parent[k]; - j++; - } - len[i - 1] = (char) j; - if (j > maxLen) - { - tooLong = true; - } - } - - if (!tooLong) - { - break; - } - - for (i = 1; i < alphaSize; i++) - { - j = weight[i] >> 8; - j = 1 + (j/2); - weight[i] = j << 8; - } - } - } - - /* - index of the last char in the block, so - the block size == last + 1. - */ - private int last; - - /* - index in zptr[] of original string after sorting. - */ - private int origPtr; - - /* - always: in the range 0 .. 9. - The current block size is 100000 * this number. - */ - private int blockSize100k; - - private bool blockRandomised; - - private int bytesOut; - private int bsBuff; - private int bsLive; - private CRC mCrc = new CRC(); - - private bool[] inUse = new bool[256]; - private int nInUse; - - private char[] seqToUnseq = new char[256]; - private char[] unseqToSeq = new char[256]; - - private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; - private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; - - private char[] block; - private int[] quadrant; - private int[] zptr; - private short[] szptr; - private int[] ftab; - - private int nMTF; - - private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE]; - - /* - * Used when sorting. If too many long comparisons - * happen, we stop sorting, randomise the block - * slightly, and try again. - */ - private int workFactor; - private int workDone; - private int workLimit; - private bool firstAttempt; - private int nBlocksRandomised; - - private int currentChar = -1; - private int runLength = 0; - - public CBZip2OutputStream(Stream inStream) - : this(inStream, 9, false) - { - } - - public CBZip2OutputStream(Stream inStream, bool leaveOpen) - : this(inStream, 9, leaveOpen) - { - } - - public CBZip2OutputStream(Stream inStream, int inBlockSize, bool leaveOpen) - { - block = null; - quadrant = null; - zptr = null; - ftab = null; - - inStream.WriteByte((byte) 'B'); - inStream.WriteByte((byte) 'Z'); - - BsSetStream(inStream, leaveOpen); - - workFactor = 50; - if (inBlockSize > 9) - { - inBlockSize = 9; - } - if (inBlockSize < 1) - { - inBlockSize = 1; - } - blockSize100k = inBlockSize; - AllocateCompressStructures(); - Initialize(); - InitBlock(); - } - - /** - * - * modified by Oliver Merkel, 010128 - * - */ - - public override void WriteByte(byte bv) - { - int b = (256 + bv)%256; - if (currentChar != -1) - { - if (currentChar == b) - { - runLength++; - if (runLength > 254) - { - WriteRun(); - currentChar = -1; - runLength = 0; - } - } - else - { - WriteRun(); - runLength = 1; - currentChar = b; - } - } - else - { - currentChar = b; - runLength++; - } - } - - private void WriteRun() - { - if (last < allowableBlockSize) - { - inUse[currentChar] = true; - for (int i = 0; i < runLength; i++) - { - mCrc.UpdateCRC((char) currentChar); - } - switch (runLength) - { - case 1: - last++; - block[last + 1] = (char) currentChar; - break; - case 2: - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) currentChar; - break; - case 3: - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) currentChar; - break; - default: - inUse[runLength - 4] = true; - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) currentChar; - last++; - block[last + 1] = (char) (runLength - 4); - break; - } - } - else - { - EndBlock(); - InitBlock(); - WriteRun(); - } - } - - private bool disposed = false; - - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (disposed) - { - return; - } - - Finish(); - - disposed = true; - base.Dispose(); - if (!leaveOpen) - bsStream.Dispose(); - bsStream = null; - } - } - - public void Finish() - { - if (finished) - { - return; - } - - if (runLength > 0) - { - WriteRun(); - } - currentChar = -1; - EndBlock(); - EndCompression(); - finished = true; - Flush(); - } - - public override void Flush() - { - bsStream.Flush(); - } - - private int blockCRC, combinedCRC; - - private void Initialize() - { - bytesOut = 0; - nBlocksRandomised = 0; - - /* Write `magic' bytes h indicating file-format == huffmanised, - followed by a digit indicating blockSize100k. - */ - BsPutUChar('h'); - BsPutUChar('0' + blockSize100k); - - combinedCRC = 0; - } - - private int allowableBlockSize; - - private void InitBlock() - { - // blockNo++; - mCrc.InitialiseCRC(); - last = -1; - // ch = 0; - - for (int i = 0; i < 256; i++) - { - inUse[i] = false; - } - - /* 20 is just a paranoia constant */ - allowableBlockSize = BZip2Constants.baseBlockSize*blockSize100k - 20; - } - - private void EndBlock() - { - blockCRC = mCrc.GetFinalCRC(); - combinedCRC = (combinedCRC << 1) | (int) (((uint) combinedCRC) >> 31); - combinedCRC ^= blockCRC; - - /* sort the block and establish posn of original string */ - DoReversibleTransformation(); - - /* - A 6-byte block header, the value chosen arbitrarily - as 0x314159265359 :-). A 32 bit value does not really - give a strong enough guarantee that the value will not - appear by chance in the compressed datastream. Worst-case - probability of this event, for a 900k block, is about - 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits. - For a compressed file of size 100Gb -- about 100000 blocks -- - only a 48-bit marker will do. NB: normal compression/ - decompression do *not* rely on these statistical properties. - They are only important when trying to recover blocks from - damaged files. - */ - BsPutUChar(0x31); - BsPutUChar(0x41); - BsPutUChar(0x59); - BsPutUChar(0x26); - BsPutUChar(0x53); - BsPutUChar(0x59); - - /* Now the block's CRC, so it is in a known place. */ - BsPutint(blockCRC); - - /* Now a single bit indicating randomisation. */ - if (blockRandomised) - { - BsW(1, 1); - nBlocksRandomised++; - } - else - { - BsW(1, 0); - } - - /* Finally, block's contents proper. */ - MoveToFrontCodeAndSend(); - } - - private void EndCompression() - { - /* - Now another magic 48-bit number, 0x177245385090, to - indicate the end of the last block. (Sqrt(pi), if - you want to know. I did want to use e, but it contains - too much repetition -- 27 18 28 18 28 46 -- for me - to feel statistically comfortable. Call me paranoid.) - */ - BsPutUChar(0x17); - BsPutUChar(0x72); - BsPutUChar(0x45); - BsPutUChar(0x38); - BsPutUChar(0x50); - BsPutUChar(0x90); - - BsPutint(combinedCRC); - - BsFinishedWithStream(); - } - - private void HbAssignCodes(int[] code, char[] length, int minLen, - int maxLen, int alphaSize) - { - int n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) - { - for (i = 0; i < alphaSize; i++) - { - if (length[i] == n) - { - code[i] = vec; - vec++; - } - } - ; - vec <<= 1; - } - } - - private void BsSetStream(Stream f, bool leaveOpen) - { - bsStream = f; - bsLive = 0; - bsBuff = 0; - bytesOut = 0; - this.leaveOpen = leaveOpen; - } - - private void BsFinishedWithStream() - { - while (bsLive > 0) - { - int ch = (bsBuff >> 24); - try - { - bsStream.WriteByte((byte) ch); // write 8-bit - } - catch (IOException e) - { - throw e; - } - bsBuff <<= 8; - bsLive -= 8; - bytesOut++; - } - } - - private void BsW(int n, int v) - { - while (bsLive >= 8) - { - int ch = (bsBuff >> 24); - try - { - bsStream.WriteByte((byte) ch); // write 8-bit - } - catch (IOException e) - { - throw e; - } - bsBuff <<= 8; - bsLive -= 8; - bytesOut++; - } - bsBuff |= (v << (32 - bsLive - n)); - bsLive += n; - } - - private void BsPutUChar(int c) - { - BsW(8, c); - } - - private void BsPutint(int u) - { - BsW(8, (u >> 24) & 0xff); - BsW(8, (u >> 16) & 0xff); - BsW(8, (u >> 8) & 0xff); - BsW(8, u & 0xff); - } - - private void BsPutIntVS(int numBits, int c) - { - BsW(numBits, c); - } - - private void SendMTFValues() - { - char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - - int v, t, i, j, gs, ge, totc, bt, bc, iter; - int nSelectors = 0, alphaSize, minLen, maxLen, selCtr; - int nGroups; //, nBytes; - - alphaSize = nInUse + 2; - for (t = 0; t < BZip2Constants.N_GROUPS; t++) - { - for (v = 0; v < alphaSize; v++) - { - len[t][v] = (char) GREATER_ICOST; - } - } - - /* Decide how many coding tables to use */ - if (nMTF <= 0) - { - Panic(); - } - - if (nMTF < 200) - { - nGroups = 2; - } - else if (nMTF < 600) - { - nGroups = 3; - } - else if (nMTF < 1200) - { - nGroups = 4; - } - else if (nMTF < 2400) - { - nGroups = 5; - } - else - { - nGroups = 6; - } - - /* Generate an initial set of coding tables */ - { - int nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = nMTF; - gs = 0; - while (nPart > 0) - { - tFreq = remF/nPart; - ge = gs - 1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize - 1) - { - ge++; - aFreq += mtfFreq[ge]; - } - - if (ge > gs && nPart != nGroups && nPart != 1 - && ((nGroups - nPart)%2 == 1)) - { - aFreq -= mtfFreq[ge]; - ge--; - } - - for (v = 0; v < alphaSize; v++) - { - if (v >= gs && v <= ge) - { - len[nPart - 1][v] = (char) LESSER_ICOST; - } - else - { - len[nPart - 1][v] = (char) GREATER_ICOST; - } - } - - nPart--; - gs = ge + 1; - remF -= aFreq; - } - } - - int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - int[] fave = new int[BZip2Constants.N_GROUPS]; - short[] cost = new short[BZip2Constants.N_GROUPS]; - /* - Iterate up to N_ITERS times to improve the tables. - */ - for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) - { - for (t = 0; t < nGroups; t++) - { - fave[t] = 0; - } - - for (t = 0; t < nGroups; t++) - { - for (v = 0; v < alphaSize; v++) - { - rfreq[t][v] = 0; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (true) - { - /* Set group start & end marks. */ - if (gs >= nMTF) - { - break; - } - ge = gs + BZip2Constants.G_SIZE - 1; - if (ge >= nMTF) - { - ge = nMTF - 1; - } - - /* - Calculate the cost of this group as coded - by each of the coding tables. - */ - for (t = 0; t < nGroups; t++) - { - cost[t] = 0; - } - - if (nGroups == 6) - { - short cost0, cost1, cost2, cost3, cost4, cost5; - cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; - for (i = gs; i <= ge; i++) - { - short icv = szptr[i]; - cost0 += (short) len[0][icv]; - cost1 += (short) len[1][icv]; - cost2 += (short) len[2][icv]; - cost3 += (short) len[3][icv]; - cost4 += (short) len[4][icv]; - cost5 += (short) len[5][icv]; - } - cost[0] = cost0; - cost[1] = cost1; - cost[2] = cost2; - cost[3] = cost3; - cost[4] = cost4; - cost[5] = cost5; - } - else - { - for (i = gs; i <= ge; i++) - { - short icv = szptr[i]; - for (t = 0; t < nGroups; t++) - { - cost[t] += (short) len[t][icv]; - } - } - } - - /* - Find the coding table which is best for this group, - and record its identity in the selector table. - */ - bc = 999999999; - bt = -1; - for (t = 0; t < nGroups; t++) - { - if (cost[t] < bc) - { - bc = cost[t]; - bt = t; - } - } - ; - totc += bc; - fave[bt]++; - selector[nSelectors] = (char) bt; - nSelectors++; - - /* - Increment the symbol frequencies for the selected table. - */ - for (i = gs; i <= ge; i++) - { - rfreq[bt][szptr[i]]++; - } - - gs = ge + 1; - } - - /* - Recompute the tables based on the accumulated frequencies. - */ - for (t = 0; t < nGroups; t++) - { - HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20); - } - } - - rfreq = null; - fave = null; - cost = null; - - if (!(nGroups < 8)) - { - Panic(); - } - if (!(nSelectors < 32768 && nSelectors <= (2 + (900000/BZip2Constants.G_SIZE)))) - { - Panic(); - } - - - /* Compute MTF values for the selectors. */ - { - char[] pos = new char[BZip2Constants.N_GROUPS]; - char ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) - { - pos[i] = (char) i; - } - for (i = 0; i < nSelectors; i++) - { - ll_i = selector[i]; - j = 0; - tmp = pos[j]; - while (ll_i != tmp) - { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - } - pos[0] = tmp; - selectorMtf[i] = (char) j; - } - } - - int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - - /* Assign actual codes for the tables. */ - for (t = 0; t < nGroups; t++) - { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) - { - if (len[t][i] > maxLen) - { - maxLen = len[t][i]; - } - if (len[t][i] < minLen) - { - minLen = len[t][i]; - } - } - if (maxLen > 20) - { - Panic(); - } - if (minLen < 1) - { - Panic(); - } - HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize); - } - - /* Transmit the mapping table. */ - { - bool[] inUse16 = new bool[16]; - for (i = 0; i < 16; i++) - { - inUse16[i] = false; - for (j = 0; j < 16; j++) - { - if (inUse[i*16 + j]) - { - inUse16[i] = true; - } - } - } - - //nBytes = bytesOut; - for (i = 0; i < 16; i++) - { - if (inUse16[i]) - { - BsW(1, 1); - } - else - { - BsW(1, 0); - } - } - - for (i = 0; i < 16; i++) - { - if (inUse16[i]) - { - for (j = 0; j < 16; j++) - { - if (inUse[i*16 + j]) - { - BsW(1, 1); - } - else - { - BsW(1, 0); - } - } - } - } - } - - /* Now the selectors. */ - //nBytes = bytesOut; - BsW(3, nGroups); - BsW(15, nSelectors); - for (i = 0; i < nSelectors; i++) - { - for (j = 0; j < selectorMtf[i]; j++) - { - BsW(1, 1); - } - BsW(1, 0); - } - - /* Now the coding tables. */ - //nBytes = bytesOut; - - for (t = 0; t < nGroups; t++) - { - int curr = len[t][0]; - BsW(5, curr); - for (i = 0; i < alphaSize; i++) - { - while (curr < len[t][i]) - { - BsW(2, 2); - curr++; /* 10 */ - } - while (curr > len[t][i]) - { - BsW(2, 3); - curr--; /* 11 */ - } - BsW(1, 0); - } - } - - /* And finally, the block data proper */ - //nBytes = bytesOut; - selCtr = 0; - gs = 0; - while (true) - { - if (gs >= nMTF) - { - break; - } - ge = gs + BZip2Constants.G_SIZE - 1; - if (ge >= nMTF) - { - ge = nMTF - 1; - } - for (i = gs; i <= ge; i++) - { - BsW(len[selector[selCtr]][szptr[i]], - code[selector[selCtr]][szptr[i]]); - } - - gs = ge + 1; - selCtr++; - } - if (!(selCtr == nSelectors)) - { - Panic(); - } - } - - private void MoveToFrontCodeAndSend() - { - BsPutIntVS(24, origPtr); - GenerateMTFValues(); - SendMTFValues(); - } - - private Stream bsStream; - private bool leaveOpen; - - private void SimpleSort(int lo, int hi, int d) - { - int i, j, h, bigN, hp; - int v; - - bigN = hi - lo + 1; - if (bigN < 2) - { - return; - } - - hp = 0; - while (incs[hp] < bigN) - { - hp++; - } - hp--; - - for (; hp >= 0; hp--) - { - h = incs[hp]; - - i = lo + h; - while (true) - { - /* copy 1 */ - if (i > hi) - { - break; - } - v = zptr[i]; - j = i; - while (FullGtU(zptr[j - h] + d, v + d)) - { - zptr[j] = zptr[j - h]; - j = j - h; - if (j <= (lo + h - 1)) - { - break; - } - } - zptr[j] = v; - i++; - - /* copy 2 */ - if (i > hi) - { - break; - } - v = zptr[i]; - j = i; - while (FullGtU(zptr[j - h] + d, v + d)) - { - zptr[j] = zptr[j - h]; - j = j - h; - if (j <= (lo + h - 1)) - { - break; - } - } - zptr[j] = v; - i++; - - /* copy 3 */ - if (i > hi) - { - break; - } - v = zptr[i]; - j = i; - while (FullGtU(zptr[j - h] + d, v + d)) - { - zptr[j] = zptr[j - h]; - j = j - h; - if (j <= (lo + h - 1)) - { - break; - } - } - zptr[j] = v; - i++; - - if (workDone > workLimit && firstAttempt) - { - return; - } - } - } - } - - private void Vswap(int p1, int p2, int n) - { - int temp = 0; - while (n > 0) - { - temp = zptr[p1]; - zptr[p1] = zptr[p2]; - zptr[p2] = temp; - p1++; - p2++; - n--; - } - } - - private char Med3(char a, char b, char c) - { - char t; - if (a > b) - { - t = a; - a = b; - b = t; - } - if (b > c) - { - t = b; - b = c; - c = t; - } - if (a > b) - { - b = a; - } - return b; - } - - internal class StackElem - { - internal int ll; - internal int hh; - internal int dd; - } - - private void QSort3(int loSt, int hiSt, int dSt) - { - int unLo, unHi, ltLo, gtHi, med, n, m; - int sp, lo, hi, d; - StackElem[] stack = new StackElem[QSORT_STACK_SIZE]; - for (int count = 0; count < QSORT_STACK_SIZE; count++) - { - stack[count] = new StackElem(); - } - - sp = 0; - - stack[sp].ll = loSt; - stack[sp].hh = hiSt; - stack[sp].dd = dSt; - sp++; - - while (sp > 0) - { - if (sp >= QSORT_STACK_SIZE) - { - Panic(); - } - - sp--; - lo = stack[sp].ll; - hi = stack[sp].hh; - d = stack[sp].dd; - - if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) - { - SimpleSort(lo, hi, d); - if (workDone > workLimit && firstAttempt) - { - return; - } - continue; - } - - med = Med3(block[zptr[lo] + d + 1], - block[zptr[hi] + d + 1], - block[zptr[(lo + hi) >> 1] + d + 1]); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (true) - { - while (true) - { - if (unLo > unHi) - { - break; - } - n = ((int) block[zptr[unLo] + d + 1]) - med; - if (n == 0) - { - int temp = 0; - temp = zptr[unLo]; - zptr[unLo] = zptr[ltLo]; - zptr[ltLo] = temp; - ltLo++; - unLo++; - continue; - } - ; - if (n > 0) - { - break; - } - unLo++; - } - while (true) - { - if (unLo > unHi) - { - break; - } - n = ((int) block[zptr[unHi] + d + 1]) - med; - if (n == 0) - { - int temp = 0; - temp = zptr[unHi]; - zptr[unHi] = zptr[gtHi]; - zptr[gtHi] = temp; - gtHi--; - unHi--; - continue; - } - ; - if (n < 0) - { - break; - } - unHi--; - } - if (unLo > unHi) - { - break; - } - int tempx = zptr[unLo]; - zptr[unLo] = zptr[unHi]; - zptr[unHi] = tempx; - unLo++; - unHi--; - } - - if (gtHi < ltLo) - { - stack[sp].ll = lo; - stack[sp].hh = hi; - stack[sp].dd = d + 1; - sp++; - continue; - } - - n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo); - Vswap(lo, unLo - n, n); - m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi); - Vswap(unLo, hi - m + 1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - stack[sp].ll = lo; - stack[sp].hh = n; - stack[sp].dd = d; - sp++; - - stack[sp].ll = n + 1; - stack[sp].hh = m - 1; - stack[sp].dd = d + 1; - sp++; - - stack[sp].ll = m; - stack[sp].hh = hi; - stack[sp].dd = d; - sp++; - } - } - - private void MainSort() - { - int i, j, ss, sb; - int[] runningOrder = new int[256]; - int[] copy = new int[256]; - bool[] bigDone = new bool[256]; - int c1, c2; - int numQSorted; - - /* - In the various block-sized structures, live data runs - from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First, - set up the overshoot area for block. - */ - - // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" ); - for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) - { - block[last + i + 2] = block[(i%(last + 1)) + 1]; - } - for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) - { - quadrant[i] = 0; - } - - block[0] = (char) (block[last + 1]); - - if (last < 4000) - { - /* - Use SimpleSort(), since the full sorting mechanism - has quite a large constant overhead. - */ - for (i = 0; i <= last; i++) - { - zptr[i] = i; - } - firstAttempt = false; - workDone = workLimit = 0; - SimpleSort(0, last, 0); - } - else - { - numQSorted = 0; - for (i = 0; i <= 255; i++) - { - bigDone[i] = false; - } - - for (i = 0; i <= 65536; i++) - { - ftab[i] = 0; - } - - c1 = block[0]; - for (i = 0; i <= last; i++) - { - c2 = block[i + 1]; - ftab[(c1 << 8) + c2]++; - c1 = c2; - } - - for (i = 1; i <= 65536; i++) - { - ftab[i] += ftab[i - 1]; - } - - c1 = block[1]; - for (i = 0; i < last; i++) - { - c2 = block[i + 2]; - j = (c1 << 8) + c2; - c1 = c2; - ftab[j]--; - zptr[ftab[j]] = i; - } - - j = ((block[last + 1]) << 8) + (block[1]); - ftab[j]--; - zptr[ftab[j]] = last; - - /* - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - */ - - for (i = 0; i <= 255; i++) - { - runningOrder[i] = i; - } - - { - int vv; - int h = 1; - do - { - h = 3*h + 1; - } while (h <= 256); - do - { - h = h/3; - for (i = h; i <= 255; i++) - { - vv = runningOrder[i]; - j = i; - while ((ftab[((runningOrder[j - h]) + 1) << 8] - - ftab[(runningOrder[j - h]) << 8]) > - (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) - { - runningOrder[j] = runningOrder[j - h]; - j = j - h; - if (j <= (h - 1)) - { - break; - } - } - runningOrder[j] = vv; - } - } while (h != 1); - } - - /* - The main sorting loop. - */ - for (i = 0; i <= 255; i++) - { - /* - Process big buckets, starting with the least full. - */ - ss = runningOrder[i]; - - /* - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j]. Hopefully - previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - */ - for (j = 0; j <= 255; j++) - { - sb = (ss << 8) + j; - if (!((ftab[sb] & SETMASK) == SETMASK)) - { - int lo = ftab[sb] & CLEARMASK; - int hi = (ftab[sb + 1] & CLEARMASK) - 1; - if (hi > lo) - { - QSort3(lo, hi, 2); - numQSorted += (hi - lo + 1); - if (workDone > workLimit && firstAttempt) - { - return; - } - } - ftab[sb] |= SETMASK; - } - } - - /* - The ss big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - */ - bigDone[ss] = true; - - if (i < 255) - { - int bbStart = ftab[ss << 8] & CLEARMASK; - int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart; - int shifts = 0; - - while ((bbSize >> shifts) > 65534) - { - shifts++; - } - - for (j = 0; j < bbSize; j++) - { - int a2update = zptr[bbStart + j]; - int qVal = (j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) - { - quadrant[a2update + last + 1] = qVal; - } - } - - if (!(((bbSize - 1) >> shifts) <= 65535)) - { - Panic(); - } - } - - /* - Now scan this big bucket so as to synthesise the - sorted order for small buckets [t, ss] for all t != ss. - */ - for (j = 0; j <= 255; j++) - { - copy[j] = ftab[(j << 8) + ss] & CLEARMASK; - } - - for (j = ftab[ss << 8] & CLEARMASK; - j < (ftab[(ss + 1) << 8] & CLEARMASK); - j++) - { - c1 = block[zptr[j]]; - if (!bigDone[c1]) - { - zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1; - copy[c1]++; - } - } - - for (j = 0; j <= 255; j++) - { - ftab[(j << 8) + ss] |= SETMASK; - } - } - } - } - - private void RandomiseBlock() - { - int i; - int rNToGo = 0; - int rTPos = 0; - for (i = 0; i < 256; i++) - { - inUse[i] = false; - } - - for (i = 0; i <= last; i++) - { - if (rNToGo == 0) - { - rNToGo = (char) BZip2Constants.rNums[rTPos]; - rTPos++; - if (rTPos == 512) - { - rTPos = 0; - } - } - rNToGo--; - block[i + 1] ^= (char) ((rNToGo == 1) ? 1 : 0); - // handle 16 bit signed numbers - block[i + 1] &= (char) 0xFF; - - inUse[block[i + 1]] = true; - } - } - - private void DoReversibleTransformation() - { - int i; - - workLimit = workFactor*last; - workDone = 0; - blockRandomised = false; - firstAttempt = true; - - MainSort(); - - if (workDone > workLimit && firstAttempt) - { - RandomiseBlock(); - workLimit = workDone = 0; - blockRandomised = true; - firstAttempt = false; - MainSort(); - } - - origPtr = -1; - for (i = 0; i <= last; i++) - { - if (zptr[i] == 0) - { - origPtr = i; - break; - } - } - ; - - if (origPtr == -1) - { - Panic(); - } - } - - private bool FullGtU(int i1, int i2) - { - int k; - char c1, c2; - int s1, s2; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - k = last + 1; - - do - { - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - if (i1 > last) - { - i1 -= last; - i1--; - } - ; - if (i2 > last) - { - i2 -= last; - i2--; - } - ; - - k -= 4; - workDone++; - } while (k >= 0); - - return false; - } - - /* - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. - */ - - private int[] incs = - { - 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 - }; - - private void AllocateCompressStructures() - { - int n = BZip2Constants.baseBlockSize*blockSize100k; - block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)]; - quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)]; - zptr = new int[n]; - ftab = new int[65537]; - - if (block == null || quadrant == null || zptr == null - || ftab == null) - { - //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537; - //compressOutOfMemory ( totalDraw, n ); - } - - /* - The back end needs a place to store the MTF values - whilst it calculates the coding tables. We could - put them in the zptr array. However, these values - will fit in a short, so we overlay szptr at the - start of zptr, in the hope of reducing the number - of cache misses induced by the multiple traversals - of the MTF values when calculating coding tables. - Seems to improve compression speed by about 1%. - */ - // szptr = zptr; - - - szptr = new short[2*n]; - } - - private void GenerateMTFValues() - { - char[] yy = new char[256]; - int i, j; - char tmp; - char tmp2; - int zPend; - int wr; - int EOB; - - MakeMaps(); - EOB = nInUse + 1; - - for (i = 0; i <= EOB; i++) - { - mtfFreq[i] = 0; - } - - wr = 0; - zPend = 0; - for (i = 0; i < nInUse; i++) - { - yy[i] = (char) i; - } - - - for (i = 0; i <= last; i++) - { - char ll_i; - - ll_i = unseqToSeq[block[zptr[i]]]; - - j = 0; - tmp = yy[j]; - while (ll_i != tmp) - { - j++; - tmp2 = tmp; - tmp = yy[j]; - yy[j] = tmp2; - } - ; - yy[0] = tmp; - - if (j == 0) - { - zPend++; - } - else - { - if (zPend > 0) - { - zPend--; - while (true) - { - switch (zPend%2) - { - case 0: - szptr[wr] = (short) BZip2Constants.RUNA; - wr++; - mtfFreq[BZip2Constants.RUNA]++; - break; - case 1: - szptr[wr] = (short) BZip2Constants.RUNB; - wr++; - mtfFreq[BZip2Constants.RUNB]++; - break; - } - ; - if (zPend < 2) - { - break; - } - zPend = (zPend - 2)/2; - } - ; - zPend = 0; - } - szptr[wr] = (short) (j + 1); - wr++; - mtfFreq[j + 1]++; - } - } - - if (zPend > 0) - { - zPend--; - while (true) - { - switch (zPend%2) - { - case 0: - szptr[wr] = (short) BZip2Constants.RUNA; - wr++; - mtfFreq[BZip2Constants.RUNA]++; - break; - case 1: - szptr[wr] = (short) BZip2Constants.RUNB; - wr++; - mtfFreq[BZip2Constants.RUNB]++; - break; - } - if (zPend < 2) - { - break; - } - zPend = (zPend - 2)/2; - } - } - - szptr[wr] = (short) EOB; - wr++; - mtfFreq[EOB]++; - - nMTF = wr; - } - - public override int Read(byte[] buffer, int offset, int count) - { - return 0; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return 0; - } - - public override void SetLength(long value) - { - } - - public override void Write(byte[] buffer, int offset, int count) - { - for (int k = 0; k < count; ++k) - { - WriteByte(buffer[k + offset]); - } - } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override long Length - { - get { return 0; } - } - - public override long Position - { - get { return 0; } - set { } - } - } +using System.IO; + +/* + * Copyright 2001,2004-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace SharpCompress.Compressor.BZip2 +{ + /** + * An output stream that compresses into the BZip2 format (with the file + * header chars) into another stream. + * + * @author Keiron Liddle + * + * TODO: Update to BZip2 1.0.1 + * NB: note this class has been modified to add a leading BZ to the + * start of the BZIP2 stream to make it compatible with other PGP programs. + */ + + internal class CBZip2OutputStream : Stream + { + protected const int SETMASK = (1 << 21); + protected const int CLEARMASK = (~SETMASK); + protected const int GREATER_ICOST = 15; + protected const int LESSER_ICOST = 0; + protected const int SMALL_THRESH = 20; + protected const int DEPTH_THRESH = 10; + + /* + If you are ever unlucky/improbable enough + to get a stack overflow whilst sorting, + increase the following constant and try + again. In practice I have never seen the + stack go above 27 elems, so the following + limit seems very generous. + */ + protected const int QSORT_STACK_SIZE = 1000; + private bool finished; + + private static void Panic() + { + //System.out.Println("panic"); + //throw new CError(); + } + + private void MakeMaps() + { + int i; + nInUse = 0; + for (i = 0; i < 256; i++) + { + if (inUse[i]) + { + seqToUnseq[nInUse] = (char) i; + unseqToSeq[i] = (char) nInUse; + nInUse++; + } + } + } + + protected static void HbMakeCodeLengths(char[] len, int[] freq, + int alphaSize, int maxLen) + { + /* + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + */ + int nNodes, nHeap, n1, n2, i, j, k; + bool tooLong; + + int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2]; + int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE*2]; + int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE*2]; + + for (i = 0; i < alphaSize; i++) + { + weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + } + + while (true) + { + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) + { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + { + int zz, tmp; + zz = nHeap; + tmp = heap[zz]; + while (weight[tmp] < weight[heap[zz >> 1]]) + { + heap[zz] = heap[zz >> 1]; + zz >>= 1; + } + heap[zz] = tmp; + } + } + if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) + { + Panic(); + } + + while (nHeap > 1) + { + n1 = heap[1]; + heap[1] = heap[nHeap]; + nHeap--; + { + int zz = 0, yy = 0, tmp = 0; + zz = 1; + tmp = heap[zz]; + while (true) + { + yy = zz << 1; + if (yy > nHeap) + { + break; + } + if (yy < nHeap + && weight[heap[yy + 1]] < weight[heap[yy]]) + { + yy++; + } + if (weight[tmp] < weight[heap[yy]]) + { + break; + } + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; + } + n2 = heap[1]; + heap[1] = heap[nHeap]; + nHeap--; + { + int zz = 0, yy = 0, tmp = 0; + zz = 1; + tmp = heap[zz]; + while (true) + { + yy = zz << 1; + if (yy > nHeap) + { + break; + } + if (yy < nHeap + && weight[heap[yy + 1]] < weight[heap[yy]]) + { + yy++; + } + if (weight[tmp] < weight[heap[yy]]) + { + break; + } + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; + } + nNodes++; + parent[n1] = parent[n2] = nNodes; + + weight[nNodes] = (int) ((uint) ((weight[n1] & 0xffffff00) + + (weight[n2] & 0xffffff00)) + | (uint) (1 + (((weight[n1] & 0x000000ff) > + (weight[n2] & 0x000000ff)) + ? (weight[n1] & 0x000000ff) + : (weight[n2] & 0x000000ff)))); + + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + { + int zz = 0, tmp = 0; + zz = nHeap; + tmp = heap[zz]; + while (weight[tmp] < weight[heap[zz >> 1]]) + { + heap[zz] = heap[zz >> 1]; + zz >>= 1; + } + heap[zz] = tmp; + } + } + if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE*2))) + { + Panic(); + } + + tooLong = false; + for (i = 1; i <= alphaSize; i++) + { + j = 0; + k = i; + while (parent[k] >= 0) + { + k = parent[k]; + j++; + } + len[i - 1] = (char) j; + if (j > maxLen) + { + tooLong = true; + } + } + + if (!tooLong) + { + break; + } + + for (i = 1; i < alphaSize; i++) + { + j = weight[i] >> 8; + j = 1 + (j/2); + weight[i] = j << 8; + } + } + } + + /* + index of the last char in the block, so + the block size == last + 1. + */ + private int last; + + /* + index in zptr[] of original string after sorting. + */ + private int origPtr; + + /* + always: in the range 0 .. 9. + The current block size is 100000 * this number. + */ + private int blockSize100k; + + private bool blockRandomised; + + private int bytesOut; + private int bsBuff; + private int bsLive; + private CRC mCrc = new CRC(); + + private bool[] inUse = new bool[256]; + private int nInUse; + + private char[] seqToUnseq = new char[256]; + private char[] unseqToSeq = new char[256]; + + private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; + private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; + + private char[] block; + private int[] quadrant; + private int[] zptr; + private short[] szptr; + private int[] ftab; + + private int nMTF; + + private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE]; + + /* + * Used when sorting. If too many long comparisons + * happen, we stop sorting, randomise the block + * slightly, and try again. + */ + private int workFactor; + private int workDone; + private int workLimit; + private bool firstAttempt; + private int nBlocksRandomised; + + private int currentChar = -1; + private int runLength = 0; + + public CBZip2OutputStream(Stream inStream) + : this(inStream, 9, false) + { + } + + public CBZip2OutputStream(Stream inStream, bool leaveOpen) + : this(inStream, 9, leaveOpen) + { + } + + public CBZip2OutputStream(Stream inStream, int inBlockSize, bool leaveOpen) + { + block = null; + quadrant = null; + zptr = null; + ftab = null; + + inStream.WriteByte((byte) 'B'); + inStream.WriteByte((byte) 'Z'); + + BsSetStream(inStream, leaveOpen); + + workFactor = 50; + if (inBlockSize > 9) + { + inBlockSize = 9; + } + if (inBlockSize < 1) + { + inBlockSize = 1; + } + blockSize100k = inBlockSize; + AllocateCompressStructures(); + Initialize(); + InitBlock(); + } + + /** + * + * modified by Oliver Merkel, 010128 + * + */ + + public override void WriteByte(byte bv) + { + int b = (256 + bv)%256; + if (currentChar != -1) + { + if (currentChar == b) + { + runLength++; + if (runLength > 254) + { + WriteRun(); + currentChar = -1; + runLength = 0; + } + } + else + { + WriteRun(); + runLength = 1; + currentChar = b; + } + } + else + { + currentChar = b; + runLength++; + } + } + + private void WriteRun() + { + if (last < allowableBlockSize) + { + inUse[currentChar] = true; + for (int i = 0; i < runLength; i++) + { + mCrc.UpdateCRC((char) currentChar); + } + switch (runLength) + { + case 1: + last++; + block[last + 1] = (char) currentChar; + break; + case 2: + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + break; + case 3: + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + break; + default: + inUse[runLength - 4] = true; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) (runLength - 4); + break; + } + } + else + { + EndBlock(); + InitBlock(); + WriteRun(); + } + } + + private bool disposed = false; + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (disposed) + { + return; + } + + Finish(); + + disposed = true; + base.Dispose(); + if (!leaveOpen) + bsStream.Dispose(); + bsStream = null; + } + } + + public void Finish() + { + if (finished) + { + return; + } + + if (runLength > 0) + { + WriteRun(); + } + currentChar = -1; + EndBlock(); + EndCompression(); + finished = true; + Flush(); + } + + public override void Flush() + { + bsStream.Flush(); + } + + private int blockCRC, combinedCRC; + + private void Initialize() + { + bytesOut = 0; + nBlocksRandomised = 0; + + /* Write `magic' bytes h indicating file-format == huffmanised, + followed by a digit indicating blockSize100k. + */ + BsPutUChar('h'); + BsPutUChar('0' + blockSize100k); + + combinedCRC = 0; + } + + private int allowableBlockSize; + + private void InitBlock() + { + // blockNo++; + mCrc.InitialiseCRC(); + last = -1; + // ch = 0; + + for (int i = 0; i < 256; i++) + { + inUse[i] = false; + } + + /* 20 is just a paranoia constant */ + allowableBlockSize = BZip2Constants.baseBlockSize*blockSize100k - 20; + } + + private void EndBlock() + { + blockCRC = mCrc.GetFinalCRC(); + combinedCRC = (combinedCRC << 1) | (int) (((uint) combinedCRC) >> 31); + combinedCRC ^= blockCRC; + + /* sort the block and establish posn of original string */ + DoReversibleTransformation(); + + /* + A 6-byte block header, the value chosen arbitrarily + as 0x314159265359 :-). A 32 bit value does not really + give a strong enough guarantee that the value will not + appear by chance in the compressed datastream. Worst-case + probability of this event, for a 900k block, is about + 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits. + For a compressed file of size 100Gb -- about 100000 blocks -- + only a 48-bit marker will do. NB: normal compression/ + decompression do *not* rely on these statistical properties. + They are only important when trying to recover blocks from + damaged files. + */ + BsPutUChar(0x31); + BsPutUChar(0x41); + BsPutUChar(0x59); + BsPutUChar(0x26); + BsPutUChar(0x53); + BsPutUChar(0x59); + + /* Now the block's CRC, so it is in a known place. */ + BsPutint(blockCRC); + + /* Now a single bit indicating randomisation. */ + if (blockRandomised) + { + BsW(1, 1); + nBlocksRandomised++; + } + else + { + BsW(1, 0); + } + + /* Finally, block's contents proper. */ + MoveToFrontCodeAndSend(); + } + + private void EndCompression() + { + /* + Now another magic 48-bit number, 0x177245385090, to + indicate the end of the last block. (Sqrt(pi), if + you want to know. I did want to use e, but it contains + too much repetition -- 27 18 28 18 28 46 -- for me + to feel statistically comfortable. Call me paranoid.) + */ + BsPutUChar(0x17); + BsPutUChar(0x72); + BsPutUChar(0x45); + BsPutUChar(0x38); + BsPutUChar(0x50); + BsPutUChar(0x90); + + BsPutint(combinedCRC); + + BsFinishedWithStream(); + } + + private void HbAssignCodes(int[] code, char[] length, int minLen, + int maxLen, int alphaSize) + { + int n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) + { + for (i = 0; i < alphaSize; i++) + { + if (length[i] == n) + { + code[i] = vec; + vec++; + } + } + ; + vec <<= 1; + } + } + + private void BsSetStream(Stream f, bool leaveOpen) + { + bsStream = f; + bsLive = 0; + bsBuff = 0; + bytesOut = 0; + this.leaveOpen = leaveOpen; + } + + private void BsFinishedWithStream() + { + while (bsLive > 0) + { + int ch = (bsBuff >> 24); + try + { + bsStream.WriteByte((byte) ch); // write 8-bit + } + catch (IOException e) + { + throw e; + } + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + } + + private void BsW(int n, int v) + { + while (bsLive >= 8) + { + int ch = (bsBuff >> 24); + try + { + bsStream.WriteByte((byte) ch); // write 8-bit + } + catch (IOException e) + { + throw e; + } + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + bsBuff |= (v << (32 - bsLive - n)); + bsLive += n; + } + + private void BsPutUChar(int c) + { + BsW(8, c); + } + + private void BsPutint(int u) + { + BsW(8, (u >> 24) & 0xff); + BsW(8, (u >> 16) & 0xff); + BsW(8, (u >> 8) & 0xff); + BsW(8, u & 0xff); + } + + private void BsPutIntVS(int numBits, int c) + { + BsW(numBits, c); + } + + private void SendMTFValues() + { + char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + + int v, t, i, j, gs, ge, totc, bt, bc, iter; + int nSelectors = 0, alphaSize, minLen, maxLen, selCtr; + int nGroups; //, nBytes; + + alphaSize = nInUse + 2; + for (t = 0; t < BZip2Constants.N_GROUPS; t++) + { + for (v = 0; v < alphaSize; v++) + { + len[t][v] = (char) GREATER_ICOST; + } + } + + /* Decide how many coding tables to use */ + if (nMTF <= 0) + { + Panic(); + } + + if (nMTF < 200) + { + nGroups = 2; + } + else if (nMTF < 600) + { + nGroups = 3; + } + else if (nMTF < 1200) + { + nGroups = 4; + } + else if (nMTF < 2400) + { + nGroups = 5; + } + else + { + nGroups = 6; + } + + /* Generate an initial set of coding tables */ + { + int nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = nMTF; + gs = 0; + while (nPart > 0) + { + tFreq = remF/nPart; + ge = gs - 1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize - 1) + { + ge++; + aFreq += mtfFreq[ge]; + } + + if (ge > gs && nPart != nGroups && nPart != 1 + && ((nGroups - nPart)%2 == 1)) + { + aFreq -= mtfFreq[ge]; + ge--; + } + + for (v = 0; v < alphaSize; v++) + { + if (v >= gs && v <= ge) + { + len[nPart - 1][v] = (char) LESSER_ICOST; + } + else + { + len[nPart - 1][v] = (char) GREATER_ICOST; + } + } + + nPart--; + gs = ge + 1; + remF -= aFreq; + } + } + + int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int[] fave = new int[BZip2Constants.N_GROUPS]; + short[] cost = new short[BZip2Constants.N_GROUPS]; + /* + Iterate up to N_ITERS times to improve the tables. + */ + for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) + { + for (t = 0; t < nGroups; t++) + { + fave[t] = 0; + } + + for (t = 0; t < nGroups; t++) + { + for (v = 0; v < alphaSize; v++) + { + rfreq[t][v] = 0; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (true) + { + /* Set group start & end marks. */ + if (gs >= nMTF) + { + break; + } + ge = gs + BZip2Constants.G_SIZE - 1; + if (ge >= nMTF) + { + ge = nMTF - 1; + } + + /* + Calculate the cost of this group as coded + by each of the coding tables. + */ + for (t = 0; t < nGroups; t++) + { + cost[t] = 0; + } + + if (nGroups == 6) + { + short cost0, cost1, cost2, cost3, cost4, cost5; + cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; + for (i = gs; i <= ge; i++) + { + short icv = szptr[i]; + cost0 += (short) len[0][icv]; + cost1 += (short) len[1][icv]; + cost2 += (short) len[2][icv]; + cost3 += (short) len[3][icv]; + cost4 += (short) len[4][icv]; + cost5 += (short) len[5][icv]; + } + cost[0] = cost0; + cost[1] = cost1; + cost[2] = cost2; + cost[3] = cost3; + cost[4] = cost4; + cost[5] = cost5; + } + else + { + for (i = gs; i <= ge; i++) + { + short icv = szptr[i]; + for (t = 0; t < nGroups; t++) + { + cost[t] += (short) len[t][icv]; + } + } + } + + /* + Find the coding table which is best for this group, + and record its identity in the selector table. + */ + bc = 999999999; + bt = -1; + for (t = 0; t < nGroups; t++) + { + if (cost[t] < bc) + { + bc = cost[t]; + bt = t; + } + } + ; + totc += bc; + fave[bt]++; + selector[nSelectors] = (char) bt; + nSelectors++; + + /* + Increment the symbol frequencies for the selected table. + */ + for (i = gs; i <= ge; i++) + { + rfreq[bt][szptr[i]]++; + } + + gs = ge + 1; + } + + /* + Recompute the tables based on the accumulated frequencies. + */ + for (t = 0; t < nGroups; t++) + { + HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20); + } + } + + rfreq = null; + fave = null; + cost = null; + + if (!(nGroups < 8)) + { + Panic(); + } + if (!(nSelectors < 32768 && nSelectors <= (2 + (900000/BZip2Constants.G_SIZE)))) + { + Panic(); + } + + + /* Compute MTF values for the selectors. */ + { + char[] pos = new char[BZip2Constants.N_GROUPS]; + char ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) + { + pos[i] = (char) i; + } + for (i = 0; i < nSelectors; i++) + { + ll_i = selector[i]; + j = 0; + tmp = pos[j]; + while (ll_i != tmp) + { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + } + pos[0] = tmp; + selectorMtf[i] = (char) j; + } + } + + int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + + /* Assign actual codes for the tables. */ + for (t = 0; t < nGroups; t++) + { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) + { + if (len[t][i] > maxLen) + { + maxLen = len[t][i]; + } + if (len[t][i] < minLen) + { + minLen = len[t][i]; + } + } + if (maxLen > 20) + { + Panic(); + } + if (minLen < 1) + { + Panic(); + } + HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize); + } + + /* Transmit the mapping table. */ + { + bool[] inUse16 = new bool[16]; + for (i = 0; i < 16; i++) + { + inUse16[i] = false; + for (j = 0; j < 16; j++) + { + if (inUse[i*16 + j]) + { + inUse16[i] = true; + } + } + } + + //nBytes = bytesOut; + for (i = 0; i < 16; i++) + { + if (inUse16[i]) + { + BsW(1, 1); + } + else + { + BsW(1, 0); + } + } + + for (i = 0; i < 16; i++) + { + if (inUse16[i]) + { + for (j = 0; j < 16; j++) + { + if (inUse[i*16 + j]) + { + BsW(1, 1); + } + else + { + BsW(1, 0); + } + } + } + } + } + + /* Now the selectors. */ + //nBytes = bytesOut; + BsW(3, nGroups); + BsW(15, nSelectors); + for (i = 0; i < nSelectors; i++) + { + for (j = 0; j < selectorMtf[i]; j++) + { + BsW(1, 1); + } + BsW(1, 0); + } + + /* Now the coding tables. */ + //nBytes = bytesOut; + + for (t = 0; t < nGroups; t++) + { + int curr = len[t][0]; + BsW(5, curr); + for (i = 0; i < alphaSize; i++) + { + while (curr < len[t][i]) + { + BsW(2, 2); + curr++; /* 10 */ + } + while (curr > len[t][i]) + { + BsW(2, 3); + curr--; /* 11 */ + } + BsW(1, 0); + } + } + + /* And finally, the block data proper */ + //nBytes = bytesOut; + selCtr = 0; + gs = 0; + while (true) + { + if (gs >= nMTF) + { + break; + } + ge = gs + BZip2Constants.G_SIZE - 1; + if (ge >= nMTF) + { + ge = nMTF - 1; + } + for (i = gs; i <= ge; i++) + { + BsW(len[selector[selCtr]][szptr[i]], + code[selector[selCtr]][szptr[i]]); + } + + gs = ge + 1; + selCtr++; + } + if (!(selCtr == nSelectors)) + { + Panic(); + } + } + + private void MoveToFrontCodeAndSend() + { + BsPutIntVS(24, origPtr); + GenerateMTFValues(); + SendMTFValues(); + } + + private Stream bsStream; + private bool leaveOpen; + + private void SimpleSort(int lo, int hi, int d) + { + int i, j, h, bigN, hp; + int v; + + bigN = hi - lo + 1; + if (bigN < 2) + { + return; + } + + hp = 0; + while (incs[hp] < bigN) + { + hp++; + } + hp--; + + for (; hp >= 0; hp--) + { + h = incs[hp]; + + i = lo + h; + while (true) + { + /* copy 1 */ + if (i > hi) + { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) + { + zptr[j] = zptr[j - h]; + j = j - h; + if (j <= (lo + h - 1)) + { + break; + } + } + zptr[j] = v; + i++; + + /* copy 2 */ + if (i > hi) + { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) + { + zptr[j] = zptr[j - h]; + j = j - h; + if (j <= (lo + h - 1)) + { + break; + } + } + zptr[j] = v; + i++; + + /* copy 3 */ + if (i > hi) + { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) + { + zptr[j] = zptr[j - h]; + j = j - h; + if (j <= (lo + h - 1)) + { + break; + } + } + zptr[j] = v; + i++; + + if (workDone > workLimit && firstAttempt) + { + return; + } + } + } + } + + private void Vswap(int p1, int p2, int n) + { + int temp = 0; + while (n > 0) + { + temp = zptr[p1]; + zptr[p1] = zptr[p2]; + zptr[p2] = temp; + p1++; + p2++; + n--; + } + } + + private char Med3(char a, char b, char c) + { + char t; + if (a > b) + { + t = a; + a = b; + b = t; + } + if (b > c) + { + t = b; + b = c; + c = t; + } + if (a > b) + { + b = a; + } + return b; + } + + internal class StackElem + { + internal int ll; + internal int hh; + internal int dd; + } + + private void QSort3(int loSt, int hiSt, int dSt) + { + int unLo, unHi, ltLo, gtHi, med, n, m; + int sp, lo, hi, d; + StackElem[] stack = new StackElem[QSORT_STACK_SIZE]; + for (int count = 0; count < QSORT_STACK_SIZE; count++) + { + stack[count] = new StackElem(); + } + + sp = 0; + + stack[sp].ll = loSt; + stack[sp].hh = hiSt; + stack[sp].dd = dSt; + sp++; + + while (sp > 0) + { + if (sp >= QSORT_STACK_SIZE) + { + Panic(); + } + + sp--; + lo = stack[sp].ll; + hi = stack[sp].hh; + d = stack[sp].dd; + + if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) + { + SimpleSort(lo, hi, d); + if (workDone > workLimit && firstAttempt) + { + return; + } + continue; + } + + med = Med3(block[zptr[lo] + d + 1], + block[zptr[hi] + d + 1], + block[zptr[(lo + hi) >> 1] + d + 1]); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (true) + { + while (true) + { + if (unLo > unHi) + { + break; + } + n = ((int) block[zptr[unLo] + d + 1]) - med; + if (n == 0) + { + int temp = 0; + temp = zptr[unLo]; + zptr[unLo] = zptr[ltLo]; + zptr[ltLo] = temp; + ltLo++; + unLo++; + continue; + } + ; + if (n > 0) + { + break; + } + unLo++; + } + while (true) + { + if (unLo > unHi) + { + break; + } + n = ((int) block[zptr[unHi] + d + 1]) - med; + if (n == 0) + { + int temp = 0; + temp = zptr[unHi]; + zptr[unHi] = zptr[gtHi]; + zptr[gtHi] = temp; + gtHi--; + unHi--; + continue; + } + ; + if (n < 0) + { + break; + } + unHi--; + } + if (unLo > unHi) + { + break; + } + int tempx = zptr[unLo]; + zptr[unLo] = zptr[unHi]; + zptr[unHi] = tempx; + unLo++; + unHi--; + } + + if (gtHi < ltLo) + { + stack[sp].ll = lo; + stack[sp].hh = hi; + stack[sp].dd = d + 1; + sp++; + continue; + } + + n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo); + Vswap(lo, unLo - n, n); + m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi); + Vswap(unLo, hi - m + 1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + stack[sp].ll = lo; + stack[sp].hh = n; + stack[sp].dd = d; + sp++; + + stack[sp].ll = n + 1; + stack[sp].hh = m - 1; + stack[sp].dd = d + 1; + sp++; + + stack[sp].ll = m; + stack[sp].hh = hi; + stack[sp].dd = d; + sp++; + } + } + + private void MainSort() + { + int i, j, ss, sb; + int[] runningOrder = new int[256]; + int[] copy = new int[256]; + bool[] bigDone = new bool[256]; + int c1, c2; + int numQSorted; + + /* + In the various block-sized structures, live data runs + from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First, + set up the overshoot area for block. + */ + + // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" ); + for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) + { + block[last + i + 2] = block[(i%(last + 1)) + 1]; + } + for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) + { + quadrant[i] = 0; + } + + block[0] = (char) (block[last + 1]); + + if (last < 4000) + { + /* + Use SimpleSort(), since the full sorting mechanism + has quite a large constant overhead. + */ + for (i = 0; i <= last; i++) + { + zptr[i] = i; + } + firstAttempt = false; + workDone = workLimit = 0; + SimpleSort(0, last, 0); + } + else + { + numQSorted = 0; + for (i = 0; i <= 255; i++) + { + bigDone[i] = false; + } + + for (i = 0; i <= 65536; i++) + { + ftab[i] = 0; + } + + c1 = block[0]; + for (i = 0; i <= last; i++) + { + c2 = block[i + 1]; + ftab[(c1 << 8) + c2]++; + c1 = c2; + } + + for (i = 1; i <= 65536; i++) + { + ftab[i] += ftab[i - 1]; + } + + c1 = block[1]; + for (i = 0; i < last; i++) + { + c2 = block[i + 2]; + j = (c1 << 8) + c2; + c1 = c2; + ftab[j]--; + zptr[ftab[j]] = i; + } + + j = ((block[last + 1]) << 8) + (block[1]); + ftab[j]--; + zptr[ftab[j]] = last; + + /* + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + */ + + for (i = 0; i <= 255; i++) + { + runningOrder[i] = i; + } + + { + int vv; + int h = 1; + do + { + h = 3*h + 1; + } while (h <= 256); + do + { + h = h/3; + for (i = h; i <= 255; i++) + { + vv = runningOrder[i]; + j = i; + while ((ftab[((runningOrder[j - h]) + 1) << 8] + - ftab[(runningOrder[j - h]) << 8]) > + (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) + { + runningOrder[j] = runningOrder[j - h]; + j = j - h; + if (j <= (h - 1)) + { + break; + } + } + runningOrder[j] = vv; + } + } while (h != 1); + } + + /* + The main sorting loop. + */ + for (i = 0; i <= 255; i++) + { + /* + Process big buckets, starting with the least full. + */ + ss = runningOrder[i]; + + /* + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j]. Hopefully + previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + */ + for (j = 0; j <= 255; j++) + { + sb = (ss << 8) + j; + if (!((ftab[sb] & SETMASK) == SETMASK)) + { + int lo = ftab[sb] & CLEARMASK; + int hi = (ftab[sb + 1] & CLEARMASK) - 1; + if (hi > lo) + { + QSort3(lo, hi, 2); + numQSorted += (hi - lo + 1); + if (workDone > workLimit && firstAttempt) + { + return; + } + } + ftab[sb] |= SETMASK; + } + } + + /* + The ss big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + */ + bigDone[ss] = true; + + if (i < 255) + { + int bbStart = ftab[ss << 8] & CLEARMASK; + int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart; + int shifts = 0; + + while ((bbSize >> shifts) > 65534) + { + shifts++; + } + + for (j = 0; j < bbSize; j++) + { + int a2update = zptr[bbStart + j]; + int qVal = (j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) + { + quadrant[a2update + last + 1] = qVal; + } + } + + if (!(((bbSize - 1) >> shifts) <= 65535)) + { + Panic(); + } + } + + /* + Now scan this big bucket so as to synthesise the + sorted order for small buckets [t, ss] for all t != ss. + */ + for (j = 0; j <= 255; j++) + { + copy[j] = ftab[(j << 8) + ss] & CLEARMASK; + } + + for (j = ftab[ss << 8] & CLEARMASK; + j < (ftab[(ss + 1) << 8] & CLEARMASK); + j++) + { + c1 = block[zptr[j]]; + if (!bigDone[c1]) + { + zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1; + copy[c1]++; + } + } + + for (j = 0; j <= 255; j++) + { + ftab[(j << 8) + ss] |= SETMASK; + } + } + } + } + + private void RandomiseBlock() + { + int i; + int rNToGo = 0; + int rTPos = 0; + for (i = 0; i < 256; i++) + { + inUse[i] = false; + } + + for (i = 0; i <= last; i++) + { + if (rNToGo == 0) + { + rNToGo = (char) BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) + { + rTPos = 0; + } + } + rNToGo--; + block[i + 1] ^= (char) ((rNToGo == 1) ? 1 : 0); + // handle 16 bit signed numbers + block[i + 1] &= (char) 0xFF; + + inUse[block[i + 1]] = true; + } + } + + private void DoReversibleTransformation() + { + int i; + + workLimit = workFactor*last; + workDone = 0; + blockRandomised = false; + firstAttempt = true; + + MainSort(); + + if (workDone > workLimit && firstAttempt) + { + RandomiseBlock(); + workLimit = workDone = 0; + blockRandomised = true; + firstAttempt = false; + MainSort(); + } + + origPtr = -1; + for (i = 0; i <= last; i++) + { + if (zptr[i] == 0) + { + origPtr = i; + break; + } + } + ; + + if (origPtr == -1) + { + Panic(); + } + } + + private bool FullGtU(int i1, int i2) + { + int k; + char c1, c2; + int s1, s2; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + k = last + 1; + + do + { + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + if (i1 > last) + { + i1 -= last; + i1--; + } + ; + if (i2 > last) + { + i2 -= last; + i2--; + } + ; + + k -= 4; + workDone++; + } while (k >= 0); + + return false; + } + + /* + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. + */ + + private int[] incs = + { + 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 + }; + + private void AllocateCompressStructures() + { + int n = BZip2Constants.baseBlockSize*blockSize100k; + block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)]; + quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)]; + zptr = new int[n]; + ftab = new int[65537]; + + if (block == null || quadrant == null || zptr == null + || ftab == null) + { + //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537; + //compressOutOfMemory ( totalDraw, n ); + } + + /* + The back end needs a place to store the MTF values + whilst it calculates the coding tables. We could + put them in the zptr array. However, these values + will fit in a short, so we overlay szptr at the + start of zptr, in the hope of reducing the number + of cache misses induced by the multiple traversals + of the MTF values when calculating coding tables. + Seems to improve compression speed by about 1%. + */ + // szptr = zptr; + + + szptr = new short[2*n]; + } + + private void GenerateMTFValues() + { + char[] yy = new char[256]; + int i, j; + char tmp; + char tmp2; + int zPend; + int wr; + int EOB; + + MakeMaps(); + EOB = nInUse + 1; + + for (i = 0; i <= EOB; i++) + { + mtfFreq[i] = 0; + } + + wr = 0; + zPend = 0; + for (i = 0; i < nInUse; i++) + { + yy[i] = (char) i; + } + + + for (i = 0; i <= last; i++) + { + char ll_i; + + ll_i = unseqToSeq[block[zptr[i]]]; + + j = 0; + tmp = yy[j]; + while (ll_i != tmp) + { + j++; + tmp2 = tmp; + tmp = yy[j]; + yy[j] = tmp2; + } + ; + yy[0] = tmp; + + if (j == 0) + { + zPend++; + } + else + { + if (zPend > 0) + { + zPend--; + while (true) + { + switch (zPend%2) + { + case 0: + szptr[wr] = (short) BZip2Constants.RUNA; + wr++; + mtfFreq[BZip2Constants.RUNA]++; + break; + case 1: + szptr[wr] = (short) BZip2Constants.RUNB; + wr++; + mtfFreq[BZip2Constants.RUNB]++; + break; + } + ; + if (zPend < 2) + { + break; + } + zPend = (zPend - 2)/2; + } + ; + zPend = 0; + } + szptr[wr] = (short) (j + 1); + wr++; + mtfFreq[j + 1]++; + } + } + + if (zPend > 0) + { + zPend--; + while (true) + { + switch (zPend%2) + { + case 0: + szptr[wr] = (short) BZip2Constants.RUNA; + wr++; + mtfFreq[BZip2Constants.RUNA]++; + break; + case 1: + szptr[wr] = (short) BZip2Constants.RUNB; + wr++; + mtfFreq[BZip2Constants.RUNB]++; + break; + } + if (zPend < 2) + { + break; + } + zPend = (zPend - 2)/2; + } + } + + szptr[wr] = (short) EOB; + wr++; + mtfFreq[EOB]++; + + nMTF = wr; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + + public override void SetLength(long value) + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + for (int k = 0; k < count; ++k) + { + WriteByte(buffer[k + offset]); + } + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get { return 0; } + } + + public override long Position + { + get { return 0; } + set { } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/BZip2/CRC.cs b/src/SharpCompress/Compressor/BZip2/CRC.cs similarity index 98% rename from SharpCompress/Compressor/BZip2/CRC.cs rename to src/SharpCompress/Compressor/BZip2/CRC.cs index 626297fb..42aa516f 100644 --- a/SharpCompress/Compressor/BZip2/CRC.cs +++ b/src/SharpCompress/Compressor/BZip2/CRC.cs @@ -1,203 +1,203 @@ -/* - * Copyright 2001,2004-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package is based on the work done by Keiron Liddle), Aftex Software - * to whom the Ant project is very grateful for his - * great code. - */ - -namespace SharpCompress.Compressor.BZip2 -{ - /** - * A simple class the hold and calculate the CRC for sanity checking - * of the data. - * - * @author Keiron Liddle - */ - - internal class CRC - { - public static int[] crc32Table = - { - unchecked((int) 0x00000000), unchecked((int) 0x04c11db7), unchecked((int) 0x09823b6e), - unchecked((int) 0x0d4326d9), - unchecked((int) 0x130476dc), unchecked((int) 0x17c56b6b), unchecked((int) 0x1a864db2), - unchecked((int) 0x1e475005), - unchecked((int) 0x2608edb8), unchecked((int) 0x22c9f00f), unchecked((int) 0x2f8ad6d6), - unchecked((int) 0x2b4bcb61), - unchecked((int) 0x350c9b64), unchecked((int) 0x31cd86d3), unchecked((int) 0x3c8ea00a), - unchecked((int) 0x384fbdbd), - unchecked((int) 0x4c11db70), unchecked((int) 0x48d0c6c7), unchecked((int) 0x4593e01e), - unchecked((int) 0x4152fda9), - unchecked((int) 0x5f15adac), unchecked((int) 0x5bd4b01b), unchecked((int) 0x569796c2), - unchecked((int) 0x52568b75), - unchecked((int) 0x6a1936c8), unchecked((int) 0x6ed82b7f), unchecked((int) 0x639b0da6), - unchecked((int) 0x675a1011), - unchecked((int) 0x791d4014), unchecked((int) 0x7ddc5da3), unchecked((int) 0x709f7b7a), - unchecked((int) 0x745e66cd), - unchecked((int) 0x9823b6e0), unchecked((int) 0x9ce2ab57), unchecked((int) 0x91a18d8e), - unchecked((int) 0x95609039), - unchecked((int) 0x8b27c03c), unchecked((int) 0x8fe6dd8b), unchecked((int) 0x82a5fb52), - unchecked((int) 0x8664e6e5), - unchecked((int) 0xbe2b5b58), unchecked((int) 0xbaea46ef), unchecked((int) 0xb7a96036), - unchecked((int) 0xb3687d81), - unchecked((int) 0xad2f2d84), unchecked((int) 0xa9ee3033), unchecked((int) 0xa4ad16ea), - unchecked((int) 0xa06c0b5d), - unchecked((int) 0xd4326d90), unchecked((int) 0xd0f37027), unchecked((int) 0xddb056fe), - unchecked((int) 0xd9714b49), - unchecked((int) 0xc7361b4c), unchecked((int) 0xc3f706fb), unchecked((int) 0xceb42022), - unchecked((int) 0xca753d95), - unchecked((int) 0xf23a8028), unchecked((int) 0xf6fb9d9f), unchecked((int) 0xfbb8bb46), - unchecked((int) 0xff79a6f1), - unchecked((int) 0xe13ef6f4), unchecked((int) 0xe5ffeb43), unchecked((int) 0xe8bccd9a), - unchecked((int) 0xec7dd02d), - unchecked((int) 0x34867077), unchecked((int) 0x30476dc0), unchecked((int) 0x3d044b19), - unchecked((int) 0x39c556ae), - unchecked((int) 0x278206ab), unchecked((int) 0x23431b1c), unchecked((int) 0x2e003dc5), - unchecked((int) 0x2ac12072), - unchecked((int) 0x128e9dcf), unchecked((int) 0x164f8078), unchecked((int) 0x1b0ca6a1), - unchecked((int) 0x1fcdbb16), - unchecked((int) 0x018aeb13), unchecked((int) 0x054bf6a4), unchecked((int) 0x0808d07d), - unchecked((int) 0x0cc9cdca), - unchecked((int) 0x7897ab07), unchecked((int) 0x7c56b6b0), unchecked((int) 0x71159069), - unchecked((int) 0x75d48dde), - unchecked((int) 0x6b93dddb), unchecked((int) 0x6f52c06c), unchecked((int) 0x6211e6b5), - unchecked((int) 0x66d0fb02), - unchecked((int) 0x5e9f46bf), unchecked((int) 0x5a5e5b08), unchecked((int) 0x571d7dd1), - unchecked((int) 0x53dc6066), - unchecked((int) 0x4d9b3063), unchecked((int) 0x495a2dd4), unchecked((int) 0x44190b0d), - unchecked((int) 0x40d816ba), - unchecked((int) 0xaca5c697), unchecked((int) 0xa864db20), unchecked((int) 0xa527fdf9), - unchecked((int) 0xa1e6e04e), - unchecked((int) 0xbfa1b04b), unchecked((int) 0xbb60adfc), unchecked((int) 0xb6238b25), - unchecked((int) 0xb2e29692), - unchecked((int) 0x8aad2b2f), unchecked((int) 0x8e6c3698), unchecked((int) 0x832f1041), - unchecked((int) 0x87ee0df6), - unchecked((int) 0x99a95df3), unchecked((int) 0x9d684044), unchecked((int) 0x902b669d), - unchecked((int) 0x94ea7b2a), - unchecked((int) 0xe0b41de7), unchecked((int) 0xe4750050), unchecked((int) 0xe9362689), - unchecked((int) 0xedf73b3e), - unchecked((int) 0xf3b06b3b), unchecked((int) 0xf771768c), unchecked((int) 0xfa325055), - unchecked((int) 0xfef34de2), - unchecked((int) 0xc6bcf05f), unchecked((int) 0xc27dede8), unchecked((int) 0xcf3ecb31), - unchecked((int) 0xcbffd686), - unchecked((int) 0xd5b88683), unchecked((int) 0xd1799b34), unchecked((int) 0xdc3abded), - unchecked((int) 0xd8fba05a), - unchecked((int) 0x690ce0ee), unchecked((int) 0x6dcdfd59), unchecked((int) 0x608edb80), - unchecked((int) 0x644fc637), - unchecked((int) 0x7a089632), unchecked((int) 0x7ec98b85), unchecked((int) 0x738aad5c), - unchecked((int) 0x774bb0eb), - unchecked((int) 0x4f040d56), unchecked((int) 0x4bc510e1), unchecked((int) 0x46863638), - unchecked((int) 0x42472b8f), - unchecked((int) 0x5c007b8a), unchecked((int) 0x58c1663d), unchecked((int) 0x558240e4), - unchecked((int) 0x51435d53), - unchecked((int) 0x251d3b9e), unchecked((int) 0x21dc2629), unchecked((int) 0x2c9f00f0), - unchecked((int) 0x285e1d47), - unchecked((int) 0x36194d42), unchecked((int) 0x32d850f5), unchecked((int) 0x3f9b762c), - unchecked((int) 0x3b5a6b9b), - unchecked((int) 0x0315d626), unchecked((int) 0x07d4cb91), unchecked((int) 0x0a97ed48), - unchecked((int) 0x0e56f0ff), - unchecked((int) 0x1011a0fa), unchecked((int) 0x14d0bd4d), unchecked((int) 0x19939b94), - unchecked((int) 0x1d528623), - unchecked((int) 0xf12f560e), unchecked((int) 0xf5ee4bb9), unchecked((int) 0xf8ad6d60), - unchecked((int) 0xfc6c70d7), - unchecked((int) 0xe22b20d2), unchecked((int) 0xe6ea3d65), unchecked((int) 0xeba91bbc), - unchecked((int) 0xef68060b), - unchecked((int) 0xd727bbb6), unchecked((int) 0xd3e6a601), unchecked((int) 0xdea580d8), - unchecked((int) 0xda649d6f), - unchecked((int) 0xc423cd6a), unchecked((int) 0xc0e2d0dd), unchecked((int) 0xcda1f604), - unchecked((int) 0xc960ebb3), - unchecked((int) 0xbd3e8d7e), unchecked((int) 0xb9ff90c9), unchecked((int) 0xb4bcb610), - unchecked((int) 0xb07daba7), - unchecked((int) 0xae3afba2), unchecked((int) 0xaafbe615), unchecked((int) 0xa7b8c0cc), - unchecked((int) 0xa379dd7b), - unchecked((int) 0x9b3660c6), unchecked((int) 0x9ff77d71), unchecked((int) 0x92b45ba8), - unchecked((int) 0x9675461f), - unchecked((int) 0x8832161a), unchecked((int) 0x8cf30bad), unchecked((int) 0x81b02d74), - unchecked((int) 0x857130c3), - unchecked((int) 0x5d8a9099), unchecked((int) 0x594b8d2e), unchecked((int) 0x5408abf7), - unchecked((int) 0x50c9b640), - unchecked((int) 0x4e8ee645), unchecked((int) 0x4a4ffbf2), unchecked((int) 0x470cdd2b), - unchecked((int) 0x43cdc09c), - unchecked((int) 0x7b827d21), unchecked((int) 0x7f436096), unchecked((int) 0x7200464f), - unchecked((int) 0x76c15bf8), - unchecked((int) 0x68860bfd), unchecked((int) 0x6c47164a), unchecked((int) 0x61043093), - unchecked((int) 0x65c52d24), - unchecked((int) 0x119b4be9), unchecked((int) 0x155a565e), unchecked((int) 0x18197087), - unchecked((int) 0x1cd86d30), - unchecked((int) 0x029f3d35), unchecked((int) 0x065e2082), unchecked((int) 0x0b1d065b), - unchecked((int) 0x0fdc1bec), - unchecked((int) 0x3793a651), unchecked((int) 0x3352bbe6), unchecked((int) 0x3e119d3f), - unchecked((int) 0x3ad08088), - unchecked((int) 0x2497d08d), unchecked((int) 0x2056cd3a), unchecked((int) 0x2d15ebe3), - unchecked((int) 0x29d4f654), - unchecked((int) 0xc5a92679), unchecked((int) 0xc1683bce), unchecked((int) 0xcc2b1d17), - unchecked((int) 0xc8ea00a0), - unchecked((int) 0xd6ad50a5), unchecked((int) 0xd26c4d12), unchecked((int) 0xdf2f6bcb), - unchecked((int) 0xdbee767c), - unchecked((int) 0xe3a1cbc1), unchecked((int) 0xe760d676), unchecked((int) 0xea23f0af), - unchecked((int) 0xeee2ed18), - unchecked((int) 0xf0a5bd1d), unchecked((int) 0xf464a0aa), unchecked((int) 0xf9278673), - unchecked((int) 0xfde69bc4), - unchecked((int) 0x89b8fd09), unchecked((int) 0x8d79e0be), unchecked((int) 0x803ac667), - unchecked((int) 0x84fbdbd0), - unchecked((int) 0x9abc8bd5), unchecked((int) 0x9e7d9662), unchecked((int) 0x933eb0bb), - unchecked((int) 0x97ffad0c), - unchecked((int) 0xafb010b1), unchecked((int) 0xab710d06), unchecked((int) 0xa6322bdf), - unchecked((int) 0xa2f33668), - unchecked((int) 0xbcb4666d), unchecked((int) 0xb8757bda), unchecked((int) 0xb5365d03), - unchecked((int) 0xb1f740b4) - }; - - public CRC() - { - InitialiseCRC(); - } - - internal void InitialiseCRC() - { - globalCrc = unchecked((int) 0xffffffff); - } - - internal int GetFinalCRC() - { - return ~globalCrc; - } - - internal int GetGlobalCRC() - { - return globalCrc; - } - - internal void SetGlobalCRC(int newCrc) - { - globalCrc = newCrc; - } - - internal void UpdateCRC(int inCh) - { - int temp = (globalCrc >> 24) ^ inCh; - if (temp < 0) - { - temp = 256 + temp; - } - globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp]; - } - - internal int globalCrc; - } +/* + * Copyright 2001,2004-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This package is based on the work done by Keiron Liddle), Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace SharpCompress.Compressor.BZip2 +{ + /** + * A simple class the hold and calculate the CRC for sanity checking + * of the data. + * + * @author Keiron Liddle + */ + + internal class CRC + { + public static int[] crc32Table = + { + unchecked((int) 0x00000000), unchecked((int) 0x04c11db7), unchecked((int) 0x09823b6e), + unchecked((int) 0x0d4326d9), + unchecked((int) 0x130476dc), unchecked((int) 0x17c56b6b), unchecked((int) 0x1a864db2), + unchecked((int) 0x1e475005), + unchecked((int) 0x2608edb8), unchecked((int) 0x22c9f00f), unchecked((int) 0x2f8ad6d6), + unchecked((int) 0x2b4bcb61), + unchecked((int) 0x350c9b64), unchecked((int) 0x31cd86d3), unchecked((int) 0x3c8ea00a), + unchecked((int) 0x384fbdbd), + unchecked((int) 0x4c11db70), unchecked((int) 0x48d0c6c7), unchecked((int) 0x4593e01e), + unchecked((int) 0x4152fda9), + unchecked((int) 0x5f15adac), unchecked((int) 0x5bd4b01b), unchecked((int) 0x569796c2), + unchecked((int) 0x52568b75), + unchecked((int) 0x6a1936c8), unchecked((int) 0x6ed82b7f), unchecked((int) 0x639b0da6), + unchecked((int) 0x675a1011), + unchecked((int) 0x791d4014), unchecked((int) 0x7ddc5da3), unchecked((int) 0x709f7b7a), + unchecked((int) 0x745e66cd), + unchecked((int) 0x9823b6e0), unchecked((int) 0x9ce2ab57), unchecked((int) 0x91a18d8e), + unchecked((int) 0x95609039), + unchecked((int) 0x8b27c03c), unchecked((int) 0x8fe6dd8b), unchecked((int) 0x82a5fb52), + unchecked((int) 0x8664e6e5), + unchecked((int) 0xbe2b5b58), unchecked((int) 0xbaea46ef), unchecked((int) 0xb7a96036), + unchecked((int) 0xb3687d81), + unchecked((int) 0xad2f2d84), unchecked((int) 0xa9ee3033), unchecked((int) 0xa4ad16ea), + unchecked((int) 0xa06c0b5d), + unchecked((int) 0xd4326d90), unchecked((int) 0xd0f37027), unchecked((int) 0xddb056fe), + unchecked((int) 0xd9714b49), + unchecked((int) 0xc7361b4c), unchecked((int) 0xc3f706fb), unchecked((int) 0xceb42022), + unchecked((int) 0xca753d95), + unchecked((int) 0xf23a8028), unchecked((int) 0xf6fb9d9f), unchecked((int) 0xfbb8bb46), + unchecked((int) 0xff79a6f1), + unchecked((int) 0xe13ef6f4), unchecked((int) 0xe5ffeb43), unchecked((int) 0xe8bccd9a), + unchecked((int) 0xec7dd02d), + unchecked((int) 0x34867077), unchecked((int) 0x30476dc0), unchecked((int) 0x3d044b19), + unchecked((int) 0x39c556ae), + unchecked((int) 0x278206ab), unchecked((int) 0x23431b1c), unchecked((int) 0x2e003dc5), + unchecked((int) 0x2ac12072), + unchecked((int) 0x128e9dcf), unchecked((int) 0x164f8078), unchecked((int) 0x1b0ca6a1), + unchecked((int) 0x1fcdbb16), + unchecked((int) 0x018aeb13), unchecked((int) 0x054bf6a4), unchecked((int) 0x0808d07d), + unchecked((int) 0x0cc9cdca), + unchecked((int) 0x7897ab07), unchecked((int) 0x7c56b6b0), unchecked((int) 0x71159069), + unchecked((int) 0x75d48dde), + unchecked((int) 0x6b93dddb), unchecked((int) 0x6f52c06c), unchecked((int) 0x6211e6b5), + unchecked((int) 0x66d0fb02), + unchecked((int) 0x5e9f46bf), unchecked((int) 0x5a5e5b08), unchecked((int) 0x571d7dd1), + unchecked((int) 0x53dc6066), + unchecked((int) 0x4d9b3063), unchecked((int) 0x495a2dd4), unchecked((int) 0x44190b0d), + unchecked((int) 0x40d816ba), + unchecked((int) 0xaca5c697), unchecked((int) 0xa864db20), unchecked((int) 0xa527fdf9), + unchecked((int) 0xa1e6e04e), + unchecked((int) 0xbfa1b04b), unchecked((int) 0xbb60adfc), unchecked((int) 0xb6238b25), + unchecked((int) 0xb2e29692), + unchecked((int) 0x8aad2b2f), unchecked((int) 0x8e6c3698), unchecked((int) 0x832f1041), + unchecked((int) 0x87ee0df6), + unchecked((int) 0x99a95df3), unchecked((int) 0x9d684044), unchecked((int) 0x902b669d), + unchecked((int) 0x94ea7b2a), + unchecked((int) 0xe0b41de7), unchecked((int) 0xe4750050), unchecked((int) 0xe9362689), + unchecked((int) 0xedf73b3e), + unchecked((int) 0xf3b06b3b), unchecked((int) 0xf771768c), unchecked((int) 0xfa325055), + unchecked((int) 0xfef34de2), + unchecked((int) 0xc6bcf05f), unchecked((int) 0xc27dede8), unchecked((int) 0xcf3ecb31), + unchecked((int) 0xcbffd686), + unchecked((int) 0xd5b88683), unchecked((int) 0xd1799b34), unchecked((int) 0xdc3abded), + unchecked((int) 0xd8fba05a), + unchecked((int) 0x690ce0ee), unchecked((int) 0x6dcdfd59), unchecked((int) 0x608edb80), + unchecked((int) 0x644fc637), + unchecked((int) 0x7a089632), unchecked((int) 0x7ec98b85), unchecked((int) 0x738aad5c), + unchecked((int) 0x774bb0eb), + unchecked((int) 0x4f040d56), unchecked((int) 0x4bc510e1), unchecked((int) 0x46863638), + unchecked((int) 0x42472b8f), + unchecked((int) 0x5c007b8a), unchecked((int) 0x58c1663d), unchecked((int) 0x558240e4), + unchecked((int) 0x51435d53), + unchecked((int) 0x251d3b9e), unchecked((int) 0x21dc2629), unchecked((int) 0x2c9f00f0), + unchecked((int) 0x285e1d47), + unchecked((int) 0x36194d42), unchecked((int) 0x32d850f5), unchecked((int) 0x3f9b762c), + unchecked((int) 0x3b5a6b9b), + unchecked((int) 0x0315d626), unchecked((int) 0x07d4cb91), unchecked((int) 0x0a97ed48), + unchecked((int) 0x0e56f0ff), + unchecked((int) 0x1011a0fa), unchecked((int) 0x14d0bd4d), unchecked((int) 0x19939b94), + unchecked((int) 0x1d528623), + unchecked((int) 0xf12f560e), unchecked((int) 0xf5ee4bb9), unchecked((int) 0xf8ad6d60), + unchecked((int) 0xfc6c70d7), + unchecked((int) 0xe22b20d2), unchecked((int) 0xe6ea3d65), unchecked((int) 0xeba91bbc), + unchecked((int) 0xef68060b), + unchecked((int) 0xd727bbb6), unchecked((int) 0xd3e6a601), unchecked((int) 0xdea580d8), + unchecked((int) 0xda649d6f), + unchecked((int) 0xc423cd6a), unchecked((int) 0xc0e2d0dd), unchecked((int) 0xcda1f604), + unchecked((int) 0xc960ebb3), + unchecked((int) 0xbd3e8d7e), unchecked((int) 0xb9ff90c9), unchecked((int) 0xb4bcb610), + unchecked((int) 0xb07daba7), + unchecked((int) 0xae3afba2), unchecked((int) 0xaafbe615), unchecked((int) 0xa7b8c0cc), + unchecked((int) 0xa379dd7b), + unchecked((int) 0x9b3660c6), unchecked((int) 0x9ff77d71), unchecked((int) 0x92b45ba8), + unchecked((int) 0x9675461f), + unchecked((int) 0x8832161a), unchecked((int) 0x8cf30bad), unchecked((int) 0x81b02d74), + unchecked((int) 0x857130c3), + unchecked((int) 0x5d8a9099), unchecked((int) 0x594b8d2e), unchecked((int) 0x5408abf7), + unchecked((int) 0x50c9b640), + unchecked((int) 0x4e8ee645), unchecked((int) 0x4a4ffbf2), unchecked((int) 0x470cdd2b), + unchecked((int) 0x43cdc09c), + unchecked((int) 0x7b827d21), unchecked((int) 0x7f436096), unchecked((int) 0x7200464f), + unchecked((int) 0x76c15bf8), + unchecked((int) 0x68860bfd), unchecked((int) 0x6c47164a), unchecked((int) 0x61043093), + unchecked((int) 0x65c52d24), + unchecked((int) 0x119b4be9), unchecked((int) 0x155a565e), unchecked((int) 0x18197087), + unchecked((int) 0x1cd86d30), + unchecked((int) 0x029f3d35), unchecked((int) 0x065e2082), unchecked((int) 0x0b1d065b), + unchecked((int) 0x0fdc1bec), + unchecked((int) 0x3793a651), unchecked((int) 0x3352bbe6), unchecked((int) 0x3e119d3f), + unchecked((int) 0x3ad08088), + unchecked((int) 0x2497d08d), unchecked((int) 0x2056cd3a), unchecked((int) 0x2d15ebe3), + unchecked((int) 0x29d4f654), + unchecked((int) 0xc5a92679), unchecked((int) 0xc1683bce), unchecked((int) 0xcc2b1d17), + unchecked((int) 0xc8ea00a0), + unchecked((int) 0xd6ad50a5), unchecked((int) 0xd26c4d12), unchecked((int) 0xdf2f6bcb), + unchecked((int) 0xdbee767c), + unchecked((int) 0xe3a1cbc1), unchecked((int) 0xe760d676), unchecked((int) 0xea23f0af), + unchecked((int) 0xeee2ed18), + unchecked((int) 0xf0a5bd1d), unchecked((int) 0xf464a0aa), unchecked((int) 0xf9278673), + unchecked((int) 0xfde69bc4), + unchecked((int) 0x89b8fd09), unchecked((int) 0x8d79e0be), unchecked((int) 0x803ac667), + unchecked((int) 0x84fbdbd0), + unchecked((int) 0x9abc8bd5), unchecked((int) 0x9e7d9662), unchecked((int) 0x933eb0bb), + unchecked((int) 0x97ffad0c), + unchecked((int) 0xafb010b1), unchecked((int) 0xab710d06), unchecked((int) 0xa6322bdf), + unchecked((int) 0xa2f33668), + unchecked((int) 0xbcb4666d), unchecked((int) 0xb8757bda), unchecked((int) 0xb5365d03), + unchecked((int) 0xb1f740b4) + }; + + public CRC() + { + InitialiseCRC(); + } + + internal void InitialiseCRC() + { + globalCrc = unchecked((int) 0xffffffff); + } + + internal int GetFinalCRC() + { + return ~globalCrc; + } + + internal int GetGlobalCRC() + { + return globalCrc; + } + + internal void SetGlobalCRC(int newCrc) + { + globalCrc = newCrc; + } + + internal void UpdateCRC(int inCh) + { + int temp = (globalCrc >> 24) ^ inCh; + if (temp < 0) + { + temp = 256 + temp; + } + globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp]; + } + + internal int globalCrc; + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/CompressionMode.cs b/src/SharpCompress/Compressor/CompressionMode.cs similarity index 94% rename from SharpCompress/Compressor/CompressionMode.cs rename to src/SharpCompress/Compressor/CompressionMode.cs index 29dc4923..31d1ebe4 100644 --- a/SharpCompress/Compressor/CompressionMode.cs +++ b/src/SharpCompress/Compressor/CompressionMode.cs @@ -1,8 +1,8 @@ -namespace SharpCompress.Compressor -{ - public enum CompressionMode - { - Compress = 0, - Decompress = 1, - } +namespace SharpCompress.Compressor +{ + public enum CompressionMode + { + Compress = 0, + Decompress = 1, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/CRC32.cs b/src/SharpCompress/Compressor/Deflate/CRC32.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/CRC32.cs rename to src/SharpCompress/Compressor/Deflate/CRC32.cs index 4cc14fff..acc179b2 100644 --- a/SharpCompress/Compressor/Deflate/CRC32.cs +++ b/src/SharpCompress/Compressor/Deflate/CRC32.cs @@ -1,288 +1,288 @@ -// Crc32.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2006-2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2010-January-16 13:16:27> -// -// ------------------------------------------------------------------ -// -// Implements the CRC algorithm, which is used in zip files. The zip format calls for -// the zipfile to contain a CRC for the unencrypted byte stream of each file. -// -// It is based on example source code published at -// http://www.vbaccelerator.com/home/net/code/libraries/CRC32/Crc32_zip_CRC32_CRC32_cs.asp -// -// This implementation adds a tweak of that code for use within zip creation. While -// computing the CRC we also compress the byte stream, in the same read loop. This -// avoids the need to read through the uncompressed stream twice - once to compute CRC -// and another time to compress. -// -// ------------------------------------------------------------------ - - -using System; -using System.IO; - -namespace SharpCompress.Compressor.Deflate -{ - /// - /// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the same polynomial - /// used by Zip. This type is used internally by DotNetZip; it is generally not used - /// directly by applications wishing to create, read, or manipulate zip archive - /// files. - /// - internal class CRC32 - { - private const int BUFFER_SIZE = 8192; - private static readonly UInt32[] crc32Table; - private UInt32 runningCrc32Result = 0xFFFFFFFF; - private Int64 totalBytesRead; - - static CRC32() - { - unchecked - { - // PKZip specifies CRC32 with a polynomial of 0xEDB88320; - // This is also the CRC-32 polynomial used bby Ethernet, FDDI, - // bzip2, gzip, and others. - // Often the polynomial is shown reversed as 0x04C11DB7. - // For more details, see http://en.wikipedia.org/wiki/Cyclic_redundancy_check - UInt32 dwPolynomial = 0xEDB88320; - UInt32 i, j; - - crc32Table = new UInt32[256]; - - UInt32 dwCrc; - for (i = 0; i < 256; i++) - { - dwCrc = i; - for (j = 8; j > 0; j--) - { - if ((dwCrc & 1) == 1) - { - dwCrc = (dwCrc >> 1) ^ dwPolynomial; - } - else - { - dwCrc >>= 1; - } - } - crc32Table[i] = dwCrc; - } - } - } - - /// - /// indicates the total number of bytes read on the CRC stream. - /// This is used when writing the ZipDirEntry when compressing files. - /// - public Int64 TotalBytesRead - { - get { return totalBytesRead; } - } - - /// - /// Indicates the current CRC for all blocks slurped in. - /// - public Int32 Crc32Result - { - get - { - // return one's complement of the running result - return unchecked((Int32) (~runningCrc32Result)); - } - } - - /// - /// Returns the CRC32 for the specified stream. - /// - /// The stream over which to calculate the CRC32 - /// the CRC32 calculation - public Int32 GetCrc32(Stream input) - { - return GetCrc32AndCopy(input, null); - } - - /// - /// Returns the CRC32 for the specified stream, and writes the input into the - /// output stream. - /// - /// The stream over which to calculate the CRC32 - /// The stream into which to deflate the input - /// the CRC32 calculation - public Int32 GetCrc32AndCopy(Stream input, Stream output) - { - if (input == null) - throw new ZlibException("The input stream must not be null."); - - unchecked - { - //UInt32 crc32Result; - //crc32Result = 0xFFFFFFFF; - var buffer = new byte[BUFFER_SIZE]; - int readSize = BUFFER_SIZE; - - totalBytesRead = 0; - int count = input.Read(buffer, 0, readSize); - if (output != null) output.Write(buffer, 0, count); - totalBytesRead += count; - while (count > 0) - { - SlurpBlock(buffer, 0, count); - count = input.Read(buffer, 0, readSize); - if (output != null) output.Write(buffer, 0, count); - totalBytesRead += count; - } - - return (Int32) (~runningCrc32Result); - } - } - - - /// - /// Get the CRC32 for the given (word,byte) combo. This is a computation - /// defined by PKzip. - /// - /// The word to start with. - /// The byte to combine it with. - /// The CRC-ized result. - public Int32 ComputeCrc32(Int32 W, byte B) - { - return _InternalComputeCrc32((UInt32) W, B); - } - - internal Int32 _InternalComputeCrc32(UInt32 W, byte B) - { - return (Int32) (crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); - } - - /// - /// Update the value for the running CRC32 using the given block of bytes. - /// This is useful when using the CRC32() class in a Stream. - /// - /// block of bytes to slurp - /// starting point in the block - /// how many bytes within the block to slurp - public void SlurpBlock(byte[] block, int offset, int count) - { - if (block == null) - throw new ZlibException("The data buffer must not be null."); - - for (int i = 0; i < count; i++) - { - int x = offset + i; - runningCrc32Result = ((runningCrc32Result) >> 8) ^ - crc32Table[(block[x]) ^ ((runningCrc32Result) & 0x000000FF)]; - } - totalBytesRead += count; - } - - - // pre-initialize the crc table for speed of lookup. - - - private uint gf2_matrix_times(uint[] matrix, uint vec) - { - uint sum = 0; - int i = 0; - while (vec != 0) - { - if ((vec & 0x01) == 0x01) - sum ^= matrix[i]; - vec >>= 1; - i++; - } - return sum; - } - - private void gf2_matrix_square(uint[] square, uint[] mat) - { - for (int i = 0; i < 32; i++) - square[i] = gf2_matrix_times(mat, mat[i]); - } - - - /// - /// Combines the given CRC32 value with the current running total. - /// - /// - /// This is useful when using a divide-and-conquer approach to calculating a CRC. - /// Multiple threads can each calculate a CRC32 on a segment of the data, and then - /// combine the individual CRC32 values at the end. - /// - /// the crc value to be combined with this one - /// the length of data the CRC value was calculated on - public void Combine(int crc, int length) - { - var even = new uint[32]; // even-power-of-two zeros operator - var odd = new uint[32]; // odd-power-of-two zeros operator - - if (length == 0) - return; - - uint crc1 = ~runningCrc32Result; - var crc2 = (uint) crc; - - // put operator for one zero bit in odd - odd[0] = 0xEDB88320; // the CRC-32 polynomial - uint row = 1; - for (int i = 1; i < 32; i++) - { - odd[i] = 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); - - var len2 = (uint) length; - - // 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) == 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - if (len2 == 0) - break; - - // another iteration of the loop with odd and even swapped - gf2_matrix_square(odd, even); - if ((len2 & 1) == 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - } while (len2 != 0); - - crc1 ^= crc2; - - runningCrc32Result = ~crc1; - - //return (int) crc1; - return; - } - - - // private member vars - } +// Crc32.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2006-2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2010-January-16 13:16:27> +// +// ------------------------------------------------------------------ +// +// Implements the CRC algorithm, which is used in zip files. The zip format calls for +// the zipfile to contain a CRC for the unencrypted byte stream of each file. +// +// It is based on example source code published at +// http://www.vbaccelerator.com/home/net/code/libraries/CRC32/Crc32_zip_CRC32_CRC32_cs.asp +// +// This implementation adds a tweak of that code for use within zip creation. While +// computing the CRC we also compress the byte stream, in the same read loop. This +// avoids the need to read through the uncompressed stream twice - once to compute CRC +// and another time to compress. +// +// ------------------------------------------------------------------ + + +using System; +using System.IO; + +namespace SharpCompress.Compressor.Deflate +{ + /// + /// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the same polynomial + /// used by Zip. This type is used internally by DotNetZip; it is generally not used + /// directly by applications wishing to create, read, or manipulate zip archive + /// files. + /// + internal class CRC32 + { + private const int BUFFER_SIZE = 8192; + private static readonly UInt32[] crc32Table; + private UInt32 runningCrc32Result = 0xFFFFFFFF; + private Int64 totalBytesRead; + + static CRC32() + { + unchecked + { + // PKZip specifies CRC32 with a polynomial of 0xEDB88320; + // This is also the CRC-32 polynomial used bby Ethernet, FDDI, + // bzip2, gzip, and others. + // Often the polynomial is shown reversed as 0x04C11DB7. + // For more details, see http://en.wikipedia.org/wiki/Cyclic_redundancy_check + UInt32 dwPolynomial = 0xEDB88320; + UInt32 i, j; + + crc32Table = new UInt32[256]; + + UInt32 dwCrc; + for (i = 0; i < 256; i++) + { + dwCrc = i; + for (j = 8; j > 0; j--) + { + if ((dwCrc & 1) == 1) + { + dwCrc = (dwCrc >> 1) ^ dwPolynomial; + } + else + { + dwCrc >>= 1; + } + } + crc32Table[i] = dwCrc; + } + } + } + + /// + /// indicates the total number of bytes read on the CRC stream. + /// This is used when writing the ZipDirEntry when compressing files. + /// + public Int64 TotalBytesRead + { + get { return totalBytesRead; } + } + + /// + /// Indicates the current CRC for all blocks slurped in. + /// + public Int32 Crc32Result + { + get + { + // return one's complement of the running result + return unchecked((Int32) (~runningCrc32Result)); + } + } + + /// + /// Returns the CRC32 for the specified stream. + /// + /// The stream over which to calculate the CRC32 + /// the CRC32 calculation + public Int32 GetCrc32(Stream input) + { + return GetCrc32AndCopy(input, null); + } + + /// + /// Returns the CRC32 for the specified stream, and writes the input into the + /// output stream. + /// + /// The stream over which to calculate the CRC32 + /// The stream into which to deflate the input + /// the CRC32 calculation + public Int32 GetCrc32AndCopy(Stream input, Stream output) + { + if (input == null) + throw new ZlibException("The input stream must not be null."); + + unchecked + { + //UInt32 crc32Result; + //crc32Result = 0xFFFFFFFF; + var buffer = new byte[BUFFER_SIZE]; + int readSize = BUFFER_SIZE; + + totalBytesRead = 0; + int count = input.Read(buffer, 0, readSize); + if (output != null) output.Write(buffer, 0, count); + totalBytesRead += count; + while (count > 0) + { + SlurpBlock(buffer, 0, count); + count = input.Read(buffer, 0, readSize); + if (output != null) output.Write(buffer, 0, count); + totalBytesRead += count; + } + + return (Int32) (~runningCrc32Result); + } + } + + + /// + /// Get the CRC32 for the given (word,byte) combo. This is a computation + /// defined by PKzip. + /// + /// The word to start with. + /// The byte to combine it with. + /// The CRC-ized result. + public Int32 ComputeCrc32(Int32 W, byte B) + { + return _InternalComputeCrc32((UInt32) W, B); + } + + internal Int32 _InternalComputeCrc32(UInt32 W, byte B) + { + return (Int32) (crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); + } + + /// + /// Update the value for the running CRC32 using the given block of bytes. + /// This is useful when using the CRC32() class in a Stream. + /// + /// block of bytes to slurp + /// starting point in the block + /// how many bytes within the block to slurp + public void SlurpBlock(byte[] block, int offset, int count) + { + if (block == null) + throw new ZlibException("The data buffer must not be null."); + + for (int i = 0; i < count; i++) + { + int x = offset + i; + runningCrc32Result = ((runningCrc32Result) >> 8) ^ + crc32Table[(block[x]) ^ ((runningCrc32Result) & 0x000000FF)]; + } + totalBytesRead += count; + } + + + // pre-initialize the crc table for speed of lookup. + + + private uint gf2_matrix_times(uint[] matrix, uint vec) + { + uint sum = 0; + int i = 0; + while (vec != 0) + { + if ((vec & 0x01) == 0x01) + sum ^= matrix[i]; + vec >>= 1; + i++; + } + return sum; + } + + private void gf2_matrix_square(uint[] square, uint[] mat) + { + for (int i = 0; i < 32; i++) + square[i] = gf2_matrix_times(mat, mat[i]); + } + + + /// + /// Combines the given CRC32 value with the current running total. + /// + /// + /// This is useful when using a divide-and-conquer approach to calculating a CRC. + /// Multiple threads can each calculate a CRC32 on a segment of the data, and then + /// combine the individual CRC32 values at the end. + /// + /// the crc value to be combined with this one + /// the length of data the CRC value was calculated on + public void Combine(int crc, int length) + { + var even = new uint[32]; // even-power-of-two zeros operator + var odd = new uint[32]; // odd-power-of-two zeros operator + + if (length == 0) + return; + + uint crc1 = ~runningCrc32Result; + var crc2 = (uint) crc; + + // put operator for one zero bit in odd + odd[0] = 0xEDB88320; // the CRC-32 polynomial + uint row = 1; + for (int i = 1; i < 32; i++) + { + odd[i] = 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); + + var len2 = (uint) length; + + // 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) == 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + if (len2 == 0) + break; + + // another iteration of the loop with odd and even swapped + gf2_matrix_square(odd, even); + if ((len2 & 1) == 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + } while (len2 != 0); + + crc1 ^= crc2; + + runningCrc32Result = ~crc1; + + //return (int) crc1; + return; + } + + + // private member vars + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/DeflateManager.cs b/src/SharpCompress/Compressor/Deflate/DeflateManager.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/DeflateManager.cs rename to src/SharpCompress/Compressor/Deflate/DeflateManager.cs index f87aa00c..cf46ae37 100644 --- a/SharpCompress/Compressor/Deflate/DeflateManager.cs +++ b/src/SharpCompress/Compressor/Deflate/DeflateManager.cs @@ -1,1906 +1,1906 @@ -// Deflate.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-October-28 13:44:59> -// -// ------------------------------------------------------------------ -// -// This module defines logic for handling the Deflate or compression. -// -// This code is based on multiple sources: -// - the original zlib v1.2.3 source, which is Copyright (C) 1995-2005 Jean-loup Gailly. -// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc. -// -// However, this code is significantly different from both. -// The object model is not the same, and many of the behaviors are different. -// -// In keeping with the license for these other works, the copyrights for -// jzlib and zlib are here. -// -// ----------------------------------------------------------------------- -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -using System; - -namespace SharpCompress.Compressor.Deflate -{ - internal sealed partial class DeflateManager - { - // extra bits for each length code - internal static readonly int[] ExtraLengthBits = new int[] - { - 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 - }; - - // extra bits for each distance code - internal static readonly int[] ExtraDistanceBits = new int[] - { - 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 - }; - - internal enum BlockState - { - NeedMore = 0, // block not completed, need more input or more output - BlockDone, // block flush performed - FinishStarted, // finish started, need only more output at next deflate - FinishDone // finish done, accept no more input or output - } - - internal enum DeflateFlavor - { - Store, - Fast, - Slow - } - - private const int MEM_LEVEL_MAX = 9; - private const int MEM_LEVEL_DEFAULT = 8; - - internal delegate BlockState CompressFunc(FlushType flush); - - internal class Config - { - // Use a faster search when the previous match is longer than this - internal int GoodLength; // reduce lazy search above this match length - - // 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. For levels 1,2,3: MaxLazy is actually - // MaxInsertLength. (See DeflateFast) - - internal int MaxLazy; // do not perform lazy search above this match length - - internal int NiceLength; // quit search above this match length - - // To speed up deflation, hash chains are never searched beyond this - // length. A higher limit improves compression ratio but degrades the speed. - - internal int MaxChainLength; - - internal DeflateFlavor Flavor; - - private Config(int goodLength, int maxLazy, int niceLength, int maxChainLength, DeflateFlavor flavor) - { - this.GoodLength = goodLength; - this.MaxLazy = maxLazy; - this.NiceLength = niceLength; - this.MaxChainLength = maxChainLength; - this.Flavor = flavor; - } - - public static Config Lookup(CompressionLevel level) - { - return Table[(int) level]; - } - - - static Config() - { - Table = new Config[] - { - new Config(0, 0, 0, 0, DeflateFlavor.Store), - new Config(4, 4, 8, 4, DeflateFlavor.Fast), - new Config(4, 5, 16, 8, DeflateFlavor.Fast), - new Config(4, 6, 32, 32, DeflateFlavor.Fast), - new Config(4, 4, 16, 16, DeflateFlavor.Slow), - new Config(8, 16, 32, 32, DeflateFlavor.Slow), - new Config(8, 16, 128, 128, DeflateFlavor.Slow), - new Config(8, 32, 128, 256, DeflateFlavor.Slow), - new Config(32, 128, 258, 1024, DeflateFlavor.Slow), - new Config(32, 258, 258, 4096, DeflateFlavor.Slow), - }; - } - - private static readonly Config[] Table; - } - - - private CompressFunc DeflateFunction; - - private static readonly System.String[] _ErrorMessage = new System.String[] - { - "need dictionary", - "stream end", - "", - "file error", - "stream error", - "data error", - "insufficient memory", - "buffer error", - "incompatible version", - "" - }; - - // preset dictionary flag in zlib header - private const int PRESET_DICT = 0x20; - - private const int INIT_STATE = 42; - private const int BUSY_STATE = 113; - private const int FINISH_STATE = 666; - - // The deflate compression method - private const int Z_DEFLATED = 8; - - private const int STORED_BLOCK = 0; - private const int STATIC_TREES = 1; - private const int DYN_TREES = 2; - - // The three kinds of block type - private const int Z_BINARY = 0; - private const int Z_ASCII = 1; - private const int Z_UNKNOWN = 2; - - private const int Buf_size = 8*2; - - private const int MIN_MATCH = 3; - private const int MAX_MATCH = 258; - - private const int MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); - - private static readonly int HEAP_SIZE = (2*InternalConstants.L_CODES + 1); - - private const int END_BLOCK = 256; - - internal ZlibCodec _codec; // the zlib encoder/decoder - internal int status; // as the name implies - internal byte[] pending; // output still pending - waiting to be compressed - internal int nextPending; // index of next pending byte to output to the stream - internal int pendingCount; // number of bytes in the pending buffer - - internal sbyte data_type; // UNKNOWN, BINARY or ASCII - internal int last_flush; // value of flush param for previous deflate call - - internal int w_size; // LZ77 window size (32K by default) - internal int w_bits; // log2(w_size) (8..16) - internal int w_mask; // w_size - 1 - - //internal byte[] dictionary; - internal byte[] 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. - // - // To do: use the user input buffer as sliding window. - - internal int window_size; - // Actual size of window: 2*wSize, except when the user input buffer - // is directly used as sliding window. - - internal short[] 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. - - private short[] head; // Heads of the hash chains or NIL. - - private int ins_h; // hash index of string to be inserted - private int hash_size; // number of elements in hash table - private int hash_bits; // log2(hash_size) - private int hash_mask; // hash_size-1 - - // 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 - private int hash_shift; - - // Window position at the beginning of the current output block. Gets - // negative when the window is moved backwards. - - private int blockStart; - - private Config config; - private int match_length; // length of best match - private int prev_match; // previous match - private int match_available; // set if previous match exists - private int strstart; // start of string to insert into.....???? - private int match_start; // start of matching string - private int lookahead; // number of valid bytes ahead in window - - // Length of the best match at previous step. Matches not greater than this - // are discarded. This is used in the lazy match evaluation. - private int prev_length; - - // 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. - - private CompressionLevel compressionLevel; // compression level (1..9) - private CompressionStrategy compressionStrategy; // favor or force Huffman coding - - - private short[] dyn_ltree; // literal and length tree - private short[] dyn_dtree; // distance tree - private short[] bl_tree; // Huffman tree for bit lengths - - private Tree treeLiterals = new Tree(); // desc for literal tree - private Tree treeDistances = new Tree(); // desc for distance tree - private Tree treeBitLengths = new Tree(); // desc for bit length tree - - // number of codes at each bit length for an optimal tree - private short[] bl_count = new short[InternalConstants.MAX_BITS + 1]; - - // heap used to build the Huffman trees - private int[] heap = new int[2*InternalConstants.L_CODES + 1]; - - private int heap_len; // number of elements in the heap - private 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. - - // Depth of each subtree used as tie breaker for trees of equal frequency - private sbyte[] depth = new sbyte[2*InternalConstants.L_CODES + 1]; - - private int _lengthOffset; // index for literals or lengths - - - // 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. - - internal int lit_bufsize; - - internal int last_lit; // running index in l_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. - - internal int _distanceOffset; // index into pending; points to distance data?? - - internal int opt_len; // bit length of current block with optimal trees - internal int static_len; // bit length of current block with static trees - internal int matches; // number of string matches in current block - internal int last_eob_len; // bit length of EOB code for last block - - // Output buffer. bits are inserted starting at the bottom (least - // significant bits). - internal short bi_buf; - - // Number of valid bits in bi_buf. All bits above the last valid bit - // are always zero. - internal int bi_valid; - - - internal DeflateManager() - { - dyn_ltree = new short[HEAP_SIZE*2]; - dyn_dtree = new short[(2*InternalConstants.D_CODES + 1)*2]; // distance tree - bl_tree = new short[(2*InternalConstants.BL_CODES + 1)*2]; // Huffman tree for bit lengths - } - - - // lm_init - private void _InitializeLazyMatch() - { - window_size = 2*w_size; - - // clear the hash - workitem 9063 - Array.Clear(head, 0, hash_size); - //for (int i = 0; i < hash_size; i++) head[i] = 0; - - config = Config.Lookup(compressionLevel); - SetDeflater(); - - strstart = 0; - blockStart = 0; - lookahead = 0; - match_length = prev_length = MIN_MATCH - 1; - match_available = 0; - ins_h = 0; - } - - // Initialize the tree data structures for a new zlib stream. - private void _InitializeTreeData() - { - treeLiterals.dyn_tree = dyn_ltree; - treeLiterals.staticTree = StaticTree.Literals; - - treeDistances.dyn_tree = dyn_dtree; - treeDistances.staticTree = StaticTree.Distances; - - treeBitLengths.dyn_tree = bl_tree; - treeBitLengths.staticTree = StaticTree.BitLengths; - - bi_buf = 0; - bi_valid = 0; - last_eob_len = 8; // enough lookahead for inflate - - // Initialize the first block of the first file: - _InitializeBlocks(); - } - - internal void _InitializeBlocks() - { - // Initialize the trees. - for (int i = 0; i < InternalConstants.L_CODES; i++) - dyn_ltree[i*2] = 0; - for (int i = 0; i < InternalConstants.D_CODES; i++) - dyn_dtree[i*2] = 0; - for (int i = 0; i < InternalConstants.BL_CODES; i++) - bl_tree[i*2] = 0; - - dyn_ltree[END_BLOCK*2] = 1; - opt_len = static_len = 0; - last_lit = matches = 0; - } - - // 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). - internal void pqdownheap(short[] tree, int k) - { - int v = heap[k]; - int j = k << 1; // left son of k - while (j <= heap_len) - { - // Set j to the smallest of the two sons: - if (j < heap_len && IsSmaller(tree, heap[j + 1], heap[j], depth)) - { - j++; - } - // Exit if v is smaller than both sons - if (IsSmaller(tree, v, heap[j], depth)) - break; - - // Exchange v with the smallest son - heap[k] = heap[j]; - k = j; - // And continue down the tree, setting j to the left son of k - j <<= 1; - } - heap[k] = v; - } - - internal static bool IsSmaller(short[] tree, int n, int m, sbyte[] depth) - { - short tn2 = tree[n*2]; - short tm2 = tree[m*2]; - return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m])); - } - - - // Scan a literal or distance tree to determine the frequencies of the codes - // in the bit length tree. - internal void ScanTree(short[] tree, int maxCode) - { - int n; // iterates over all tree elements - int prevlen = -1; // last emitted length - int curlen; // length of current code - int nextlen = (int) tree[0*2 + 1]; // 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[(maxCode + 1)*2 + 1] = (short) 0x7fff; // guard //?? - - for (n = 0; n <= maxCode; n++) - { - curlen = nextlen; - nextlen = (int) tree[(n + 1)*2 + 1]; - if (++count < max_count && curlen == nextlen) - { - continue; - } - else if (count < min_count) - { - bl_tree[curlen*2] = (short) (bl_tree[curlen*2] + count); - } - else if (curlen != 0) - { - if (curlen != prevlen) - bl_tree[curlen*2]++; - bl_tree[InternalConstants.REP_3_6*2]++; - } - else if (count <= 10) - { - bl_tree[InternalConstants.REPZ_3_10*2]++; - } - else - { - bl_tree[InternalConstants.REPZ_11_138*2]++; - } - 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. - internal int BuildBlTree() - { - int max_blindex; // index of last bit length code of non zero freq - - // Determine the bit length frequencies for literal and distance trees - ScanTree(dyn_ltree, treeLiterals.max_code); - ScanTree(dyn_dtree, treeDistances.max_code); - - // Build the bit length tree: - treeBitLengths.build_tree(this); - // 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 = InternalConstants.BL_CODES - 1; max_blindex >= 3; max_blindex--) - { - if (bl_tree[Tree.bl_order[max_blindex]*2 + 1] != 0) - break; - } - // Update opt_len to include the bit length tree and counts - opt_len += 3*(max_blindex + 1) + 5 + 5 + 4; - - 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. - internal void send_all_trees(int lcodes, int dcodes, int blcodes) - { - int rank; // index in bl_order - - send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt - send_bits(dcodes - 1, 5); - send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt - for (rank = 0; rank < blcodes; rank++) - { - send_bits(bl_tree[Tree.bl_order[rank]*2 + 1], 3); - } - send_tree(dyn_ltree, lcodes - 1); // literal tree - send_tree(dyn_dtree, dcodes - 1); // distance tree - } - - // Send a literal or distance tree in compressed form, using the codes in - // bl_tree. - internal void send_tree(short[] tree, int max_code) - { - int n; // iterates over all tree elements - int prevlen = -1; // last emitted length - int curlen; // length of current code - int nextlen = tree[0*2 + 1]; // 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; - } - - for (n = 0; n <= max_code; n++) - { - curlen = nextlen; - nextlen = tree[(n + 1)*2 + 1]; - if (++count < max_count && curlen == nextlen) - { - continue; - } - else if (count < min_count) - { - do - { - send_code(curlen, bl_tree); - } while (--count != 0); - } - else if (curlen != 0) - { - if (curlen != prevlen) - { - send_code(curlen, bl_tree); - count--; - } - send_code(InternalConstants.REP_3_6, bl_tree); - send_bits(count - 3, 2); - } - else if (count <= 10) - { - send_code(InternalConstants.REPZ_3_10, bl_tree); - send_bits(count - 3, 3); - } - else - { - send_code(InternalConstants.REPZ_11_138, bl_tree); - send_bits(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; - } - } - } - - // Output a block of bytes on the stream. - // IN assertion: there is enough room in pending_buf. - private void put_bytes(byte[] p, int start, int len) - { - Array.Copy(p, start, pending, pendingCount, len); - pendingCount += len; - } - -#if NOTNEEDED - private void put_byte(byte c) - { - pending[pendingCount++] = c; - } - internal void put_short(int b) - { - unchecked - { - pending[pendingCount++] = (byte)b; - pending[pendingCount++] = (byte)(b >> 8); - } - } - internal void putShortMSB(int b) - { - unchecked - { - pending[pendingCount++] = (byte)(b >> 8); - pending[pendingCount++] = (byte)b; - } - } -#endif - - internal void send_code(int c, short[] tree) - { - int c2 = c*2; - send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff)); - } - -#pragma warning disable 675 // workaround for Visual Studio 2015 compiler bug: https://github.com/dotnet/roslyn/issues/4027 - internal void send_bits(int value, int length) - { - int len = length; - unchecked - { - if (bi_valid > (int) Buf_size - len) - { - //int val = value; - // bi_buf |= (val << bi_valid); - - bi_buf |= (short)((value << bi_valid) & 0xffff); - //put_short(bi_buf); - pending[pendingCount++] = (byte) bi_buf; - pending[pendingCount++] = (byte) (bi_buf >> 8); - - - bi_buf = (short) ((uint) value >> (Buf_size - bi_valid)); - bi_valid += len - Buf_size; - } - else - { - // bi_buf |= (value) << bi_valid; - bi_buf |= (short)((value << bi_valid) & 0xffff); - bi_valid += len; - } - } - } -#pragma warning restore 675 - - // 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. - internal void _tr_align() - { - send_bits(STATIC_TREES << 1, 3); - send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); - - bi_flush(); - - // 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 + last_eob_len + 10 - bi_valid < 9) - { - send_bits(STATIC_TREES << 1, 3); - send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); - bi_flush(); - } - last_eob_len = 7; - } - - - // Save the match info and tally the frequency counts. Return true if - // the current block must be flushed. - internal bool _tr_tally(int dist, int lc) - { - pending[_distanceOffset + last_lit*2] = unchecked((byte) ((uint) dist >> 8)); - pending[_distanceOffset + last_lit*2 + 1] = unchecked((byte) dist); - pending[_lengthOffset + last_lit] = unchecked((byte) lc); - last_lit++; - - if (dist == 0) - { - // lc is the unmatched char - dyn_ltree[lc*2]++; - } - else - { - matches++; - // Here, lc is the match length - MIN_MATCH - dist--; // dist = match distance - 1 - dyn_ltree[(Tree.LengthCode[lc] + InternalConstants.LITERALS + 1)*2]++; - dyn_dtree[Tree.DistanceCode(dist)*2]++; - } - - if ((last_lit & 0x1fff) == 0 && (int) compressionLevel > 2) - { - // Compute an upper bound for the compressed length - int out_length = last_lit << 3; - int in_length = strstart - blockStart; - int dcode; - for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++) - { - out_length = - (int) (out_length + (int) dyn_dtree[dcode*2]*(5L + DeflateManager.ExtraDistanceBits[dcode])); - } - out_length >>= 3; - if ((matches < (last_lit/2)) && out_length < in_length/2) - return true; - } - - return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize); - // dinoch - wraparound? - // 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 - internal void send_compressed_block(short[] ltree, short[] dtree) - { - int distance; // distance of matched string - int lc; // match length or unmatched char (if dist == 0) - int lx = 0; // running index in l_buf - int code; // the code to send - int extra; // number of extra bits to send - - if (last_lit != 0) - { - do - { - int ix = _distanceOffset + lx*2; - distance = ((pending[ix] << 8) & 0xff00) | - (pending[ix + 1] & 0xff); - lc = (pending[_lengthOffset + lx]) & 0xff; - lx++; - - if (distance == 0) - { - send_code(lc, ltree); // send a literal byte - } - else - { - // literal or match pair - // Here, lc is the match length - MIN_MATCH - code = Tree.LengthCode[lc]; - - // send the length code - send_code(code + InternalConstants.LITERALS + 1, ltree); - extra = DeflateManager.ExtraLengthBits[code]; - if (extra != 0) - { - // send the extra length bits - lc -= Tree.LengthBase[code]; - send_bits(lc, extra); - } - distance--; // dist is now the match distance - 1 - code = Tree.DistanceCode(distance); - - // send the distance code - send_code(code, dtree); - - extra = DeflateManager.ExtraDistanceBits[code]; - if (extra != 0) - { - // send the extra distance bits - distance -= Tree.DistanceBase[code]; - send_bits(distance, extra); - } - } - - // Check that the overlay between pending and d_buf+l_buf is ok: - } while (lx < last_lit); - } - - send_code(END_BLOCK, ltree); - last_eob_len = ltree[END_BLOCK*2 + 1]; - } - - - // Set the data type to ASCII or BINARY, using a crude approximation: - // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - // IN assertion: the fields freq of dyn_ltree are set and the total of all - // frequencies does not exceed 64K (to fit in an int on 16 bit machines). - internal void set_data_type() - { - int n = 0; - int ascii_freq = 0; - int bin_freq = 0; - while (n < 7) - { - bin_freq += dyn_ltree[n*2]; - n++; - } - while (n < 128) - { - ascii_freq += dyn_ltree[n*2]; - n++; - } - while (n < InternalConstants.LITERALS) - { - bin_freq += dyn_ltree[n*2]; - n++; - } - data_type = (sbyte) (bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); - } - - - // Flush the bit buffer, keeping at most 7 bits in it. - internal void bi_flush() - { - if (bi_valid == 16) - { - pending[pendingCount++] = (byte) bi_buf; - pending[pendingCount++] = (byte) (bi_buf >> 8); - bi_buf = 0; - bi_valid = 0; - } - else if (bi_valid >= 8) - { - //put_byte((byte)bi_buf); - pending[pendingCount++] = (byte) bi_buf; - bi_buf >>= 8; - bi_valid -= 8; - } - } - - // Flush the bit buffer and align the output on a byte boundary - internal void bi_windup() - { - if (bi_valid > 8) - { - pending[pendingCount++] = (byte) bi_buf; - pending[pendingCount++] = (byte) (bi_buf >> 8); - } - else if (bi_valid > 0) - { - //put_byte((byte)bi_buf); - pending[pendingCount++] = (byte) bi_buf; - } - bi_buf = 0; - bi_valid = 0; - } - - // Copy a stored block, storing first the length and its - // one's complement if requested. - internal void copy_block(int buf, int len, bool header) - { - bi_windup(); // align on byte boundary - last_eob_len = 8; // enough lookahead for inflate - - if (header) - unchecked - { - //put_short((short)len); - pending[pendingCount++] = (byte) len; - pending[pendingCount++] = (byte) (len >> 8); - //put_short((short)~len); - pending[pendingCount++] = (byte) ~len; - pending[pendingCount++] = (byte) (~len >> 8); - } - - put_bytes(window, buf, len); - } - - internal void flush_block_only(bool eof) - { - _tr_flush_block(blockStart >= 0 ? blockStart : -1, strstart - blockStart, eof); - blockStart = strstart; - _codec.flush_pending(); - } - - // 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. - internal BlockState DeflateNone(FlushType flush) - { - // Stored blocks are limited to 0xffff bytes, pending is limited - // to pending_buf_size, and each stored block has a 5 byte header: - - int max_block_size = 0xffff; - int max_start; - - if (max_block_size > pending.Length - 5) - { - max_block_size = pending.Length - 5; - } - - // Copy as much as possible from input to output: - while (true) - { - // Fill the window as much as possible: - if (lookahead <= 1) - { - _fillWindow(); - if (lookahead == 0 && flush == FlushType.None) - return BlockState.NeedMore; - if (lookahead == 0) - break; // flush the current block - } - - strstart += lookahead; - lookahead = 0; - - // Emit a stored block if pending will be full: - max_start = blockStart + max_block_size; - if (strstart == 0 || strstart >= max_start) - { - // strstart == 0 is possible when wraparound on 16-bit machine - lookahead = (int) (strstart - max_start); - strstart = (int) max_start; - - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - return BlockState.NeedMore; - } - - // Flush if we may have to slide, otherwise block_start may become - // negative and the data will be gone: - if (strstart - blockStart >= w_size - MIN_LOOKAHEAD) - { - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - return BlockState.NeedMore; - } - } - - flush_block_only(flush == FlushType.Finish); - if (_codec.AvailableBytesOut == 0) - return (flush == FlushType.Finish) ? BlockState.FinishStarted : BlockState.NeedMore; - - return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; - } - - - // Send a stored block - internal void _tr_stored_block(int buf, int stored_len, bool eof) - { - send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type - copy_block(buf, stored_len, true); // with header - } - - // Determine the best encoding for the current block: dynamic trees, static - // trees or store, and output the encoded block to the zip file. - internal void _tr_flush_block(int buf, int stored_len, bool eof) - { - int 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 (compressionLevel > 0) - { - // Check if the file is ascii or binary - if (data_type == Z_UNKNOWN) - set_data_type(); - - // Construct the literal and distance trees - treeLiterals.build_tree(this); - - treeDistances.build_tree(this); - - // 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 = BuildBlTree(); - - // Determine the best encoding. Compute first the block length in bytes - opt_lenb = (opt_len + 3 + 7) >> 3; - static_lenb = (static_len + 3 + 7) >> 3; - - if (static_lenb <= opt_lenb) - opt_lenb = static_lenb; - } - else - { - opt_lenb = static_lenb = stored_len + 5; // force a stored block - } - - if (stored_len + 4 <= opt_lenb && buf != -1) - { - // 4: two words for the lengths - // 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(buf, stored_len, eof); - } - else if (static_lenb == opt_lenb) - { - send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); - send_compressed_block(StaticTree.lengthAndLiteralsTreeCodes, StaticTree.distTreeCodes); - } - else - { - send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); - send_all_trees(treeLiterals.max_code + 1, treeDistances.max_code + 1, max_blindex + 1); - send_compressed_block(dyn_ltree, dyn_dtree); - } - - // The above check is made mod 2^32, for files larger than 512 MB - // and uLong implemented on 32 bits. - - _InitializeBlocks(); - - if (eof) - { - bi_windup(); - } - } - - // 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). - private void _fillWindow() - { - int n, m; - int p; - int more; // Amount of free space at the end of the window. - - do - { - more = (window_size - lookahead - strstart); - - // Deal with !@#$% 64K limit: - if (more == 0 && strstart == 0 && lookahead == 0) - { - more = w_size; - } - else if (more == -1) - { - // Very unlikely, but possible on 16 bit machine if strstart == 0 - // and lookahead == 1 (input done one 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. - } - else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) - { - Array.Copy(window, w_size, window, 0, w_size); - match_start -= w_size; - strstart -= w_size; // we now have strstart >= MAX_DIST - blockStart -= w_size; - - // 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.) - - n = hash_size; - p = n; - do - { - m = (head[--p] & 0xffff); - head[p] = (short) ((m >= w_size) ? (m - w_size) : 0); - } while (--n != 0); - - n = w_size; - p = n; - do - { - m = (prev[--p] & 0xffff); - prev[p] = (short) ((m >= w_size) ? (m - w_size) : 0); - // If n is not on any hash chain, prev[n] is garbage but - // its value will never be used. - } while (--n != 0); - more += w_size; - } - - if (_codec.AvailableBytesIn == 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. - - n = _codec.read_buf(window, strstart + lookahead, more); - lookahead += n; - - // Initialize the hash value now that we have some input: - if (lookahead >= MIN_MATCH) - { - ins_h = window[strstart] & 0xff; - ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; - } - // 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 (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0); - } - - // 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. - internal BlockState DeflateFast(FlushType flush) - { - // short hash_head = 0; // head of the hash chain - int hash_head = 0; // head of the hash chain - bool bflush; // set if current block must be flushed - - while (true) - { - // 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 (lookahead < MIN_LOOKAHEAD) - { - _fillWindow(); - if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) - { - return BlockState.NeedMore; - } - if (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 (lookahead >= MIN_MATCH) - { - ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; - - // prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short) strstart); - } - - // Find the longest match, discarding those <= prev_length. - // At this point we have always match_length < MIN_MATCH - - if (hash_head != 0L && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) - { - // 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 (compressionStrategy != CompressionStrategy.HuffmanOnly) - { - match_length = longest_match(hash_head); - } - // longest_match() sets match_start - } - if (match_length >= MIN_MATCH) - { - // check_match(strstart, match_start, match_length); - - bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); - - lookahead -= match_length; - - // Insert new strings in the hash table only if the match length - // is not too large. This saves time but degrades compression. - if (match_length <= config.MaxLazy && lookahead >= MIN_MATCH) - { - match_length--; // string at strstart already in hash table - do - { - strstart++; - - ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; - // prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short) strstart); - - // strstart never exceeds WSIZE-MAX_MATCH, so there are - // always MIN_MATCH bytes ahead. - } while (--match_length != 0); - strstart++; - } - else - { - strstart += match_length; - match_length = 0; - ins_h = window[strstart] & 0xff; - - ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; - // 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 - - bflush = _tr_tally(0, window[strstart] & 0xff); - lookahead--; - strstart++; - } - if (bflush) - { - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - return BlockState.NeedMore; - } - } - - flush_block_only(flush == FlushType.Finish); - if (_codec.AvailableBytesOut == 0) - { - if (flush == FlushType.Finish) - return BlockState.FinishStarted; - else - return BlockState.NeedMore; - } - return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; - } - - // 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. - internal BlockState DeflateSlow(FlushType flush) - { - // short hash_head = 0; // head of hash chain - int hash_head = 0; // head of hash chain - bool bflush; // set if current block must be flushed - - // Process the input block. - while (true) - { - // 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 (lookahead < MIN_LOOKAHEAD) - { - _fillWindow(); - if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) - return BlockState.NeedMore; - - if (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 (lookahead >= MIN_MATCH) - { - ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; - // prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short) strstart); - } - - // Find the longest match, discarding those <= prev_length. - prev_length = match_length; - prev_match = match_start; - match_length = MIN_MATCH - 1; - - if (hash_head != 0 && prev_length < config.MaxLazy && - ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) - { - // 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 (compressionStrategy != CompressionStrategy.HuffmanOnly) - { - match_length = longest_match(hash_head); - } - // longest_match() sets match_start - - if (match_length <= 5 && (compressionStrategy == CompressionStrategy.Filtered || - (match_length == MIN_MATCH && strstart - match_start > 4096))) - { - // If prev_match is also MIN_MATCH, match_start is garbage - // but we will ignore the current match anyway. - 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 (prev_length >= MIN_MATCH && match_length <= prev_length) - { - int max_insert = strstart + lookahead - MIN_MATCH; - // Do not insert strings in hash table beyond this. - - // check_match(strstart-1, prev_match, prev_length); - - bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); - - // 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. - lookahead -= (prev_length - 1); - prev_length -= 2; - do - { - if (++strstart <= max_insert) - { - ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & - hash_mask; - //prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short) strstart); - } - } while (--prev_length != 0); - match_available = 0; - match_length = MIN_MATCH - 1; - strstart++; - - if (bflush) - { - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - return BlockState.NeedMore; - } - } - else if (match_available != 0) - { - // 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. - - bflush = _tr_tally(0, window[strstart - 1] & 0xff); - - if (bflush) - { - flush_block_only(false); - } - strstart++; - lookahead--; - if (_codec.AvailableBytesOut == 0) - return BlockState.NeedMore; - } - else - { - // There is no previous match to compare with, wait for - // the next step to decide. - - match_available = 1; - strstart++; - lookahead--; - } - } - - if (match_available != 0) - { - bflush = _tr_tally(0, window[strstart - 1] & 0xff); - match_available = 0; - } - flush_block_only(flush == FlushType.Finish); - - if (_codec.AvailableBytesOut == 0) - { - if (flush == FlushType.Finish) - return BlockState.FinishStarted; - else - return BlockState.NeedMore; - } - - return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; - } - - - internal int longest_match(int cur_match) - { - int chain_length = config.MaxChainLength; // max hash chain length - int scan = strstart; // current string - int match; // matched string - int len; // length of current match - int best_len = prev_length; // best match length so far - int limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; - - int niceLength = config.NiceLength; - - // Stop when cur_match becomes <= limit. To simplify the code, - // we prevent matches with the string of window index 0. - - int wmask = w_mask; - - int strend = strstart + MAX_MATCH; - byte scan_end1 = window[scan + best_len - 1]; - byte scan_end = window[scan + best_len]; - - // 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. - - // Do not waste too much time if we already have a good match: - if (prev_length >= config.GoodLength) - { - chain_length >>= 2; - } - - // Do not look for matches beyond the end of the input. This is necessary - // to make deflate deterministic. - if (niceLength > lookahead) - niceLength = lookahead; - - do - { - match = cur_match; - - // Skip to next match if the match length cannot increase - // or if the match length is less than 2: - if (window[match + best_len] != scan_end || - window[match + best_len - 1] != scan_end1 || - window[match] != window[scan] || - window[++match] != window[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++; - - // We check for insufficient lookahead only every 8th comparison; - // the 256th check will be made at strstart+258. - do - { - } while (window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && scan < strend); - - len = MAX_MATCH - (int) (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) - { - match_start = cur_match; - best_len = len; - if (len >= niceLength) - break; - scan_end1 = window[scan + best_len - 1]; - scan_end = window[scan + best_len]; - } - } while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0); - - if (best_len <= lookahead) - return best_len; - return lookahead; - } - - - private bool Rfc1950BytesEmitted = false; - private bool _WantRfc1950HeaderBytes = true; - - internal bool WantRfc1950HeaderBytes - { - get { return _WantRfc1950HeaderBytes; } - set { _WantRfc1950HeaderBytes = value; } - } - - - internal int Initialize(ZlibCodec codec, CompressionLevel level) - { - return Initialize(codec, level, ZlibConstants.WindowBitsMax); - } - - internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) - { - return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); - } - - internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits, - CompressionStrategy compressionStrategy) - { - return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); - } - - internal int Initialize(ZlibCodec codec, CompressionLevel level, int windowBits, int memLevel, - CompressionStrategy strategy) - { - _codec = codec; - _codec.Message = null; - - // validation - if (windowBits < 9 || windowBits > 15) - throw new ZlibException("windowBits must be in the range 9..15."); - - if (memLevel < 1 || memLevel > MEM_LEVEL_MAX) - throw new ZlibException(String.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX)); - - _codec.dstate = this; - - w_bits = windowBits; - w_size = 1 << w_bits; - w_mask = w_size - 1; - - hash_bits = memLevel + 7; - hash_size = 1 << hash_bits; - hash_mask = hash_size - 1; - hash_shift = ((hash_bits + MIN_MATCH - 1)/MIN_MATCH); - - window = new byte[w_size*2]; - prev = new short[w_size]; - head = new short[hash_size]; - - // for memLevel==8, this will be 16384, 16k - lit_bufsize = 1 << (memLevel + 6); - - // Use a single array as the buffer for data pending compression, - // the output distance codes, and the output length codes (aka tree). - // orig comment: This works just fine since the average - // output size for (length,distance) codes is <= 24 bits. - pending = new byte[lit_bufsize*4]; - _distanceOffset = lit_bufsize; - _lengthOffset = (1 + 2)*lit_bufsize; - - // So, for memLevel 8, the length of the pending buffer is 65536. 64k. - // The first 16k are pending bytes. - // The middle slice, of 32k, is used for distance codes. - // The final 16k are length codes. - - this.compressionLevel = level; - this.compressionStrategy = strategy; - - Reset(); - return ZlibConstants.Z_OK; - } - - - internal void Reset() - { - _codec.TotalBytesIn = _codec.TotalBytesOut = 0; - _codec.Message = null; - //strm.data_type = Z_UNKNOWN; - - pendingCount = 0; - nextPending = 0; - - Rfc1950BytesEmitted = false; - - status = (WantRfc1950HeaderBytes) ? INIT_STATE : BUSY_STATE; - _codec._Adler32 = Adler.Adler32(0, null, 0, 0); - - last_flush = (int) FlushType.None; - - _InitializeTreeData(); - _InitializeLazyMatch(); - } - - - internal int End() - { - if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) - { - return ZlibConstants.Z_STREAM_ERROR; - } - // Deallocate in reverse order of allocations: - pending = null; - head = null; - prev = null; - window = null; - // free - // dstate=null; - return status == BUSY_STATE ? ZlibConstants.Z_DATA_ERROR : ZlibConstants.Z_OK; - } - - - private void SetDeflater() - { - switch (config.Flavor) - { - case DeflateFlavor.Store: - DeflateFunction = DeflateNone; - break; - case DeflateFlavor.Fast: - DeflateFunction = DeflateFast; - break; - case DeflateFlavor.Slow: - DeflateFunction = DeflateSlow; - break; - } - } - - - internal int SetParams(CompressionLevel level, CompressionStrategy strategy) - { - int result = ZlibConstants.Z_OK; - - if (compressionLevel != level) - { - Config newConfig = Config.Lookup(level); - - // change in the deflate flavor (Fast vs slow vs none)? - if (newConfig.Flavor != config.Flavor && _codec.TotalBytesIn != 0) - { - // Flush the last buffer: - result = _codec.Deflate(FlushType.Partial); - } - - compressionLevel = level; - config = newConfig; - SetDeflater(); - } - - // no need to flush with change in strategy? Really? - compressionStrategy = strategy; - - return result; - } - - - internal int SetDictionary(byte[] dictionary) - { - int length = dictionary.Length; - int index = 0; - - if (dictionary == null || status != INIT_STATE) - throw new ZlibException("Stream error."); - - _codec._Adler32 = Adler.Adler32(_codec._Adler32, dictionary, 0, dictionary.Length); - - if (length < MIN_MATCH) - return ZlibConstants.Z_OK; - if (length > w_size - MIN_LOOKAHEAD) - { - length = w_size - MIN_LOOKAHEAD; - index = dictionary.Length - length; // use the tail of the dictionary - } - Array.Copy(dictionary, index, window, 0, length); - strstart = length; - blockStart = 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. - - ins_h = window[0] & 0xff; - ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask; - - for (int n = 0; n <= length - MIN_MATCH; n++) - { - ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; - prev[n & w_mask] = head[ins_h]; - head[ins_h] = (short) n; - } - return ZlibConstants.Z_OK; - } - - - internal int Deflate(FlushType flush) - { - int old_flush; - - if (_codec.OutputBuffer == null || - (_codec.InputBuffer == null && _codec.AvailableBytesIn != 0) || - (status == FINISH_STATE && flush != FlushType.Finish)) - { - _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR)]; - throw new ZlibException(String.Format("Something is fishy. [{0}]", _codec.Message)); - //return ZlibConstants.Z_STREAM_ERROR; - } - if (_codec.AvailableBytesOut == 0) - { - _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; - throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); - //return ZlibConstants.Z_BUF_ERROR; - } - - old_flush = last_flush; - last_flush = (int) flush; - - // Write the zlib (rfc1950) header bytes - if (status == INIT_STATE) - { - int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8; - int level_flags = (((int) compressionLevel - 1) & 0xff) >> 1; - - if (level_flags > 3) - level_flags = 3; - header |= (level_flags << 6); - if (strstart != 0) - header |= PRESET_DICT; - header += 31 - (header%31); - - status = BUSY_STATE; - //putShortMSB(header); - unchecked - { - pending[pendingCount++] = (byte) (header >> 8); - pending[pendingCount++] = (byte) header; - } - // Save the adler32 of the preset dictionary: - if (strstart != 0) - { - ////putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); - //putShortMSB((int)((UInt64)_codec._Adler32 >> 16)); - //putShortMSB((int)(_codec._Adler32 & 0xffff)); - pending[pendingCount++] = (byte) ((_codec._Adler32 & 0xFF000000) >> 24); - pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x00FF0000) >> 16); - pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x0000FF00) >> 8); - pending[pendingCount++] = (byte) (_codec._Adler32 & 0x000000FF); - } - _codec._Adler32 = Adler.Adler32(0, null, 0, 0); - } - - // Flush as much pending output as possible - if (pendingCount != 0) - { - _codec.flush_pending(); - if (_codec.AvailableBytesOut == 0) - { - //System.out.println(" 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: - last_flush = -1; - return ZlibConstants.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_BUFF_ERROR. - } - else if (_codec.AvailableBytesIn == 0 && - (int) flush <= old_flush && - flush != FlushType.Finish) - { - // workitem 8557 - // Not sure why this needs to be an error. - // pendingCount == 0, which means there's nothing to deflate. - // And the caller has not asked for a FlushType.Finish, but... - // that seems very non-fatal. We can just say "OK" and do nthing. - - // _codec.Message = z_errmsg[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; - // throw new ZlibException("AvailableBytesIn == 0 && flush<=old_flush && flush != FlushType.Finish"); - - return ZlibConstants.Z_OK; - } - - // User must not provide more input after the first FINISH: - if (status == FINISH_STATE && _codec.AvailableBytesIn != 0) - { - _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; - throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); - } - - - // Start a new block or continue the current one. - if (_codec.AvailableBytesIn != 0 || lookahead != 0 || (flush != FlushType.None && status != FINISH_STATE)) - { - BlockState bstate = DeflateFunction(flush); - - if (bstate == BlockState.FinishStarted || bstate == BlockState.FinishDone) - { - status = FINISH_STATE; - } - if (bstate == BlockState.NeedMore || bstate == BlockState.FinishStarted) - { - if (_codec.AvailableBytesOut == 0) - { - last_flush = -1; // avoid BUF_ERROR next call, see above - } - return ZlibConstants.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 == BlockState.BlockDone) - { - if (flush == FlushType.Partial) - { - _tr_align(); - } - else - { - // FlushType.Full or FlushType.Sync - _tr_stored_block(0, 0, false); - // For a full flush, this empty block will be recognized - // as a special marker by inflate_sync(). - if (flush == FlushType.Full) - { - // clear hash (forget the history) - for (int i = 0; i < hash_size; i++) - head[i] = 0; - } - } - _codec.flush_pending(); - if (_codec.AvailableBytesOut == 0) - { - last_flush = -1; // avoid BUF_ERROR at next call, see above - return ZlibConstants.Z_OK; - } - } - } - - if (flush != FlushType.Finish) - return ZlibConstants.Z_OK; - - if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted) - return ZlibConstants.Z_STREAM_END; - - // Write the zlib trailer (adler32) - pending[pendingCount++] = (byte) ((_codec._Adler32 & 0xFF000000) >> 24); - pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x00FF0000) >> 16); - pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x0000FF00) >> 8); - pending[pendingCount++] = (byte) (_codec._Adler32 & 0x000000FF); - //putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); - //putShortMSB((int)(_codec._Adler32 & 0xffff)); - - _codec.flush_pending(); - - // If avail_out is zero, the application will call deflate again - // to flush the rest. - - Rfc1950BytesEmitted = true; // write the trailer only once! - - return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END; - } - } +// Deflate.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2009-October-28 13:44:59> +// +// ------------------------------------------------------------------ +// +// This module defines logic for handling the Deflate or compression. +// +// This code is based on multiple sources: +// - the original zlib v1.2.3 source, which is Copyright (C) 1995-2005 Jean-loup Gailly. +// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc. +// +// However, this code is significantly different from both. +// The object model is not the same, and many of the behaviors are different. +// +// In keeping with the license for these other works, the copyrights for +// jzlib and zlib are here. +// +// ----------------------------------------------------------------------- +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +using System; + +namespace SharpCompress.Compressor.Deflate +{ + internal sealed partial class DeflateManager + { + // extra bits for each length code + internal static readonly int[] ExtraLengthBits = new int[] + { + 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 + }; + + // extra bits for each distance code + internal static readonly int[] ExtraDistanceBits = new int[] + { + 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 + }; + + internal enum BlockState + { + NeedMore = 0, // block not completed, need more input or more output + BlockDone, // block flush performed + FinishStarted, // finish started, need only more output at next deflate + FinishDone // finish done, accept no more input or output + } + + internal enum DeflateFlavor + { + Store, + Fast, + Slow + } + + private const int MEM_LEVEL_MAX = 9; + private const int MEM_LEVEL_DEFAULT = 8; + + internal delegate BlockState CompressFunc(FlushType flush); + + internal class Config + { + // Use a faster search when the previous match is longer than this + internal int GoodLength; // reduce lazy search above this match length + + // 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. For levels 1,2,3: MaxLazy is actually + // MaxInsertLength. (See DeflateFast) + + internal int MaxLazy; // do not perform lazy search above this match length + + internal int NiceLength; // quit search above this match length + + // To speed up deflation, hash chains are never searched beyond this + // length. A higher limit improves compression ratio but degrades the speed. + + internal int MaxChainLength; + + internal DeflateFlavor Flavor; + + private Config(int goodLength, int maxLazy, int niceLength, int maxChainLength, DeflateFlavor flavor) + { + this.GoodLength = goodLength; + this.MaxLazy = maxLazy; + this.NiceLength = niceLength; + this.MaxChainLength = maxChainLength; + this.Flavor = flavor; + } + + public static Config Lookup(CompressionLevel level) + { + return Table[(int) level]; + } + + + static Config() + { + Table = new Config[] + { + new Config(0, 0, 0, 0, DeflateFlavor.Store), + new Config(4, 4, 8, 4, DeflateFlavor.Fast), + new Config(4, 5, 16, 8, DeflateFlavor.Fast), + new Config(4, 6, 32, 32, DeflateFlavor.Fast), + new Config(4, 4, 16, 16, DeflateFlavor.Slow), + new Config(8, 16, 32, 32, DeflateFlavor.Slow), + new Config(8, 16, 128, 128, DeflateFlavor.Slow), + new Config(8, 32, 128, 256, DeflateFlavor.Slow), + new Config(32, 128, 258, 1024, DeflateFlavor.Slow), + new Config(32, 258, 258, 4096, DeflateFlavor.Slow), + }; + } + + private static readonly Config[] Table; + } + + + private CompressFunc DeflateFunction; + + private static readonly System.String[] _ErrorMessage = new System.String[] + { + "need dictionary", + "stream end", + "", + "file error", + "stream error", + "data error", + "insufficient memory", + "buffer error", + "incompatible version", + "" + }; + + // preset dictionary flag in zlib header + private const int PRESET_DICT = 0x20; + + private const int INIT_STATE = 42; + private const int BUSY_STATE = 113; + private const int FINISH_STATE = 666; + + // The deflate compression method + private const int Z_DEFLATED = 8; + + private const int STORED_BLOCK = 0; + private const int STATIC_TREES = 1; + private const int DYN_TREES = 2; + + // The three kinds of block type + private const int Z_BINARY = 0; + private const int Z_ASCII = 1; + private const int Z_UNKNOWN = 2; + + private const int Buf_size = 8*2; + + private const int MIN_MATCH = 3; + private const int MAX_MATCH = 258; + + private const int MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + + private static readonly int HEAP_SIZE = (2*InternalConstants.L_CODES + 1); + + private const int END_BLOCK = 256; + + internal ZlibCodec _codec; // the zlib encoder/decoder + internal int status; // as the name implies + internal byte[] pending; // output still pending - waiting to be compressed + internal int nextPending; // index of next pending byte to output to the stream + internal int pendingCount; // number of bytes in the pending buffer + + internal sbyte data_type; // UNKNOWN, BINARY or ASCII + internal int last_flush; // value of flush param for previous deflate call + + internal int w_size; // LZ77 window size (32K by default) + internal int w_bits; // log2(w_size) (8..16) + internal int w_mask; // w_size - 1 + + //internal byte[] dictionary; + internal byte[] 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. + // + // To do: use the user input buffer as sliding window. + + internal int window_size; + // Actual size of window: 2*wSize, except when the user input buffer + // is directly used as sliding window. + + internal short[] 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. + + private short[] head; // Heads of the hash chains or NIL. + + private int ins_h; // hash index of string to be inserted + private int hash_size; // number of elements in hash table + private int hash_bits; // log2(hash_size) + private int hash_mask; // hash_size-1 + + // 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 + private int hash_shift; + + // Window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + private int blockStart; + + private Config config; + private int match_length; // length of best match + private int prev_match; // previous match + private int match_available; // set if previous match exists + private int strstart; // start of string to insert into.....???? + private int match_start; // start of matching string + private int lookahead; // number of valid bytes ahead in window + + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + private int prev_length; + + // 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. + + private CompressionLevel compressionLevel; // compression level (1..9) + private CompressionStrategy compressionStrategy; // favor or force Huffman coding + + + private short[] dyn_ltree; // literal and length tree + private short[] dyn_dtree; // distance tree + private short[] bl_tree; // Huffman tree for bit lengths + + private Tree treeLiterals = new Tree(); // desc for literal tree + private Tree treeDistances = new Tree(); // desc for distance tree + private Tree treeBitLengths = new Tree(); // desc for bit length tree + + // number of codes at each bit length for an optimal tree + private short[] bl_count = new short[InternalConstants.MAX_BITS + 1]; + + // heap used to build the Huffman trees + private int[] heap = new int[2*InternalConstants.L_CODES + 1]; + + private int heap_len; // number of elements in the heap + private 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. + + // Depth of each subtree used as tie breaker for trees of equal frequency + private sbyte[] depth = new sbyte[2*InternalConstants.L_CODES + 1]; + + private int _lengthOffset; // index for literals or lengths + + + // 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. + + internal int lit_bufsize; + + internal int last_lit; // running index in l_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. + + internal int _distanceOffset; // index into pending; points to distance data?? + + internal int opt_len; // bit length of current block with optimal trees + internal int static_len; // bit length of current block with static trees + internal int matches; // number of string matches in current block + internal int last_eob_len; // bit length of EOB code for last block + + // Output buffer. bits are inserted starting at the bottom (least + // significant bits). + internal short bi_buf; + + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + internal int bi_valid; + + + internal DeflateManager() + { + dyn_ltree = new short[HEAP_SIZE*2]; + dyn_dtree = new short[(2*InternalConstants.D_CODES + 1)*2]; // distance tree + bl_tree = new short[(2*InternalConstants.BL_CODES + 1)*2]; // Huffman tree for bit lengths + } + + + // lm_init + private void _InitializeLazyMatch() + { + window_size = 2*w_size; + + // clear the hash - workitem 9063 + Array.Clear(head, 0, hash_size); + //for (int i = 0; i < hash_size; i++) head[i] = 0; + + config = Config.Lookup(compressionLevel); + SetDeflater(); + + strstart = 0; + blockStart = 0; + lookahead = 0; + match_length = prev_length = MIN_MATCH - 1; + match_available = 0; + ins_h = 0; + } + + // Initialize the tree data structures for a new zlib stream. + private void _InitializeTreeData() + { + treeLiterals.dyn_tree = dyn_ltree; + treeLiterals.staticTree = StaticTree.Literals; + + treeDistances.dyn_tree = dyn_dtree; + treeDistances.staticTree = StaticTree.Distances; + + treeBitLengths.dyn_tree = bl_tree; + treeBitLengths.staticTree = StaticTree.BitLengths; + + bi_buf = 0; + bi_valid = 0; + last_eob_len = 8; // enough lookahead for inflate + + // Initialize the first block of the first file: + _InitializeBlocks(); + } + + internal void _InitializeBlocks() + { + // Initialize the trees. + for (int i = 0; i < InternalConstants.L_CODES; i++) + dyn_ltree[i*2] = 0; + for (int i = 0; i < InternalConstants.D_CODES; i++) + dyn_dtree[i*2] = 0; + for (int i = 0; i < InternalConstants.BL_CODES; i++) + bl_tree[i*2] = 0; + + dyn_ltree[END_BLOCK*2] = 1; + opt_len = static_len = 0; + last_lit = matches = 0; + } + + // 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). + internal void pqdownheap(short[] tree, int k) + { + int v = heap[k]; + int j = k << 1; // left son of k + while (j <= heap_len) + { + // Set j to the smallest of the two sons: + if (j < heap_len && IsSmaller(tree, heap[j + 1], heap[j], depth)) + { + j++; + } + // Exit if v is smaller than both sons + if (IsSmaller(tree, v, heap[j], depth)) + break; + + // Exchange v with the smallest son + heap[k] = heap[j]; + k = j; + // And continue down the tree, setting j to the left son of k + j <<= 1; + } + heap[k] = v; + } + + internal static bool IsSmaller(short[] tree, int n, int m, sbyte[] depth) + { + short tn2 = tree[n*2]; + short tm2 = tree[m*2]; + return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m])); + } + + + // Scan a literal or distance tree to determine the frequencies of the codes + // in the bit length tree. + internal void ScanTree(short[] tree, int maxCode) + { + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = (int) tree[0*2 + 1]; // 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[(maxCode + 1)*2 + 1] = (short) 0x7fff; // guard //?? + + for (n = 0; n <= maxCode; n++) + { + curlen = nextlen; + nextlen = (int) tree[(n + 1)*2 + 1]; + if (++count < max_count && curlen == nextlen) + { + continue; + } + else if (count < min_count) + { + bl_tree[curlen*2] = (short) (bl_tree[curlen*2] + count); + } + else if (curlen != 0) + { + if (curlen != prevlen) + bl_tree[curlen*2]++; + bl_tree[InternalConstants.REP_3_6*2]++; + } + else if (count <= 10) + { + bl_tree[InternalConstants.REPZ_3_10*2]++; + } + else + { + bl_tree[InternalConstants.REPZ_11_138*2]++; + } + 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. + internal int BuildBlTree() + { + int max_blindex; // index of last bit length code of non zero freq + + // Determine the bit length frequencies for literal and distance trees + ScanTree(dyn_ltree, treeLiterals.max_code); + ScanTree(dyn_dtree, treeDistances.max_code); + + // Build the bit length tree: + treeBitLengths.build_tree(this); + // 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 = InternalConstants.BL_CODES - 1; max_blindex >= 3; max_blindex--) + { + if (bl_tree[Tree.bl_order[max_blindex]*2 + 1] != 0) + break; + } + // Update opt_len to include the bit length tree and counts + opt_len += 3*(max_blindex + 1) + 5 + 5 + 4; + + 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. + internal void send_all_trees(int lcodes, int dcodes, int blcodes) + { + int rank; // index in bl_order + + send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes - 1, 5); + send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) + { + send_bits(bl_tree[Tree.bl_order[rank]*2 + 1], 3); + } + send_tree(dyn_ltree, lcodes - 1); // literal tree + send_tree(dyn_dtree, dcodes - 1); // distance tree + } + + // Send a literal or distance tree in compressed form, using the codes in + // bl_tree. + internal void send_tree(short[] tree, int max_code) + { + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0*2 + 1]; // 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; + } + + for (n = 0; n <= max_code; n++) + { + curlen = nextlen; + nextlen = tree[(n + 1)*2 + 1]; + if (++count < max_count && curlen == nextlen) + { + continue; + } + else if (count < min_count) + { + do + { + send_code(curlen, bl_tree); + } while (--count != 0); + } + else if (curlen != 0) + { + if (curlen != prevlen) + { + send_code(curlen, bl_tree); + count--; + } + send_code(InternalConstants.REP_3_6, bl_tree); + send_bits(count - 3, 2); + } + else if (count <= 10) + { + send_code(InternalConstants.REPZ_3_10, bl_tree); + send_bits(count - 3, 3); + } + else + { + send_code(InternalConstants.REPZ_11_138, bl_tree); + send_bits(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; + } + } + } + + // Output a block of bytes on the stream. + // IN assertion: there is enough room in pending_buf. + private void put_bytes(byte[] p, int start, int len) + { + Array.Copy(p, start, pending, pendingCount, len); + pendingCount += len; + } + +#if NOTNEEDED + private void put_byte(byte c) + { + pending[pendingCount++] = c; + } + internal void put_short(int b) + { + unchecked + { + pending[pendingCount++] = (byte)b; + pending[pendingCount++] = (byte)(b >> 8); + } + } + internal void putShortMSB(int b) + { + unchecked + { + pending[pendingCount++] = (byte)(b >> 8); + pending[pendingCount++] = (byte)b; + } + } +#endif + + internal void send_code(int c, short[] tree) + { + int c2 = c*2; + send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff)); + } + +#pragma warning disable 675 // workaround for Visual Studio 2015 compiler bug: https://github.com/dotnet/roslyn/issues/4027 + internal void send_bits(int value, int length) + { + int len = length; + unchecked + { + if (bi_valid > (int) Buf_size - len) + { + //int val = value; + // bi_buf |= (val << bi_valid); + + bi_buf |= (short)((value << bi_valid) & 0xffff); + //put_short(bi_buf); + pending[pendingCount++] = (byte) bi_buf; + pending[pendingCount++] = (byte) (bi_buf >> 8); + + + bi_buf = (short) ((uint) value >> (Buf_size - bi_valid)); + bi_valid += len - Buf_size; + } + else + { + // bi_buf |= (value) << bi_valid; + bi_buf |= (short)((value << bi_valid) & 0xffff); + bi_valid += len; + } + } + } +#pragma warning restore 675 + + // 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. + internal void _tr_align() + { + send_bits(STATIC_TREES << 1, 3); + send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); + + bi_flush(); + + // 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 + last_eob_len + 10 - bi_valid < 9) + { + send_bits(STATIC_TREES << 1, 3); + send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); + bi_flush(); + } + last_eob_len = 7; + } + + + // Save the match info and tally the frequency counts. Return true if + // the current block must be flushed. + internal bool _tr_tally(int dist, int lc) + { + pending[_distanceOffset + last_lit*2] = unchecked((byte) ((uint) dist >> 8)); + pending[_distanceOffset + last_lit*2 + 1] = unchecked((byte) dist); + pending[_lengthOffset + last_lit] = unchecked((byte) lc); + last_lit++; + + if (dist == 0) + { + // lc is the unmatched char + dyn_ltree[lc*2]++; + } + else + { + matches++; + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + dyn_ltree[(Tree.LengthCode[lc] + InternalConstants.LITERALS + 1)*2]++; + dyn_dtree[Tree.DistanceCode(dist)*2]++; + } + + if ((last_lit & 0x1fff) == 0 && (int) compressionLevel > 2) + { + // Compute an upper bound for the compressed length + int out_length = last_lit << 3; + int in_length = strstart - blockStart; + int dcode; + for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++) + { + out_length = + (int) (out_length + (int) dyn_dtree[dcode*2]*(5L + DeflateManager.ExtraDistanceBits[dcode])); + } + out_length >>= 3; + if ((matches < (last_lit/2)) && out_length < in_length/2) + return true; + } + + return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize); + // dinoch - wraparound? + // 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 + internal void send_compressed_block(short[] ltree, short[] dtree) + { + int distance; // distance of matched string + int lc; // match length or unmatched char (if dist == 0) + int lx = 0; // running index in l_buf + int code; // the code to send + int extra; // number of extra bits to send + + if (last_lit != 0) + { + do + { + int ix = _distanceOffset + lx*2; + distance = ((pending[ix] << 8) & 0xff00) | + (pending[ix + 1] & 0xff); + lc = (pending[_lengthOffset + lx]) & 0xff; + lx++; + + if (distance == 0) + { + send_code(lc, ltree); // send a literal byte + } + else + { + // literal or match pair + // Here, lc is the match length - MIN_MATCH + code = Tree.LengthCode[lc]; + + // send the length code + send_code(code + InternalConstants.LITERALS + 1, ltree); + extra = DeflateManager.ExtraLengthBits[code]; + if (extra != 0) + { + // send the extra length bits + lc -= Tree.LengthBase[code]; + send_bits(lc, extra); + } + distance--; // dist is now the match distance - 1 + code = Tree.DistanceCode(distance); + + // send the distance code + send_code(code, dtree); + + extra = DeflateManager.ExtraDistanceBits[code]; + if (extra != 0) + { + // send the extra distance bits + distance -= Tree.DistanceBase[code]; + send_bits(distance, extra); + } + } + + // Check that the overlay between pending and d_buf+l_buf is ok: + } while (lx < last_lit); + } + + send_code(END_BLOCK, ltree); + last_eob_len = ltree[END_BLOCK*2 + 1]; + } + + + // Set the data type to ASCII or BINARY, using a crude approximation: + // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + // IN assertion: the fields freq of dyn_ltree are set and the total of all + // frequencies does not exceed 64K (to fit in an int on 16 bit machines). + internal void set_data_type() + { + int n = 0; + int ascii_freq = 0; + int bin_freq = 0; + while (n < 7) + { + bin_freq += dyn_ltree[n*2]; + n++; + } + while (n < 128) + { + ascii_freq += dyn_ltree[n*2]; + n++; + } + while (n < InternalConstants.LITERALS) + { + bin_freq += dyn_ltree[n*2]; + n++; + } + data_type = (sbyte) (bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); + } + + + // Flush the bit buffer, keeping at most 7 bits in it. + internal void bi_flush() + { + if (bi_valid == 16) + { + pending[pendingCount++] = (byte) bi_buf; + pending[pendingCount++] = (byte) (bi_buf >> 8); + bi_buf = 0; + bi_valid = 0; + } + else if (bi_valid >= 8) + { + //put_byte((byte)bi_buf); + pending[pendingCount++] = (byte) bi_buf; + bi_buf >>= 8; + bi_valid -= 8; + } + } + + // Flush the bit buffer and align the output on a byte boundary + internal void bi_windup() + { + if (bi_valid > 8) + { + pending[pendingCount++] = (byte) bi_buf; + pending[pendingCount++] = (byte) (bi_buf >> 8); + } + else if (bi_valid > 0) + { + //put_byte((byte)bi_buf); + pending[pendingCount++] = (byte) bi_buf; + } + bi_buf = 0; + bi_valid = 0; + } + + // Copy a stored block, storing first the length and its + // one's complement if requested. + internal void copy_block(int buf, int len, bool header) + { + bi_windup(); // align on byte boundary + last_eob_len = 8; // enough lookahead for inflate + + if (header) + unchecked + { + //put_short((short)len); + pending[pendingCount++] = (byte) len; + pending[pendingCount++] = (byte) (len >> 8); + //put_short((short)~len); + pending[pendingCount++] = (byte) ~len; + pending[pendingCount++] = (byte) (~len >> 8); + } + + put_bytes(window, buf, len); + } + + internal void flush_block_only(bool eof) + { + _tr_flush_block(blockStart >= 0 ? blockStart : -1, strstart - blockStart, eof); + blockStart = strstart; + _codec.flush_pending(); + } + + // 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. + internal BlockState DeflateNone(FlushType flush) + { + // Stored blocks are limited to 0xffff bytes, pending is limited + // to pending_buf_size, and each stored block has a 5 byte header: + + int max_block_size = 0xffff; + int max_start; + + if (max_block_size > pending.Length - 5) + { + max_block_size = pending.Length - 5; + } + + // Copy as much as possible from input to output: + while (true) + { + // Fill the window as much as possible: + if (lookahead <= 1) + { + _fillWindow(); + if (lookahead == 0 && flush == FlushType.None) + return BlockState.NeedMore; + if (lookahead == 0) + break; // flush the current block + } + + strstart += lookahead; + lookahead = 0; + + // Emit a stored block if pending will be full: + max_start = blockStart + max_block_size; + if (strstart == 0 || strstart >= max_start) + { + // strstart == 0 is possible when wraparound on 16-bit machine + lookahead = (int) (strstart - max_start); + strstart = (int) max_start; + + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + return BlockState.NeedMore; + } + + // Flush if we may have to slide, otherwise block_start may become + // negative and the data will be gone: + if (strstart - blockStart >= w_size - MIN_LOOKAHEAD) + { + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + return BlockState.NeedMore; + } + } + + flush_block_only(flush == FlushType.Finish); + if (_codec.AvailableBytesOut == 0) + return (flush == FlushType.Finish) ? BlockState.FinishStarted : BlockState.NeedMore; + + return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + } + + + // Send a stored block + internal void _tr_stored_block(int buf, int stored_len, bool eof) + { + send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type + copy_block(buf, stored_len, true); // with header + } + + // Determine the best encoding for the current block: dynamic trees, static + // trees or store, and output the encoded block to the zip file. + internal void _tr_flush_block(int buf, int stored_len, bool eof) + { + int 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 (compressionLevel > 0) + { + // Check if the file is ascii or binary + if (data_type == Z_UNKNOWN) + set_data_type(); + + // Construct the literal and distance trees + treeLiterals.build_tree(this); + + treeDistances.build_tree(this); + + // 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 = BuildBlTree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb = (opt_len + 3 + 7) >> 3; + static_lenb = (static_len + 3 + 7) >> 3; + + if (static_lenb <= opt_lenb) + opt_lenb = static_lenb; + } + else + { + opt_lenb = static_lenb = stored_len + 5; // force a stored block + } + + if (stored_len + 4 <= opt_lenb && buf != -1) + { + // 4: two words for the lengths + // 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(buf, stored_len, eof); + } + else if (static_lenb == opt_lenb) + { + send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); + send_compressed_block(StaticTree.lengthAndLiteralsTreeCodes, StaticTree.distTreeCodes); + } + else + { + send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); + send_all_trees(treeLiterals.max_code + 1, treeDistances.max_code + 1, max_blindex + 1); + send_compressed_block(dyn_ltree, dyn_dtree); + } + + // The above check is made mod 2^32, for files larger than 512 MB + // and uLong implemented on 32 bits. + + _InitializeBlocks(); + + if (eof) + { + bi_windup(); + } + } + + // 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). + private void _fillWindow() + { + int n, m; + int p; + int more; // Amount of free space at the end of the window. + + do + { + more = (window_size - lookahead - strstart); + + // Deal with !@#$% 64K limit: + if (more == 0 && strstart == 0 && lookahead == 0) + { + more = w_size; + } + else if (more == -1) + { + // Very unlikely, but possible on 16 bit machine if strstart == 0 + // and lookahead == 1 (input done one 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. + } + else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) + { + Array.Copy(window, w_size, window, 0, w_size); + match_start -= w_size; + strstart -= w_size; // we now have strstart >= MAX_DIST + blockStart -= w_size; + + // 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.) + + n = hash_size; + p = n; + do + { + m = (head[--p] & 0xffff); + head[p] = (short) ((m >= w_size) ? (m - w_size) : 0); + } while (--n != 0); + + n = w_size; + p = n; + do + { + m = (prev[--p] & 0xffff); + prev[p] = (short) ((m >= w_size) ? (m - w_size) : 0); + // If n is not on any hash chain, prev[n] is garbage but + // its value will never be used. + } while (--n != 0); + more += w_size; + } + + if (_codec.AvailableBytesIn == 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. + + n = _codec.read_buf(window, strstart + lookahead, more); + lookahead += n; + + // Initialize the hash value now that we have some input: + if (lookahead >= MIN_MATCH) + { + ins_h = window[strstart] & 0xff; + ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; + } + // 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 (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0); + } + + // 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. + internal BlockState DeflateFast(FlushType flush) + { + // short hash_head = 0; // head of the hash chain + int hash_head = 0; // head of the hash chain + bool bflush; // set if current block must be flushed + + while (true) + { + // 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 (lookahead < MIN_LOOKAHEAD) + { + _fillWindow(); + if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) + { + return BlockState.NeedMore; + } + if (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 (lookahead >= MIN_MATCH) + { + ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short) strstart); + } + + // Find the longest match, discarding those <= prev_length. + // At this point we have always match_length < MIN_MATCH + + if (hash_head != 0L && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) + { + // 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 (compressionStrategy != CompressionStrategy.HuffmanOnly) + { + match_length = longest_match(hash_head); + } + // longest_match() sets match_start + } + if (match_length >= MIN_MATCH) + { + // check_match(strstart, match_start, match_length); + + bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if (match_length <= config.MaxLazy && lookahead >= MIN_MATCH) + { + match_length--; // string at strstart already in hash table + do + { + strstart++; + + ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short) strstart); + + // strstart never exceeds WSIZE-MAX_MATCH, so there are + // always MIN_MATCH bytes ahead. + } while (--match_length != 0); + strstart++; + } + else + { + strstart += match_length; + match_length = 0; + ins_h = window[strstart] & 0xff; + + ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; + // 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 + + bflush = _tr_tally(0, window[strstart] & 0xff); + lookahead--; + strstart++; + } + if (bflush) + { + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + return BlockState.NeedMore; + } + } + + flush_block_only(flush == FlushType.Finish); + if (_codec.AvailableBytesOut == 0) + { + if (flush == FlushType.Finish) + return BlockState.FinishStarted; + else + return BlockState.NeedMore; + } + return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + } + + // 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. + internal BlockState DeflateSlow(FlushType flush) + { + // short hash_head = 0; // head of hash chain + int hash_head = 0; // head of hash chain + bool bflush; // set if current block must be flushed + + // Process the input block. + while (true) + { + // 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 (lookahead < MIN_LOOKAHEAD) + { + _fillWindow(); + if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) + return BlockState.NeedMore; + + if (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 (lookahead >= MIN_MATCH) + { + ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short) strstart); + } + + // Find the longest match, discarding those <= prev_length. + prev_length = match_length; + prev_match = match_start; + match_length = MIN_MATCH - 1; + + if (hash_head != 0 && prev_length < config.MaxLazy && + ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) + { + // 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 (compressionStrategy != CompressionStrategy.HuffmanOnly) + { + match_length = longest_match(hash_head); + } + // longest_match() sets match_start + + if (match_length <= 5 && (compressionStrategy == CompressionStrategy.Filtered || + (match_length == MIN_MATCH && strstart - match_start > 4096))) + { + // If prev_match is also MIN_MATCH, match_start is garbage + // but we will ignore the current match anyway. + 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 (prev_length >= MIN_MATCH && match_length <= prev_length) + { + int max_insert = strstart + lookahead - MIN_MATCH; + // Do not insert strings in hash table beyond this. + + // check_match(strstart-1, prev_match, prev_length); + + bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); + + // 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. + lookahead -= (prev_length - 1); + prev_length -= 2; + do + { + if (++strstart <= max_insert) + { + ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & + hash_mask; + //prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short) strstart); + } + } while (--prev_length != 0); + match_available = 0; + match_length = MIN_MATCH - 1; + strstart++; + + if (bflush) + { + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + return BlockState.NeedMore; + } + } + else if (match_available != 0) + { + // 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. + + bflush = _tr_tally(0, window[strstart - 1] & 0xff); + + if (bflush) + { + flush_block_only(false); + } + strstart++; + lookahead--; + if (_codec.AvailableBytesOut == 0) + return BlockState.NeedMore; + } + else + { + // There is no previous match to compare with, wait for + // the next step to decide. + + match_available = 1; + strstart++; + lookahead--; + } + } + + if (match_available != 0) + { + bflush = _tr_tally(0, window[strstart - 1] & 0xff); + match_available = 0; + } + flush_block_only(flush == FlushType.Finish); + + if (_codec.AvailableBytesOut == 0) + { + if (flush == FlushType.Finish) + return BlockState.FinishStarted; + else + return BlockState.NeedMore; + } + + return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + } + + + internal int longest_match(int cur_match) + { + int chain_length = config.MaxChainLength; // max hash chain length + int scan = strstart; // current string + int match; // matched string + int len; // length of current match + int best_len = prev_length; // best match length so far + int limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; + + int niceLength = config.NiceLength; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0. + + int wmask = w_mask; + + int strend = strstart + MAX_MATCH; + byte scan_end1 = window[scan + best_len - 1]; + byte scan_end = window[scan + best_len]; + + // 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. + + // Do not waste too much time if we already have a good match: + if (prev_length >= config.GoodLength) + { + chain_length >>= 2; + } + + // Do not look for matches beyond the end of the input. This is necessary + // to make deflate deterministic. + if (niceLength > lookahead) + niceLength = lookahead; + + do + { + match = cur_match; + + // Skip to next match if the match length cannot increase + // or if the match length is less than 2: + if (window[match + best_len] != scan_end || + window[match + best_len - 1] != scan_end1 || + window[match] != window[scan] || + window[++match] != window[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++; + + // We check for insufficient lookahead only every 8th comparison; + // the 256th check will be made at strstart+258. + do + { + } while (window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && scan < strend); + + len = MAX_MATCH - (int) (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) + { + match_start = cur_match; + best_len = len; + if (len >= niceLength) + break; + scan_end1 = window[scan + best_len - 1]; + scan_end = window[scan + best_len]; + } + } while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0); + + if (best_len <= lookahead) + return best_len; + return lookahead; + } + + + private bool Rfc1950BytesEmitted = false; + private bool _WantRfc1950HeaderBytes = true; + + internal bool WantRfc1950HeaderBytes + { + get { return _WantRfc1950HeaderBytes; } + set { _WantRfc1950HeaderBytes = value; } + } + + + internal int Initialize(ZlibCodec codec, CompressionLevel level) + { + return Initialize(codec, level, ZlibConstants.WindowBitsMax); + } + + internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) + { + return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); + } + + internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits, + CompressionStrategy compressionStrategy) + { + return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); + } + + internal int Initialize(ZlibCodec codec, CompressionLevel level, int windowBits, int memLevel, + CompressionStrategy strategy) + { + _codec = codec; + _codec.Message = null; + + // validation + if (windowBits < 9 || windowBits > 15) + throw new ZlibException("windowBits must be in the range 9..15."); + + if (memLevel < 1 || memLevel > MEM_LEVEL_MAX) + throw new ZlibException(String.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX)); + + _codec.dstate = this; + + w_bits = windowBits; + w_size = 1 << w_bits; + w_mask = w_size - 1; + + hash_bits = memLevel + 7; + hash_size = 1 << hash_bits; + hash_mask = hash_size - 1; + hash_shift = ((hash_bits + MIN_MATCH - 1)/MIN_MATCH); + + window = new byte[w_size*2]; + prev = new short[w_size]; + head = new short[hash_size]; + + // for memLevel==8, this will be 16384, 16k + lit_bufsize = 1 << (memLevel + 6); + + // Use a single array as the buffer for data pending compression, + // the output distance codes, and the output length codes (aka tree). + // orig comment: This works just fine since the average + // output size for (length,distance) codes is <= 24 bits. + pending = new byte[lit_bufsize*4]; + _distanceOffset = lit_bufsize; + _lengthOffset = (1 + 2)*lit_bufsize; + + // So, for memLevel 8, the length of the pending buffer is 65536. 64k. + // The first 16k are pending bytes. + // The middle slice, of 32k, is used for distance codes. + // The final 16k are length codes. + + this.compressionLevel = level; + this.compressionStrategy = strategy; + + Reset(); + return ZlibConstants.Z_OK; + } + + + internal void Reset() + { + _codec.TotalBytesIn = _codec.TotalBytesOut = 0; + _codec.Message = null; + //strm.data_type = Z_UNKNOWN; + + pendingCount = 0; + nextPending = 0; + + Rfc1950BytesEmitted = false; + + status = (WantRfc1950HeaderBytes) ? INIT_STATE : BUSY_STATE; + _codec._Adler32 = Adler.Adler32(0, null, 0, 0); + + last_flush = (int) FlushType.None; + + _InitializeTreeData(); + _InitializeLazyMatch(); + } + + + internal int End() + { + if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) + { + return ZlibConstants.Z_STREAM_ERROR; + } + // Deallocate in reverse order of allocations: + pending = null; + head = null; + prev = null; + window = null; + // free + // dstate=null; + return status == BUSY_STATE ? ZlibConstants.Z_DATA_ERROR : ZlibConstants.Z_OK; + } + + + private void SetDeflater() + { + switch (config.Flavor) + { + case DeflateFlavor.Store: + DeflateFunction = DeflateNone; + break; + case DeflateFlavor.Fast: + DeflateFunction = DeflateFast; + break; + case DeflateFlavor.Slow: + DeflateFunction = DeflateSlow; + break; + } + } + + + internal int SetParams(CompressionLevel level, CompressionStrategy strategy) + { + int result = ZlibConstants.Z_OK; + + if (compressionLevel != level) + { + Config newConfig = Config.Lookup(level); + + // change in the deflate flavor (Fast vs slow vs none)? + if (newConfig.Flavor != config.Flavor && _codec.TotalBytesIn != 0) + { + // Flush the last buffer: + result = _codec.Deflate(FlushType.Partial); + } + + compressionLevel = level; + config = newConfig; + SetDeflater(); + } + + // no need to flush with change in strategy? Really? + compressionStrategy = strategy; + + return result; + } + + + internal int SetDictionary(byte[] dictionary) + { + int length = dictionary.Length; + int index = 0; + + if (dictionary == null || status != INIT_STATE) + throw new ZlibException("Stream error."); + + _codec._Adler32 = Adler.Adler32(_codec._Adler32, dictionary, 0, dictionary.Length); + + if (length < MIN_MATCH) + return ZlibConstants.Z_OK; + if (length > w_size - MIN_LOOKAHEAD) + { + length = w_size - MIN_LOOKAHEAD; + index = dictionary.Length - length; // use the tail of the dictionary + } + Array.Copy(dictionary, index, window, 0, length); + strstart = length; + blockStart = 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. + + ins_h = window[0] & 0xff; + ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask; + + for (int n = 0; n <= length - MIN_MATCH; n++) + { + ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + prev[n & w_mask] = head[ins_h]; + head[ins_h] = (short) n; + } + return ZlibConstants.Z_OK; + } + + + internal int Deflate(FlushType flush) + { + int old_flush; + + if (_codec.OutputBuffer == null || + (_codec.InputBuffer == null && _codec.AvailableBytesIn != 0) || + (status == FINISH_STATE && flush != FlushType.Finish)) + { + _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR)]; + throw new ZlibException(String.Format("Something is fishy. [{0}]", _codec.Message)); + //return ZlibConstants.Z_STREAM_ERROR; + } + if (_codec.AvailableBytesOut == 0) + { + _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; + throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); + //return ZlibConstants.Z_BUF_ERROR; + } + + old_flush = last_flush; + last_flush = (int) flush; + + // Write the zlib (rfc1950) header bytes + if (status == INIT_STATE) + { + int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8; + int level_flags = (((int) compressionLevel - 1) & 0xff) >> 1; + + if (level_flags > 3) + level_flags = 3; + header |= (level_flags << 6); + if (strstart != 0) + header |= PRESET_DICT; + header += 31 - (header%31); + + status = BUSY_STATE; + //putShortMSB(header); + unchecked + { + pending[pendingCount++] = (byte) (header >> 8); + pending[pendingCount++] = (byte) header; + } + // Save the adler32 of the preset dictionary: + if (strstart != 0) + { + ////putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); + //putShortMSB((int)((UInt64)_codec._Adler32 >> 16)); + //putShortMSB((int)(_codec._Adler32 & 0xffff)); + pending[pendingCount++] = (byte) ((_codec._Adler32 & 0xFF000000) >> 24); + pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x00FF0000) >> 16); + pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x0000FF00) >> 8); + pending[pendingCount++] = (byte) (_codec._Adler32 & 0x000000FF); + } + _codec._Adler32 = Adler.Adler32(0, null, 0, 0); + } + + // Flush as much pending output as possible + if (pendingCount != 0) + { + _codec.flush_pending(); + if (_codec.AvailableBytesOut == 0) + { + //System.out.println(" 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: + last_flush = -1; + return ZlibConstants.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_BUFF_ERROR. + } + else if (_codec.AvailableBytesIn == 0 && + (int) flush <= old_flush && + flush != FlushType.Finish) + { + // workitem 8557 + // Not sure why this needs to be an error. + // pendingCount == 0, which means there's nothing to deflate. + // And the caller has not asked for a FlushType.Finish, but... + // that seems very non-fatal. We can just say "OK" and do nthing. + + // _codec.Message = z_errmsg[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; + // throw new ZlibException("AvailableBytesIn == 0 && flush<=old_flush && flush != FlushType.Finish"); + + return ZlibConstants.Z_OK; + } + + // User must not provide more input after the first FINISH: + if (status == FINISH_STATE && _codec.AvailableBytesIn != 0) + { + _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; + throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); + } + + + // Start a new block or continue the current one. + if (_codec.AvailableBytesIn != 0 || lookahead != 0 || (flush != FlushType.None && status != FINISH_STATE)) + { + BlockState bstate = DeflateFunction(flush); + + if (bstate == BlockState.FinishStarted || bstate == BlockState.FinishDone) + { + status = FINISH_STATE; + } + if (bstate == BlockState.NeedMore || bstate == BlockState.FinishStarted) + { + if (_codec.AvailableBytesOut == 0) + { + last_flush = -1; // avoid BUF_ERROR next call, see above + } + return ZlibConstants.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 == BlockState.BlockDone) + { + if (flush == FlushType.Partial) + { + _tr_align(); + } + else + { + // FlushType.Full or FlushType.Sync + _tr_stored_block(0, 0, false); + // For a full flush, this empty block will be recognized + // as a special marker by inflate_sync(). + if (flush == FlushType.Full) + { + // clear hash (forget the history) + for (int i = 0; i < hash_size; i++) + head[i] = 0; + } + } + _codec.flush_pending(); + if (_codec.AvailableBytesOut == 0) + { + last_flush = -1; // avoid BUF_ERROR at next call, see above + return ZlibConstants.Z_OK; + } + } + } + + if (flush != FlushType.Finish) + return ZlibConstants.Z_OK; + + if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted) + return ZlibConstants.Z_STREAM_END; + + // Write the zlib trailer (adler32) + pending[pendingCount++] = (byte) ((_codec._Adler32 & 0xFF000000) >> 24); + pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x00FF0000) >> 16); + pending[pendingCount++] = (byte) ((_codec._Adler32 & 0x0000FF00) >> 8); + pending[pendingCount++] = (byte) (_codec._Adler32 & 0x000000FF); + //putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); + //putShortMSB((int)(_codec._Adler32 & 0xffff)); + + _codec.flush_pending(); + + // If avail_out is zero, the application will call deflate again + // to flush the rest. + + Rfc1950BytesEmitted = true; // write the trailer only once! + + return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/DeflateStream.cs b/src/SharpCompress/Compressor/Deflate/DeflateStream.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/DeflateStream.cs rename to src/SharpCompress/Compressor/Deflate/DeflateStream.cs index 8035c749..ccf88b31 100644 --- a/SharpCompress/Compressor/Deflate/DeflateStream.cs +++ b/src/SharpCompress/Compressor/Deflate/DeflateStream.cs @@ -1,336 +1,336 @@ -// DeflateStream.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009-2010 Dino Chiesa. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2010-February-05 08:49:04> -// -// ------------------------------------------------------------------ -// -// This module defines the DeflateStream class, which can be used as a replacement for -// the System.IO.Compression.DeflateStream class in the .NET BCL. -// -// ------------------------------------------------------------------ - - -using System; -using System.IO; - -namespace SharpCompress.Compressor.Deflate -{ - public class DeflateStream : Stream - { - private readonly ZlibBaseStream _baseStream; - private bool _disposed; - - - public DeflateStream(Stream stream, CompressionMode mode, - CompressionLevel level = CompressionLevel.Default, - bool leaveOpen = false) - { - _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen); - } - - #region Zlib properties - - /// - /// This property sets the flush behavior on the stream. - /// - /// See the ZLIB documentation for the meaning of the flush behavior. - /// - public virtual FlushType FlushMode - { - get { return (_baseStream._flushMode); } - set - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - _baseStream._flushMode = value; - } - } - - /// - /// The size of the working buffer for the compression codec. - /// - /// - /// - /// - /// The working buffer is used for all stream operations. The default size is - /// 1024 bytes. The minimum size is 128 bytes. You may get better performance - /// with a larger buffer. Then again, you might not. You would have to test - /// it. - /// - /// - /// - /// Set this before the first call to Read() or Write() on the - /// stream. If you try to set it afterwards, it will throw. - /// - /// - public int BufferSize - { - get { return _baseStream._bufferSize; } - set - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - if (_baseStream._workingBuffer != null) - throw new ZlibException("The working buffer is already set."); - if (value < ZlibConstants.WorkingBufferSizeMin) - throw new ZlibException( - String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, - ZlibConstants.WorkingBufferSizeMin)); - _baseStream._bufferSize = value; - } - } - - /// - /// The ZLIB strategy to be used during compression. - /// - /// - /// - /// By tweaking this parameter, you may be able to optimize the compression for - /// data with particular characteristics. - /// - public CompressionStrategy Strategy - { - get { return _baseStream.Strategy; } - set - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - _baseStream.Strategy = value; - } - } - - /// Returns the total number of bytes input so far. - public virtual long TotalIn - { - get { return _baseStream._z.TotalBytesIn; } - } - - /// Returns the total number of bytes output so far. - public virtual long TotalOut - { - get { return _baseStream._z.TotalBytesOut; } - } - - #endregion - - #region System.IO.Stream methods - - /// - /// Indicates whether the stream can be read. - /// - /// - /// The return value depends on whether the captive stream supports reading. - /// - public override bool CanRead - { - get - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - return _baseStream._stream.CanRead; - } - } - - /// - /// Indicates whether the stream supports Seek operations. - /// - /// - /// Always returns false. - /// - public override bool CanSeek - { - get { return false; } - } - - - /// - /// Indicates whether the stream can be written. - /// - /// - /// The return value depends on whether the captive stream supports writing. - /// - public override bool CanWrite - { - get - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - return _baseStream._stream.CanWrite; - } - } - - /// - /// Reading this property always throws a . - /// - public override long Length - { - get { throw new NotSupportedException(); } - } - - /// - /// The position of the stream pointer. - /// - /// - /// - /// Setting this property always throws a . Reading will return the total bytes - /// written out, if used in writing, or the total bytes read in, if used in - /// reading. The count may refer to compressed bytes or uncompressed bytes, - /// depending on how you've used the stream. - /// - public override long Position - { - get - { - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) - return _baseStream._z.TotalBytesOut; - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) - return _baseStream._z.TotalBytesIn; - return 0; - } - set { throw new NotSupportedException(); } - } - - /// - /// Dispose the stream. - /// - /// - /// This may or may not result in a Close() call on the captive stream. - /// See the constructors that have a leaveOpen parameter for more information. - /// - protected override void Dispose(bool disposing) - { - try - { - if (!_disposed) - { - if (disposing && (_baseStream != null)) - _baseStream.Dispose(); - _disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - - /// - /// Flush the stream. - /// - public override void Flush() - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - _baseStream.Flush(); - } - - /// - /// Read data from the stream. - /// - /// - /// - /// - /// If you wish to use the DeflateStream to compress data while - /// reading, you can create a DeflateStream with - /// CompressionMode.Compress, providing an uncompressed data stream. - /// Then call Read() on that DeflateStream, and the data read will be - /// compressed as you read. If you wish to use the DeflateStream to - /// decompress data while reading, you can create a DeflateStream with - /// CompressionMode.Decompress, providing a readable compressed data - /// stream. Then call Read() on that DeflateStream, and the data read - /// will be decompressed as you read. - /// - /// - /// - /// A DeflateStream can be used for Read() or Write(), but not both. - /// - /// - /// - /// The buffer into which the read data should be placed. - /// the offset within that data array to put the first byte read. - /// the number of bytes to read. - /// the number of bytes actually read - public override int Read(byte[] buffer, int offset, int count) - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - return _baseStream.Read(buffer, offset, count); - } - - - /// - /// Calling this method always throws a . - /// - /// this is irrelevant, since it will always throw! - /// this is irrelevant, since it will always throw! - /// irrelevant! - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Calling this method always throws a . - /// - /// this is irrelevant, since it will always throw! - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - /// - /// Write data to the stream. - /// - /// - /// - /// - /// If you wish to use the DeflateStream to compress data while - /// writing, you can create a DeflateStream with - /// CompressionMode.Compress, and a writable output stream. Then call - /// Write() on that DeflateStream, providing uncompressed data - /// as input. The data sent to the output stream will be the compressed form - /// of the data written. If you wish to use the DeflateStream to - /// decompress data while writing, you can create a DeflateStream with - /// CompressionMode.Decompress, and a writable output stream. Then - /// call Write() on that stream, providing previously compressed - /// data. The data sent to the output stream will be the decompressed form of - /// the data written. - /// - /// - /// - /// A DeflateStream can be used for Read() or Write(), - /// but not both. - /// - /// - /// - /// - /// The buffer holding data to write to the stream. - /// the offset within that data array to find the first byte to write. - /// the number of bytes to write. - public override void Write(byte[] buffer, int offset, int count) - { - if (_disposed) throw new ObjectDisposedException("DeflateStream"); - _baseStream.Write(buffer, offset, count); - } - - #endregion - - public MemoryStream InputBuffer - { - get - { - return new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn, - _baseStream._z.AvailableBytesIn); - } - } - } +// DeflateStream.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009-2010 Dino Chiesa. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2010-February-05 08:49:04> +// +// ------------------------------------------------------------------ +// +// This module defines the DeflateStream class, which can be used as a replacement for +// the System.IO.Compression.DeflateStream class in the .NET BCL. +// +// ------------------------------------------------------------------ + + +using System; +using System.IO; + +namespace SharpCompress.Compressor.Deflate +{ + public class DeflateStream : Stream + { + private readonly ZlibBaseStream _baseStream; + private bool _disposed; + + + public DeflateStream(Stream stream, CompressionMode mode, + CompressionLevel level = CompressionLevel.Default, + bool leaveOpen = false) + { + _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen); + } + + #region Zlib properties + + /// + /// This property sets the flush behavior on the stream. + /// + /// See the ZLIB documentation for the meaning of the flush behavior. + /// + public virtual FlushType FlushMode + { + get { return (_baseStream._flushMode); } + set + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + _baseStream._flushMode = value; + } + } + + /// + /// The size of the working buffer for the compression codec. + /// + /// + /// + /// + /// The working buffer is used for all stream operations. The default size is + /// 1024 bytes. The minimum size is 128 bytes. You may get better performance + /// with a larger buffer. Then again, you might not. You would have to test + /// it. + /// + /// + /// + /// Set this before the first call to Read() or Write() on the + /// stream. If you try to set it afterwards, it will throw. + /// + /// + public int BufferSize + { + get { return _baseStream._bufferSize; } + set + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + if (_baseStream._workingBuffer != null) + throw new ZlibException("The working buffer is already set."); + if (value < ZlibConstants.WorkingBufferSizeMin) + throw new ZlibException( + String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, + ZlibConstants.WorkingBufferSizeMin)); + _baseStream._bufferSize = value; + } + } + + /// + /// The ZLIB strategy to be used during compression. + /// + /// + /// + /// By tweaking this parameter, you may be able to optimize the compression for + /// data with particular characteristics. + /// + public CompressionStrategy Strategy + { + get { return _baseStream.Strategy; } + set + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + _baseStream.Strategy = value; + } + } + + /// Returns the total number of bytes input so far. + public virtual long TotalIn + { + get { return _baseStream._z.TotalBytesIn; } + } + + /// Returns the total number of bytes output so far. + public virtual long TotalOut + { + get { return _baseStream._z.TotalBytesOut; } + } + + #endregion + + #region System.IO.Stream methods + + /// + /// Indicates whether the stream can be read. + /// + /// + /// The return value depends on whether the captive stream supports reading. + /// + public override bool CanRead + { + get + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + return _baseStream._stream.CanRead; + } + } + + /// + /// Indicates whether the stream supports Seek operations. + /// + /// + /// Always returns false. + /// + public override bool CanSeek + { + get { return false; } + } + + + /// + /// Indicates whether the stream can be written. + /// + /// + /// The return value depends on whether the captive stream supports writing. + /// + public override bool CanWrite + { + get + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + return _baseStream._stream.CanWrite; + } + } + + /// + /// Reading this property always throws a . + /// + public override long Length + { + get { throw new NotSupportedException(); } + } + + /// + /// The position of the stream pointer. + /// + /// + /// + /// Setting this property always throws a . Reading will return the total bytes + /// written out, if used in writing, or the total bytes read in, if used in + /// reading. The count may refer to compressed bytes or uncompressed bytes, + /// depending on how you've used the stream. + /// + public override long Position + { + get + { + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) + return _baseStream._z.TotalBytesOut; + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) + return _baseStream._z.TotalBytesIn; + return 0; + } + set { throw new NotSupportedException(); } + } + + /// + /// Dispose the stream. + /// + /// + /// This may or may not result in a Close() call on the captive stream. + /// See the constructors that have a leaveOpen parameter for more information. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!_disposed) + { + if (disposing && (_baseStream != null)) + _baseStream.Dispose(); + _disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Flush the stream. + /// + public override void Flush() + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + _baseStream.Flush(); + } + + /// + /// Read data from the stream. + /// + /// + /// + /// + /// If you wish to use the DeflateStream to compress data while + /// reading, you can create a DeflateStream with + /// CompressionMode.Compress, providing an uncompressed data stream. + /// Then call Read() on that DeflateStream, and the data read will be + /// compressed as you read. If you wish to use the DeflateStream to + /// decompress data while reading, you can create a DeflateStream with + /// CompressionMode.Decompress, providing a readable compressed data + /// stream. Then call Read() on that DeflateStream, and the data read + /// will be decompressed as you read. + /// + /// + /// + /// A DeflateStream can be used for Read() or Write(), but not both. + /// + /// + /// + /// The buffer into which the read data should be placed. + /// the offset within that data array to put the first byte read. + /// the number of bytes to read. + /// the number of bytes actually read + public override int Read(byte[] buffer, int offset, int count) + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + return _baseStream.Read(buffer, offset, count); + } + + + /// + /// Calling this method always throws a . + /// + /// this is irrelevant, since it will always throw! + /// this is irrelevant, since it will always throw! + /// irrelevant! + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Calling this method always throws a . + /// + /// this is irrelevant, since it will always throw! + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Write data to the stream. + /// + /// + /// + /// + /// If you wish to use the DeflateStream to compress data while + /// writing, you can create a DeflateStream with + /// CompressionMode.Compress, and a writable output stream. Then call + /// Write() on that DeflateStream, providing uncompressed data + /// as input. The data sent to the output stream will be the compressed form + /// of the data written. If you wish to use the DeflateStream to + /// decompress data while writing, you can create a DeflateStream with + /// CompressionMode.Decompress, and a writable output stream. Then + /// call Write() on that stream, providing previously compressed + /// data. The data sent to the output stream will be the decompressed form of + /// the data written. + /// + /// + /// + /// A DeflateStream can be used for Read() or Write(), + /// but not both. + /// + /// + /// + /// + /// The buffer holding data to write to the stream. + /// the offset within that data array to find the first byte to write. + /// the number of bytes to write. + public override void Write(byte[] buffer, int offset, int count) + { + if (_disposed) throw new ObjectDisposedException("DeflateStream"); + _baseStream.Write(buffer, offset, count); + } + + #endregion + + public MemoryStream InputBuffer + { + get + { + return new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn, + _baseStream._z.AvailableBytesIn); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/FlushType.cs b/src/SharpCompress/Compressor/Deflate/FlushType.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/FlushType.cs rename to src/SharpCompress/Compressor/Deflate/FlushType.cs index 79b8403b..fd8d7b20 100644 --- a/SharpCompress/Compressor/Deflate/FlushType.cs +++ b/src/SharpCompress/Compressor/Deflate/FlushType.cs @@ -1,44 +1,44 @@ -namespace SharpCompress.Compressor.Deflate -{ - /// - /// Describes how to flush the current deflate operation. - /// - /// - /// The different FlushType values are useful when using a Deflate in a streaming application. - /// - public enum FlushType - { - /// No flush at all. - None = 0, - - /// Closes the current block, but doesn't flush it to - /// the output. Used internally only in hypothetical - /// scenarios. This was supposed to be removed by Zlib, but it is - /// still in use in some edge cases. - /// - Partial, - - /// - /// Use this during compression to specify that all pending output should be - /// flushed to the output buffer and the output should be aligned on a byte - /// boundary. You might use this in a streaming communication scenario, so that - /// the decompressor can get all input data available so far. When using this - /// with a ZlibCodec, AvailableBytesIn will be zero after the call if - /// enough output space has been provided before the call. Flushing will - /// degrade compression and so it should be used only when necessary. - /// - Sync, - - /// - /// Use this during compression to specify that all output should be flushed, as - /// with FlushType.Sync, but also, the compression state should be reset - /// so that decompression can restart from this point if previous compressed - /// data has been damaged or if random access is desired. Using - /// FlushType.Full too often can significantly degrade the compression. - /// - Full, - - /// Signals the end of the compression/decompression stream. - Finish, - } +namespace SharpCompress.Compressor.Deflate +{ + /// + /// Describes how to flush the current deflate operation. + /// + /// + /// The different FlushType values are useful when using a Deflate in a streaming application. + /// + public enum FlushType + { + /// No flush at all. + None = 0, + + /// Closes the current block, but doesn't flush it to + /// the output. Used internally only in hypothetical + /// scenarios. This was supposed to be removed by Zlib, but it is + /// still in use in some edge cases. + /// + Partial, + + /// + /// Use this during compression to specify that all pending output should be + /// flushed to the output buffer and the output should be aligned on a byte + /// boundary. You might use this in a streaming communication scenario, so that + /// the decompressor can get all input data available so far. When using this + /// with a ZlibCodec, AvailableBytesIn will be zero after the call if + /// enough output space has been provided before the call. Flushing will + /// degrade compression and so it should be used only when necessary. + /// + Sync, + + /// + /// Use this during compression to specify that all output should be flushed, as + /// with FlushType.Sync, but also, the compression state should be reset + /// so that decompression can restart from this point if previous compressed + /// data has been damaged or if random access is desired. Using + /// FlushType.Full too often can significantly degrade the compression. + /// + Full, + + /// Signals the end of the compression/decompression stream. + Finish, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/GZipStream.cs b/src/SharpCompress/Compressor/Deflate/GZipStream.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/GZipStream.cs rename to src/SharpCompress/Compressor/Deflate/GZipStream.cs index 8bee25a5..4f110da5 100644 --- a/SharpCompress/Compressor/Deflate/GZipStream.cs +++ b/src/SharpCompress/Compressor/Deflate/GZipStream.cs @@ -1,452 +1,452 @@ -// GZipStream.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2010-January-09 12:04:28> -// -// ------------------------------------------------------------------ -// -// This module defines the GZipStream class, which can be used as a replacement for -// the System.IO.Compression.GZipStream class in the .NET BCL. NB: The design is not -// completely OO clean: there is some intelligence in the ZlibBaseStream that reads the -// GZip header. -// -// ------------------------------------------------------------------ - - -using System; -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.Compressor.Deflate -{ - public class GZipStream : Stream - { - internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - public DateTime? LastModified { get; set; } - - private string comment; - private int crc32; - private string fileName; - - internal ZlibBaseStream BaseStream; - private bool disposed; - private bool firstReadDone; - private int headerByteCount; - - - public GZipStream(Stream stream, CompressionMode mode) - : this(stream, mode, CompressionLevel.Default, false) - { - } - - public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level) - : this(stream, mode, level, false) - { - } - - public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen) - : this(stream, mode, CompressionLevel.Default, leaveOpen) - { - } - - public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen) - { - BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, leaveOpen); - } - - #region Zlib properties - - public virtual FlushType FlushMode - { - get { return (BaseStream._flushMode); } - set - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - BaseStream._flushMode = value; - } - } - - public int BufferSize - { - get { return BaseStream._bufferSize; } - set - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - if (BaseStream._workingBuffer != null) - throw new ZlibException("The working buffer is already set."); - if (value < ZlibConstants.WorkingBufferSizeMin) - throw new ZlibException( - String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, - ZlibConstants.WorkingBufferSizeMin)); - BaseStream._bufferSize = value; - } - } - - - internal virtual long TotalIn - { - get { return BaseStream._z.TotalBytesIn; } - } - - internal virtual long TotalOut - { - get { return BaseStream._z.TotalBytesOut; } - } - - #endregion - - #region Stream methods - - /// - /// Indicates whether the stream can be read. - /// - /// - /// The return value depends on whether the captive stream supports reading. - /// - public override bool CanRead - { - get - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - return BaseStream._stream.CanRead; - } - } - - /// - /// Indicates whether the stream supports Seek operations. - /// - /// - /// Always returns false. - /// - public override bool CanSeek - { - get { return false; } - } - - - /// - /// Indicates whether the stream can be written. - /// - /// - /// The return value depends on whether the captive stream supports writing. - /// - public override bool CanWrite - { - get - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - return BaseStream._stream.CanWrite; - } - } - - /// - /// Reading this property always throws a . - /// - public override long Length - { - get { throw new NotSupportedException(); } - } - - /// - /// The position of the stream pointer. - /// - /// - /// - /// Setting this property always throws a . Reading will return the total bytes - /// written out, if used in writing, or the total bytes read in, if used in - /// reading. The count may refer to compressed bytes or uncompressed bytes, - /// depending on how you've used the stream. - /// - public override long Position - { - get - { - if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Writer) - return BaseStream._z.TotalBytesOut + headerByteCount; - if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Reader) - return BaseStream._z.TotalBytesIn + BaseStream._gzipHeaderByteCount; - return 0; - } - - set { throw new NotSupportedException(); } - } - - /// - /// Dispose the stream. - /// - /// - /// This may or may not result in a Close() call on the captive stream. - /// See the doc on constructors that take a leaveOpen parameter for more information. - /// - protected override void Dispose(bool disposing) - { - try - { - if (!disposed) - { - if (disposing && (BaseStream != null)) - { - BaseStream.Dispose(); - crc32 = BaseStream.Crc32; - } - disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - - /// - /// Flush the stream. - /// - public override void Flush() - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - BaseStream.Flush(); - } - - /// - /// Read and decompress data from the source stream. - /// - /// - /// - /// With a GZipStream, decompression is done through reading. - /// - /// - /// - /// - /// byte[] working = new byte[WORKING_BUFFER_SIZE]; - /// using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) - /// { - /// using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) - /// { - /// using (var output = System.IO.File.Create(_DecompressedFile)) - /// { - /// int n; - /// while ((n= decompressor.Read(working, 0, working.Length)) !=0) - /// { - /// output.Write(working, 0, n); - /// } - /// } - /// } - /// } - /// - /// - /// The buffer into which the decompressed data should be placed. - /// the offset within that data array to put the first byte read. - /// the number of bytes to read. - /// the number of bytes actually read - public override int Read(byte[] buffer, int offset, int count) - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - int n = BaseStream.Read(buffer, offset, count); - - // Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n); - // Console.WriteLine( Util.FormatByteArray(buffer, offset, n) ); - - if (!firstReadDone) - { - firstReadDone = true; - FileName = BaseStream._GzipFileName; - Comment = BaseStream._GzipComment; - } - return n; - } - - - /// - /// Calling this method always throws a . - /// - /// irrelevant; it will always throw! - /// irrelevant; it will always throw! - /// irrelevant! - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Calling this method always throws a . - /// - /// irrelevant; this method will always throw! - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - /// - /// Write data to the stream. - /// - /// - /// - /// - /// If you wish to use the GZipStream to compress data while writing, - /// you can create a GZipStream with CompressionMode.Compress, and a - /// writable output stream. Then call Write() on that GZipStream, - /// providing uncompressed data as input. The data sent to the output stream - /// will be the compressed form of the data written. - /// - /// - /// - /// A GZipStream can be used for Read() or Write(), but not - /// both. Writing implies compression. Reading implies decompression. - /// - /// - /// - /// The buffer holding data to write to the stream. - /// the offset within that data array to find the first byte to write. - /// the number of bytes to write. - public override void Write(byte[] buffer, int offset, int count) - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Undefined) - { - //Console.WriteLine("GZipStream: First write"); - if (BaseStream._wantCompress) - { - // first write in compression, therefore, emit the GZIP header - headerByteCount = EmitHeader(); - } - else - { - throw new InvalidOperationException(); - } - } - - BaseStream.Write(buffer, offset, count); - } - - #endregion - - public String Comment - { - get { return comment; } - set - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - comment = value; - } - } - - public String FileName - { - get { return fileName; } - set - { - if (disposed) - throw new ObjectDisposedException("GZipStream"); - fileName = value; - if (fileName == null) - return; - if (fileName.IndexOf("/") != -1) - { - fileName = fileName.Replace("/", "\\"); - } - if (fileName.EndsWith("\\")) - throw new InvalidOperationException("Illegal filename"); - - if (fileName.IndexOf("\\") != -1) - { - // trim any leading path - fileName = Path.GetFileName(fileName); - } - } - } - - public int Crc32 - { - get { return crc32; } - } - - - private int EmitHeader() - { - byte[] commentBytes = (Comment == null) ? null : ArchiveEncoding.Default.GetBytes(Comment); - byte[] filenameBytes = (FileName == null) ? null : ArchiveEncoding.Default.GetBytes(FileName); - - int cbLength = (Comment == null) ? 0 : commentBytes.Length + 1; - int fnLength = (FileName == null) ? 0 : filenameBytes.Length + 1; - - int bufferLength = 10 + cbLength + fnLength; - var header = new byte[bufferLength]; - int i = 0; - // ID - header[i++] = 0x1F; - header[i++] = 0x8B; - - // compression method - header[i++] = 8; - byte flag = 0; - if (Comment != null) - flag ^= 0x10; - if (FileName != null) - flag ^= 0x8; - - // flag - header[i++] = flag; - - // mtime - if (!LastModified.HasValue) - LastModified = DateTime.Now; - TimeSpan delta = LastModified.Value - UnixEpoch; - var timet = (Int32) delta.TotalSeconds; - Array.Copy(BitConverter.GetBytes(timet), 0, header, i, 4); - i += 4; - - // xflg - header[i++] = 0; // this field is totally useless - // OS - header[i++] = 0xFF; // 0xFF == unspecified - - // extra field length - only if FEXTRA is set, which it is not. - //header[i++]= 0; - //header[i++]= 0; - - // filename - if (fnLength != 0) - { - Array.Copy(filenameBytes, 0, header, i, fnLength - 1); - i += fnLength - 1; - header[i++] = 0; // terminate - } - - // comment - if (cbLength != 0) - { - Array.Copy(commentBytes, 0, header, i, cbLength - 1); - i += cbLength - 1; - header[i++] = 0; // terminate - } - - BaseStream._stream.Write(header, 0, header.Length); - - return header.Length; // bytes written - } - } +// GZipStream.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2010-January-09 12:04:28> +// +// ------------------------------------------------------------------ +// +// This module defines the GZipStream class, which can be used as a replacement for +// the System.IO.Compression.GZipStream class in the .NET BCL. NB: The design is not +// completely OO clean: there is some intelligence in the ZlibBaseStream that reads the +// GZip header. +// +// ------------------------------------------------------------------ + + +using System; +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Compressor.Deflate +{ + public class GZipStream : Stream + { + internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public DateTime? LastModified { get; set; } + + private string comment; + private int crc32; + private string fileName; + + internal ZlibBaseStream BaseStream; + private bool disposed; + private bool firstReadDone; + private int headerByteCount; + + + public GZipStream(Stream stream, CompressionMode mode) + : this(stream, mode, CompressionLevel.Default, false) + { + } + + public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level) + : this(stream, mode, level, false) + { + } + + public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen) + : this(stream, mode, CompressionLevel.Default, leaveOpen) + { + } + + public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen) + { + BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, leaveOpen); + } + + #region Zlib properties + + public virtual FlushType FlushMode + { + get { return (BaseStream._flushMode); } + set + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + BaseStream._flushMode = value; + } + } + + public int BufferSize + { + get { return BaseStream._bufferSize; } + set + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + if (BaseStream._workingBuffer != null) + throw new ZlibException("The working buffer is already set."); + if (value < ZlibConstants.WorkingBufferSizeMin) + throw new ZlibException( + String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, + ZlibConstants.WorkingBufferSizeMin)); + BaseStream._bufferSize = value; + } + } + + + internal virtual long TotalIn + { + get { return BaseStream._z.TotalBytesIn; } + } + + internal virtual long TotalOut + { + get { return BaseStream._z.TotalBytesOut; } + } + + #endregion + + #region Stream methods + + /// + /// Indicates whether the stream can be read. + /// + /// + /// The return value depends on whether the captive stream supports reading. + /// + public override bool CanRead + { + get + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + return BaseStream._stream.CanRead; + } + } + + /// + /// Indicates whether the stream supports Seek operations. + /// + /// + /// Always returns false. + /// + public override bool CanSeek + { + get { return false; } + } + + + /// + /// Indicates whether the stream can be written. + /// + /// + /// The return value depends on whether the captive stream supports writing. + /// + public override bool CanWrite + { + get + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + return BaseStream._stream.CanWrite; + } + } + + /// + /// Reading this property always throws a . + /// + public override long Length + { + get { throw new NotSupportedException(); } + } + + /// + /// The position of the stream pointer. + /// + /// + /// + /// Setting this property always throws a . Reading will return the total bytes + /// written out, if used in writing, or the total bytes read in, if used in + /// reading. The count may refer to compressed bytes or uncompressed bytes, + /// depending on how you've used the stream. + /// + public override long Position + { + get + { + if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Writer) + return BaseStream._z.TotalBytesOut + headerByteCount; + if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Reader) + return BaseStream._z.TotalBytesIn + BaseStream._gzipHeaderByteCount; + return 0; + } + + set { throw new NotSupportedException(); } + } + + /// + /// Dispose the stream. + /// + /// + /// This may or may not result in a Close() call on the captive stream. + /// See the doc on constructors that take a leaveOpen parameter for more information. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!disposed) + { + if (disposing && (BaseStream != null)) + { + BaseStream.Dispose(); + crc32 = BaseStream.Crc32; + } + disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Flush the stream. + /// + public override void Flush() + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + BaseStream.Flush(); + } + + /// + /// Read and decompress data from the source stream. + /// + /// + /// + /// With a GZipStream, decompression is done through reading. + /// + /// + /// + /// + /// byte[] working = new byte[WORKING_BUFFER_SIZE]; + /// using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) + /// { + /// using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) + /// { + /// using (var output = System.IO.File.Create(_DecompressedFile)) + /// { + /// int n; + /// while ((n= decompressor.Read(working, 0, working.Length)) !=0) + /// { + /// output.Write(working, 0, n); + /// } + /// } + /// } + /// } + /// + /// + /// The buffer into which the decompressed data should be placed. + /// the offset within that data array to put the first byte read. + /// the number of bytes to read. + /// the number of bytes actually read + public override int Read(byte[] buffer, int offset, int count) + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + int n = BaseStream.Read(buffer, offset, count); + + // Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n); + // Console.WriteLine( Util.FormatByteArray(buffer, offset, n) ); + + if (!firstReadDone) + { + firstReadDone = true; + FileName = BaseStream._GzipFileName; + Comment = BaseStream._GzipComment; + } + return n; + } + + + /// + /// Calling this method always throws a . + /// + /// irrelevant; it will always throw! + /// irrelevant; it will always throw! + /// irrelevant! + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Calling this method always throws a . + /// + /// irrelevant; this method will always throw! + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Write data to the stream. + /// + /// + /// + /// + /// If you wish to use the GZipStream to compress data while writing, + /// you can create a GZipStream with CompressionMode.Compress, and a + /// writable output stream. Then call Write() on that GZipStream, + /// providing uncompressed data as input. The data sent to the output stream + /// will be the compressed form of the data written. + /// + /// + /// + /// A GZipStream can be used for Read() or Write(), but not + /// both. Writing implies compression. Reading implies decompression. + /// + /// + /// + /// The buffer holding data to write to the stream. + /// the offset within that data array to find the first byte to write. + /// the number of bytes to write. + public override void Write(byte[] buffer, int offset, int count) + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Undefined) + { + //Console.WriteLine("GZipStream: First write"); + if (BaseStream._wantCompress) + { + // first write in compression, therefore, emit the GZIP header + headerByteCount = EmitHeader(); + } + else + { + throw new InvalidOperationException(); + } + } + + BaseStream.Write(buffer, offset, count); + } + + #endregion + + public String Comment + { + get { return comment; } + set + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + comment = value; + } + } + + public String FileName + { + get { return fileName; } + set + { + if (disposed) + throw new ObjectDisposedException("GZipStream"); + fileName = value; + if (fileName == null) + return; + if (fileName.IndexOf("/") != -1) + { + fileName = fileName.Replace("/", "\\"); + } + if (fileName.EndsWith("\\")) + throw new InvalidOperationException("Illegal filename"); + + if (fileName.IndexOf("\\") != -1) + { + // trim any leading path + fileName = Path.GetFileName(fileName); + } + } + } + + public int Crc32 + { + get { return crc32; } + } + + + private int EmitHeader() + { + byte[] commentBytes = (Comment == null) ? null : ArchiveEncoding.Default.GetBytes(Comment); + byte[] filenameBytes = (FileName == null) ? null : ArchiveEncoding.Default.GetBytes(FileName); + + int cbLength = (Comment == null) ? 0 : commentBytes.Length + 1; + int fnLength = (FileName == null) ? 0 : filenameBytes.Length + 1; + + int bufferLength = 10 + cbLength + fnLength; + var header = new byte[bufferLength]; + int i = 0; + // ID + header[i++] = 0x1F; + header[i++] = 0x8B; + + // compression method + header[i++] = 8; + byte flag = 0; + if (Comment != null) + flag ^= 0x10; + if (FileName != null) + flag ^= 0x8; + + // flag + header[i++] = flag; + + // mtime + if (!LastModified.HasValue) + LastModified = DateTime.Now; + TimeSpan delta = LastModified.Value - UnixEpoch; + var timet = (Int32) delta.TotalSeconds; + Array.Copy(BitConverter.GetBytes(timet), 0, header, i, 4); + i += 4; + + // xflg + header[i++] = 0; // this field is totally useless + // OS + header[i++] = 0xFF; // 0xFF == unspecified + + // extra field length - only if FEXTRA is set, which it is not. + //header[i++]= 0; + //header[i++]= 0; + + // filename + if (fnLength != 0) + { + Array.Copy(filenameBytes, 0, header, i, fnLength - 1); + i += fnLength - 1; + header[i++] = 0; // terminate + } + + // comment + if (cbLength != 0) + { + Array.Copy(commentBytes, 0, header, i, cbLength - 1); + i += cbLength - 1; + header[i++] = 0; // terminate + } + + BaseStream._stream.Write(header, 0, header.Length); + + return header.Length; // bytes written + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/InfTree.cs b/src/SharpCompress/Compressor/Deflate/InfTree.cs similarity index 98% rename from SharpCompress/Compressor/Deflate/InfTree.cs rename to src/SharpCompress/Compressor/Deflate/InfTree.cs index 055a1b79..8a304a4f 100644 --- a/SharpCompress/Compressor/Deflate/InfTree.cs +++ b/src/SharpCompress/Compressor/Deflate/InfTree.cs @@ -1,563 +1,563 @@ -// Inftree.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-October-28 12:43:54> -// -// ------------------------------------------------------------------ -// -// This module defines classes used in decompression. This code is derived -// from the jzlib implementation of zlib. In keeping with the license for jzlib, -// the copyright to that code is below. -// -// ------------------------------------------------------------------ -// -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -using System; - -namespace SharpCompress.Compressor.Deflate -{ - internal sealed class InfTree - { - private const int MANY = 1440; - - private const int Z_OK = 0; - private const int Z_STREAM_END = 1; - private const int Z_NEED_DICT = 2; - private const int Z_ERRNO = -1; - private const int Z_STREAM_ERROR = -2; - private const int Z_DATA_ERROR = -3; - private const int Z_MEM_ERROR = -4; - private const int Z_BUF_ERROR = -5; - private const int Z_VERSION_ERROR = -6; - - internal const int fixed_bl = 9; - internal const int fixed_bd = 5; - internal const int BMAX = 15; // maximum bit length of any code - - //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] fixed_tl = new[] - { - 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, - 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, - 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, - 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, - 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, - 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, - 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, - 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, - 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, - 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0 - , 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, - 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50 - , 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2 - , 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26 - , 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, - 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, - 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, - 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8 - , 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, - 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, - 8, 62, 0, 9, 220, 82, 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, 256, 0, 8, 81, - 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, - 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, - 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, - 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, - 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, - 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0 - , 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, - 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, - 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, - 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, - 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, - 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, - 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, - 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, - 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, - 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, - 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, - 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0 - , 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0 - , 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, - 0, 9, 222, 82, 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, 256, 0, 8, 80, 0, 8, - 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, - 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8 - , 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, - 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0 - , 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, - 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116 - , 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, - 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, - 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, - 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8 - , 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, - 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, - 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0 - , 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, - 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42 - , 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, - 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, - 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8 - , 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, - 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, - 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, 256, 0, 8, 81, 0, 8 - , 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, - 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, - 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, - 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, - 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, - 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8 - , 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, - 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, - 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, - 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0 - , 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, - 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, - 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, - 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, - 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8 - , 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, - 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, - 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0 - , 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, - 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, - 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143 - , 0, 8, 79, 0, 9, 255 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] fixed_td = new[] - { - 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, - 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33 - , - 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, - 80 - , 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, - 1537 - , 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92 - , 5 - , 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 - }; - - // Tables for deflate from PKZIP's appnote.txt. - //UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cplens = new[] - { - 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 - }; - - // see note #13 above about 258 - //UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cplext = new[] - { - 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, 112, 112 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cpdist = new[] - { - 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 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cpdext = new[] - { - 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 - }; - - // If BMAX needs to be larger than 16, then h and x[] should be uLong. - internal int[] c; // bit length count table - internal int[] hn; // hufts used in space - internal int[] r; // table entry for structure assignment - internal int[] u; // table stack - internal int[] v; // work area for huft_build - internal int[] x; // bit offsets, then code stack - - private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, - int[] v) - { - // Given a list of code lengths and a maximum table size, make a set of - // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - // if the given code set is incomplete (the tables are still built in this - // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - // lengths), or Z_MEM_ERROR if not enough memory. - - int a; // counter for codes of length k - int f; // i repeats in table every f entries - int g; // maximum code length - int h; // table level - int i; // counter, current code - int j; // counter - int k; // number of bits in current code - int l; // bits per table (returned in m) - int mask; // (1 << w) - 1, to avoid cc -O bug on HP - int p; // pointer into c[], b[], or v[] - int q; // points to current table - int w; // bits before this table == (l * h) - int xp; // pointer into x - int y; // number of dummy codes added - int z; // number of entries in current table - - // Generate counts for each bit length - - p = 0; - i = n; - do - { - c[b[bindex + p]]++; - p++; - i--; // assume all entries <= BMAX - } while (i != 0); - - if (c[0] == n) - { - // null input--all zero length codes - t[0] = -1; - m[0] = 0; - return Z_OK; - } - - // Find minimum and maximum length, bound *m by those - l = m[0]; - for (j = 1; j <= BMAX; j++) - if (c[j] != 0) - break; - k = j; // minimum code length - if (l < j) - { - l = j; - } - for (i = BMAX; i != 0; i--) - { - if (c[i] != 0) - break; - } - g = i; // maximum code length - if (l > i) - { - l = i; - } - m[0] = l; - - // Adjust last length count to fill out codes, if needed - for (y = 1 << j; j < i; j++, y <<= 1) - { - if ((y -= c[j]) < 0) - { - return Z_DATA_ERROR; - } - } - if ((y -= c[i]) < 0) - { - return Z_DATA_ERROR; - } - c[i] += y; - - // Generate starting offsets into the value table for each length - x[1] = j = 0; - p = 1; - xp = 2; - while (--i != 0) - { - // note that i == g from above - x[xp] = (j += c[p]); - xp++; - p++; - } - - // Make a table of values in order of bit lengths - i = 0; - p = 0; - do - { - if ((j = b[bindex + p]) != 0) - { - v[x[j]++] = i; - } - p++; - } while (++i < n); - n = x[g]; // set n to length of v - - // Generate the Huffman codes and for each, make the table entries - x[0] = i = 0; // first Huffman code is zero - p = 0; // grab values in bit order - h = -1; // no tables yet--level -1 - w = -l; // bits decoded == (l * h) - u[0] = 0; // just to keep compilers happy - q = 0; // ditto - z = 0; // ditto - - // go through the bit lengths (k already is bits in shortest code) - for (; k <= g; k++) - { - a = c[k]; - while (a-- != 0) - { - // here i is the Huffman code of length k bits for value *p - // make tables up to required level - while (k > w + l) - { - h++; - w += l; // previous table always l bits - // compute minimum size table less than or equal to l bits - z = g - w; - z = (z > l) ? l : z; // table size upper limit - if ((f = 1 << (j = k - w)) > a + 1) - { - // try a k-w bit table - // too few codes for k-w bit table - f -= (a + 1); // deduct codes from patterns left - xp = k; - if (j < z) - { - while (++j < z) - { - // try smaller tables up to z bits - if ((f <<= 1) <= c[++xp]) - break; // enough codes to use up j bits - f -= c[xp]; // else deduct codes from patterns - } - } - } - z = 1 << j; // table entries for j-bit table - - // allocate new table - if (hn[0] + z > MANY) - { - // (note: doesn't matter for fixed) - return Z_DATA_ERROR; // overflow of MANY - } - u[h] = q = hn[0]; // DEBUG - hn[0] += z; - - // connect to last table, if there is one - if (h != 0) - { - x[h] = i; // save pattern for backing up - r[0] = (sbyte) j; // bits in this table - r[1] = (sbyte) l; // bits to dump before this table - j = SharedUtils.URShift(i, (w - l)); - r[2] = (q - u[h - 1] - j); // offset to this table - Array.Copy(r, 0, hp, (u[h - 1] + j)*3, 3); // connect to last table - } - else - { - t[0] = q; // first table is returned result - } - } - - // set up table entry in r - r[1] = (sbyte) (k - w); - if (p >= n) - { - r[0] = 128 + 64; // out of values--invalid code - } - else if (v[p] < s) - { - r[0] = (sbyte) (v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block - r[2] = v[p++]; // simple code is just the value - } - else - { - r[0] = (sbyte) (e[v[p] - s] + 16 + 64); // non-simple--look up in lists - r[2] = d[v[p++] - s]; - } - - // fill code-like entries with r - f = 1 << (k - w); - for (j = SharedUtils.URShift(i, w); j < z; j += f) - { - Array.Copy(r, 0, hp, (q + j)*3, 3); - } - - // backwards increment the k-bit code i - for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1)) - { - i ^= j; - } - i ^= j; - - // backup over finished tables - mask = (1 << w) - 1; // needed on HP, cc -O bug - while ((i & mask) != x[h]) - { - h--; // don't need to update q - w -= l; - mask = (1 << w) - 1; - } - } - } - // Return Z_BUF_ERROR if we were given an incomplete table - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; - } - - internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z) - { - int result; - initWorkArea(19); - hn[0] = 0; - result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); - - if (result == Z_DATA_ERROR) - { - z.Message = "oversubscribed dynamic bit lengths tree"; - } - else if (result == Z_BUF_ERROR || bb[0] == 0) - { - z.Message = "incomplete dynamic bit lengths tree"; - result = Z_DATA_ERROR; - } - return result; - } - - internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, - ZlibCodec z) - { - int result; - - // build literal/length tree - initWorkArea(288); - hn[0] = 0; - result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); - if (result != Z_OK || bl[0] == 0) - { - if (result == Z_DATA_ERROR) - { - z.Message = "oversubscribed literal/length tree"; - } - else if (result != Z_MEM_ERROR) - { - z.Message = "incomplete literal/length tree"; - result = Z_DATA_ERROR; - } - return result; - } - - // build distance tree - initWorkArea(288); - result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); - - if (result != Z_OK || (bd[0] == 0 && nl > 257)) - { - if (result == Z_DATA_ERROR) - { - z.Message = "oversubscribed distance tree"; - } - else if (result == Z_BUF_ERROR) - { - z.Message = "incomplete distance tree"; - result = Z_DATA_ERROR; - } - else if (result != Z_MEM_ERROR) - { - z.Message = "empty distance tree with lengths"; - result = Z_DATA_ERROR; - } - return result; - } - - return Z_OK; - } - - internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z) - { - bl[0] = fixed_bl; - bd[0] = fixed_bd; - tl[0] = fixed_tl; - td[0] = fixed_td; - return Z_OK; - } - - private void initWorkArea(int vsize) - { - if (hn == null) - { - hn = new int[1]; - v = new int[vsize]; - c = new int[BMAX + 1]; - r = new int[3]; - u = new int[BMAX]; - x = new int[BMAX + 1]; - } - else - { - if (v.Length < vsize) - { - v = new int[vsize]; - } - Array.Clear(v, 0, vsize); - Array.Clear(c, 0, BMAX + 1); - r[0] = 0; - r[1] = 0; - r[2] = 0; - // for(int i=0; i +// +// ------------------------------------------------------------------ +// +// This module defines classes used in decompression. This code is derived +// from the jzlib implementation of zlib. In keeping with the license for jzlib, +// the copyright to that code is below. +// +// ------------------------------------------------------------------ +// +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +using System; + +namespace SharpCompress.Compressor.Deflate +{ + internal sealed class InfTree + { + private const int MANY = 1440; + + private const int Z_OK = 0; + private const int Z_STREAM_END = 1; + private const int Z_NEED_DICT = 2; + private const int Z_ERRNO = -1; + private const int Z_STREAM_ERROR = -2; + private const int Z_DATA_ERROR = -3; + private const int Z_MEM_ERROR = -4; + private const int Z_BUF_ERROR = -5; + private const int Z_VERSION_ERROR = -6; + + internal const int fixed_bl = 9; + internal const int fixed_bd = 5; + internal const int BMAX = 15; // maximum bit length of any code + + //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] fixed_tl = new[] + { + 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, + 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, + 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, + 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, + 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, + 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, + 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, + 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, + 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, + 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0 + , 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, + 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50 + , 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2 + , 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26 + , 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, + 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, + 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, + 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8 + , 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, + 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, + 8, 62, 0, 9, 220, 82, 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, 256, 0, 8, 81, + 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, + 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, + 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, + 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, + 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, + 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0 + , 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, + 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, + 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, + 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, + 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, + 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, + 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, + 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, + 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, + 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, + 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, + 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0 + , 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0 + , 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, + 0, 9, 222, 82, 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, 256, 0, 8, 80, 0, 8, + 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, + 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8 + , 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, + 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0 + , 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, + 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116 + , 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, + 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, + 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, + 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8 + , 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, + 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, + 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0 + , 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, + 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42 + , 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, + 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, + 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8 + , 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, + 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, + 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, 256, 0, 8, 81, 0, 8 + , 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, + 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, + 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, + 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, + 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, + 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8 + , 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, + 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, + 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, + 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0 + , 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, + 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, + 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, + 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, + 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8 + , 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, + 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, + 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0 + , 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, + 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, + 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143 + , 0, 8, 79, 0, 9, 255 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] fixed_td = new[] + { + 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, + 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33 + , + 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, + 80 + , 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, + 1537 + , 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92 + , 5 + , 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 + }; + + // Tables for deflate from PKZIP's appnote.txt. + //UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cplens = new[] + { + 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 + }; + + // see note #13 above about 258 + //UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cplext = new[] + { + 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, 112, 112 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cpdist = new[] + { + 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 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cpdext = new[] + { + 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 + }; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + internal int[] c; // bit length count table + internal int[] hn; // hufts used in space + internal int[] r; // table entry for structure assignment + internal int[] u; // table stack + internal int[] v; // work area for huft_build + internal int[] x; // bit offsets, then code stack + + private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, + int[] v) + { + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + // lengths), or Z_MEM_ERROR if not enough memory. + + int a; // counter for codes of length k + int f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + int i; // counter, current code + int j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + int mask; // (1 << w) - 1, to avoid cc -O bug on HP + int p; // pointer into c[], b[], or v[] + int q; // points to current table + int w; // bits before this table == (l * h) + int xp; // pointer into x + int y; // number of dummy codes added + int z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; + i = n; + do + { + c[b[bindex + p]]++; + p++; + i--; // assume all entries <= BMAX + } while (i != 0); + + if (c[0] == n) + { + // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } + + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) + if (c[j] != 0) + break; + k = j; // minimum code length + if (l < j) + { + l = j; + } + for (i = BMAX; i != 0; i--) + { + if (c[i] != 0) + break; + } + g = i; // maximum code length + if (l > i) + { + l = i; + } + m[0] = l; + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1) + { + if ((y -= c[j]) < 0) + { + return Z_DATA_ERROR; + } + } + if ((y -= c[i]) < 0) + { + return Z_DATA_ERROR; + } + c[i] += y; + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; + xp = 2; + while (--i != 0) + { + // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; + p = 0; + do + { + if ((j = b[bindex + p]) != 0) + { + v[x[j]++] = i; + } + p++; + } while (++i < n); + n = x[g]; // set n to length of v + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++) + { + a = c[k]; + while (a-- != 0) + { + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l) + { + h++; + w += l; // previous table always l bits + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if ((f = 1 << (j = k - w)) > a + 1) + { + // try a k-w bit table + // too few codes for k-w bit table + f -= (a + 1); // deduct codes from patterns left + xp = k; + if (j < z) + { + while (++j < z) + { + // try smaller tables up to z bits + if ((f <<= 1) <= c[++xp]) + break; // enough codes to use up j bits + f -= c[xp]; // else deduct codes from patterns + } + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (hn[0] + z > MANY) + { + // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + } + u[h] = q = hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if (h != 0) + { + x[h] = i; // save pattern for backing up + r[0] = (sbyte) j; // bits in this table + r[1] = (sbyte) l; // bits to dump before this table + j = SharedUtils.URShift(i, (w - l)); + r[2] = (q - u[h - 1] - j); // offset to this table + Array.Copy(r, 0, hp, (u[h - 1] + j)*3, 3); // connect to last table + } + else + { + t[0] = q; // first table is returned result + } + } + + // set up table entry in r + r[1] = (sbyte) (k - w); + if (p >= n) + { + r[0] = 128 + 64; // out of values--invalid code + } + else if (v[p] < s) + { + r[0] = (sbyte) (v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block + r[2] = v[p++]; // simple code is just the value + } + else + { + r[0] = (sbyte) (e[v[p] - s] + 16 + 64); // non-simple--look up in lists + r[2] = d[v[p++] - s]; + } + + // fill code-like entries with r + f = 1 << (k - w); + for (j = SharedUtils.URShift(i, w); j < z; j += f) + { + Array.Copy(r, 0, hp, (q + j)*3, 3); + } + + // backwards increment the k-bit code i + for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1)) + { + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]) + { + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + + internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z) + { + int result; + initWorkArea(19); + hn[0] = 0; + result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + + if (result == Z_DATA_ERROR) + { + z.Message = "oversubscribed dynamic bit lengths tree"; + } + else if (result == Z_BUF_ERROR || bb[0] == 0) + { + z.Message = "incomplete dynamic bit lengths tree"; + result = Z_DATA_ERROR; + } + return result; + } + + internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, + ZlibCodec z) + { + int result; + + // build literal/length tree + initWorkArea(288); + hn[0] = 0; + result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); + if (result != Z_OK || bl[0] == 0) + { + if (result == Z_DATA_ERROR) + { + z.Message = "oversubscribed literal/length tree"; + } + else if (result != Z_MEM_ERROR) + { + z.Message = "incomplete literal/length tree"; + result = Z_DATA_ERROR; + } + return result; + } + + // build distance tree + initWorkArea(288); + result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); + + if (result != Z_OK || (bd[0] == 0 && nl > 257)) + { + if (result == Z_DATA_ERROR) + { + z.Message = "oversubscribed distance tree"; + } + else if (result == Z_BUF_ERROR) + { + z.Message = "incomplete distance tree"; + result = Z_DATA_ERROR; + } + else if (result != Z_MEM_ERROR) + { + z.Message = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; + } + + return Z_OK; + } + + internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z) + { + bl[0] = fixed_bl; + bd[0] = fixed_bd; + tl[0] = fixed_tl; + td[0] = fixed_td; + return Z_OK; + } + + private void initWorkArea(int vsize) + { + if (hn == null) + { + hn = new int[1]; + v = new int[vsize]; + c = new int[BMAX + 1]; + r = new int[3]; + u = new int[BMAX]; + x = new int[BMAX + 1]; + } + else + { + if (v.Length < vsize) + { + v = new int[vsize]; + } + Array.Clear(v, 0, vsize); + Array.Clear(c, 0, BMAX + 1); + r[0] = 0; + r[1] = 0; + r[2] = 0; + // for(int i=0; i -// -// ------------------------------------------------------------------ -// -// This module defines classes for decompression. This code is derived -// from the jzlib implementation of zlib, but significantly modified. -// The object model is not the same, and many of the behaviors are -// different. Nonetheless, in keeping with the license for jzlib, I am -// reproducing the copyright to that code here. -// -// ------------------------------------------------------------------ -// -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -using System; - -namespace SharpCompress.Compressor.Deflate -{ - internal sealed class InflateBlocks - { - private const int MANY = 1440; - - // Table for deflate from PKZIP's appnote.txt. - internal static readonly int[] border = new[] {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - internal ZlibCodec _codec; // pointer back to this zlib stream - internal int[] bb = new int[1]; // bit length tree depth - - // mode independent information - internal int bitb; // bit buffer - internal int bitk; // bits in bit buffer - internal int[] blens; // bit lengths of codes - internal uint check; // check on output - internal Object checkfn; // check function - internal InflateCodes codes = new InflateCodes(); // if CODES, current state - internal int end; // one byte after sliding window - internal int[] hufts; // single malloc for tree space - internal int index; // index into blens (or border) - internal InfTree inftree = new InfTree(); - internal int last; // true if this block is the last block - internal int left; // if STORED, bytes left to copy - private InflateBlockMode mode; // current inflate_block mode - internal int readAt; // window read pointer - internal int table; // table lengths (14 bits) - internal int[] tb = new int[1]; // bit length decoding tree - internal byte[] window; // sliding window - internal int writeAt; // window write pointer - - internal InflateBlocks(ZlibCodec codec, Object checkfn, int w) - { - _codec = codec; - hufts = new int[MANY*3]; - window = new byte[w]; - end = w; - this.checkfn = checkfn; - mode = InflateBlockMode.TYPE; - Reset(); - } - - internal uint Reset() - { - uint oldCheck = check; - mode = InflateBlockMode.TYPE; - bitk = 0; - bitb = 0; - readAt = writeAt = 0; - - if (checkfn != null) - _codec._Adler32 = check = Adler.Adler32(0, null, 0, 0); - return oldCheck; - } - - - internal int Process(int r) - { - int t; // temporary storage - int b; // bit buffer - int k; // bits in bit buffer - int p; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - - // copy input/output information to locals (UPDATE macro restores) - - p = _codec.NextIn; - n = _codec.AvailableBytesIn; - b = bitb; - k = bitk; - - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - - - // process input based on current state - while (true) - { - switch (mode) - { - case InflateBlockMode.TYPE: - - while (k < (3)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - t = (b & 7); - last = t & 1; - - switch ((uint) t >> 1) - { - case 0: // stored - b >>= 3; - k -= (3); - t = k & 7; // go to byte boundary - b >>= t; - k -= t; - mode = InflateBlockMode.LENS; // get length of stored block - break; - - case 1: // fixed - var bl = new int[1]; - var bd = new int[1]; - var tl = new int[1][]; - var td = new int[1][]; - InfTree.inflate_trees_fixed(bl, bd, tl, td, _codec); - codes.Init(bl[0], bd[0], tl[0], 0, td[0], 0); - b >>= 3; - k -= 3; - mode = InflateBlockMode.CODES; - break; - - case 2: // dynamic - b >>= 3; - k -= 3; - mode = InflateBlockMode.TABLE; - break; - - case 3: // illegal - b >>= 3; - k -= 3; - mode = InflateBlockMode.BAD; - _codec.Message = "invalid block type"; - r = ZlibConstants.Z_DATA_ERROR; - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - break; - - case InflateBlockMode.LENS: - - while (k < (32)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - ; - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - mode = InflateBlockMode.BAD; - _codec.Message = "invalid stored block lengths"; - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - left = (b & 0xffff); - b = k = 0; // dump bits - mode = left != 0 - ? InflateBlockMode.STORED - : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE); - break; - - case InflateBlockMode.STORED: - if (n == 0) - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - if (m == 0) - { - if (q == end && readAt != 0) - { - q = 0; - m = (q < readAt ? readAt - q - 1 : end - q); - } - if (m == 0) - { - writeAt = q; - r = Flush(r); - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - if (q == end && readAt != 0) - { - q = 0; - m = (q < readAt ? readAt - q - 1 : end - q); - } - if (m == 0) - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - } - } - r = ZlibConstants.Z_OK; - - t = left; - if (t > n) - t = n; - if (t > m) - t = m; - Array.Copy(_codec.InputBuffer, p, window, q, t); - p += t; - n -= t; - q += t; - m -= t; - if ((left -= t) != 0) - break; - mode = last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE; - break; - - case InflateBlockMode.TABLE: - - while (k < (14)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - table = t = (b & 0x3fff); - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - mode = InflateBlockMode.BAD; - _codec.Message = "too many length or distance symbols"; - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (blens == null || blens.Length < t) - { - blens = new int[t]; - } - else - { - Array.Clear(blens, 0, t); - // for (int i = 0; i < t; i++) - // { - // blens[i] = 0; - // } - } - - b >>= 14; - k -= 14; - - - index = 0; - mode = InflateBlockMode.BTREE; - goto case InflateBlockMode.BTREE; - - case InflateBlockMode.BTREE: - while (index < 4 + (table >> 10)) - { - while (k < (3)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - blens[border[index++]] = b & 7; - - b >>= 3; - k -= 3; - } - - while (index < 19) - { - blens[border[index++]] = 0; - } - - bb[0] = 7; - t = inftree.inflate_trees_bits(blens, bb, tb, hufts, _codec); - if (t != ZlibConstants.Z_OK) - { - r = t; - if (r == ZlibConstants.Z_DATA_ERROR) - { - blens = null; - mode = InflateBlockMode.BAD; - } - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - index = 0; - mode = InflateBlockMode.DTREE; - goto case InflateBlockMode.DTREE; - - case InflateBlockMode.DTREE: - while (true) - { - t = table; - if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) - { - break; - } - - int i, j, c; - - t = bb[0]; - - while (k < t) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - t = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t]))*3 + 1]; - c = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t]))*3 + 2]; - - if (c < 16) - { - b >>= t; - k -= t; - blens[index++] = c; - } - else - { - // c == 16..18 - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - - while (k < (t + i)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - b >>= t; - k -= t; - - j += (b & InternalInflateConstants.InflateMask[i]); - - b >>= i; - k -= i; - - i = index; - t = table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) - { - blens = null; - mode = InflateBlockMode.BAD; - _codec.Message = "invalid bit length repeat"; - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - c = (c == 16) ? blens[i - 1] : 0; - do - { - blens[i++] = c; - } while (--j != 0); - index = i; - } - } - - tb[0] = -1; - { - var bl = new[] {9}; // must be <= 9 for lookahead assumptions - var bd = new[] {6}; // must be <= 9 for lookahead assumptions - var tl = new int[1]; - var td = new int[1]; - - t = table; - t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl, bd, tl, - td, hufts, _codec); - - if (t != ZlibConstants.Z_OK) - { - if (t == ZlibConstants.Z_DATA_ERROR) - { - blens = null; - mode = InflateBlockMode.BAD; - } - r = t; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - codes.Init(bl[0], bd[0], hufts, tl[0], hufts, td[0]); - } - mode = InflateBlockMode.CODES; - goto case InflateBlockMode.CODES; - - case InflateBlockMode.CODES: - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - - r = codes.Process(this, r); - if (r != ZlibConstants.Z_STREAM_END) - { - return Flush(r); - } - - r = ZlibConstants.Z_OK; - p = _codec.NextIn; - n = _codec.AvailableBytesIn; - b = bitb; - k = bitk; - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - - if (last == 0) - { - mode = InflateBlockMode.TYPE; - break; - } - mode = InflateBlockMode.DRY; - goto case InflateBlockMode.DRY; - - case InflateBlockMode.DRY: - writeAt = q; - r = Flush(r); - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - if (readAt != writeAt) - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - mode = InflateBlockMode.DONE; - goto case InflateBlockMode.DONE; - - case InflateBlockMode.DONE: - r = ZlibConstants.Z_STREAM_END; - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - - case InflateBlockMode.BAD: - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - - - default: - r = ZlibConstants.Z_STREAM_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - } - } - - - internal void Free() - { - Reset(); - window = null; - hufts = null; - } - - internal void SetDictionary(byte[] d, int start, int n) - { - Array.Copy(d, start, window, 0, n); - readAt = writeAt = n; - } - - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. - internal int SyncPoint() - { - return mode == InflateBlockMode.LENS ? 1 : 0; - } - - // copy as much as possible from the sliding window to the output area - internal int Flush(int r) - { - int nBytes; - - for (int pass = 0; pass < 2; pass++) - { - if (pass == 0) - { - // compute number of bytes to copy as far as end of window - nBytes = ((readAt <= writeAt ? writeAt : end) - readAt); - } - else - { - // compute bytes to copy - nBytes = writeAt - readAt; - } - - // workitem 8870 - if (nBytes == 0) - { - if (r == ZlibConstants.Z_BUF_ERROR) - r = ZlibConstants.Z_OK; - return r; - } - - if (nBytes > _codec.AvailableBytesOut) - nBytes = _codec.AvailableBytesOut; - - if (nBytes != 0 && r == ZlibConstants.Z_BUF_ERROR) - r = ZlibConstants.Z_OK; - - // update counters - _codec.AvailableBytesOut -= nBytes; - _codec.TotalBytesOut += nBytes; - - // update check information - if (checkfn != null) - _codec._Adler32 = check = Adler.Adler32(check, window, readAt, nBytes); - - // copy as far as end of window - Array.Copy(window, readAt, _codec.OutputBuffer, _codec.NextOut, nBytes); - _codec.NextOut += nBytes; - readAt += nBytes; - - // see if more to copy at beginning of window - if (readAt == end && pass == 0) - { - // wrap pointers - readAt = 0; - if (writeAt == end) - writeAt = 0; - } - else pass++; - } - - // done - return r; - } - - #region Nested type: InflateBlockMode - - private enum InflateBlockMode - { - TYPE = 0, // get type bits (3, including end bit) - LENS = 1, // get lengths for stored - STORED = 2, // processing stored block - TABLE = 3, // get table lengths - BTREE = 4, // get bit lengths tree for a dynamic block - DTREE = 5, // get length, distance trees for a dynamic block - CODES = 6, // processing fixed or dynamic block - DRY = 7, // output remaining window bytes - DONE = 8, // finished last block, done - BAD = 9, // ot a data error--stuck here - } - - #endregion - } - - - internal static class InternalInflateConstants - { - // And'ing with mask[n] masks the lower n bits - internal static readonly int[] InflateMask = new[] - { - 0x00000000, 0x00000001, 0x00000003, 0x00000007, - 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, - 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, - 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff - }; - } - - - internal sealed class InflateCodes - { - // waiting for "i:"=input, - // "o:"=output, - // "x:"=nothing - private const int START = 0; // x: set up for LEN - private const int LEN = 1; // i: get length/literal/eob next - private const int LENEXT = 2; // i: getting length extra (have base) - private const int DIST = 3; // i: get distance next - private const int DISTEXT = 4; // i: getting distance extra - private const int COPY = 5; // o: copying bytes in window, waiting for space - private const int LIT = 6; // o: got literal, waiting for output space - private const int WASH = 7; // o: got eob, possibly still output waiting - private const int END = 8; // x: got eob and all data flushed - private const int BADCODE = 9; // x: got error - - // if EXT or COPY, where and how much - internal int bitsToGet; // bits to get for extra - internal byte dbits; // dtree bits decoder per branch - internal int dist; // distance back to copy from - internal int[] dtree; // distance tree - internal int dtree_index; // distance tree - - internal byte lbits; // ltree bits decoded per branch - internal int len; - internal int lit; - internal int[] ltree; // literal/length/eob tree - internal int ltree_index; // literal/length/eob tree - internal int mode; // current inflate_codes mode - internal int need; // bits needed - internal int[] tree; // pointer into tree - internal int tree_index; - - internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) - { - mode = START; - lbits = (byte) bl; - dbits = (byte) bd; - ltree = tl; - ltree_index = tl_index; - dtree = td; - dtree_index = td_index; - tree = null; - } - - internal int Process(InflateBlocks blocks, int r) - { - int j; // temporary storage - int tindex; // temporary pointer - int e; // extra bits or operation - int b = 0; // bit buffer - int k = 0; // bits in bit buffer - int p = 0; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - int f; // pointer to copy strings from - - ZlibCodec z = blocks._codec; - - // copy input/output information to locals (UPDATE macro restores) - p = z.NextIn; - n = z.AvailableBytesIn; - b = blocks.bitb; - k = blocks.bitk; - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - // process input and output based on current state - while (true) - { - switch (mode) - { - // waiting for "i:"=input, "o:"=output, "x:"=nothing - case START: // x: set up for LEN - if (m >= 258 && n >= 10) - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z); - - p = z.NextIn; - n = z.AvailableBytesIn; - b = blocks.bitb; - k = blocks.bitk; - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - if (r != ZlibConstants.Z_OK) - { - mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE; - break; - } - } - need = lbits; - tree = ltree; - tree_index = ltree_index; - - mode = LEN; - goto case LEN; - - case LEN: // i: get length/literal/eob next - j = need; - - while (k < j) - { - if (n != 0) - r = ZlibConstants.Z_OK; - else - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j]))*3; - - b >>= (tree[tindex + 1]); - k -= (tree[tindex + 1]); - - e = tree[tindex]; - - if (e == 0) - { - // literal - lit = tree[tindex + 2]; - mode = LIT; - break; - } - if ((e & 16) != 0) - { - // length - bitsToGet = e & 15; - len = tree[tindex + 2]; - mode = LENEXT; - break; - } - if ((e & 64) == 0) - { - // next table - need = e; - tree_index = tindex/3 + tree[tindex + 2]; - break; - } - if ((e & 32) != 0) - { - // end of block - mode = WASH; - break; - } - mode = BADCODE; // invalid code - z.Message = "invalid literal/length code"; - r = ZlibConstants.Z_DATA_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - - case LENEXT: // i: getting length extra (have base) - j = bitsToGet; - - while (k < j) - { - if (n != 0) - r = ZlibConstants.Z_OK; - else - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - len += (b & InternalInflateConstants.InflateMask[j]); - - b >>= j; - k -= j; - - need = dbits; - tree = dtree; - tree_index = dtree_index; - mode = DIST; - goto case DIST; - - case DIST: // i: get distance next - j = need; - - while (k < j) - { - if (n != 0) - r = ZlibConstants.Z_OK; - else - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j]))*3; - - b >>= tree[tindex + 1]; - k -= tree[tindex + 1]; - - e = (tree[tindex]); - if ((e & 0x10) != 0) - { - // distance - bitsToGet = e & 15; - dist = tree[tindex + 2]; - mode = DISTEXT; - break; - } - if ((e & 64) == 0) - { - // next table - need = e; - tree_index = tindex/3 + tree[tindex + 2]; - break; - } - mode = BADCODE; // invalid code - z.Message = "invalid distance code"; - r = ZlibConstants.Z_DATA_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - - case DISTEXT: // i: getting distance extra - j = bitsToGet; - - while (k < j) - { - if (n != 0) - r = ZlibConstants.Z_OK; - else - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - dist += (b & InternalInflateConstants.InflateMask[j]); - - b >>= j; - k -= j; - - mode = COPY; - goto case COPY; - - case COPY: // o: copying bytes in window, waiting for space - f = q - dist; - while (f < 0) - { - // modulo window size-"while" instead - f += blocks.end; // of "if" handles invalid distances - } - while (len != 0) - { - if (m == 0) - { - if (q == blocks.end && blocks.readAt != 0) - { - q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - } - if (m == 0) - { - blocks.writeAt = q; - r = blocks.Flush(r); - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - if (q == blocks.end && blocks.readAt != 0) - { - q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - } - - if (m == 0) - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - } - } - - blocks.window[q++] = blocks.window[f++]; - m--; - - if (f == blocks.end) - f = 0; - len--; - } - mode = START; - break; - - case LIT: // o: got literal, waiting for output space - if (m == 0) - { - if (q == blocks.end && blocks.readAt != 0) - { - q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - } - if (m == 0) - { - blocks.writeAt = q; - r = blocks.Flush(r); - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - if (q == blocks.end && blocks.readAt != 0) - { - q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - } - if (m == 0) - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - } - } - r = ZlibConstants.Z_OK; - - blocks.window[q++] = (byte) lit; - m--; - - mode = START; - break; - - case WASH: // o: got eob, possibly more output - if (k > 7) - { - // return unused byte, if any - k -= 8; - n++; - p--; // can always return one - } - - blocks.writeAt = q; - r = blocks.Flush(r); - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - if (blocks.readAt != blocks.writeAt) - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - mode = END; - goto case END; - - case END: - r = ZlibConstants.Z_STREAM_END; - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - case BADCODE: // x: got error - - r = ZlibConstants.Z_DATA_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - default: - r = ZlibConstants.Z_STREAM_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - } - } - - - // Called with number of bytes left to write in window at least 258 - // (the maximum string length) and number of input bytes available - // at least ten. The ten bytes are six bytes for the longest length/ - // distance pair plus four bytes for overloading the bit buffer. - - internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, - ZlibCodec z) - { - int t; // temporary pointer - int[] tp; // temporary pointer - int tp_index; // temporary pointer - int e; // extra bits or operation - int b; // bit buffer - int k; // bits in bit buffer - int p; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - int ml; // mask for literal/length tree - int md; // mask for distance tree - int c; // bytes to copy - int d; // distance back to copy from - int r; // copy source pointer - - int tp_index_t_3; // (tp_index+t)*3 - - // load input, output, bit values - p = z.NextIn; - n = z.AvailableBytesIn; - b = s.bitb; - k = s.bitk; - q = s.writeAt; - m = q < s.readAt ? s.readAt - q - 1 : s.end - q; - - // initialize masks - ml = InternalInflateConstants.InflateMask[bl]; - md = InternalInflateConstants.InflateMask[bd]; - - // do until not enough input or output space for fast loop - do - { - // assume called with m >= 258 && n >= 10 - // get literal/length code - while (k < (20)) - { - // max bits for literal/length code - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - t = b & ml; - tp = tl; - tp_index = tl_index; - tp_index_t_3 = (tp_index + t)*3; - if ((e = tp[tp_index_t_3]) == 0) - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - s.window[q++] = (byte) tp[tp_index_t_3 + 2]; - m--; - continue; - } - do - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - if ((e & 16) != 0) - { - e &= 15; - c = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); - - b >>= e; - k -= e; - - // decode distance base of block to copy - while (k < 15) - { - // max bits for distance code - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - t = b & md; - tp = td; - tp_index = td_index; - tp_index_t_3 = (tp_index + t)*3; - e = tp[tp_index_t_3]; - - do - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - if ((e & 16) != 0) - { - // get extra bits to add to distance base - e &= 15; - while (k < e) - { - // get extra bits (up to 13) - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - d = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); - - b >>= e; - k -= e; - - // do the copy - m -= c; - if (q >= d) - { - // offset before dest - // just copy - r = q - d; - if (q - r > 0 && 2 > (q - r)) - { - s.window[q++] = s.window[r++]; // minimum count is three, - s.window[q++] = s.window[r++]; // so unroll loop a little - c -= 2; - } - else - { - Array.Copy(s.window, r, s.window, q, 2); - q += 2; - r += 2; - c -= 2; - } - } - else - { - // else offset after destination - r = q - d; - do - { - r += s.end; // force pointer in window - } while (r < 0); // covers invalid distances - e = s.end - r; - if (c > e) - { - // if source crosses, - c -= e; // wrapped copy - if (q - r > 0 && e > (q - r)) - { - do - { - s.window[q++] = s.window[r++]; - } while (--e != 0); - } - else - { - Array.Copy(s.window, r, s.window, q, e); - q += e; - r += e; - e = 0; - } - r = 0; // copy rest from start of window - } - } - - // copy all or what's left - if (q - r > 0 && c > (q - r)) - { - do - { - s.window[q++] = s.window[r++]; - } while (--c != 0); - } - else - { - Array.Copy(s.window, r, s.window, q, c); - q += c; - r += c; - c = 0; - } - break; - } - else if ((e & 64) == 0) - { - t += tp[tp_index_t_3 + 2]; - t += (b & InternalInflateConstants.InflateMask[e]); - tp_index_t_3 = (tp_index + t)*3; - e = tp[tp_index_t_3]; - } - else - { - z.Message = "invalid distance code"; - - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); - - s.bitb = b; - s.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - s.writeAt = q; - - return ZlibConstants.Z_DATA_ERROR; - } - } while (true); - break; - } - - if ((e & 64) == 0) - { - t += tp[tp_index_t_3 + 2]; - t += (b & InternalInflateConstants.InflateMask[e]); - tp_index_t_3 = (tp_index + t)*3; - if ((e = tp[tp_index_t_3]) == 0) - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - s.window[q++] = (byte) tp[tp_index_t_3 + 2]; - m--; - break; - } - } - else if ((e & 32) != 0) - { - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); - - s.bitb = b; - s.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - s.writeAt = q; - - return ZlibConstants.Z_STREAM_END; - } - else - { - z.Message = "invalid literal/length code"; - - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); - - s.bitb = b; - s.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - s.writeAt = q; - - return ZlibConstants.Z_DATA_ERROR; - } - } while (true); - } while (m >= 258 && n >= 10); - - // not enough input or output--restore pointers and return - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); - - s.bitb = b; - s.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - s.writeAt = q; - - return ZlibConstants.Z_OK; - } - } - - - internal sealed class InflateManager - { - // preset dictionary flag in zlib header - private const int PRESET_DICT = 0x20; - - private const int Z_DEFLATED = 8; - private static readonly byte[] mark = new byte[] {0, 0, 0xff, 0xff}; - - internal ZlibCodec _codec; // pointer back to this zlib stream - private bool _handleRfc1950HeaderBytes = true; - internal InflateBlocks blocks; // current inflate_blocks state - - // mode dependent information - - // if CHECK, check values to compare - internal uint computedCheck; // computed check value - internal uint expectedCheck; // stream check value - - // if BAD, inflateSync's marker bytes count - internal int marker; - internal int method; // if FLAGS, method byte - private InflateManagerMode mode; // current inflate mode - - // mode independent information - //internal int nowrap; // flag for no wrapper - - internal int wbits; // log2(window size) (8..15, defaults to 15) - - public InflateManager() - { - } - - public InflateManager(bool expectRfc1950HeaderBytes) - { - _handleRfc1950HeaderBytes = expectRfc1950HeaderBytes; - } - - internal bool HandleRfc1950HeaderBytes - { - get { return _handleRfc1950HeaderBytes; } - set { _handleRfc1950HeaderBytes = value; } - } - - internal int Reset() - { - _codec.TotalBytesIn = _codec.TotalBytesOut = 0; - _codec.Message = null; - mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS; - blocks.Reset(); - return ZlibConstants.Z_OK; - } - - internal int End() - { - if (blocks != null) - blocks.Free(); - blocks = null; - return ZlibConstants.Z_OK; - } - - internal int Initialize(ZlibCodec codec, int w) - { - _codec = codec; - _codec.Message = null; - blocks = null; - - // handle undocumented nowrap option (no zlib header or check) - //nowrap = 0; - //if (w < 0) - //{ - // w = - w; - // nowrap = 1; - //} - - // set window size - if (w < 8 || w > 15) - { - End(); - throw new ZlibException("Bad window size."); - - //return ZlibConstants.Z_STREAM_ERROR; - } - wbits = w; - - blocks = new InflateBlocks(codec, - HandleRfc1950HeaderBytes ? this : null, - 1 << w); - - // reset state - Reset(); - return ZlibConstants.Z_OK; - } - - - internal int Inflate(FlushType flush) - { - int b; - - if (_codec.InputBuffer == null) - throw new ZlibException("InputBuffer is null. "); - - // int f = (flush == FlushType.Finish) - // ? ZlibConstants.Z_BUF_ERROR - // : ZlibConstants.Z_OK; - - // workitem 8870 - int f = ZlibConstants.Z_OK; - int r = ZlibConstants.Z_BUF_ERROR; - - while (true) - { - switch (mode) - { - case InflateManagerMode.METHOD: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED) - { - mode = InflateManagerMode.BAD; - _codec.Message = String.Format("unknown compression method (0x{0:X2})", method); - marker = 5; // can't try inflateSync - break; - } - if ((method >> 4) + 8 > wbits) - { - mode = InflateManagerMode.BAD; - _codec.Message = String.Format("invalid window size ({0})", (method >> 4) + 8); - marker = 5; // can't try inflateSync - break; - } - mode = InflateManagerMode.FLAG; - break; - - - case InflateManagerMode.FLAG: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff; - - if ((((method << 8) + b)%31) != 0) - { - mode = InflateManagerMode.BAD; - _codec.Message = "incorrect header check"; - marker = 5; // can't try inflateSync - break; - } - - mode = ((b & PRESET_DICT) == 0) - ? InflateManagerMode.BLOCKS - : InflateManagerMode.DICT4; - break; - - case InflateManagerMode.DICT4: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck = (uint) ((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000); - mode = InflateManagerMode.DICT3; - break; - - case InflateManagerMode.DICT3: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000); - mode = InflateManagerMode.DICT2; - break; - - case InflateManagerMode.DICT2: - - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00); - mode = InflateManagerMode.DICT1; - break; - - - case InflateManagerMode.DICT1: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint) (_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); - _codec._Adler32 = expectedCheck; - mode = InflateManagerMode.DICT0; - return ZlibConstants.Z_NEED_DICT; - - - case InflateManagerMode.DICT0: - mode = InflateManagerMode.BAD; - _codec.Message = "need dictionary"; - marker = 0; // can try inflateSync - return ZlibConstants.Z_STREAM_ERROR; - - - case InflateManagerMode.BLOCKS: - r = blocks.Process(r); - if (r == ZlibConstants.Z_DATA_ERROR) - { - mode = InflateManagerMode.BAD; - marker = 0; // can try inflateSync - break; - } - - if (r == ZlibConstants.Z_OK) r = f; - - if (r != ZlibConstants.Z_STREAM_END) - return r; - - r = f; - computedCheck = blocks.Reset(); - if (!HandleRfc1950HeaderBytes) - { - mode = InflateManagerMode.DONE; - return ZlibConstants.Z_STREAM_END; - } - mode = InflateManagerMode.CHECK4; - break; - - case InflateManagerMode.CHECK4: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck = (uint) ((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000); - mode = InflateManagerMode.CHECK3; - break; - - case InflateManagerMode.CHECK3: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000); - mode = InflateManagerMode.CHECK2; - break; - - case InflateManagerMode.CHECK2: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00); - mode = InflateManagerMode.CHECK1; - break; - - case InflateManagerMode.CHECK1: - if (_codec.AvailableBytesIn == 0) return r; - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint) (_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); - if (computedCheck != expectedCheck) - { - mode = InflateManagerMode.BAD; - _codec.Message = "incorrect data check"; - marker = 5; // can't try inflateSync - break; - } - mode = InflateManagerMode.DONE; - return ZlibConstants.Z_STREAM_END; - - case InflateManagerMode.DONE: - return ZlibConstants.Z_STREAM_END; - - case InflateManagerMode.BAD: - throw new ZlibException(String.Format("Bad state ({0})", _codec.Message)); - - default: - throw new ZlibException("Stream error."); - } - } - } - - - internal int SetDictionary(byte[] dictionary) - { - int index = 0; - int length = dictionary.Length; - if (mode != InflateManagerMode.DICT0) - throw new ZlibException("Stream error."); - - if (Adler.Adler32(1, dictionary, 0, dictionary.Length) != _codec._Adler32) - { - return ZlibConstants.Z_DATA_ERROR; - } - - _codec._Adler32 = Adler.Adler32(0, null, 0, 0); - - if (length >= (1 << wbits)) - { - length = (1 << wbits) - 1; - index = dictionary.Length - length; - } - blocks.SetDictionary(dictionary, index, length); - mode = InflateManagerMode.BLOCKS; - return ZlibConstants.Z_OK; - } - - - internal int Sync() - { - int n; // number of bytes to look at - int p; // pointer to bytes - int m; // number of marker bytes found in a row - long r, w; // temporaries to save total_in and total_out - - // set up - if (mode != InflateManagerMode.BAD) - { - mode = InflateManagerMode.BAD; - marker = 0; - } - if ((n = _codec.AvailableBytesIn) == 0) - return ZlibConstants.Z_BUF_ERROR; - p = _codec.NextIn; - m = marker; - - // search - while (n != 0 && m < 4) - { - if (_codec.InputBuffer[p] == mark[m]) - { - m++; - } - else if (_codec.InputBuffer[p] != 0) - { - m = 0; - } - else - { - m = 4 - m; - } - p++; - n--; - } - - // restore - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - _codec.AvailableBytesIn = n; - marker = m; - - // return no joy or set up to restart on a new block - if (m != 4) - { - return ZlibConstants.Z_DATA_ERROR; - } - r = _codec.TotalBytesIn; - w = _codec.TotalBytesOut; - Reset(); - _codec.TotalBytesIn = r; - _codec.TotalBytesOut = w; - mode = InflateManagerMode.BLOCKS; - return ZlibConstants.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. - internal int SyncPoint(ZlibCodec z) - { - return blocks.SyncPoint(); - } - - #region Nested type: InflateManagerMode - - private enum InflateManagerMode - { - METHOD = 0, // waiting for method byte - FLAG = 1, // waiting for flag byte - DICT4 = 2, // four dictionary check bytes to go - DICT3 = 3, // three dictionary check bytes to go - DICT2 = 4, // two dictionary check bytes to go - DICT1 = 5, // one dictionary check byte to go - DICT0 = 6, // waiting for inflateSetDictionary - BLOCKS = 7, // decompressing blocks - CHECK4 = 8, // four check bytes to go - CHECK3 = 9, // three check bytes to go - CHECK2 = 10, // two check bytes to go - CHECK1 = 11, // one check byte to go - DONE = 12, // finished check, done - BAD = 13, // got an error--stay here - } - - #endregion - } +// Inflate.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2010-January-08 18:32:12> +// +// ------------------------------------------------------------------ +// +// This module defines classes for decompression. This code is derived +// from the jzlib implementation of zlib, but significantly modified. +// The object model is not the same, and many of the behaviors are +// different. Nonetheless, in keeping with the license for jzlib, I am +// reproducing the copyright to that code here. +// +// ------------------------------------------------------------------ +// +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +using System; + +namespace SharpCompress.Compressor.Deflate +{ + internal sealed class InflateBlocks + { + private const int MANY = 1440; + + // Table for deflate from PKZIP's appnote.txt. + internal static readonly int[] border = new[] {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + internal ZlibCodec _codec; // pointer back to this zlib stream + internal int[] bb = new int[1]; // bit length tree depth + + // mode independent information + internal int bitb; // bit buffer + internal int bitk; // bits in bit buffer + internal int[] blens; // bit lengths of codes + internal uint check; // check on output + internal Object checkfn; // check function + internal InflateCodes codes = new InflateCodes(); // if CODES, current state + internal int end; // one byte after sliding window + internal int[] hufts; // single malloc for tree space + internal int index; // index into blens (or border) + internal InfTree inftree = new InfTree(); + internal int last; // true if this block is the last block + internal int left; // if STORED, bytes left to copy + private InflateBlockMode mode; // current inflate_block mode + internal int readAt; // window read pointer + internal int table; // table lengths (14 bits) + internal int[] tb = new int[1]; // bit length decoding tree + internal byte[] window; // sliding window + internal int writeAt; // window write pointer + + internal InflateBlocks(ZlibCodec codec, Object checkfn, int w) + { + _codec = codec; + hufts = new int[MANY*3]; + window = new byte[w]; + end = w; + this.checkfn = checkfn; + mode = InflateBlockMode.TYPE; + Reset(); + } + + internal uint Reset() + { + uint oldCheck = check; + mode = InflateBlockMode.TYPE; + bitk = 0; + bitb = 0; + readAt = writeAt = 0; + + if (checkfn != null) + _codec._Adler32 = check = Adler.Adler32(0, null, 0, 0); + return oldCheck; + } + + + internal int Process(int r) + { + int t; // temporary storage + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + + p = _codec.NextIn; + n = _codec.AvailableBytesIn; + b = bitb; + k = bitk; + + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + + + // process input based on current state + while (true) + { + switch (mode) + { + case InflateBlockMode.TYPE: + + while (k < (3)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + t = (b & 7); + last = t & 1; + + switch ((uint) t >> 1) + { + case 0: // stored + b >>= 3; + k -= (3); + t = k & 7; // go to byte boundary + b >>= t; + k -= t; + mode = InflateBlockMode.LENS; // get length of stored block + break; + + case 1: // fixed + var bl = new int[1]; + var bd = new int[1]; + var tl = new int[1][]; + var td = new int[1][]; + InfTree.inflate_trees_fixed(bl, bd, tl, td, _codec); + codes.Init(bl[0], bd[0], tl[0], 0, td[0], 0); + b >>= 3; + k -= 3; + mode = InflateBlockMode.CODES; + break; + + case 2: // dynamic + b >>= 3; + k -= 3; + mode = InflateBlockMode.TABLE; + break; + + case 3: // illegal + b >>= 3; + k -= 3; + mode = InflateBlockMode.BAD; + _codec.Message = "invalid block type"; + r = ZlibConstants.Z_DATA_ERROR; + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + break; + + case InflateBlockMode.LENS: + + while (k < (32)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + ; + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + mode = InflateBlockMode.BAD; + _codec.Message = "invalid stored block lengths"; + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = left != 0 + ? InflateBlockMode.STORED + : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE); + break; + + case InflateBlockMode.STORED: + if (n == 0) + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + if (m == 0) + { + if (q == end && readAt != 0) + { + q = 0; + m = (q < readAt ? readAt - q - 1 : end - q); + } + if (m == 0) + { + writeAt = q; + r = Flush(r); + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + if (q == end && readAt != 0) + { + q = 0; + m = (q < readAt ? readAt - q - 1 : end - q); + } + if (m == 0) + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + } + } + r = ZlibConstants.Z_OK; + + t = left; + if (t > n) + t = n; + if (t > m) + t = m; + Array.Copy(_codec.InputBuffer, p, window, q, t); + p += t; + n -= t; + q += t; + m -= t; + if ((left -= t) != 0) + break; + mode = last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE; + break; + + case InflateBlockMode.TABLE: + + while (k < (14)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + table = t = (b & 0x3fff); + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + mode = InflateBlockMode.BAD; + _codec.Message = "too many length or distance symbols"; + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (blens == null || blens.Length < t) + { + blens = new int[t]; + } + else + { + Array.Clear(blens, 0, t); + // for (int i = 0; i < t; i++) + // { + // blens[i] = 0; + // } + } + + b >>= 14; + k -= 14; + + + index = 0; + mode = InflateBlockMode.BTREE; + goto case InflateBlockMode.BTREE; + + case InflateBlockMode.BTREE: + while (index < 4 + (table >> 10)) + { + while (k < (3)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + blens[border[index++]] = b & 7; + + b >>= 3; + k -= 3; + } + + while (index < 19) + { + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, _codec); + if (t != ZlibConstants.Z_OK) + { + r = t; + if (r == ZlibConstants.Z_DATA_ERROR) + { + blens = null; + mode = InflateBlockMode.BAD; + } + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + index = 0; + mode = InflateBlockMode.DTREE; + goto case InflateBlockMode.DTREE; + + case InflateBlockMode.DTREE: + while (true) + { + t = table; + if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) + { + break; + } + + int i, j, c; + + t = bb[0]; + + while (k < t) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + t = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t]))*3 + 1]; + c = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t]))*3 + 2]; + + if (c < 16) + { + b >>= t; + k -= t; + blens[index++] = c; + } + else + { + // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + + while (k < (t + i)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + b >>= t; + k -= t; + + j += (b & InternalInflateConstants.InflateMask[i]); + + b >>= i; + k -= i; + + i = index; + t = table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) + { + blens = null; + mode = InflateBlockMode.BAD; + _codec.Message = "invalid bit length repeat"; + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + c = (c == 16) ? blens[i - 1] : 0; + do + { + blens[i++] = c; + } while (--j != 0); + index = i; + } + } + + tb[0] = -1; + { + var bl = new[] {9}; // must be <= 9 for lookahead assumptions + var bd = new[] {6}; // must be <= 9 for lookahead assumptions + var tl = new int[1]; + var td = new int[1]; + + t = table; + t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl, bd, tl, + td, hufts, _codec); + + if (t != ZlibConstants.Z_OK) + { + if (t == ZlibConstants.Z_DATA_ERROR) + { + blens = null; + mode = InflateBlockMode.BAD; + } + r = t; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + codes.Init(bl[0], bd[0], hufts, tl[0], hufts, td[0]); + } + mode = InflateBlockMode.CODES; + goto case InflateBlockMode.CODES; + + case InflateBlockMode.CODES: + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + + r = codes.Process(this, r); + if (r != ZlibConstants.Z_STREAM_END) + { + return Flush(r); + } + + r = ZlibConstants.Z_OK; + p = _codec.NextIn; + n = _codec.AvailableBytesIn; + b = bitb; + k = bitk; + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + + if (last == 0) + { + mode = InflateBlockMode.TYPE; + break; + } + mode = InflateBlockMode.DRY; + goto case InflateBlockMode.DRY; + + case InflateBlockMode.DRY: + writeAt = q; + r = Flush(r); + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + if (readAt != writeAt) + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + mode = InflateBlockMode.DONE; + goto case InflateBlockMode.DONE; + + case InflateBlockMode.DONE: + r = ZlibConstants.Z_STREAM_END; + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + + case InflateBlockMode.BAD: + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + + + default: + r = ZlibConstants.Z_STREAM_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + } + } + + + internal void Free() + { + Reset(); + window = null; + hufts = null; + } + + internal void SetDictionary(byte[] d, int start, int n) + { + Array.Copy(d, start, window, 0, n); + readAt = writeAt = n; + } + + // Returns true if inflate is currently at the end of a block generated + // by Z_SYNC_FLUSH or Z_FULL_FLUSH. + internal int SyncPoint() + { + return mode == InflateBlockMode.LENS ? 1 : 0; + } + + // copy as much as possible from the sliding window to the output area + internal int Flush(int r) + { + int nBytes; + + for (int pass = 0; pass < 2; pass++) + { + if (pass == 0) + { + // compute number of bytes to copy as far as end of window + nBytes = ((readAt <= writeAt ? writeAt : end) - readAt); + } + else + { + // compute bytes to copy + nBytes = writeAt - readAt; + } + + // workitem 8870 + if (nBytes == 0) + { + if (r == ZlibConstants.Z_BUF_ERROR) + r = ZlibConstants.Z_OK; + return r; + } + + if (nBytes > _codec.AvailableBytesOut) + nBytes = _codec.AvailableBytesOut; + + if (nBytes != 0 && r == ZlibConstants.Z_BUF_ERROR) + r = ZlibConstants.Z_OK; + + // update counters + _codec.AvailableBytesOut -= nBytes; + _codec.TotalBytesOut += nBytes; + + // update check information + if (checkfn != null) + _codec._Adler32 = check = Adler.Adler32(check, window, readAt, nBytes); + + // copy as far as end of window + Array.Copy(window, readAt, _codec.OutputBuffer, _codec.NextOut, nBytes); + _codec.NextOut += nBytes; + readAt += nBytes; + + // see if more to copy at beginning of window + if (readAt == end && pass == 0) + { + // wrap pointers + readAt = 0; + if (writeAt == end) + writeAt = 0; + } + else pass++; + } + + // done + return r; + } + + #region Nested type: InflateBlockMode + + private enum InflateBlockMode + { + TYPE = 0, // get type bits (3, including end bit) + LENS = 1, // get lengths for stored + STORED = 2, // processing stored block + TABLE = 3, // get table lengths + BTREE = 4, // get bit lengths tree for a dynamic block + DTREE = 5, // get length, distance trees for a dynamic block + CODES = 6, // processing fixed or dynamic block + DRY = 7, // output remaining window bytes + DONE = 8, // finished last block, done + BAD = 9, // ot a data error--stuck here + } + + #endregion + } + + + internal static class InternalInflateConstants + { + // And'ing with mask[n] masks the lower n bits + internal static readonly int[] InflateMask = new[] + { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff + }; + } + + + internal sealed class InflateCodes + { + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + private const int START = 0; // x: set up for LEN + private const int LEN = 1; // i: get length/literal/eob next + private const int LENEXT = 2; // i: getting length extra (have base) + private const int DIST = 3; // i: get distance next + private const int DISTEXT = 4; // i: getting distance extra + private const int COPY = 5; // o: copying bytes in window, waiting for space + private const int LIT = 6; // o: got literal, waiting for output space + private const int WASH = 7; // o: got eob, possibly still output waiting + private const int END = 8; // x: got eob and all data flushed + private const int BADCODE = 9; // x: got error + + // if EXT or COPY, where and how much + internal int bitsToGet; // bits to get for extra + internal byte dbits; // dtree bits decoder per branch + internal int dist; // distance back to copy from + internal int[] dtree; // distance tree + internal int dtree_index; // distance tree + + internal byte lbits; // ltree bits decoded per branch + internal int len; + internal int lit; + internal int[] ltree; // literal/length/eob tree + internal int ltree_index; // literal/length/eob tree + internal int mode; // current inflate_codes mode + internal int need; // bits needed + internal int[] tree; // pointer into tree + internal int tree_index; + + internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) + { + mode = START; + lbits = (byte) bl; + dbits = (byte) bd; + ltree = tl; + ltree_index = tl_index; + dtree = td; + dtree_index = td_index; + tree = null; + } + + internal int Process(InflateBlocks blocks, int r) + { + int j; // temporary storage + int tindex; // temporary pointer + int e; // extra bits or operation + int b = 0; // bit buffer + int k = 0; // bits in bit buffer + int p = 0; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int f; // pointer to copy strings from + + ZlibCodec z = blocks._codec; + + // copy input/output information to locals (UPDATE macro restores) + p = z.NextIn; + n = z.AvailableBytesIn; + b = blocks.bitb; + k = blocks.bitk; + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + // process input and output based on current state + while (true) + { + switch (mode) + { + // waiting for "i:"=input, "o:"=output, "x:"=nothing + case START: // x: set up for LEN + if (m >= 258 && n >= 10) + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z); + + p = z.NextIn; + n = z.AvailableBytesIn; + b = blocks.bitb; + k = blocks.bitk; + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + if (r != ZlibConstants.Z_OK) + { + mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE; + break; + } + } + need = lbits; + tree = ltree; + tree_index = ltree_index; + + mode = LEN; + goto case LEN; + + case LEN: // i: get length/literal/eob next + j = need; + + while (k < j) + { + if (n != 0) + r = ZlibConstants.Z_OK; + else + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j]))*3; + + b >>= (tree[tindex + 1]); + k -= (tree[tindex + 1]); + + e = tree[tindex]; + + if (e == 0) + { + // literal + lit = tree[tindex + 2]; + mode = LIT; + break; + } + if ((e & 16) != 0) + { + // length + bitsToGet = e & 15; + len = tree[tindex + 2]; + mode = LENEXT; + break; + } + if ((e & 64) == 0) + { + // next table + need = e; + tree_index = tindex/3 + tree[tindex + 2]; + break; + } + if ((e & 32) != 0) + { + // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.Message = "invalid literal/length code"; + r = ZlibConstants.Z_DATA_ERROR; + + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + + + case LENEXT: // i: getting length extra (have base) + j = bitsToGet; + + while (k < j) + { + if (n != 0) + r = ZlibConstants.Z_OK; + else + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + len += (b & InternalInflateConstants.InflateMask[j]); + + b >>= j; + k -= j; + + need = dbits; + tree = dtree; + tree_index = dtree_index; + mode = DIST; + goto case DIST; + + case DIST: // i: get distance next + j = need; + + while (k < j) + { + if (n != 0) + r = ZlibConstants.Z_OK; + else + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j]))*3; + + b >>= tree[tindex + 1]; + k -= tree[tindex + 1]; + + e = (tree[tindex]); + if ((e & 0x10) != 0) + { + // distance + bitsToGet = e & 15; + dist = tree[tindex + 2]; + mode = DISTEXT; + break; + } + if ((e & 64) == 0) + { + // next table + need = e; + tree_index = tindex/3 + tree[tindex + 2]; + break; + } + mode = BADCODE; // invalid code + z.Message = "invalid distance code"; + r = ZlibConstants.Z_DATA_ERROR; + + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + + + case DISTEXT: // i: getting distance extra + j = bitsToGet; + + while (k < j) + { + if (n != 0) + r = ZlibConstants.Z_OK; + else + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + dist += (b & InternalInflateConstants.InflateMask[j]); + + b >>= j; + k -= j; + + mode = COPY; + goto case COPY; + + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while (f < 0) + { + // modulo window size-"while" instead + f += blocks.end; // of "if" handles invalid distances + } + while (len != 0) + { + if (m == 0) + { + if (q == blocks.end && blocks.readAt != 0) + { + q = 0; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + } + if (m == 0) + { + blocks.writeAt = q; + r = blocks.Flush(r); + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + if (q == blocks.end && blocks.readAt != 0) + { + q = 0; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + } + + if (m == 0) + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + } + } + + blocks.window[q++] = blocks.window[f++]; + m--; + + if (f == blocks.end) + f = 0; + len--; + } + mode = START; + break; + + case LIT: // o: got literal, waiting for output space + if (m == 0) + { + if (q == blocks.end && blocks.readAt != 0) + { + q = 0; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + } + if (m == 0) + { + blocks.writeAt = q; + r = blocks.Flush(r); + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + if (q == blocks.end && blocks.readAt != 0) + { + q = 0; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + } + if (m == 0) + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + } + } + r = ZlibConstants.Z_OK; + + blocks.window[q++] = (byte) lit; + m--; + + mode = START; + break; + + case WASH: // o: got eob, possibly more output + if (k > 7) + { + // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + blocks.writeAt = q; + r = blocks.Flush(r); + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + if (blocks.readAt != blocks.writeAt) + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + mode = END; + goto case END; + + case END: + r = ZlibConstants.Z_STREAM_END; + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + + case BADCODE: // x: got error + + r = ZlibConstants.Z_DATA_ERROR; + + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + + default: + r = ZlibConstants.Z_STREAM_ERROR; + + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + } + } + + + // Called with number of bytes left to write in window at least 258 + // (the maximum string length) and number of input bytes available + // at least ten. The ten bytes are six bytes for the longest length/ + // distance pair plus four bytes for overloading the bit buffer. + + internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, + ZlibCodec z) + { + int t; // temporary pointer + int[] tp; // temporary pointer + int tp_index; // temporary pointer + int e; // extra bits or operation + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int ml; // mask for literal/length tree + int md; // mask for distance tree + int c; // bytes to copy + int d; // distance back to copy from + int r; // copy source pointer + + int tp_index_t_3; // (tp_index+t)*3 + + // load input, output, bit values + p = z.NextIn; + n = z.AvailableBytesIn; + b = s.bitb; + k = s.bitk; + q = s.writeAt; + m = q < s.readAt ? s.readAt - q - 1 : s.end - q; + + // initialize masks + ml = InternalInflateConstants.InflateMask[bl]; + md = InternalInflateConstants.InflateMask[bd]; + + // do until not enough input or output space for fast loop + do + { + // assume called with m >= 258 && n >= 10 + // get literal/length code + while (k < (20)) + { + // max bits for literal/length code + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + t = b & ml; + tp = tl; + tp_index = tl_index; + tp_index_t_3 = (tp_index + t)*3; + if ((e = tp[tp_index_t_3]) == 0) + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + s.window[q++] = (byte) tp[tp_index_t_3 + 2]; + m--; + continue; + } + do + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + if ((e & 16) != 0) + { + e &= 15; + c = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); + + b >>= e; + k -= e; + + // decode distance base of block to copy + while (k < 15) + { + // max bits for distance code + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + t = b & md; + tp = td; + tp_index = td_index; + tp_index_t_3 = (tp_index + t)*3; + e = tp[tp_index_t_3]; + + do + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + if ((e & 16) != 0) + { + // get extra bits to add to distance base + e &= 15; + while (k < e) + { + // get extra bits (up to 13) + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + d = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); + + b >>= e; + k -= e; + + // do the copy + m -= c; + if (q >= d) + { + // offset before dest + // just copy + r = q - d; + if (q - r > 0 && 2 > (q - r)) + { + s.window[q++] = s.window[r++]; // minimum count is three, + s.window[q++] = s.window[r++]; // so unroll loop a little + c -= 2; + } + else + { + Array.Copy(s.window, r, s.window, q, 2); + q += 2; + r += 2; + c -= 2; + } + } + else + { + // else offset after destination + r = q - d; + do + { + r += s.end; // force pointer in window + } while (r < 0); // covers invalid distances + e = s.end - r; + if (c > e) + { + // if source crosses, + c -= e; // wrapped copy + if (q - r > 0 && e > (q - r)) + { + do + { + s.window[q++] = s.window[r++]; + } while (--e != 0); + } + else + { + Array.Copy(s.window, r, s.window, q, e); + q += e; + r += e; + e = 0; + } + r = 0; // copy rest from start of window + } + } + + // copy all or what's left + if (q - r > 0 && c > (q - r)) + { + do + { + s.window[q++] = s.window[r++]; + } while (--c != 0); + } + else + { + Array.Copy(s.window, r, s.window, q, c); + q += c; + r += c; + c = 0; + } + break; + } + else if ((e & 64) == 0) + { + t += tp[tp_index_t_3 + 2]; + t += (b & InternalInflateConstants.InflateMask[e]); + tp_index_t_3 = (tp_index + t)*3; + e = tp[tp_index_t_3]; + } + else + { + z.Message = "invalid distance code"; + + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_DATA_ERROR; + } + } while (true); + break; + } + + if ((e & 64) == 0) + { + t += tp[tp_index_t_3 + 2]; + t += (b & InternalInflateConstants.InflateMask[e]); + tp_index_t_3 = (tp_index + t)*3; + if ((e = tp[tp_index_t_3]) == 0) + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + s.window[q++] = (byte) tp[tp_index_t_3 + 2]; + m--; + break; + } + } + else if ((e & 32) != 0) + { + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_STREAM_END; + } + else + { + z.Message = "invalid literal/length code"; + + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_DATA_ERROR; + } + } while (true); + } while (m >= 258 && n >= 10); + + // not enough input or output--restore pointers and return + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_OK; + } + } + + + internal sealed class InflateManager + { + // preset dictionary flag in zlib header + private const int PRESET_DICT = 0x20; + + private const int Z_DEFLATED = 8; + private static readonly byte[] mark = new byte[] {0, 0, 0xff, 0xff}; + + internal ZlibCodec _codec; // pointer back to this zlib stream + private bool _handleRfc1950HeaderBytes = true; + internal InflateBlocks blocks; // current inflate_blocks state + + // mode dependent information + + // if CHECK, check values to compare + internal uint computedCheck; // computed check value + internal uint expectedCheck; // stream check value + + // if BAD, inflateSync's marker bytes count + internal int marker; + internal int method; // if FLAGS, method byte + private InflateManagerMode mode; // current inflate mode + + // mode independent information + //internal int nowrap; // flag for no wrapper + + internal int wbits; // log2(window size) (8..15, defaults to 15) + + public InflateManager() + { + } + + public InflateManager(bool expectRfc1950HeaderBytes) + { + _handleRfc1950HeaderBytes = expectRfc1950HeaderBytes; + } + + internal bool HandleRfc1950HeaderBytes + { + get { return _handleRfc1950HeaderBytes; } + set { _handleRfc1950HeaderBytes = value; } + } + + internal int Reset() + { + _codec.TotalBytesIn = _codec.TotalBytesOut = 0; + _codec.Message = null; + mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS; + blocks.Reset(); + return ZlibConstants.Z_OK; + } + + internal int End() + { + if (blocks != null) + blocks.Free(); + blocks = null; + return ZlibConstants.Z_OK; + } + + internal int Initialize(ZlibCodec codec, int w) + { + _codec = codec; + _codec.Message = null; + blocks = null; + + // handle undocumented nowrap option (no zlib header or check) + //nowrap = 0; + //if (w < 0) + //{ + // w = - w; + // nowrap = 1; + //} + + // set window size + if (w < 8 || w > 15) + { + End(); + throw new ZlibException("Bad window size."); + + //return ZlibConstants.Z_STREAM_ERROR; + } + wbits = w; + + blocks = new InflateBlocks(codec, + HandleRfc1950HeaderBytes ? this : null, + 1 << w); + + // reset state + Reset(); + return ZlibConstants.Z_OK; + } + + + internal int Inflate(FlushType flush) + { + int b; + + if (_codec.InputBuffer == null) + throw new ZlibException("InputBuffer is null. "); + + // int f = (flush == FlushType.Finish) + // ? ZlibConstants.Z_BUF_ERROR + // : ZlibConstants.Z_OK; + + // workitem 8870 + int f = ZlibConstants.Z_OK; + int r = ZlibConstants.Z_BUF_ERROR; + + while (true) + { + switch (mode) + { + case InflateManagerMode.METHOD: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED) + { + mode = InflateManagerMode.BAD; + _codec.Message = String.Format("unknown compression method (0x{0:X2})", method); + marker = 5; // can't try inflateSync + break; + } + if ((method >> 4) + 8 > wbits) + { + mode = InflateManagerMode.BAD; + _codec.Message = String.Format("invalid window size ({0})", (method >> 4) + 8); + marker = 5; // can't try inflateSync + break; + } + mode = InflateManagerMode.FLAG; + break; + + + case InflateManagerMode.FLAG: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff; + + if ((((method << 8) + b)%31) != 0) + { + mode = InflateManagerMode.BAD; + _codec.Message = "incorrect header check"; + marker = 5; // can't try inflateSync + break; + } + + mode = ((b & PRESET_DICT) == 0) + ? InflateManagerMode.BLOCKS + : InflateManagerMode.DICT4; + break; + + case InflateManagerMode.DICT4: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck = (uint) ((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000); + mode = InflateManagerMode.DICT3; + break; + + case InflateManagerMode.DICT3: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000); + mode = InflateManagerMode.DICT2; + break; + + case InflateManagerMode.DICT2: + + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00); + mode = InflateManagerMode.DICT1; + break; + + + case InflateManagerMode.DICT1: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint) (_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); + _codec._Adler32 = expectedCheck; + mode = InflateManagerMode.DICT0; + return ZlibConstants.Z_NEED_DICT; + + + case InflateManagerMode.DICT0: + mode = InflateManagerMode.BAD; + _codec.Message = "need dictionary"; + marker = 0; // can try inflateSync + return ZlibConstants.Z_STREAM_ERROR; + + + case InflateManagerMode.BLOCKS: + r = blocks.Process(r); + if (r == ZlibConstants.Z_DATA_ERROR) + { + mode = InflateManagerMode.BAD; + marker = 0; // can try inflateSync + break; + } + + if (r == ZlibConstants.Z_OK) r = f; + + if (r != ZlibConstants.Z_STREAM_END) + return r; + + r = f; + computedCheck = blocks.Reset(); + if (!HandleRfc1950HeaderBytes) + { + mode = InflateManagerMode.DONE; + return ZlibConstants.Z_STREAM_END; + } + mode = InflateManagerMode.CHECK4; + break; + + case InflateManagerMode.CHECK4: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck = (uint) ((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000); + mode = InflateManagerMode.CHECK3; + break; + + case InflateManagerMode.CHECK3: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000); + mode = InflateManagerMode.CHECK2; + break; + + case InflateManagerMode.CHECK2: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint) ((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00); + mode = InflateManagerMode.CHECK1; + break; + + case InflateManagerMode.CHECK1: + if (_codec.AvailableBytesIn == 0) return r; + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint) (_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); + if (computedCheck != expectedCheck) + { + mode = InflateManagerMode.BAD; + _codec.Message = "incorrect data check"; + marker = 5; // can't try inflateSync + break; + } + mode = InflateManagerMode.DONE; + return ZlibConstants.Z_STREAM_END; + + case InflateManagerMode.DONE: + return ZlibConstants.Z_STREAM_END; + + case InflateManagerMode.BAD: + throw new ZlibException(String.Format("Bad state ({0})", _codec.Message)); + + default: + throw new ZlibException("Stream error."); + } + } + } + + + internal int SetDictionary(byte[] dictionary) + { + int index = 0; + int length = dictionary.Length; + if (mode != InflateManagerMode.DICT0) + throw new ZlibException("Stream error."); + + if (Adler.Adler32(1, dictionary, 0, dictionary.Length) != _codec._Adler32) + { + return ZlibConstants.Z_DATA_ERROR; + } + + _codec._Adler32 = Adler.Adler32(0, null, 0, 0); + + if (length >= (1 << wbits)) + { + length = (1 << wbits) - 1; + index = dictionary.Length - length; + } + blocks.SetDictionary(dictionary, index, length); + mode = InflateManagerMode.BLOCKS; + return ZlibConstants.Z_OK; + } + + + internal int Sync() + { + int n; // number of bytes to look at + int p; // pointer to bytes + int m; // number of marker bytes found in a row + long r, w; // temporaries to save total_in and total_out + + // set up + if (mode != InflateManagerMode.BAD) + { + mode = InflateManagerMode.BAD; + marker = 0; + } + if ((n = _codec.AvailableBytesIn) == 0) + return ZlibConstants.Z_BUF_ERROR; + p = _codec.NextIn; + m = marker; + + // search + while (n != 0 && m < 4) + { + if (_codec.InputBuffer[p] == mark[m]) + { + m++; + } + else if (_codec.InputBuffer[p] != 0) + { + m = 0; + } + else + { + m = 4 - m; + } + p++; + n--; + } + + // restore + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + _codec.AvailableBytesIn = n; + marker = m; + + // return no joy or set up to restart on a new block + if (m != 4) + { + return ZlibConstants.Z_DATA_ERROR; + } + r = _codec.TotalBytesIn; + w = _codec.TotalBytesOut; + Reset(); + _codec.TotalBytesIn = r; + _codec.TotalBytesOut = w; + mode = InflateManagerMode.BLOCKS; + return ZlibConstants.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. + internal int SyncPoint(ZlibCodec z) + { + return blocks.SyncPoint(); + } + + #region Nested type: InflateManagerMode + + private enum InflateManagerMode + { + METHOD = 0, // waiting for method byte + FLAG = 1, // waiting for flag byte + DICT4 = 2, // four dictionary check bytes to go + DICT3 = 3, // three dictionary check bytes to go + DICT2 = 4, // two dictionary check bytes to go + DICT1 = 5, // one dictionary check byte to go + DICT0 = 6, // waiting for inflateSetDictionary + BLOCKS = 7, // decompressing blocks + CHECK4 = 8, // four check bytes to go + CHECK3 = 9, // three check bytes to go + CHECK2 = 10, // two check bytes to go + CHECK1 = 11, // one check byte to go + DONE = 12, // finished check, done + BAD = 13, // got an error--stay here + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/Tree.cs b/src/SharpCompress/Compressor/Deflate/Tree.cs similarity index 98% rename from SharpCompress/Compressor/Deflate/Tree.cs rename to src/SharpCompress/Compressor/Deflate/Tree.cs index e49708ce..fd9e27f0 100644 --- a/SharpCompress/Compressor/Deflate/Tree.cs +++ b/src/SharpCompress/Compressor/Deflate/Tree.cs @@ -1,464 +1,464 @@ -// Tree.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-October-28 13:29:50> -// -// ------------------------------------------------------------------ -// -// This module defines classes for zlib compression and -// decompression. This code is derived from the jzlib implementation of -// zlib. In keeping with the license for jzlib, the copyright to that -// code is below. -// -// ------------------------------------------------------------------ -// -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -using System; - -namespace SharpCompress.Compressor.Deflate -{ - internal sealed partial class DeflateManager - { - #region Nested type: Tree - - private sealed class Tree - { - internal const int Buf_size = 8*2; - private static readonly int HEAP_SIZE = (2*InternalConstants.L_CODES + 1); - - - internal static readonly sbyte[] bl_order = new sbyte[] - { - 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. - - // see definition of array dist_code below - //internal const int DIST_CODE_LEN = 512; - - private static readonly sbyte[] _dist_code = new sbyte[] - { - 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 - }; - - internal static readonly sbyte[] LengthCode = new sbyte[] - { - 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 - }; - - - internal static readonly int[] LengthBase = new[] - { - 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 - }; - - - internal static readonly int[] DistanceBase = new[] - { - 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 - }; - - - internal short[] dyn_tree; // the dynamic tree - internal int max_code; // largest code with non zero frequency - internal StaticTree staticTree; // the corresponding static tree - - /// - /// Map from a distance to a distance code. - /// - /// - /// No side effects. _dist_code[256] and _dist_code[257] are never used. - /// - internal static int DistanceCode(int dist) - { - return (dist < 256) - ? _dist_code[dist] - : _dist_code[256 + SharedUtils.URShift(dist, 7)]; - } - - // 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. - internal void gen_bitlen(DeflateManager s) - { - short[] tree = dyn_tree; - short[] stree = staticTree.treeCodes; - int[] extra = staticTree.extraBits; - int base_Renamed = staticTree.extraBase; - int max_length = staticTree.maxLength; - int h; // heap index - int n, m; // iterate over the tree elements - int bits; // bit length - int xbits; // extra bits - short f; // frequency - int overflow = 0; // number of elements with bit length too large - - for (bits = 0; bits <= InternalConstants.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]*2 + 1] = 0; // root of the heap - - for (h = s.heap_max + 1; h < HEAP_SIZE; h++) - { - n = s.heap[h]; - bits = tree[tree[n*2 + 1]*2 + 1] + 1; - if (bits > max_length) - { - bits = max_length; - overflow++; - } - tree[n*2 + 1] = (short) bits; - // We overwrite tree[n*2+1] which is no longer needed - - if (n > max_code) - continue; // not a leaf node - - s.bl_count[bits]++; - xbits = 0; - if (n >= base_Renamed) - xbits = extra[n - base_Renamed]; - f = tree[n*2]; - s.opt_len += f*(bits + xbits); - if (stree != null) - s.static_len += f*(stree[n*2 + 1] + xbits); - } - if (overflow == 0) - return; - - // 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] = (short) (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); - - 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 (tree[m*2 + 1] != bits) - { - s.opt_len = (int) (s.opt_len + (bits - (long) tree[m*2 + 1])*tree[m*2]); - tree[m*2 + 1] = (short) bits; - } - n--; - } - } - } - - // 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. - internal void build_tree(DeflateManager s) - { - short[] tree = dyn_tree; - short[] stree = staticTree.treeCodes; - int elems = staticTree.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[1]. 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*2] != 0) - { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - } - else - { - tree[n*2 + 1] = 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*2] = 1; - s.depth[node] = 0; - s.opt_len--; - if (stree != null) - s.static_len -= stree[node*2 + 1]; - // node is 0 or 1 so it does not have extra bits - } - this.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--) - s.pqdownheap(tree, n); - - // Construct the Huffman tree by repeatedly combining the least two - // frequent nodes. - - node = elems; // next internal node of the tree - do - { - // n = node of least frequency - n = s.heap[1]; - s.heap[1] = s.heap[s.heap_len--]; - s.pqdownheap(tree, 1); - m = s.heap[1]; // 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*2] = unchecked((short) (tree[n*2] + tree[m*2])); - s.depth[node] = (sbyte) (Math.Max((byte) s.depth[n], (byte) s.depth[m]) + 1); - tree[n*2 + 1] = tree[m*2 + 1] = (short) node; - - // and insert the new node in the heap - s.heap[1] = node++; - s.pqdownheap(tree, 1); - } while (s.heap_len >= 2); - - s.heap[--s.heap_max] = s.heap[1]; - - // At this point, the fields freq and dad are set. We can now - // generate the bit lengths. - - gen_bitlen(s); - - // The field len is now set, we can generate the bit codes - gen_codes(tree, max_code, s.bl_count); - } - - // 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. - internal static void gen_codes(short[] tree, int max_code, short[] bl_count) - { - var next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length - short 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 <= InternalConstants.MAX_BITS; bits++) - unchecked - { - next_code[bits] = code = (short) ((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<>= 1; //SharedUtils.URShift(code, 1); - res <<= 1; - } while (--len > 0); - return res >> 1; - } - } - - #endregion - } +// Tree.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2009-October-28 13:29:50> +// +// ------------------------------------------------------------------ +// +// This module defines classes for zlib compression and +// decompression. This code is derived from the jzlib implementation of +// zlib. In keeping with the license for jzlib, the copyright to that +// code is below. +// +// ------------------------------------------------------------------ +// +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +using System; + +namespace SharpCompress.Compressor.Deflate +{ + internal sealed partial class DeflateManager + { + #region Nested type: Tree + + private sealed class Tree + { + internal const int Buf_size = 8*2; + private static readonly int HEAP_SIZE = (2*InternalConstants.L_CODES + 1); + + + internal static readonly sbyte[] bl_order = new sbyte[] + { + 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. + + // see definition of array dist_code below + //internal const int DIST_CODE_LEN = 512; + + private static readonly sbyte[] _dist_code = new sbyte[] + { + 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 + }; + + internal static readonly sbyte[] LengthCode = new sbyte[] + { + 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 + }; + + + internal static readonly int[] LengthBase = new[] + { + 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 + }; + + + internal static readonly int[] DistanceBase = new[] + { + 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 + }; + + + internal short[] dyn_tree; // the dynamic tree + internal int max_code; // largest code with non zero frequency + internal StaticTree staticTree; // the corresponding static tree + + /// + /// Map from a distance to a distance code. + /// + /// + /// No side effects. _dist_code[256] and _dist_code[257] are never used. + /// + internal static int DistanceCode(int dist) + { + return (dist < 256) + ? _dist_code[dist] + : _dist_code[256 + SharedUtils.URShift(dist, 7)]; + } + + // 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. + internal void gen_bitlen(DeflateManager s) + { + short[] tree = dyn_tree; + short[] stree = staticTree.treeCodes; + int[] extra = staticTree.extraBits; + int base_Renamed = staticTree.extraBase; + int max_length = staticTree.maxLength; + int h; // heap index + int n, m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + short f; // frequency + int overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= InternalConstants.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]*2 + 1] = 0; // root of the heap + + for (h = s.heap_max + 1; h < HEAP_SIZE; h++) + { + n = s.heap[h]; + bits = tree[tree[n*2 + 1]*2 + 1] + 1; + if (bits > max_length) + { + bits = max_length; + overflow++; + } + tree[n*2 + 1] = (short) bits; + // We overwrite tree[n*2+1] which is no longer needed + + if (n > max_code) + continue; // not a leaf node + + s.bl_count[bits]++; + xbits = 0; + if (n >= base_Renamed) + xbits = extra[n - base_Renamed]; + f = tree[n*2]; + s.opt_len += f*(bits + xbits); + if (stree != null) + s.static_len += f*(stree[n*2 + 1] + xbits); + } + if (overflow == 0) + return; + + // 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] = (short) (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); + + 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 (tree[m*2 + 1] != bits) + { + s.opt_len = (int) (s.opt_len + (bits - (long) tree[m*2 + 1])*tree[m*2]); + tree[m*2 + 1] = (short) bits; + } + n--; + } + } + } + + // 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. + internal void build_tree(DeflateManager s) + { + short[] tree = dyn_tree; + short[] stree = staticTree.treeCodes; + int elems = staticTree.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[1]. 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*2] != 0) + { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + } + else + { + tree[n*2 + 1] = 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*2] = 1; + s.depth[node] = 0; + s.opt_len--; + if (stree != null) + s.static_len -= stree[node*2 + 1]; + // node is 0 or 1 so it does not have extra bits + } + this.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--) + s.pqdownheap(tree, n); + + // Construct the Huffman tree by repeatedly combining the least two + // frequent nodes. + + node = elems; // next internal node of the tree + do + { + // n = node of least frequency + n = s.heap[1]; + s.heap[1] = s.heap[s.heap_len--]; + s.pqdownheap(tree, 1); + m = s.heap[1]; // 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*2] = unchecked((short) (tree[n*2] + tree[m*2])); + s.depth[node] = (sbyte) (Math.Max((byte) s.depth[n], (byte) s.depth[m]) + 1); + tree[n*2 + 1] = tree[m*2 + 1] = (short) node; + + // and insert the new node in the heap + s.heap[1] = node++; + s.pqdownheap(tree, 1); + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1]; + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + + gen_bitlen(s); + + // The field len is now set, we can generate the bit codes + gen_codes(tree, max_code, s.bl_count); + } + + // 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. + internal static void gen_codes(short[] tree, int max_code, short[] bl_count) + { + var next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length + short 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 <= InternalConstants.MAX_BITS; bits++) + unchecked + { + next_code[bits] = code = (short) ((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<>= 1; //SharedUtils.URShift(code, 1); + res <<= 1; + } while (--len > 0); + return res >> 1; + } + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/Zlib.cs b/src/SharpCompress/Compressor/Deflate/Zlib.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/Zlib.cs rename to src/SharpCompress/Compressor/Deflate/Zlib.cs index e6173ee1..57cd0f7a 100644 --- a/SharpCompress/Compressor/Deflate/Zlib.cs +++ b/src/SharpCompress/Compressor/Deflate/Zlib.cs @@ -1,483 +1,483 @@ -// Zlib.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-November-07 05:26:55> -// -// ------------------------------------------------------------------ -// -// This module defines classes for ZLIB compression and -// decompression. This code is derived from the jzlib implementation of -// zlib, but significantly modified. The object model is not the same, -// and many of the behaviors are new or different. Nonetheless, in -// keeping with the license for jzlib, the copyright to that code is -// included below. -// -// ------------------------------------------------------------------ -// -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -namespace SharpCompress.Compressor.Deflate -{ - /// - /// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. - /// - public enum CompressionLevel - { - /// - /// None means that the data will be simply stored, with no change at all. - /// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None - /// cannot be opened with the default zip reader. Use a different CompressionLevel. - /// - None = 0, - - /// - /// Same as None. - /// - Level0 = 0, - - /// - /// The fastest but least effective compression. - /// - BestSpeed = 1, - - /// - /// A synonym for BestSpeed. - /// - Level1 = 1, - - /// - /// A little slower, but better, than level 1. - /// - Level2 = 2, - - /// - /// A little slower, but better, than level 2. - /// - Level3 = 3, - - /// - /// A little slower, but better, than level 3. - /// - Level4 = 4, - - /// - /// A little slower than level 4, but with better compression. - /// - Level5 = 5, - - /// - /// The default compression level, with a good balance of speed and compression efficiency. - /// - Default = 6, - - /// - /// A synonym for Default. - /// - Level6 = 6, - - /// - /// Pretty good compression! - /// - Level7 = 7, - - /// - /// Better compression than Level7! - /// - Level8 = 8, - - /// - /// The "best" compression, where best means greatest reduction in size of the input data stream. - /// This is also the slowest compression. - /// - BestCompression = 9, - - /// - /// A synonym for BestCompression. - /// - Level9 = 9, - } - - /// - /// Describes options for how the compression algorithm is executed. Different strategies - /// work better on different sorts of data. The strategy parameter can affect the compression - /// ratio and the speed of compression but not the correctness of the compresssion. - /// - public enum CompressionStrategy - { - /// - /// The default strategy is probably the best for normal data. - /// - Default = 0, - - /// - /// The Filtered strategy is intended to be used most effectively with data produced by a - /// filter or predictor. By this definition, 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 Filtered is to force more Huffman - /// coding and less string matching; it is a half-step between Default and HuffmanOnly. - /// - Filtered = 1, - - /// - /// Using HuffmanOnly will force the compressor to do Huffman encoding only, with no - /// string matching. - /// - HuffmanOnly = 2, - } - - - /// - /// A general purpose exception class for exceptions in the Zlib library. - /// - public class ZlibException : System.Exception - { - /// - /// The ZlibException class captures exception information generated - /// by the Zlib library. - /// - public ZlibException() - : base() - { - } - - /// - /// This ctor collects a message attached to the exception. - /// - /// - public ZlibException(System.String s) - : base(s) - { - } - } - - - internal class SharedUtils - { - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static int URShift(int number, int bits) - { - return (int) ((uint) number >> bits); - } - -#if NOT - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static long URShift(long number, int bits) - { - return (long) ((UInt64)number >> bits); - } -#endif - - /// - /// Reads a number of characters from the current source TextReader and writes - /// the data to the target array at the specified index. - /// - /// - /// The source TextReader to read from - /// Contains the array of characteres read from the source TextReader. - /// The starting index of the target array. - /// The maximum number of characters to read from the source TextReader. - /// - /// - /// The number of characters read. The number will be less than or equal to - /// count depending on the data available in the source TextReader. Returns -1 - /// if the end of the stream is reached. - /// - public static System.Int32 ReadInput(System.IO.TextReader sourceTextReader, byte[] target, int start, int count) - { - // Returns 0 bytes if not enough space in target - if (target.Length == 0) return 0; - - char[] charArray = new char[target.Length]; - int bytesRead = sourceTextReader.Read(charArray, start, count); - - // Returns -1 if EOF - if (bytesRead == 0) return -1; - - for (int index = start; index < start + bytesRead; index++) - target[index] = (byte) charArray[index]; - - return bytesRead; - } - } - - internal static class InternalConstants - { - internal static readonly int MAX_BITS = 15; - internal static readonly int BL_CODES = 19; - internal static readonly int D_CODES = 30; - internal static readonly int LITERALS = 256; - internal static readonly int LENGTH_CODES = 29; - internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES); - - // Bit length codes must not exceed MAX_BL_BITS bits - internal static readonly int MAX_BL_BITS = 7; - - // repeat previous bit length 3-6 times (2 bits of repeat count) - internal static readonly int REP_3_6 = 16; - - // repeat a zero length 3-10 times (3 bits of repeat count) - internal static readonly int REPZ_3_10 = 17; - - // repeat a zero length 11-138 times (7 bits of repeat count) - internal static readonly int REPZ_11_138 = 18; - } - - internal sealed class StaticTree - { - internal static readonly short[] lengthAndLiteralsTreeCodes = new short[] - { - 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 - }; - - internal static readonly short[] distTreeCodes = new short[] - { - 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 - }; - - // extra bits for each bit length code - internal static readonly int[] extra_blbits = new int[] - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7}; - - - internal static readonly StaticTree Literals; - internal static readonly StaticTree Distances; - internal static readonly StaticTree BitLengths; - - internal short[] treeCodes; // static tree or null - internal int[] extraBits; // extra bits for each code or null - internal int extraBase; // base index for extra_bits - internal int elems; // max number of elements in the tree - internal int maxLength; // max bit length for the codes - - private StaticTree(short[] treeCodes, int[] extraBits, int extraBase, int elems, int maxLength) - { - this.treeCodes = treeCodes; - this.extraBits = extraBits; - this.extraBase = extraBase; - this.elems = elems; - this.maxLength = maxLength; - } - - static StaticTree() - { - Literals = new StaticTree(lengthAndLiteralsTreeCodes, DeflateManager.ExtraLengthBits, - InternalConstants.LITERALS + 1, InternalConstants.L_CODES, - InternalConstants.MAX_BITS); - Distances = new StaticTree(distTreeCodes, DeflateManager.ExtraDistanceBits, 0, InternalConstants.D_CODES, - InternalConstants.MAX_BITS); - BitLengths = new StaticTree(null, extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS); - } - } - - - /// - /// Computes an Adler-32 checksum. - /// - /// - /// The Adler checksum is similar to a CRC checksum, but faster to compute, though less - /// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum - /// is a required part of the "ZLIB" standard. Applications will almost never need to - /// use this class directly. - /// - internal sealed class Adler - { - // largest prime smaller than 65536 - private static readonly int BASE = 65521; - // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 - private static readonly int NMAX = 5552; - - internal static uint Adler32(uint adler, byte[] buf, int index, int len) - { - if (buf == null) - return 1; - - int s1 = (int) (adler & 0xffff); - int s2 = (int) ((adler >> 16) & 0xffff); - - while (len > 0) - { - int k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) - { - //s1 += (buf[index++] & 0xff); s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - s1 += buf[index++]; - s2 += s1; - k -= 16; - } - if (k != 0) - { - do - { - s1 += buf[index++]; - s2 += s1; - } while (--k != 0); - } - s1 %= BASE; - s2 %= BASE; - } - return (uint) ((s2 << 16) | s1); - } - } +// Zlib.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2009-November-07 05:26:55> +// +// ------------------------------------------------------------------ +// +// This module defines classes for ZLIB compression and +// decompression. This code is derived from the jzlib implementation of +// zlib, but significantly modified. The object model is not the same, +// and many of the behaviors are new or different. Nonetheless, in +// keeping with the license for jzlib, the copyright to that code is +// included below. +// +// ------------------------------------------------------------------ +// +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +namespace SharpCompress.Compressor.Deflate +{ + /// + /// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. + /// + public enum CompressionLevel + { + /// + /// None means that the data will be simply stored, with no change at all. + /// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None + /// cannot be opened with the default zip reader. Use a different CompressionLevel. + /// + None = 0, + + /// + /// Same as None. + /// + Level0 = 0, + + /// + /// The fastest but least effective compression. + /// + BestSpeed = 1, + + /// + /// A synonym for BestSpeed. + /// + Level1 = 1, + + /// + /// A little slower, but better, than level 1. + /// + Level2 = 2, + + /// + /// A little slower, but better, than level 2. + /// + Level3 = 3, + + /// + /// A little slower, but better, than level 3. + /// + Level4 = 4, + + /// + /// A little slower than level 4, but with better compression. + /// + Level5 = 5, + + /// + /// The default compression level, with a good balance of speed and compression efficiency. + /// + Default = 6, + + /// + /// A synonym for Default. + /// + Level6 = 6, + + /// + /// Pretty good compression! + /// + Level7 = 7, + + /// + /// Better compression than Level7! + /// + Level8 = 8, + + /// + /// The "best" compression, where best means greatest reduction in size of the input data stream. + /// This is also the slowest compression. + /// + BestCompression = 9, + + /// + /// A synonym for BestCompression. + /// + Level9 = 9, + } + + /// + /// Describes options for how the compression algorithm is executed. Different strategies + /// work better on different sorts of data. The strategy parameter can affect the compression + /// ratio and the speed of compression but not the correctness of the compresssion. + /// + public enum CompressionStrategy + { + /// + /// The default strategy is probably the best for normal data. + /// + Default = 0, + + /// + /// The Filtered strategy is intended to be used most effectively with data produced by a + /// filter or predictor. By this definition, 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 Filtered is to force more Huffman + /// coding and less string matching; it is a half-step between Default and HuffmanOnly. + /// + Filtered = 1, + + /// + /// Using HuffmanOnly will force the compressor to do Huffman encoding only, with no + /// string matching. + /// + HuffmanOnly = 2, + } + + + /// + /// A general purpose exception class for exceptions in the Zlib library. + /// + public class ZlibException : System.Exception + { + /// + /// The ZlibException class captures exception information generated + /// by the Zlib library. + /// + public ZlibException() + : base() + { + } + + /// + /// This ctor collects a message attached to the exception. + /// + /// + public ZlibException(System.String s) + : base(s) + { + } + } + + + internal class SharedUtils + { + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static int URShift(int number, int bits) + { + return (int) ((uint) number >> bits); + } + +#if NOT + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static long URShift(long number, int bits) + { + return (long) ((UInt64)number >> bits); + } +#endif + + /// + /// Reads a number of characters from the current source TextReader and writes + /// the data to the target array at the specified index. + /// + /// + /// The source TextReader to read from + /// Contains the array of characteres read from the source TextReader. + /// The starting index of the target array. + /// The maximum number of characters to read from the source TextReader. + /// + /// + /// The number of characters read. The number will be less than or equal to + /// count depending on the data available in the source TextReader. Returns -1 + /// if the end of the stream is reached. + /// + public static System.Int32 ReadInput(System.IO.TextReader sourceTextReader, byte[] target, int start, int count) + { + // Returns 0 bytes if not enough space in target + if (target.Length == 0) return 0; + + char[] charArray = new char[target.Length]; + int bytesRead = sourceTextReader.Read(charArray, start, count); + + // Returns -1 if EOF + if (bytesRead == 0) return -1; + + for (int index = start; index < start + bytesRead; index++) + target[index] = (byte) charArray[index]; + + return bytesRead; + } + } + + internal static class InternalConstants + { + internal static readonly int MAX_BITS = 15; + internal static readonly int BL_CODES = 19; + internal static readonly int D_CODES = 30; + internal static readonly int LITERALS = 256; + internal static readonly int LENGTH_CODES = 29; + internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES); + + // Bit length codes must not exceed MAX_BL_BITS bits + internal static readonly int MAX_BL_BITS = 7; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + internal static readonly int REP_3_6 = 16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + internal static readonly int REPZ_3_10 = 17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + internal static readonly int REPZ_11_138 = 18; + } + + internal sealed class StaticTree + { + internal static readonly short[] lengthAndLiteralsTreeCodes = new short[] + { + 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 + }; + + internal static readonly short[] distTreeCodes = new short[] + { + 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 + }; + + // extra bits for each bit length code + internal static readonly int[] extra_blbits = new int[] + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7}; + + + internal static readonly StaticTree Literals; + internal static readonly StaticTree Distances; + internal static readonly StaticTree BitLengths; + + internal short[] treeCodes; // static tree or null + internal int[] extraBits; // extra bits for each code or null + internal int extraBase; // base index for extra_bits + internal int elems; // max number of elements in the tree + internal int maxLength; // max bit length for the codes + + private StaticTree(short[] treeCodes, int[] extraBits, int extraBase, int elems, int maxLength) + { + this.treeCodes = treeCodes; + this.extraBits = extraBits; + this.extraBase = extraBase; + this.elems = elems; + this.maxLength = maxLength; + } + + static StaticTree() + { + Literals = new StaticTree(lengthAndLiteralsTreeCodes, DeflateManager.ExtraLengthBits, + InternalConstants.LITERALS + 1, InternalConstants.L_CODES, + InternalConstants.MAX_BITS); + Distances = new StaticTree(distTreeCodes, DeflateManager.ExtraDistanceBits, 0, InternalConstants.D_CODES, + InternalConstants.MAX_BITS); + BitLengths = new StaticTree(null, extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS); + } + } + + + /// + /// Computes an Adler-32 checksum. + /// + /// + /// The Adler checksum is similar to a CRC checksum, but faster to compute, though less + /// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum + /// is a required part of the "ZLIB" standard. Applications will almost never need to + /// use this class directly. + /// + internal sealed class Adler + { + // largest prime smaller than 65536 + private static readonly int BASE = 65521; + // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + private static readonly int NMAX = 5552; + + internal static uint Adler32(uint adler, byte[] buf, int index, int len) + { + if (buf == null) + return 1; + + int s1 = (int) (adler & 0xffff); + int s2 = (int) ((adler >> 16) & 0xffff); + + while (len > 0) + { + int k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) + { + //s1 += (buf[index++] & 0xff); s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + s1 += buf[index++]; + s2 += s1; + k -= 16; + } + if (k != 0) + { + do + { + s1 += buf[index++]; + s2 += s1; + } while (--k != 0); + } + s1 %= BASE; + s2 %= BASE; + } + return (uint) ((s2 << 16) | s1); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs b/src/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/ZlibBaseStream.cs rename to src/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs index 1bfe1f6e..4957de6f 100644 --- a/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs +++ b/src/SharpCompress/Compressor/Deflate/ZlibBaseStream.cs @@ -1,587 +1,587 @@ -// ZlibBaseStream.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-October-28 15:45:15> -// -// ------------------------------------------------------------------ -// -// This module defines the ZlibBaseStream class, which is an intnernal -// base class for DeflateStream, ZlibStream and GZipStream. -// -// ------------------------------------------------------------------ - -using System; -using SharpCompress.Common; -using SharpCompress.Common.Tar.Headers; - -namespace SharpCompress.Compressor.Deflate -{ - internal enum ZlibStreamFlavor - { - ZLIB = 1950, - DEFLATE = 1951, - GZIP = 1952 - } - - internal class ZlibBaseStream : System.IO.Stream - { - protected internal ZlibCodec _z = null; // deferred init... new ZlibCodec(); - - protected internal StreamMode _streamMode = StreamMode.Undefined; - protected internal FlushType _flushMode; - protected internal ZlibStreamFlavor _flavor; - protected internal CompressionMode _compressionMode; - protected internal CompressionLevel _level; - protected internal bool _leaveOpen; - protected internal byte[] _workingBuffer; - protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault; - protected internal byte[] _buf1 = new byte[1]; - - protected internal System.IO.Stream _stream; - protected internal CompressionStrategy Strategy = CompressionStrategy.Default; - - // workitem 7159 - private CRC32 crc; - protected internal string _GzipFileName; - protected internal string _GzipComment; - protected internal DateTime _GzipMtime; - protected internal int _gzipHeaderByteCount; - - internal int Crc32 - { - get - { - if (crc == null) - return 0; - return crc.Crc32Result; - } - } - - public ZlibBaseStream(System.IO.Stream stream, - CompressionMode compressionMode, - CompressionLevel level, - ZlibStreamFlavor flavor, - bool leaveOpen) - : base() - { - this._flushMode = FlushType.None; - //this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT]; - this._stream = stream; - this._leaveOpen = leaveOpen; - this._compressionMode = compressionMode; - this._flavor = flavor; - this._level = level; - // workitem 7159 - if (flavor == ZlibStreamFlavor.GZIP) - { - crc = new CRC32(); - } - } - - - protected internal bool _wantCompress - { - get { return (this._compressionMode == CompressionMode.Compress); } - } - - private ZlibCodec z - { - get - { - if (_z == null) - { - bool wantRfc1950Header = (this._flavor == ZlibStreamFlavor.ZLIB); - _z = new ZlibCodec(); - if (this._compressionMode == CompressionMode.Decompress) - { - _z.InitializeInflate(wantRfc1950Header); - } - else - { - _z.Strategy = Strategy; - _z.InitializeDeflate(this._level, wantRfc1950Header); - } - } - return _z; - } - } - - - private byte[] workingBuffer - { - get - { - if (_workingBuffer == null) - _workingBuffer = new byte[_bufferSize]; - return _workingBuffer; - } - } - - - public override void Write(System.Byte[] buffer, int offset, int count) - { - // workitem 7159 - // calculate the CRC on the unccompressed data (before writing) - if (crc != null) - crc.SlurpBlock(buffer, offset, count); - - if (_streamMode == StreamMode.Undefined) - _streamMode = StreamMode.Writer; - else if (_streamMode != StreamMode.Writer) - throw new ZlibException("Cannot Write after Reading."); - - if (count == 0) - return; - - // first reference of z property will initialize the private var _z - z.InputBuffer = buffer; - _z.NextIn = offset; - _z.AvailableBytesIn = count; - bool done = false; - do - { - _z.OutputBuffer = workingBuffer; - _z.NextOut = 0; - _z.AvailableBytesOut = _workingBuffer.Length; - int rc = (_wantCompress) - ? _z.Deflate(_flushMode) - : _z.Inflate(_flushMode); - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message); - - //if (_workingBuffer.Length - _z.AvailableBytesOut > 0) - _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); - - done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; - - // If GZIP and de-compress, we're done when 8 bytes remain. - if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) - done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); - } while (!done); - } - - - private void finish() - { - if (_z == null) - return; - - if (_streamMode == StreamMode.Writer) - { - bool done = false; - do - { - _z.OutputBuffer = workingBuffer; - _z.NextOut = 0; - _z.AvailableBytesOut = _workingBuffer.Length; - int rc = (_wantCompress) - ? _z.Deflate(FlushType.Finish) - : _z.Inflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - { - string verb = (_wantCompress ? "de" : "in") + "flating"; - if (_z.Message == null) - throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc)); - else - throw new ZlibException(verb + ": " + _z.Message); - } - - if (_workingBuffer.Length - _z.AvailableBytesOut > 0) - { - _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); - } - - done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; - // If GZIP and de-compress, we're done when 8 bytes remain. - if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) - done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); - } while (!done); - - Flush(); - - // workitem 7159 - if (_flavor == ZlibStreamFlavor.GZIP) - { - if (_wantCompress) - { - // Emit the GZIP trailer: CRC32 and size mod 2^32 - int c1 = crc.Crc32Result; - _stream.Write(BitConverter.GetBytes(c1), 0, 4); - int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF); - _stream.Write(BitConverter.GetBytes(c2), 0, 4); - } - else - { - throw new ZlibException("Writing with decompression is not supported."); - } - } - } - // workitem 7159 - else if (_streamMode == StreamMode.Reader) - { - if (_flavor == ZlibStreamFlavor.GZIP) - { - if (!_wantCompress) - { - // workitem 8501: handle edge case (decompress empty stream) - if (_z.TotalBytesOut == 0L) - return; - - // Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32 - byte[] trailer = new byte[8]; - - // workitem 8679 - if (_z.AvailableBytesIn != 8) - { - // Make sure we have read to the end of the stream - Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, _z.AvailableBytesIn); - int bytesNeeded = 8 - _z.AvailableBytesIn; - int bytesRead = _stream.Read(trailer, - _z.AvailableBytesIn, - bytesNeeded); - if (bytesNeeded != bytesRead) - { - throw new ZlibException(String.Format( - "Protocol error. AvailableBytesIn={0}, expected 8", - _z.AvailableBytesIn + bytesRead)); - } - } - else - { - Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, trailer.Length); - } - - - Int32 crc32_expected = BitConverter.ToInt32(trailer, 0); - Int32 crc32_actual = crc.Crc32Result; - Int32 isize_expected = BitConverter.ToInt32(trailer, 4); - Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF); - - if (crc32_actual != crc32_expected) - throw new ZlibException( - String.Format("Bad CRC32 in GZIP stream. (actual({0:X8})!=expected({1:X8}))", - crc32_actual, crc32_expected)); - - if (isize_actual != isize_expected) - throw new ZlibException( - String.Format("Bad size in GZIP stream. (actual({0})!=expected({1}))", isize_actual, - isize_expected)); - } - else - { - throw new ZlibException("Reading with compression is not supported."); - } - } - } - } - - - private void end() - { - if (z == null) - return; - if (_wantCompress) - { - _z.EndDeflate(); - } - else - { - _z.EndInflate(); - } - _z = null; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - if (disposing) - { - if (_stream == null) - return; - try - { - finish(); - } - finally - { - end(); - if (!_leaveOpen) - _stream.Dispose(); - _stream = null; - } - } - } - - public override void Flush() - { - _stream.Flush(); - } - - public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) - { - throw new NotSupportedException(); - //_outStream.Seek(offset, origin); - } - - public override void SetLength(System.Int64 value) - { - _stream.SetLength(value); - } - - -#if NOT - public int Read() - { - if (Read(_buf1, 0, 1) == 0) - return 0; - // calculate CRC after reading - if (crc!=null) - crc.SlurpBlock(_buf1,0,1); - return (_buf1[0] & 0xFF); - } -#endif - - private bool nomoreinput = false; - private bool isDisposed; - - - private string ReadZeroTerminatedString() - { - var list = new System.Collections.Generic.List(); - bool done = false; - do - { - // workitem 7740 - int n = _stream.Read(_buf1, 0, 1); - if (n != 1) - throw new ZlibException("Unexpected EOF reading GZIP header."); - else - { - if (_buf1[0] == 0) - done = true; - else - list.Add(_buf1[0]); - } - } while (!done); - byte[] a = list.ToArray(); - return ArchiveEncoding.Default.GetString(a, 0, a.Length); - } - - - private int _ReadAndValidateGzipHeader() - { - int totalBytesRead = 0; - // read the header on the first read - byte[] header = new byte[10]; - int n = _stream.Read(header, 0, header.Length); - - // workitem 8501: handle edge case (decompress empty stream) - if (n == 0) - return 0; - - if (n != 10) - throw new ZlibException("Not a valid GZIP stream."); - - if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) - throw new ZlibException("Bad GZIP header."); - - Int32 timet = BitConverter.ToInt32(header, 4); - _GzipMtime = TarHeader.Epoch.AddSeconds(timet); - totalBytesRead += n; - if ((header[3] & 0x04) == 0x04) - { - // read and discard extra field - n = _stream.Read(header, 0, 2); // 2-byte length field - totalBytesRead += n; - - Int16 extraLength = (Int16)(header[0] + header[1] * 256); - byte[] extra = new byte[extraLength]; - n = _stream.Read(extra, 0, extra.Length); - if (n != extraLength) - throw new ZlibException("Unexpected end-of-file reading GZIP header."); - totalBytesRead += n; - } - if ((header[3] & 0x08) == 0x08) - _GzipFileName = ReadZeroTerminatedString(); - if ((header[3] & 0x10) == 0x010) - _GzipComment = ReadZeroTerminatedString(); - if ((header[3] & 0x02) == 0x02) - Read(_buf1, 0, 1); // CRC16, ignore - - return totalBytesRead; - } - - - public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count) - { - // According to MS documentation, any implementation of the IO.Stream.Read function must: - // (a) throw an exception if offset & count reference an invalid part of the buffer, - // or if count < 0, or if buffer is null - // (b) return 0 only upon EOF, or if count = 0 - // (c) if not EOF, then return at least 1 byte, up to bytes - - if (_streamMode == StreamMode.Undefined) - { - if (!this._stream.CanRead) - throw new ZlibException("The stream is not readable."); - // for the first read, set up some controls. - _streamMode = StreamMode.Reader; - // (The first reference to _z goes through the private accessor which - // may initialize it.) - z.AvailableBytesIn = 0; - if (_flavor == ZlibStreamFlavor.GZIP) - { - _gzipHeaderByteCount = _ReadAndValidateGzipHeader(); - // workitem 8501: handle edge case (decompress empty stream) - if (_gzipHeaderByteCount == 0) - return 0; - } - } - - if (_streamMode != StreamMode.Reader) - throw new ZlibException("Cannot Read after Writing."); - - if (count == 0) - return 0; - if (nomoreinput && _wantCompress) - return 0; // workitem 8557 - if (buffer == null) - throw new ArgumentNullException("buffer"); - if (count < 0) - throw new ArgumentOutOfRangeException("count"); - if (offset < buffer.GetLowerBound(0)) - throw new ArgumentOutOfRangeException("offset"); - if ((offset + count) > buffer.GetLength(0)) - throw new ArgumentOutOfRangeException("count"); - - int rc = 0; - - // set up the output of the deflate/inflate codec: - _z.OutputBuffer = buffer; - _z.NextOut = offset; - _z.AvailableBytesOut = count; - - // This is necessary in case _workingBuffer has been resized. (new byte[]) - // (The first reference to _workingBuffer goes through the private accessor which - // may initialize it.) - _z.InputBuffer = workingBuffer; - - do - { - // need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any. - if ((_z.AvailableBytesIn == 0) && (!nomoreinput)) - { - // No data available, so try to Read data from the captive stream. - _z.NextIn = 0; - _z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length); - if (_z.AvailableBytesIn == 0) - nomoreinput = true; - } - // we have data in InputBuffer; now compress or decompress as appropriate - rc = (_wantCompress) - ? _z.Deflate(_flushMode) - : _z.Inflate(_flushMode); - - if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR)) - return 0; - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new ZlibException(String.Format("{0}flating: rc={1} msg={2}", (_wantCompress ? "de" : "in"), - rc, _z.Message)); - - if ((nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count)) - break; // nothing more to read - } //while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK); - while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK); - - - // workitem 8557 - // is there more room in output? - if (_z.AvailableBytesOut > 0) - { - if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0) - { - // deferred - } - - // are we completely done reading? - if (nomoreinput) - { - // and in compression? - if (_wantCompress) - { - // no more input data available; therefore we flush to - // try to complete the read - rc = _z.Deflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message)); - } - } - } - - - rc = (count - _z.AvailableBytesOut); - - // calculate CRC after reading - if (crc != null) - crc.SlurpBlock(buffer, offset, rc); - - return rc; - } - - - public override System.Boolean CanRead - { - get { return this._stream.CanRead; } - } - - public override System.Boolean CanSeek - { - get { return this._stream.CanSeek; } - } - - public override System.Boolean CanWrite - { - get { return this._stream.CanWrite; } - } - - public override System.Int64 Length - { - get { return _stream.Length; } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - internal enum StreamMode - { - Writer, - Reader, - Undefined, - } - } +// ZlibBaseStream.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2009-October-28 15:45:15> +// +// ------------------------------------------------------------------ +// +// This module defines the ZlibBaseStream class, which is an intnernal +// base class for DeflateStream, ZlibStream and GZipStream. +// +// ------------------------------------------------------------------ + +using System; +using SharpCompress.Common; +using SharpCompress.Common.Tar.Headers; + +namespace SharpCompress.Compressor.Deflate +{ + internal enum ZlibStreamFlavor + { + ZLIB = 1950, + DEFLATE = 1951, + GZIP = 1952 + } + + internal class ZlibBaseStream : System.IO.Stream + { + protected internal ZlibCodec _z = null; // deferred init... new ZlibCodec(); + + protected internal StreamMode _streamMode = StreamMode.Undefined; + protected internal FlushType _flushMode; + protected internal ZlibStreamFlavor _flavor; + protected internal CompressionMode _compressionMode; + protected internal CompressionLevel _level; + protected internal bool _leaveOpen; + protected internal byte[] _workingBuffer; + protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault; + protected internal byte[] _buf1 = new byte[1]; + + protected internal System.IO.Stream _stream; + protected internal CompressionStrategy Strategy = CompressionStrategy.Default; + + // workitem 7159 + private CRC32 crc; + protected internal string _GzipFileName; + protected internal string _GzipComment; + protected internal DateTime _GzipMtime; + protected internal int _gzipHeaderByteCount; + + internal int Crc32 + { + get + { + if (crc == null) + return 0; + return crc.Crc32Result; + } + } + + public ZlibBaseStream(System.IO.Stream stream, + CompressionMode compressionMode, + CompressionLevel level, + ZlibStreamFlavor flavor, + bool leaveOpen) + : base() + { + this._flushMode = FlushType.None; + //this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT]; + this._stream = stream; + this._leaveOpen = leaveOpen; + this._compressionMode = compressionMode; + this._flavor = flavor; + this._level = level; + // workitem 7159 + if (flavor == ZlibStreamFlavor.GZIP) + { + crc = new CRC32(); + } + } + + + protected internal bool _wantCompress + { + get { return (this._compressionMode == CompressionMode.Compress); } + } + + private ZlibCodec z + { + get + { + if (_z == null) + { + bool wantRfc1950Header = (this._flavor == ZlibStreamFlavor.ZLIB); + _z = new ZlibCodec(); + if (this._compressionMode == CompressionMode.Decompress) + { + _z.InitializeInflate(wantRfc1950Header); + } + else + { + _z.Strategy = Strategy; + _z.InitializeDeflate(this._level, wantRfc1950Header); + } + } + return _z; + } + } + + + private byte[] workingBuffer + { + get + { + if (_workingBuffer == null) + _workingBuffer = new byte[_bufferSize]; + return _workingBuffer; + } + } + + + public override void Write(System.Byte[] buffer, int offset, int count) + { + // workitem 7159 + // calculate the CRC on the unccompressed data (before writing) + if (crc != null) + crc.SlurpBlock(buffer, offset, count); + + if (_streamMode == StreamMode.Undefined) + _streamMode = StreamMode.Writer; + else if (_streamMode != StreamMode.Writer) + throw new ZlibException("Cannot Write after Reading."); + + if (count == 0) + return; + + // first reference of z property will initialize the private var _z + z.InputBuffer = buffer; + _z.NextIn = offset; + _z.AvailableBytesIn = count; + bool done = false; + do + { + _z.OutputBuffer = workingBuffer; + _z.NextOut = 0; + _z.AvailableBytesOut = _workingBuffer.Length; + int rc = (_wantCompress) + ? _z.Deflate(_flushMode) + : _z.Inflate(_flushMode); + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message); + + //if (_workingBuffer.Length - _z.AvailableBytesOut > 0) + _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); + + done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; + + // If GZIP and de-compress, we're done when 8 bytes remain. + if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) + done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); + } while (!done); + } + + + private void finish() + { + if (_z == null) + return; + + if (_streamMode == StreamMode.Writer) + { + bool done = false; + do + { + _z.OutputBuffer = workingBuffer; + _z.NextOut = 0; + _z.AvailableBytesOut = _workingBuffer.Length; + int rc = (_wantCompress) + ? _z.Deflate(FlushType.Finish) + : _z.Inflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + { + string verb = (_wantCompress ? "de" : "in") + "flating"; + if (_z.Message == null) + throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc)); + else + throw new ZlibException(verb + ": " + _z.Message); + } + + if (_workingBuffer.Length - _z.AvailableBytesOut > 0) + { + _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); + } + + done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; + // If GZIP and de-compress, we're done when 8 bytes remain. + if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) + done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); + } while (!done); + + Flush(); + + // workitem 7159 + if (_flavor == ZlibStreamFlavor.GZIP) + { + if (_wantCompress) + { + // Emit the GZIP trailer: CRC32 and size mod 2^32 + int c1 = crc.Crc32Result; + _stream.Write(BitConverter.GetBytes(c1), 0, 4); + int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF); + _stream.Write(BitConverter.GetBytes(c2), 0, 4); + } + else + { + throw new ZlibException("Writing with decompression is not supported."); + } + } + } + // workitem 7159 + else if (_streamMode == StreamMode.Reader) + { + if (_flavor == ZlibStreamFlavor.GZIP) + { + if (!_wantCompress) + { + // workitem 8501: handle edge case (decompress empty stream) + if (_z.TotalBytesOut == 0L) + return; + + // Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32 + byte[] trailer = new byte[8]; + + // workitem 8679 + if (_z.AvailableBytesIn != 8) + { + // Make sure we have read to the end of the stream + Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, _z.AvailableBytesIn); + int bytesNeeded = 8 - _z.AvailableBytesIn; + int bytesRead = _stream.Read(trailer, + _z.AvailableBytesIn, + bytesNeeded); + if (bytesNeeded != bytesRead) + { + throw new ZlibException(String.Format( + "Protocol error. AvailableBytesIn={0}, expected 8", + _z.AvailableBytesIn + bytesRead)); + } + } + else + { + Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, trailer.Length); + } + + + Int32 crc32_expected = BitConverter.ToInt32(trailer, 0); + Int32 crc32_actual = crc.Crc32Result; + Int32 isize_expected = BitConverter.ToInt32(trailer, 4); + Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF); + + if (crc32_actual != crc32_expected) + throw new ZlibException( + String.Format("Bad CRC32 in GZIP stream. (actual({0:X8})!=expected({1:X8}))", + crc32_actual, crc32_expected)); + + if (isize_actual != isize_expected) + throw new ZlibException( + String.Format("Bad size in GZIP stream. (actual({0})!=expected({1}))", isize_actual, + isize_expected)); + } + else + { + throw new ZlibException("Reading with compression is not supported."); + } + } + } + } + + + private void end() + { + if (z == null) + return; + if (_wantCompress) + { + _z.EndDeflate(); + } + else + { + _z.EndInflate(); + } + _z = null; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + if (disposing) + { + if (_stream == null) + return; + try + { + finish(); + } + finally + { + end(); + if (!_leaveOpen) + _stream.Dispose(); + _stream = null; + } + } + } + + public override void Flush() + { + _stream.Flush(); + } + + public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) + { + throw new NotSupportedException(); + //_outStream.Seek(offset, origin); + } + + public override void SetLength(System.Int64 value) + { + _stream.SetLength(value); + } + + +#if NOT + public int Read() + { + if (Read(_buf1, 0, 1) == 0) + return 0; + // calculate CRC after reading + if (crc!=null) + crc.SlurpBlock(_buf1,0,1); + return (_buf1[0] & 0xFF); + } +#endif + + private bool nomoreinput = false; + private bool isDisposed; + + + private string ReadZeroTerminatedString() + { + var list = new System.Collections.Generic.List(); + bool done = false; + do + { + // workitem 7740 + int n = _stream.Read(_buf1, 0, 1); + if (n != 1) + throw new ZlibException("Unexpected EOF reading GZIP header."); + else + { + if (_buf1[0] == 0) + done = true; + else + list.Add(_buf1[0]); + } + } while (!done); + byte[] a = list.ToArray(); + return ArchiveEncoding.Default.GetString(a, 0, a.Length); + } + + + private int _ReadAndValidateGzipHeader() + { + int totalBytesRead = 0; + // read the header on the first read + byte[] header = new byte[10]; + int n = _stream.Read(header, 0, header.Length); + + // workitem 8501: handle edge case (decompress empty stream) + if (n == 0) + return 0; + + if (n != 10) + throw new ZlibException("Not a valid GZIP stream."); + + if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) + throw new ZlibException("Bad GZIP header."); + + Int32 timet = BitConverter.ToInt32(header, 4); + _GzipMtime = TarHeader.Epoch.AddSeconds(timet); + totalBytesRead += n; + if ((header[3] & 0x04) == 0x04) + { + // read and discard extra field + n = _stream.Read(header, 0, 2); // 2-byte length field + totalBytesRead += n; + + Int16 extraLength = (Int16)(header[0] + header[1] * 256); + byte[] extra = new byte[extraLength]; + n = _stream.Read(extra, 0, extra.Length); + if (n != extraLength) + throw new ZlibException("Unexpected end-of-file reading GZIP header."); + totalBytesRead += n; + } + if ((header[3] & 0x08) == 0x08) + _GzipFileName = ReadZeroTerminatedString(); + if ((header[3] & 0x10) == 0x010) + _GzipComment = ReadZeroTerminatedString(); + if ((header[3] & 0x02) == 0x02) + Read(_buf1, 0, 1); // CRC16, ignore + + return totalBytesRead; + } + + + public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count) + { + // According to MS documentation, any implementation of the IO.Stream.Read function must: + // (a) throw an exception if offset & count reference an invalid part of the buffer, + // or if count < 0, or if buffer is null + // (b) return 0 only upon EOF, or if count = 0 + // (c) if not EOF, then return at least 1 byte, up to bytes + + if (_streamMode == StreamMode.Undefined) + { + if (!this._stream.CanRead) + throw new ZlibException("The stream is not readable."); + // for the first read, set up some controls. + _streamMode = StreamMode.Reader; + // (The first reference to _z goes through the private accessor which + // may initialize it.) + z.AvailableBytesIn = 0; + if (_flavor == ZlibStreamFlavor.GZIP) + { + _gzipHeaderByteCount = _ReadAndValidateGzipHeader(); + // workitem 8501: handle edge case (decompress empty stream) + if (_gzipHeaderByteCount == 0) + return 0; + } + } + + if (_streamMode != StreamMode.Reader) + throw new ZlibException("Cannot Read after Writing."); + + if (count == 0) + return 0; + if (nomoreinput && _wantCompress) + return 0; // workitem 8557 + if (buffer == null) + throw new ArgumentNullException("buffer"); + if (count < 0) + throw new ArgumentOutOfRangeException("count"); + if (offset < buffer.GetLowerBound(0)) + throw new ArgumentOutOfRangeException("offset"); + if ((offset + count) > buffer.GetLength(0)) + throw new ArgumentOutOfRangeException("count"); + + int rc = 0; + + // set up the output of the deflate/inflate codec: + _z.OutputBuffer = buffer; + _z.NextOut = offset; + _z.AvailableBytesOut = count; + + // This is necessary in case _workingBuffer has been resized. (new byte[]) + // (The first reference to _workingBuffer goes through the private accessor which + // may initialize it.) + _z.InputBuffer = workingBuffer; + + do + { + // need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any. + if ((_z.AvailableBytesIn == 0) && (!nomoreinput)) + { + // No data available, so try to Read data from the captive stream. + _z.NextIn = 0; + _z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length); + if (_z.AvailableBytesIn == 0) + nomoreinput = true; + } + // we have data in InputBuffer; now compress or decompress as appropriate + rc = (_wantCompress) + ? _z.Deflate(_flushMode) + : _z.Inflate(_flushMode); + + if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR)) + return 0; + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new ZlibException(String.Format("{0}flating: rc={1} msg={2}", (_wantCompress ? "de" : "in"), + rc, _z.Message)); + + if ((nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count)) + break; // nothing more to read + } //while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK); + while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK); + + + // workitem 8557 + // is there more room in output? + if (_z.AvailableBytesOut > 0) + { + if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0) + { + // deferred + } + + // are we completely done reading? + if (nomoreinput) + { + // and in compression? + if (_wantCompress) + { + // no more input data available; therefore we flush to + // try to complete the read + rc = _z.Deflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message)); + } + } + } + + + rc = (count - _z.AvailableBytesOut); + + // calculate CRC after reading + if (crc != null) + crc.SlurpBlock(buffer, offset, rc); + + return rc; + } + + + public override System.Boolean CanRead + { + get { return this._stream.CanRead; } + } + + public override System.Boolean CanSeek + { + get { return this._stream.CanSeek; } + } + + public override System.Boolean CanWrite + { + get { return this._stream.CanWrite; } + } + + public override System.Int64 Length + { + get { return _stream.Length; } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + internal enum StreamMode + { + Writer, + Reader, + Undefined, + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/ZlibCodec.cs b/src/SharpCompress/Compressor/Deflate/ZlibCodec.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/ZlibCodec.cs rename to src/SharpCompress/Compressor/Deflate/ZlibCodec.cs index cd521d34..b559838d 100644 --- a/SharpCompress/Compressor/Deflate/ZlibCodec.cs +++ b/src/SharpCompress/Compressor/Deflate/ZlibCodec.cs @@ -1,717 +1,717 @@ -// ZlibCodec.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-November-03 15:40:51> -// -// ------------------------------------------------------------------ -// -// This module defines a Codec for ZLIB compression and -// decompression. This code extends code that was based the jzlib -// implementation of zlib, but this code is completely novel. The codec -// class is new, and encapsulates some behaviors that are new, and some -// that were present in other classes in the jzlib code base. In -// keeping with the license for jzlib, the copyright to the jzlib code -// is included below. -// -// ------------------------------------------------------------------ -// -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -using System; - -namespace SharpCompress.Compressor.Deflate -{ - /// - /// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). - /// - /// - /// - /// This class compresses and decompresses data according to the Deflate algorithm - /// and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. - /// - internal sealed class ZlibCodec - { - /// - /// The buffer from which data is taken. - /// - public byte[] InputBuffer; - - /// - /// An index into the InputBuffer array, indicating where to start reading. - /// - public int NextIn; - - /// - /// The number of bytes available in the InputBuffer, starting at NextIn. - /// - /// - /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. - /// The class will update this number as calls to Inflate/Deflate are made. - /// - public int AvailableBytesIn; - - /// - /// Total number of bytes read so far, through all calls to Inflate()/Deflate(). - /// - public long TotalBytesIn; - - /// - /// Buffer to store output data. - /// - public byte[] OutputBuffer; - - /// - /// An index into the OutputBuffer array, indicating where to start writing. - /// - public int NextOut; - - /// - /// The number of bytes available in the OutputBuffer, starting at NextOut. - /// - /// - /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. - /// The class will update this number as calls to Inflate/Deflate are made. - /// - public int AvailableBytesOut; - - /// - /// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). - /// - public long TotalBytesOut; - - /// - /// used for diagnostics, when something goes wrong! - /// - public System.String Message; - - internal DeflateManager dstate; - internal InflateManager istate; - - internal uint _Adler32; - - /// - /// The compression level to use in this codec. Useful only in compression mode. - /// - public CompressionLevel CompressLevel = CompressionLevel.Default; - - /// - /// The number of Window Bits to use. - /// - /// - /// This gauges the size of the sliding window, and hence the - /// compression effectiveness as well as memory consumption. It's best to just leave this - /// setting alone if you don't know what it is. The maximum value is 15 bits, which implies - /// a 32k window. - /// - public int WindowBits = ZlibConstants.WindowBitsDefault; - - /// - /// The compression strategy to use. - /// - /// - /// This is only effective in compression. The theory offered by ZLIB is that different - /// strategies could potentially produce significant differences in compression behavior - /// for different data sets. Unfortunately I don't have any good recommendations for how - /// to set it differently. When I tested changing the strategy I got minimally different - /// compression performance. It's best to leave this property alone if you don't have a - /// good feel for it. Or, you may want to produce a test harness that runs through the - /// different strategy options and evaluates them on different file types. If you do that, - /// let me know your results. - /// - public CompressionStrategy Strategy = CompressionStrategy.Default; - - - /// - /// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. - /// - public int Adler32 - { - get { return (int) _Adler32; } - } - - - /// - /// Create a ZlibCodec. - /// - /// - /// If you use this default constructor, you will later have to explicitly call - /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress - /// or decompress. - /// - public ZlibCodec() - { - } - - /// - /// Create a ZlibCodec that either compresses or decompresses. - /// - /// - /// Indicates whether the codec should compress (deflate) or decompress (inflate). - /// - public ZlibCodec(CompressionMode mode) - { - if (mode == CompressionMode.Compress) - { - int rc = InitializeDeflate(); - if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for deflate."); - } - else if (mode == CompressionMode.Decompress) - { - int rc = InitializeInflate(); - if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for inflate."); - } - else throw new ZlibException("Invalid ZlibStreamFlavor."); - } - - /// - /// Initialize the inflation state. - /// - /// - /// It is not necessary to call this before using the ZlibCodec to inflate data; - /// It is implicitly called when you call the constructor. - /// - /// Z_OK if everything goes well. - public int InitializeInflate() - { - return InitializeInflate(this.WindowBits); - } - - /// - /// Initialize the inflation state with an explicit flag to - /// govern the handling of RFC1950 header bytes. - /// - /// - /// - /// By default, the ZLIB header defined in RFC 1950 is expected. If - /// you want to read a zlib stream you should specify true for - /// expectRfc1950Header. If you have a deflate stream, you will want to specify - /// false. It is only necessary to invoke this initializer explicitly if you - /// want to specify false. - /// - /// - /// whether to expect an RFC1950 header byte - /// pair when reading the stream of data to be inflated. - /// - /// Z_OK if everything goes well. - public int InitializeInflate(bool expectRfc1950Header) - { - return InitializeInflate(this.WindowBits, expectRfc1950Header); - } - - /// - /// Initialize the ZlibCodec for inflation, with the specified number of window bits. - /// - /// The number of window bits to use. If you need to ask what that is, - /// then you shouldn't be calling this initializer. - /// Z_OK if all goes well. - public int InitializeInflate(int windowBits) - { - this.WindowBits = windowBits; - return InitializeInflate(windowBits, true); - } - - /// - /// Initialize the inflation state with an explicit flag to govern the handling of - /// RFC1950 header bytes. - /// - /// - /// - /// If you want to read a zlib stream you should specify true for - /// expectRfc1950Header. In this case, the library will expect to find a ZLIB - /// header, as defined in RFC - /// 1950, in the compressed stream. If you will be reading a DEFLATE or - /// GZIP stream, which does not have such a header, you will want to specify - /// false. - /// - /// - /// whether to expect an RFC1950 header byte pair when reading - /// the stream of data to be inflated. - /// The number of window bits to use. If you need to ask what that is, - /// then you shouldn't be calling this initializer. - /// Z_OK if everything goes well. - public int InitializeInflate(int windowBits, bool expectRfc1950Header) - { - this.WindowBits = windowBits; - if (dstate != null) - throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate()."); - istate = new InflateManager(expectRfc1950Header); - return istate.Initialize(this, windowBits); - } - - /// - /// Inflate the data in the InputBuffer, placing the result in the OutputBuffer. - /// - /// - /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and - /// AvailableBytesOut before calling this method. - /// - /// - /// - /// private void InflateBuffer() - /// { - /// int bufferSize = 1024; - /// byte[] buffer = new byte[bufferSize]; - /// ZlibCodec decompressor = new ZlibCodec(); - /// - /// Console.WriteLine("\n============================================"); - /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); - /// MemoryStream ms = new MemoryStream(DecompressedBytes); - /// - /// int rc = decompressor.InitializeInflate(); - /// - /// decompressor.InputBuffer = CompressedBytes; - /// decompressor.NextIn = 0; - /// decompressor.AvailableBytesIn = CompressedBytes.Length; - /// - /// decompressor.OutputBuffer = buffer; - /// - /// // pass 1: inflate - /// do - /// { - /// decompressor.NextOut = 0; - /// decompressor.AvailableBytesOut = buffer.Length; - /// rc = decompressor.Inflate(FlushType.None); - /// - /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - /// throw new Exception("inflating: " + decompressor.Message); - /// - /// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); - /// } - /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - /// - /// // pass 2: finish and flush - /// do - /// { - /// decompressor.NextOut = 0; - /// decompressor.AvailableBytesOut = buffer.Length; - /// rc = decompressor.Inflate(FlushType.Finish); - /// - /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - /// throw new Exception("inflating: " + decompressor.Message); - /// - /// if (buffer.Length - decompressor.AvailableBytesOut > 0) - /// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); - /// } - /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - /// - /// decompressor.EndInflate(); - /// } - /// - /// - /// - /// The flush to use when inflating. - /// Z_OK if everything goes well. - public int Inflate(FlushType flush) - { - if (istate == null) - throw new ZlibException("No Inflate State!"); - return istate.Inflate(flush); - } - - - /// - /// Ends an inflation session. - /// - /// - /// Call this after successively calling Inflate(). This will cause all buffers to be flushed. - /// After calling this you cannot call Inflate() without a intervening call to one of the - /// InitializeInflate() overloads. - /// - /// Z_OK if everything goes well. - public int EndInflate() - { - if (istate == null) - throw new ZlibException("No Inflate State!"); - int ret = istate.End(); - istate = null; - return ret; - } - - /// - /// I don't know what this does! - /// - /// Z_OK if everything goes well. - public int SyncInflate() - { - if (istate == null) - throw new ZlibException("No Inflate State!"); - return istate.Sync(); - } - - /// - /// Initialize the ZlibCodec for deflation operation. - /// - /// - /// The codec will use the MAX window bits and the default level of compression. - /// - /// - /// - /// int bufferSize = 40000; - /// byte[] CompressedBytes = new byte[bufferSize]; - /// byte[] DecompressedBytes = new byte[bufferSize]; - /// - /// ZlibCodec compressor = new ZlibCodec(); - /// - /// compressor.InitializeDeflate(CompressionLevel.Default); - /// - /// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); - /// compressor.NextIn = 0; - /// compressor.AvailableBytesIn = compressor.InputBuffer.Length; - /// - /// compressor.OutputBuffer = CompressedBytes; - /// compressor.NextOut = 0; - /// compressor.AvailableBytesOut = CompressedBytes.Length; - /// - /// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) - /// { - /// compressor.Deflate(FlushType.None); - /// } - /// - /// while (true) - /// { - /// int rc= compressor.Deflate(FlushType.Finish); - /// if (rc == ZlibConstants.Z_STREAM_END) break; - /// } - /// - /// compressor.EndDeflate(); - /// - /// - /// - /// Z_OK if all goes well. You generally don't need to check the return code. - public int InitializeDeflate() - { - return _InternalInitializeDeflate(true); - } - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. - /// - /// - /// The codec will use the maximum window bits (15) and the specified - /// CompressionLevel. It will emit a ZLIB stream as it compresses. - /// - /// The compression level for the codec. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level) - { - this.CompressLevel = level; - return _InternalInitializeDeflate(true); - } - - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - /// and the explicit flag governing whether to emit an RFC1950 header byte pair. - /// - /// - /// The codec will use the maximum window bits (15) and the specified CompressionLevel. - /// If you want to generate a zlib stream, you should specify true for - /// wantRfc1950Header. In this case, the library will emit a ZLIB - /// header, as defined in RFC - /// 1950, in the compressed stream. - /// - /// The compression level for the codec. - /// whether to emit an initial RFC1950 byte pair in the compressed stream. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header) - { - this.CompressLevel = level; - return _InternalInitializeDeflate(wantRfc1950Header); - } - - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - /// and the specified number of window bits. - /// - /// - /// The codec will use the specified number of window bits and the specified CompressionLevel. - /// - /// The compression level for the codec. - /// the number of window bits to use. If you don't know what this means, don't use this method. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level, int bits) - { - this.CompressLevel = level; - this.WindowBits = bits; - return _InternalInitializeDeflate(true); - } - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified - /// CompressionLevel, the specified number of window bits, and the explicit flag - /// governing whether to emit an RFC1950 header byte pair. - /// - /// - /// The compression level for the codec. - /// whether to emit an initial RFC1950 byte pair in the compressed stream. - /// the number of window bits to use. If you don't know what this means, don't use this method. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header) - { - this.CompressLevel = level; - this.WindowBits = bits; - return _InternalInitializeDeflate(wantRfc1950Header); - } - - private int _InternalInitializeDeflate(bool wantRfc1950Header) - { - if (istate != null) - throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate()."); - dstate = new DeflateManager(); - dstate.WantRfc1950HeaderBytes = wantRfc1950Header; - - return dstate.Initialize(this, this.CompressLevel, this.WindowBits, this.Strategy); - } - - /// - /// Deflate one batch of data. - /// - /// - /// You must have set InputBuffer and OutputBuffer before calling this method. - /// - /// - /// - /// private void DeflateBuffer(CompressionLevel level) - /// { - /// int bufferSize = 1024; - /// byte[] buffer = new byte[bufferSize]; - /// ZlibCodec compressor = new ZlibCodec(); - /// - /// Console.WriteLine("\n============================================"); - /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); - /// MemoryStream ms = new MemoryStream(); - /// - /// int rc = compressor.InitializeDeflate(level); - /// - /// compressor.InputBuffer = UncompressedBytes; - /// compressor.NextIn = 0; - /// compressor.AvailableBytesIn = UncompressedBytes.Length; - /// - /// compressor.OutputBuffer = buffer; - /// - /// // pass 1: deflate - /// do - /// { - /// compressor.NextOut = 0; - /// compressor.AvailableBytesOut = buffer.Length; - /// rc = compressor.Deflate(FlushType.None); - /// - /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - /// throw new Exception("deflating: " + compressor.Message); - /// - /// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); - /// } - /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - /// - /// // pass 2: finish and flush - /// do - /// { - /// compressor.NextOut = 0; - /// compressor.AvailableBytesOut = buffer.Length; - /// rc = compressor.Deflate(FlushType.Finish); - /// - /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - /// throw new Exception("deflating: " + compressor.Message); - /// - /// if (buffer.Length - compressor.AvailableBytesOut > 0) - /// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); - /// } - /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - /// - /// compressor.EndDeflate(); - /// - /// ms.Seek(0, SeekOrigin.Begin); - /// CompressedBytes = new byte[compressor.TotalBytesOut]; - /// ms.Read(CompressedBytes, 0, CompressedBytes.Length); - /// } - /// - /// - /// whether to flush all data as you deflate. Generally you will want to - /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to - /// flush everything. - /// - /// Z_OK if all goes well. - public int Deflate(FlushType flush) - { - if (dstate == null) - throw new ZlibException("No Deflate State!"); - return dstate.Deflate(flush); - } - - /// - /// End a deflation session. - /// - /// - /// Call this after making a series of one or more calls to Deflate(). All buffers are flushed. - /// - /// Z_OK if all goes well. - public int EndDeflate() - { - if (dstate == null) - throw new ZlibException("No Deflate State!"); - // TODO: dinoch Tue, 03 Nov 2009 15:39 (test this) - //int ret = dstate.End(); - dstate = null; - return ZlibConstants.Z_OK; //ret; - } - - /// - /// Reset a codec for another deflation session. - /// - /// - /// Call this to reset the deflation state. For example if a thread is deflating - /// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first - /// block and before the next Deflate(None) of the second block. - /// - /// Z_OK if all goes well. - public void ResetDeflate() - { - if (dstate == null) - throw new ZlibException("No Deflate State!"); - dstate.Reset(); - } - - - /// - /// Set the CompressionStrategy and CompressionLevel for a deflation session. - /// - /// the level of compression to use. - /// the strategy to use for compression. - /// Z_OK if all goes well. - public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy) - { - if (dstate == null) - throw new ZlibException("No Deflate State!"); - return dstate.SetParams(level, strategy); - } - - - /// - /// Set the dictionary to be used for either Inflation or Deflation. - /// - /// The dictionary bytes to use. - /// Z_OK if all goes well. - public int SetDictionary(byte[] dictionary) - { - if (istate != null) - return istate.SetDictionary(dictionary); - - if (dstate != null) - return dstate.SetDictionary(dictionary); - - throw new ZlibException("No Inflate or Deflate state!"); - } - - // 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()). - internal void flush_pending() - { - int len = dstate.pendingCount; - - if (len > AvailableBytesOut) - len = AvailableBytesOut; - if (len == 0) - return; - - if (dstate.pending.Length <= dstate.nextPending || - OutputBuffer.Length <= NextOut || - dstate.pending.Length < (dstate.nextPending + len) || - OutputBuffer.Length < (NextOut + len)) - { - throw new ZlibException(String.Format("Invalid State. (pending.Length={0}, pendingCount={1})", - dstate.pending.Length, dstate.pendingCount)); - } - - Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len); - - NextOut += len; - dstate.nextPending += len; - TotalBytesOut += len; - AvailableBytesOut -= len; - dstate.pendingCount -= len; - if (dstate.pendingCount == 0) - { - dstate.nextPending = 0; - } - } - - // 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()). - internal int read_buf(byte[] buf, int start, int size) - { - int len = AvailableBytesIn; - - if (len > size) - len = size; - if (len == 0) - return 0; - - AvailableBytesIn -= len; - - if (dstate.WantRfc1950HeaderBytes) - { - _Adler32 = Adler.Adler32(_Adler32, InputBuffer, NextIn, len); - } - Array.Copy(InputBuffer, NextIn, buf, start, len); - NextIn += len; - TotalBytesIn += len; - return len; - } - } +// ZlibCodec.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2009-November-03 15:40:51> +// +// ------------------------------------------------------------------ +// +// This module defines a Codec for ZLIB compression and +// decompression. This code extends code that was based the jzlib +// implementation of zlib, but this code is completely novel. The codec +// class is new, and encapsulates some behaviors that are new, and some +// that were present in other classes in the jzlib code base. In +// keeping with the license for jzlib, the copyright to the jzlib code +// is included below. +// +// ------------------------------------------------------------------ +// +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +using System; + +namespace SharpCompress.Compressor.Deflate +{ + /// + /// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). + /// + /// + /// + /// This class compresses and decompresses data according to the Deflate algorithm + /// and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. + /// + internal sealed class ZlibCodec + { + /// + /// The buffer from which data is taken. + /// + public byte[] InputBuffer; + + /// + /// An index into the InputBuffer array, indicating where to start reading. + /// + public int NextIn; + + /// + /// The number of bytes available in the InputBuffer, starting at NextIn. + /// + /// + /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. + /// The class will update this number as calls to Inflate/Deflate are made. + /// + public int AvailableBytesIn; + + /// + /// Total number of bytes read so far, through all calls to Inflate()/Deflate(). + /// + public long TotalBytesIn; + + /// + /// Buffer to store output data. + /// + public byte[] OutputBuffer; + + /// + /// An index into the OutputBuffer array, indicating where to start writing. + /// + public int NextOut; + + /// + /// The number of bytes available in the OutputBuffer, starting at NextOut. + /// + /// + /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. + /// The class will update this number as calls to Inflate/Deflate are made. + /// + public int AvailableBytesOut; + + /// + /// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). + /// + public long TotalBytesOut; + + /// + /// used for diagnostics, when something goes wrong! + /// + public System.String Message; + + internal DeflateManager dstate; + internal InflateManager istate; + + internal uint _Adler32; + + /// + /// The compression level to use in this codec. Useful only in compression mode. + /// + public CompressionLevel CompressLevel = CompressionLevel.Default; + + /// + /// The number of Window Bits to use. + /// + /// + /// This gauges the size of the sliding window, and hence the + /// compression effectiveness as well as memory consumption. It's best to just leave this + /// setting alone if you don't know what it is. The maximum value is 15 bits, which implies + /// a 32k window. + /// + public int WindowBits = ZlibConstants.WindowBitsDefault; + + /// + /// The compression strategy to use. + /// + /// + /// This is only effective in compression. The theory offered by ZLIB is that different + /// strategies could potentially produce significant differences in compression behavior + /// for different data sets. Unfortunately I don't have any good recommendations for how + /// to set it differently. When I tested changing the strategy I got minimally different + /// compression performance. It's best to leave this property alone if you don't have a + /// good feel for it. Or, you may want to produce a test harness that runs through the + /// different strategy options and evaluates them on different file types. If you do that, + /// let me know your results. + /// + public CompressionStrategy Strategy = CompressionStrategy.Default; + + + /// + /// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. + /// + public int Adler32 + { + get { return (int) _Adler32; } + } + + + /// + /// Create a ZlibCodec. + /// + /// + /// If you use this default constructor, you will later have to explicitly call + /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress + /// or decompress. + /// + public ZlibCodec() + { + } + + /// + /// Create a ZlibCodec that either compresses or decompresses. + /// + /// + /// Indicates whether the codec should compress (deflate) or decompress (inflate). + /// + public ZlibCodec(CompressionMode mode) + { + if (mode == CompressionMode.Compress) + { + int rc = InitializeDeflate(); + if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for deflate."); + } + else if (mode == CompressionMode.Decompress) + { + int rc = InitializeInflate(); + if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for inflate."); + } + else throw new ZlibException("Invalid ZlibStreamFlavor."); + } + + /// + /// Initialize the inflation state. + /// + /// + /// It is not necessary to call this before using the ZlibCodec to inflate data; + /// It is implicitly called when you call the constructor. + /// + /// Z_OK if everything goes well. + public int InitializeInflate() + { + return InitializeInflate(this.WindowBits); + } + + /// + /// Initialize the inflation state with an explicit flag to + /// govern the handling of RFC1950 header bytes. + /// + /// + /// + /// By default, the ZLIB header defined in RFC 1950 is expected. If + /// you want to read a zlib stream you should specify true for + /// expectRfc1950Header. If you have a deflate stream, you will want to specify + /// false. It is only necessary to invoke this initializer explicitly if you + /// want to specify false. + /// + /// + /// whether to expect an RFC1950 header byte + /// pair when reading the stream of data to be inflated. + /// + /// Z_OK if everything goes well. + public int InitializeInflate(bool expectRfc1950Header) + { + return InitializeInflate(this.WindowBits, expectRfc1950Header); + } + + /// + /// Initialize the ZlibCodec for inflation, with the specified number of window bits. + /// + /// The number of window bits to use. If you need to ask what that is, + /// then you shouldn't be calling this initializer. + /// Z_OK if all goes well. + public int InitializeInflate(int windowBits) + { + this.WindowBits = windowBits; + return InitializeInflate(windowBits, true); + } + + /// + /// Initialize the inflation state with an explicit flag to govern the handling of + /// RFC1950 header bytes. + /// + /// + /// + /// If you want to read a zlib stream you should specify true for + /// expectRfc1950Header. In this case, the library will expect to find a ZLIB + /// header, as defined in RFC + /// 1950, in the compressed stream. If you will be reading a DEFLATE or + /// GZIP stream, which does not have such a header, you will want to specify + /// false. + /// + /// + /// whether to expect an RFC1950 header byte pair when reading + /// the stream of data to be inflated. + /// The number of window bits to use. If you need to ask what that is, + /// then you shouldn't be calling this initializer. + /// Z_OK if everything goes well. + public int InitializeInflate(int windowBits, bool expectRfc1950Header) + { + this.WindowBits = windowBits; + if (dstate != null) + throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate()."); + istate = new InflateManager(expectRfc1950Header); + return istate.Initialize(this, windowBits); + } + + /// + /// Inflate the data in the InputBuffer, placing the result in the OutputBuffer. + /// + /// + /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and + /// AvailableBytesOut before calling this method. + /// + /// + /// + /// private void InflateBuffer() + /// { + /// int bufferSize = 1024; + /// byte[] buffer = new byte[bufferSize]; + /// ZlibCodec decompressor = new ZlibCodec(); + /// + /// Console.WriteLine("\n============================================"); + /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); + /// MemoryStream ms = new MemoryStream(DecompressedBytes); + /// + /// int rc = decompressor.InitializeInflate(); + /// + /// decompressor.InputBuffer = CompressedBytes; + /// decompressor.NextIn = 0; + /// decompressor.AvailableBytesIn = CompressedBytes.Length; + /// + /// decompressor.OutputBuffer = buffer; + /// + /// // pass 1: inflate + /// do + /// { + /// decompressor.NextOut = 0; + /// decompressor.AvailableBytesOut = buffer.Length; + /// rc = decompressor.Inflate(FlushType.None); + /// + /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + /// throw new Exception("inflating: " + decompressor.Message); + /// + /// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); + /// } + /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + /// + /// // pass 2: finish and flush + /// do + /// { + /// decompressor.NextOut = 0; + /// decompressor.AvailableBytesOut = buffer.Length; + /// rc = decompressor.Inflate(FlushType.Finish); + /// + /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + /// throw new Exception("inflating: " + decompressor.Message); + /// + /// if (buffer.Length - decompressor.AvailableBytesOut > 0) + /// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); + /// } + /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + /// + /// decompressor.EndInflate(); + /// } + /// + /// + /// + /// The flush to use when inflating. + /// Z_OK if everything goes well. + public int Inflate(FlushType flush) + { + if (istate == null) + throw new ZlibException("No Inflate State!"); + return istate.Inflate(flush); + } + + + /// + /// Ends an inflation session. + /// + /// + /// Call this after successively calling Inflate(). This will cause all buffers to be flushed. + /// After calling this you cannot call Inflate() without a intervening call to one of the + /// InitializeInflate() overloads. + /// + /// Z_OK if everything goes well. + public int EndInflate() + { + if (istate == null) + throw new ZlibException("No Inflate State!"); + int ret = istate.End(); + istate = null; + return ret; + } + + /// + /// I don't know what this does! + /// + /// Z_OK if everything goes well. + public int SyncInflate() + { + if (istate == null) + throw new ZlibException("No Inflate State!"); + return istate.Sync(); + } + + /// + /// Initialize the ZlibCodec for deflation operation. + /// + /// + /// The codec will use the MAX window bits and the default level of compression. + /// + /// + /// + /// int bufferSize = 40000; + /// byte[] CompressedBytes = new byte[bufferSize]; + /// byte[] DecompressedBytes = new byte[bufferSize]; + /// + /// ZlibCodec compressor = new ZlibCodec(); + /// + /// compressor.InitializeDeflate(CompressionLevel.Default); + /// + /// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); + /// compressor.NextIn = 0; + /// compressor.AvailableBytesIn = compressor.InputBuffer.Length; + /// + /// compressor.OutputBuffer = CompressedBytes; + /// compressor.NextOut = 0; + /// compressor.AvailableBytesOut = CompressedBytes.Length; + /// + /// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) + /// { + /// compressor.Deflate(FlushType.None); + /// } + /// + /// while (true) + /// { + /// int rc= compressor.Deflate(FlushType.Finish); + /// if (rc == ZlibConstants.Z_STREAM_END) break; + /// } + /// + /// compressor.EndDeflate(); + /// + /// + /// + /// Z_OK if all goes well. You generally don't need to check the return code. + public int InitializeDeflate() + { + return _InternalInitializeDeflate(true); + } + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. + /// + /// + /// The codec will use the maximum window bits (15) and the specified + /// CompressionLevel. It will emit a ZLIB stream as it compresses. + /// + /// The compression level for the codec. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level) + { + this.CompressLevel = level; + return _InternalInitializeDeflate(true); + } + + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + /// and the explicit flag governing whether to emit an RFC1950 header byte pair. + /// + /// + /// The codec will use the maximum window bits (15) and the specified CompressionLevel. + /// If you want to generate a zlib stream, you should specify true for + /// wantRfc1950Header. In this case, the library will emit a ZLIB + /// header, as defined in RFC + /// 1950, in the compressed stream. + /// + /// The compression level for the codec. + /// whether to emit an initial RFC1950 byte pair in the compressed stream. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header) + { + this.CompressLevel = level; + return _InternalInitializeDeflate(wantRfc1950Header); + } + + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + /// and the specified number of window bits. + /// + /// + /// The codec will use the specified number of window bits and the specified CompressionLevel. + /// + /// The compression level for the codec. + /// the number of window bits to use. If you don't know what this means, don't use this method. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level, int bits) + { + this.CompressLevel = level; + this.WindowBits = bits; + return _InternalInitializeDeflate(true); + } + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified + /// CompressionLevel, the specified number of window bits, and the explicit flag + /// governing whether to emit an RFC1950 header byte pair. + /// + /// + /// The compression level for the codec. + /// whether to emit an initial RFC1950 byte pair in the compressed stream. + /// the number of window bits to use. If you don't know what this means, don't use this method. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header) + { + this.CompressLevel = level; + this.WindowBits = bits; + return _InternalInitializeDeflate(wantRfc1950Header); + } + + private int _InternalInitializeDeflate(bool wantRfc1950Header) + { + if (istate != null) + throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate()."); + dstate = new DeflateManager(); + dstate.WantRfc1950HeaderBytes = wantRfc1950Header; + + return dstate.Initialize(this, this.CompressLevel, this.WindowBits, this.Strategy); + } + + /// + /// Deflate one batch of data. + /// + /// + /// You must have set InputBuffer and OutputBuffer before calling this method. + /// + /// + /// + /// private void DeflateBuffer(CompressionLevel level) + /// { + /// int bufferSize = 1024; + /// byte[] buffer = new byte[bufferSize]; + /// ZlibCodec compressor = new ZlibCodec(); + /// + /// Console.WriteLine("\n============================================"); + /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); + /// MemoryStream ms = new MemoryStream(); + /// + /// int rc = compressor.InitializeDeflate(level); + /// + /// compressor.InputBuffer = UncompressedBytes; + /// compressor.NextIn = 0; + /// compressor.AvailableBytesIn = UncompressedBytes.Length; + /// + /// compressor.OutputBuffer = buffer; + /// + /// // pass 1: deflate + /// do + /// { + /// compressor.NextOut = 0; + /// compressor.AvailableBytesOut = buffer.Length; + /// rc = compressor.Deflate(FlushType.None); + /// + /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + /// throw new Exception("deflating: " + compressor.Message); + /// + /// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); + /// } + /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + /// + /// // pass 2: finish and flush + /// do + /// { + /// compressor.NextOut = 0; + /// compressor.AvailableBytesOut = buffer.Length; + /// rc = compressor.Deflate(FlushType.Finish); + /// + /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + /// throw new Exception("deflating: " + compressor.Message); + /// + /// if (buffer.Length - compressor.AvailableBytesOut > 0) + /// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); + /// } + /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + /// + /// compressor.EndDeflate(); + /// + /// ms.Seek(0, SeekOrigin.Begin); + /// CompressedBytes = new byte[compressor.TotalBytesOut]; + /// ms.Read(CompressedBytes, 0, CompressedBytes.Length); + /// } + /// + /// + /// whether to flush all data as you deflate. Generally you will want to + /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to + /// flush everything. + /// + /// Z_OK if all goes well. + public int Deflate(FlushType flush) + { + if (dstate == null) + throw new ZlibException("No Deflate State!"); + return dstate.Deflate(flush); + } + + /// + /// End a deflation session. + /// + /// + /// Call this after making a series of one or more calls to Deflate(). All buffers are flushed. + /// + /// Z_OK if all goes well. + public int EndDeflate() + { + if (dstate == null) + throw new ZlibException("No Deflate State!"); + // TODO: dinoch Tue, 03 Nov 2009 15:39 (test this) + //int ret = dstate.End(); + dstate = null; + return ZlibConstants.Z_OK; //ret; + } + + /// + /// Reset a codec for another deflation session. + /// + /// + /// Call this to reset the deflation state. For example if a thread is deflating + /// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first + /// block and before the next Deflate(None) of the second block. + /// + /// Z_OK if all goes well. + public void ResetDeflate() + { + if (dstate == null) + throw new ZlibException("No Deflate State!"); + dstate.Reset(); + } + + + /// + /// Set the CompressionStrategy and CompressionLevel for a deflation session. + /// + /// the level of compression to use. + /// the strategy to use for compression. + /// Z_OK if all goes well. + public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy) + { + if (dstate == null) + throw new ZlibException("No Deflate State!"); + return dstate.SetParams(level, strategy); + } + + + /// + /// Set the dictionary to be used for either Inflation or Deflation. + /// + /// The dictionary bytes to use. + /// Z_OK if all goes well. + public int SetDictionary(byte[] dictionary) + { + if (istate != null) + return istate.SetDictionary(dictionary); + + if (dstate != null) + return dstate.SetDictionary(dictionary); + + throw new ZlibException("No Inflate or Deflate state!"); + } + + // 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()). + internal void flush_pending() + { + int len = dstate.pendingCount; + + if (len > AvailableBytesOut) + len = AvailableBytesOut; + if (len == 0) + return; + + if (dstate.pending.Length <= dstate.nextPending || + OutputBuffer.Length <= NextOut || + dstate.pending.Length < (dstate.nextPending + len) || + OutputBuffer.Length < (NextOut + len)) + { + throw new ZlibException(String.Format("Invalid State. (pending.Length={0}, pendingCount={1})", + dstate.pending.Length, dstate.pendingCount)); + } + + Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len); + + NextOut += len; + dstate.nextPending += len; + TotalBytesOut += len; + AvailableBytesOut -= len; + dstate.pendingCount -= len; + if (dstate.pendingCount == 0) + { + dstate.nextPending = 0; + } + } + + // 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()). + internal int read_buf(byte[] buf, int start, int size) + { + int len = AvailableBytesIn; + + if (len > size) + len = size; + if (len == 0) + return 0; + + AvailableBytesIn -= len; + + if (dstate.WantRfc1950HeaderBytes) + { + _Adler32 = Adler.Adler32(_Adler32, InputBuffer, NextIn, len); + } + Array.Copy(InputBuffer, NextIn, buf, start, len); + NextIn += len; + TotalBytesIn += len; + return len; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/ZlibConstants.cs b/src/SharpCompress/Compressor/Deflate/ZlibConstants.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/ZlibConstants.cs rename to src/SharpCompress/Compressor/Deflate/ZlibConstants.cs index 97ffee4a..20643bdb 100644 --- a/SharpCompress/Compressor/Deflate/ZlibConstants.cs +++ b/src/SharpCompress/Compressor/Deflate/ZlibConstants.cs @@ -1,125 +1,125 @@ -// ZlibConstants.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2009-November-03 18:50:19> -// -// ------------------------------------------------------------------ -// -// This module defines constants used by the zlib class library. This -// code is derived from the jzlib implementation of zlib, but -// significantly modified. In keeping with the license for jzlib, the -// copyright to that code is included here. -// -// ------------------------------------------------------------------ -// -// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the distribution. -// -// 3. The names of the authors may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------- -// -// This program is based on zlib-1.1.3; credit to authors -// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) -// and contributors of zlib. -// -// ----------------------------------------------------------------------- - - -namespace SharpCompress.Compressor.Deflate -{ - /// - /// A bunch of constants used in the Zlib interface. - /// - internal static class ZlibConstants - { - /// - /// The maximum number of window bits for the Deflate algorithm. - /// - public const int WindowBitsMax = 15; // 32K LZ77 window - - /// - /// The default number of window bits for the Deflate algorithm. - /// - public const int WindowBitsDefault = WindowBitsMax; - - /// - /// indicates everything is A-OK - /// - public const int Z_OK = 0; - - /// - /// Indicates that the last operation reached the end of the stream. - /// - public const int Z_STREAM_END = 1; - - /// - /// The operation ended in need of a dictionary. - /// - public const int Z_NEED_DICT = 2; - - /// - /// There was an error with the stream - not enough data, not open and readable, etc. - /// - public const int Z_STREAM_ERROR = -2; - - /// - /// There was an error with the data - not enough data, bad data, etc. - /// - public const int Z_DATA_ERROR = -3; - - /// - /// There was an error with the working buffer. - /// - public const int Z_BUF_ERROR = -5; - - /// - /// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. - /// -#if NETCF - public const int WorkingBufferSizeDefault = 8192; -#else - public const int WorkingBufferSizeDefault = 16384; -#endif - - /// - /// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. - /// - public const int WorkingBufferSizeMin = 1024; - } +// ZlibConstants.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2009-November-03 18:50:19> +// +// ------------------------------------------------------------------ +// +// This module defines constants used by the zlib class library. This +// code is derived from the jzlib implementation of zlib, but +// significantly modified. In keeping with the license for jzlib, the +// copyright to that code is included here. +// +// ------------------------------------------------------------------ +// +// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// 3. The names of the authors may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// +// This program is based on zlib-1.1.3; credit to authors +// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) +// and contributors of zlib. +// +// ----------------------------------------------------------------------- + + +namespace SharpCompress.Compressor.Deflate +{ + /// + /// A bunch of constants used in the Zlib interface. + /// + internal static class ZlibConstants + { + /// + /// The maximum number of window bits for the Deflate algorithm. + /// + public const int WindowBitsMax = 15; // 32K LZ77 window + + /// + /// The default number of window bits for the Deflate algorithm. + /// + public const int WindowBitsDefault = WindowBitsMax; + + /// + /// indicates everything is A-OK + /// + public const int Z_OK = 0; + + /// + /// Indicates that the last operation reached the end of the stream. + /// + public const int Z_STREAM_END = 1; + + /// + /// The operation ended in need of a dictionary. + /// + public const int Z_NEED_DICT = 2; + + /// + /// There was an error with the stream - not enough data, not open and readable, etc. + /// + public const int Z_STREAM_ERROR = -2; + + /// + /// There was an error with the data - not enough data, bad data, etc. + /// + public const int Z_DATA_ERROR = -3; + + /// + /// There was an error with the working buffer. + /// + public const int Z_BUF_ERROR = -5; + + /// + /// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. + /// +#if NETCF + public const int WorkingBufferSizeDefault = 8192; +#else + public const int WorkingBufferSizeDefault = 16384; +#endif + + /// + /// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. + /// + public const int WorkingBufferSizeMin = 1024; + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Deflate/ZlibStream.cs b/src/SharpCompress/Compressor/Deflate/ZlibStream.cs similarity index 97% rename from SharpCompress/Compressor/Deflate/ZlibStream.cs rename to src/SharpCompress/Compressor/Deflate/ZlibStream.cs index 393bf817..2a0fa10b 100644 --- a/SharpCompress/Compressor/Deflate/ZlibStream.cs +++ b/src/SharpCompress/Compressor/Deflate/ZlibStream.cs @@ -1,312 +1,312 @@ -// ZlibStream.cs -// ------------------------------------------------------------------ -// -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. -// All rights reserved. -// -// This code module is part of DotNetZip, a zipfile class library. -// -// ------------------------------------------------------------------ -// -// This code is licensed under the Microsoft Public License. -// See the file License.txt for the license details. -// More info on: http://dotnetzip.codeplex.com -// -// ------------------------------------------------------------------ -// -// last saved (in emacs): -// Time-stamp: <2010-January-29 16:35:23> -// -// ------------------------------------------------------------------ -// -// This module defines the ZlibStream class, which is similar in idea to -// the System.IO.Compression.DeflateStream and -// System.IO.Compression.GZipStream classes in the .NET BCL. -// -// ------------------------------------------------------------------ - -using System; -using System.IO; - -namespace SharpCompress.Compressor.Deflate -{ - public class ZlibStream : Stream - { - private readonly ZlibBaseStream _baseStream; - private bool _disposed; - - public ZlibStream(Stream stream, CompressionMode mode) - : this(stream, mode, CompressionLevel.Default, false) - { - } - - public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level) - : this(stream, mode, level, false) - { - } - - public ZlibStream(Stream stream, CompressionMode mode, bool leaveOpen) - : this(stream, mode, CompressionLevel.Default, leaveOpen) - { - } - - public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen) - { - _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, leaveOpen); - } - - #region Zlib properties - - /// - /// This property sets the flush behavior on the stream. - /// Sorry, though, not sure exactly how to describe all the various settings. - /// - public virtual FlushType FlushMode - { - get { return (_baseStream._flushMode); } - set - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - _baseStream._flushMode = value; - } - } - - /// - /// The size of the working buffer for the compression codec. - /// - /// - /// - /// - /// The working buffer is used for all stream operations. The default size is - /// 1024 bytes. The minimum size is 128 bytes. You may get better performance - /// with a larger buffer. Then again, you might not. You would have to test - /// it. - /// - /// - /// - /// Set this before the first call to Read() or Write() on the - /// stream. If you try to set it afterwards, it will throw. - /// - /// - public int BufferSize - { - get { return _baseStream._bufferSize; } - set - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - if (_baseStream._workingBuffer != null) - throw new ZlibException("The working buffer is already set."); - if (value < ZlibConstants.WorkingBufferSizeMin) - throw new ZlibException( - String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, - ZlibConstants.WorkingBufferSizeMin)); - _baseStream._bufferSize = value; - } - } - - /// Returns the total number of bytes input so far. - public virtual long TotalIn - { - get { return _baseStream._z.TotalBytesIn; } - } - - /// Returns the total number of bytes output so far. - public virtual long TotalOut - { - get { return _baseStream._z.TotalBytesOut; } - } - - #endregion - - #region System.IO.Stream methods - - /// - /// Indicates whether the stream can be read. - /// - /// - /// The return value depends on whether the captive stream supports reading. - /// - public override bool CanRead - { - get - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - return _baseStream._stream.CanRead; - } - } - - /// - /// Indicates whether the stream supports Seek operations. - /// - /// - /// Always returns false. - /// - public override bool CanSeek - { - get { return false; } - } - - /// - /// Indicates whether the stream can be written. - /// - /// - /// The return value depends on whether the captive stream supports writing. - /// - public override bool CanWrite - { - get - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - return _baseStream._stream.CanWrite; - } - } - - /// - /// Reading this property always throws a . - /// - public override long Length - { - get { throw new NotSupportedException(); } - } - - /// - /// The position of the stream pointer. - /// - /// - /// - /// Setting this property always throws a . Reading will return the total bytes - /// written out, if used in writing, or the total bytes read in, if used in - /// reading. The count may refer to compressed bytes or uncompressed bytes, - /// depending on how you've used the stream. - /// - public override long Position - { - get - { - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) - return _baseStream._z.TotalBytesOut; - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) - return _baseStream._z.TotalBytesIn; - return 0; - } - - set { throw new NotSupportedException(); } - } - - /// - /// Dispose the stream. - /// - /// - /// This may or may not result in a Close() call on the captive stream. - /// See the constructors that have a leaveOpen parameter for more information. - /// - protected override void Dispose(bool disposing) - { - try - { - if (!_disposed) - { - if (disposing && (_baseStream != null)) - _baseStream.Dispose(); - _disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - - /// - /// Flush the stream. - /// - public override void Flush() - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - _baseStream.Flush(); - } - - /// - /// Read data from the stream. - /// - /// - /// - /// - /// - /// If you wish to use the ZlibStream to compress data while reading, - /// you can create a ZlibStream with CompressionMode.Compress, - /// providing an uncompressed data stream. Then call Read() on that - /// ZlibStream, and the data read will be compressed. If you wish to - /// use the ZlibStream to decompress data while reading, you can create - /// a ZlibStream with CompressionMode.Decompress, providing a - /// readable compressed data stream. Then call Read() on that - /// ZlibStream, and the data will be decompressed as it is read. - /// - /// - /// - /// A ZlibStream can be used for Read() or Write(), but - /// not both. - /// - /// - /// - /// The buffer into which the read data should be placed. - /// the offset within that data array to put the first byte read. - /// the number of bytes to read. - public override int Read(byte[] buffer, int offset, int count) - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - return _baseStream.Read(buffer, offset, count); - } - - /// - /// Calling this method always throws a . - /// - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Calling this method always throws a . - /// - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - /// - /// Write data to the stream. - /// - /// - /// - /// - /// - /// If you wish to use the ZlibStream to compress data while writing, - /// you can create a ZlibStream with CompressionMode.Compress, - /// and a writable output stream. Then call Write() on that - /// ZlibStream, providing uncompressed data as input. The data sent to - /// the output stream will be the compressed form of the data written. If you - /// wish to use the ZlibStream to decompress data while writing, you - /// can create a ZlibStream with CompressionMode.Decompress, and a - /// writable output stream. Then call Write() on that stream, - /// providing previously compressed data. The data sent to the output stream - /// will be the decompressed form of the data written. - /// - /// - /// - /// A ZlibStream can be used for Read() or Write(), but not both. - /// - /// - /// The buffer holding data to write to the stream. - /// the offset within that data array to find the first byte to write. - /// the number of bytes to write. - public override void Write(byte[] buffer, int offset, int count) - { - if (_disposed) throw new ObjectDisposedException("ZlibStream"); - _baseStream.Write(buffer, offset, count); - } - - #endregion - } +// ZlibStream.cs +// ------------------------------------------------------------------ +// +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// All rights reserved. +// +// This code module is part of DotNetZip, a zipfile class library. +// +// ------------------------------------------------------------------ +// +// This code is licensed under the Microsoft Public License. +// See the file License.txt for the license details. +// More info on: http://dotnetzip.codeplex.com +// +// ------------------------------------------------------------------ +// +// last saved (in emacs): +// Time-stamp: <2010-January-29 16:35:23> +// +// ------------------------------------------------------------------ +// +// This module defines the ZlibStream class, which is similar in idea to +// the System.IO.Compression.DeflateStream and +// System.IO.Compression.GZipStream classes in the .NET BCL. +// +// ------------------------------------------------------------------ + +using System; +using System.IO; + +namespace SharpCompress.Compressor.Deflate +{ + public class ZlibStream : Stream + { + private readonly ZlibBaseStream _baseStream; + private bool _disposed; + + public ZlibStream(Stream stream, CompressionMode mode) + : this(stream, mode, CompressionLevel.Default, false) + { + } + + public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level) + : this(stream, mode, level, false) + { + } + + public ZlibStream(Stream stream, CompressionMode mode, bool leaveOpen) + : this(stream, mode, CompressionLevel.Default, leaveOpen) + { + } + + public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen) + { + _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, leaveOpen); + } + + #region Zlib properties + + /// + /// This property sets the flush behavior on the stream. + /// Sorry, though, not sure exactly how to describe all the various settings. + /// + public virtual FlushType FlushMode + { + get { return (_baseStream._flushMode); } + set + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + _baseStream._flushMode = value; + } + } + + /// + /// The size of the working buffer for the compression codec. + /// + /// + /// + /// + /// The working buffer is used for all stream operations. The default size is + /// 1024 bytes. The minimum size is 128 bytes. You may get better performance + /// with a larger buffer. Then again, you might not. You would have to test + /// it. + /// + /// + /// + /// Set this before the first call to Read() or Write() on the + /// stream. If you try to set it afterwards, it will throw. + /// + /// + public int BufferSize + { + get { return _baseStream._bufferSize; } + set + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + if (_baseStream._workingBuffer != null) + throw new ZlibException("The working buffer is already set."); + if (value < ZlibConstants.WorkingBufferSizeMin) + throw new ZlibException( + String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, + ZlibConstants.WorkingBufferSizeMin)); + _baseStream._bufferSize = value; + } + } + + /// Returns the total number of bytes input so far. + public virtual long TotalIn + { + get { return _baseStream._z.TotalBytesIn; } + } + + /// Returns the total number of bytes output so far. + public virtual long TotalOut + { + get { return _baseStream._z.TotalBytesOut; } + } + + #endregion + + #region System.IO.Stream methods + + /// + /// Indicates whether the stream can be read. + /// + /// + /// The return value depends on whether the captive stream supports reading. + /// + public override bool CanRead + { + get + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + return _baseStream._stream.CanRead; + } + } + + /// + /// Indicates whether the stream supports Seek operations. + /// + /// + /// Always returns false. + /// + public override bool CanSeek + { + get { return false; } + } + + /// + /// Indicates whether the stream can be written. + /// + /// + /// The return value depends on whether the captive stream supports writing. + /// + public override bool CanWrite + { + get + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + return _baseStream._stream.CanWrite; + } + } + + /// + /// Reading this property always throws a . + /// + public override long Length + { + get { throw new NotSupportedException(); } + } + + /// + /// The position of the stream pointer. + /// + /// + /// + /// Setting this property always throws a . Reading will return the total bytes + /// written out, if used in writing, or the total bytes read in, if used in + /// reading. The count may refer to compressed bytes or uncompressed bytes, + /// depending on how you've used the stream. + /// + public override long Position + { + get + { + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) + return _baseStream._z.TotalBytesOut; + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) + return _baseStream._z.TotalBytesIn; + return 0; + } + + set { throw new NotSupportedException(); } + } + + /// + /// Dispose the stream. + /// + /// + /// This may or may not result in a Close() call on the captive stream. + /// See the constructors that have a leaveOpen parameter for more information. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!_disposed) + { + if (disposing && (_baseStream != null)) + _baseStream.Dispose(); + _disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Flush the stream. + /// + public override void Flush() + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + _baseStream.Flush(); + } + + /// + /// Read data from the stream. + /// + /// + /// + /// + /// + /// If you wish to use the ZlibStream to compress data while reading, + /// you can create a ZlibStream with CompressionMode.Compress, + /// providing an uncompressed data stream. Then call Read() on that + /// ZlibStream, and the data read will be compressed. If you wish to + /// use the ZlibStream to decompress data while reading, you can create + /// a ZlibStream with CompressionMode.Decompress, providing a + /// readable compressed data stream. Then call Read() on that + /// ZlibStream, and the data will be decompressed as it is read. + /// + /// + /// + /// A ZlibStream can be used for Read() or Write(), but + /// not both. + /// + /// + /// + /// The buffer into which the read data should be placed. + /// the offset within that data array to put the first byte read. + /// the number of bytes to read. + public override int Read(byte[] buffer, int offset, int count) + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + return _baseStream.Read(buffer, offset, count); + } + + /// + /// Calling this method always throws a . + /// + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Calling this method always throws a . + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Write data to the stream. + /// + /// + /// + /// + /// + /// If you wish to use the ZlibStream to compress data while writing, + /// you can create a ZlibStream with CompressionMode.Compress, + /// and a writable output stream. Then call Write() on that + /// ZlibStream, providing uncompressed data as input. The data sent to + /// the output stream will be the compressed form of the data written. If you + /// wish to use the ZlibStream to decompress data while writing, you + /// can create a ZlibStream with CompressionMode.Decompress, and a + /// writable output stream. Then call Write() on that stream, + /// providing previously compressed data. The data sent to the output stream + /// will be the decompressed form of the data written. + /// + /// + /// + /// A ZlibStream can be used for Read() or Write(), but not both. + /// + /// + /// The buffer holding data to write to the stream. + /// the offset within that data array to find the first byte to write. + /// the number of bytes to write. + public override void Write(byte[] buffer, int offset, int count) + { + if (_disposed) throw new ObjectDisposedException("ZlibStream"); + _baseStream.Write(buffer, offset, count); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Filters/BCJ2Filter.cs b/src/SharpCompress/Compressor/Filters/BCJ2Filter.cs similarity index 96% rename from SharpCompress/Compressor/Filters/BCJ2Filter.cs rename to src/SharpCompress/Compressor/Filters/BCJ2Filter.cs index 3ade2487..baca08ff 100644 --- a/SharpCompress/Compressor/Filters/BCJ2Filter.cs +++ b/src/SharpCompress/Compressor/Filters/BCJ2Filter.cs @@ -1,219 +1,219 @@ -using System; -using System.IO; - -namespace SharpCompress.Compressor.Filters -{ - internal class BCJ2Filter : Stream - { - private readonly Stream baseStream; - private readonly byte[] input = new byte[4096]; - private int inputOffset = 0; - private int inputCount = 0; - private bool endReached = false; - - private long position = 0; - private byte[] output = new byte[4]; - private int outputOffset = 0; - private int outputCount = 0; - - private byte[] control; - private byte[] data1; - private byte[] data2; - - private int controlPos = 0; - private int data1Pos = 0; - private int data2Pos = 0; - - private ushort[] p = new ushort[256 + 2]; - private uint range, code; - private byte prevByte = 0; - private bool isDisposed; - - private const int kNumTopBits = 24; - private const int kTopValue = 1 << kNumTopBits; - - private const int kNumBitModelTotalBits = 11; - private const int kBitModelTotal = 1 << kNumBitModelTotalBits; - private const int kNumMoveBits = 5; - - private static bool IsJ(byte b0, byte b1) - { - return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); - } - - private static bool IsJcc(byte b0, byte b1) - { - return b0 == 0x0F && (b1 & 0xF0) == 0x80; - } - - public BCJ2Filter(byte[] control, byte[] data1, byte[] data2, Stream baseStream) - { - this.control = control; - this.data1 = data1; - this.data2 = data2; - this.baseStream = baseStream; - - int i; - for (i = 0; i < p.Length; i++) - p[i] = kBitModelTotal >> 1; - - code = 0; - range = 0xFFFFFFFF; - for (i = 0; i < 5; i++) - code = (code << 8) | control[controlPos++]; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - baseStream.Dispose(); - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { return baseStream.Length + data1.Length + data2.Length; } - } - - public override long Position - { - get { return position; } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - int size = 0; - byte b = 0; - - while (!endReached && size < count) - { - while (outputOffset < outputCount) - { - b = output[outputOffset++]; - buffer[offset++] = b; - size++; - position++; - - prevByte = b; - if (size == count) - return size; - } - - if (inputOffset == inputCount) - { - inputOffset = 0; - inputCount = baseStream.Read(input, 0, input.Length); - if (inputCount == 0) - { - endReached = true; - break; - } - } - - b = input[inputOffset++]; - buffer[offset++] = b; - size++; - position++; - - if (!IsJ(prevByte, b)) - prevByte = b; - else - { - int prob; - if (b == 0xE8) - prob = prevByte; - else if (b == 0xE9) - prob = 256; - else - prob = 257; - - uint bound = (range >> kNumBitModelTotalBits) * p[prob]; - if (code < bound) - { - range = bound; - p[prob] += (ushort)((kBitModelTotal - p[prob]) >> kNumMoveBits); - if (range < kTopValue) - { - range <<= 8; - code = (code << 8) | control[controlPos++]; - } - prevByte = b; - } - else - { - range -= bound; - code -= bound; - p[prob] -= (ushort)(p[prob] >> kNumMoveBits); - if (range < kTopValue) - { - range <<= 8; - code = (code << 8) | control[controlPos++]; - } - - uint dest; - if (b == 0xE8) - dest = - (uint) - ((data1[data1Pos++] << 24) | (data1[data1Pos++] << 16) | (data1[data1Pos++] << 8) | - data1[data1Pos++]); - else - dest = - (uint) - ((data2[data2Pos++] << 24) | (data2[data2Pos++] << 16) | (data2[data2Pos++] << 8) | - data2[data2Pos++]); - dest -= (uint)(position + 4); - - output[0] = (byte)dest; - output[1] = (byte)(dest >> 8); - output[2] = (byte)(dest >> 16); - output[3] = (byte)(dest >> 24); - outputOffset = 0; - outputCount = 4; - } - } - } - - return size; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - } +using System; +using System.IO; + +namespace SharpCompress.Compressor.Filters +{ + internal class BCJ2Filter : Stream + { + private readonly Stream baseStream; + private readonly byte[] input = new byte[4096]; + private int inputOffset = 0; + private int inputCount = 0; + private bool endReached = false; + + private long position = 0; + private byte[] output = new byte[4]; + private int outputOffset = 0; + private int outputCount = 0; + + private byte[] control; + private byte[] data1; + private byte[] data2; + + private int controlPos = 0; + private int data1Pos = 0; + private int data2Pos = 0; + + private ushort[] p = new ushort[256 + 2]; + private uint range, code; + private byte prevByte = 0; + private bool isDisposed; + + private const int kNumTopBits = 24; + private const int kTopValue = 1 << kNumTopBits; + + private const int kNumBitModelTotalBits = 11; + private const int kBitModelTotal = 1 << kNumBitModelTotalBits; + private const int kNumMoveBits = 5; + + private static bool IsJ(byte b0, byte b1) + { + return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); + } + + private static bool IsJcc(byte b0, byte b1) + { + return b0 == 0x0F && (b1 & 0xF0) == 0x80; + } + + public BCJ2Filter(byte[] control, byte[] data1, byte[] data2, Stream baseStream) + { + this.control = control; + this.data1 = data1; + this.data2 = data2; + this.baseStream = baseStream; + + int i; + for (i = 0; i < p.Length; i++) + p[i] = kBitModelTotal >> 1; + + code = 0; + range = 0xFFFFFFFF; + for (i = 0; i < 5; i++) + code = (code << 8) | control[controlPos++]; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + baseStream.Dispose(); + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { return baseStream.Length + data1.Length + data2.Length; } + } + + public override long Position + { + get { return position; } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int size = 0; + byte b = 0; + + while (!endReached && size < count) + { + while (outputOffset < outputCount) + { + b = output[outputOffset++]; + buffer[offset++] = b; + size++; + position++; + + prevByte = b; + if (size == count) + return size; + } + + if (inputOffset == inputCount) + { + inputOffset = 0; + inputCount = baseStream.Read(input, 0, input.Length); + if (inputCount == 0) + { + endReached = true; + break; + } + } + + b = input[inputOffset++]; + buffer[offset++] = b; + size++; + position++; + + if (!IsJ(prevByte, b)) + prevByte = b; + else + { + int prob; + if (b == 0xE8) + prob = prevByte; + else if (b == 0xE9) + prob = 256; + else + prob = 257; + + uint bound = (range >> kNumBitModelTotalBits) * p[prob]; + if (code < bound) + { + range = bound; + p[prob] += (ushort)((kBitModelTotal - p[prob]) >> kNumMoveBits); + if (range < kTopValue) + { + range <<= 8; + code = (code << 8) | control[controlPos++]; + } + prevByte = b; + } + else + { + range -= bound; + code -= bound; + p[prob] -= (ushort)(p[prob] >> kNumMoveBits); + if (range < kTopValue) + { + range <<= 8; + code = (code << 8) | control[controlPos++]; + } + + uint dest; + if (b == 0xE8) + dest = + (uint) + ((data1[data1Pos++] << 24) | (data1[data1Pos++] << 16) | (data1[data1Pos++] << 8) | + data1[data1Pos++]); + else + dest = + (uint) + ((data2[data2Pos++] << 24) | (data2[data2Pos++] << 16) | (data2[data2Pos++] << 8) | + data2[data2Pos++]); + dest -= (uint)(position + 4); + + output[0] = (byte)dest; + output[1] = (byte)(dest >> 8); + output[2] = (byte)(dest >> 16); + output[3] = (byte)(dest >> 24); + outputOffset = 0; + outputCount = 4; + } + } + } + + return size; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Filters/BCJFilter.cs b/src/SharpCompress/Compressor/Filters/BCJFilter.cs similarity index 96% rename from SharpCompress/Compressor/Filters/BCJFilter.cs rename to src/SharpCompress/Compressor/Filters/BCJFilter.cs index 7cf1de33..8e1627d3 100644 --- a/SharpCompress/Compressor/Filters/BCJFilter.cs +++ b/src/SharpCompress/Compressor/Filters/BCJFilter.cs @@ -1,103 +1,103 @@ -using System.IO; - -namespace SharpCompress.Compressor.Filters -{ - internal class BCJFilter : Filter - { - private static readonly bool[] MASK_TO_ALLOWED_STATUS = new bool[] { true, true, true, false, true, false, false, false }; - - private static readonly int[] MASK_TO_BIT_NUMBER = new int[] { 0, 1, 2, 2, 3, 3, 3, 3 }; - - private int pos; - private int prevMask = 0; - - public BCJFilter(bool isEncoder, Stream baseStream) - : base(isEncoder, baseStream, 5) - { - pos = 5; - } - - private static bool test86MSByte(byte b) - { - return b == 0x00 || b == 0xFF; - } - - protected override int Transform(byte[] buffer, int offset, int count) - { - int prevPos = offset - 1; - int end = offset + count - 5; - int i; - - for (i = offset; i <= end; ++i) - { - if ((buffer[i] & 0xFE) != 0xE8) - continue; - - prevPos = i - prevPos; - if ((prevPos & ~3) != 0) - { - // (unsigned)prevPos > 3 - prevMask = 0; - } - else - { - prevMask = (prevMask << (prevPos - 1)) & 7; - if (prevMask != 0) - { - if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte( - buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) - { - prevPos = i; - prevMask = (prevMask << 1) | 1; - continue; - } - } - } - - prevPos = i; - - if (test86MSByte(buffer[i + 4])) - { - int src = buffer[i + 1] - | (buffer[i + 2] << 8) - | (buffer[i + 3] << 16) - | (buffer[i + 4] << 24); - int dest; - while (true) - { - if (isEncoder) - dest = src + (pos + i - offset); - else - dest = src - (pos + i - offset); - - if (prevMask == 0) - break; - - int index = MASK_TO_BIT_NUMBER[prevMask] * 8; - if (!test86MSByte((byte)(dest >> (24 - index)))) - break; - - src = dest ^ ((1 << (32 - index)) - 1); - } - - buffer[i + 1] = (byte)dest; - buffer[i + 2] = (byte)(dest >> 8); - buffer[i + 3] = (byte)(dest >> 16); - buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1)); - i += 4; - } - else - { - prevMask = (prevMask << 1) | 1; - } - } - - prevPos = i - prevPos; - prevMask = ((prevPos & ~3) != 0) ? 0 : prevMask << (prevPos - 1); - - i -= offset; - pos += i; - return i; - } - } +using System.IO; + +namespace SharpCompress.Compressor.Filters +{ + internal class BCJFilter : Filter + { + private static readonly bool[] MASK_TO_ALLOWED_STATUS = new bool[] { true, true, true, false, true, false, false, false }; + + private static readonly int[] MASK_TO_BIT_NUMBER = new int[] { 0, 1, 2, 2, 3, 3, 3, 3 }; + + private int pos; + private int prevMask = 0; + + public BCJFilter(bool isEncoder, Stream baseStream) + : base(isEncoder, baseStream, 5) + { + pos = 5; + } + + private static bool test86MSByte(byte b) + { + return b == 0x00 || b == 0xFF; + } + + protected override int Transform(byte[] buffer, int offset, int count) + { + int prevPos = offset - 1; + int end = offset + count - 5; + int i; + + for (i = offset; i <= end; ++i) + { + if ((buffer[i] & 0xFE) != 0xE8) + continue; + + prevPos = i - prevPos; + if ((prevPos & ~3) != 0) + { + // (unsigned)prevPos > 3 + prevMask = 0; + } + else + { + prevMask = (prevMask << (prevPos - 1)) & 7; + if (prevMask != 0) + { + if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte( + buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) + { + prevPos = i; + prevMask = (prevMask << 1) | 1; + continue; + } + } + } + + prevPos = i; + + if (test86MSByte(buffer[i + 4])) + { + int src = buffer[i + 1] + | (buffer[i + 2] << 8) + | (buffer[i + 3] << 16) + | (buffer[i + 4] << 24); + int dest; + while (true) + { + if (isEncoder) + dest = src + (pos + i - offset); + else + dest = src - (pos + i - offset); + + if (prevMask == 0) + break; + + int index = MASK_TO_BIT_NUMBER[prevMask] * 8; + if (!test86MSByte((byte)(dest >> (24 - index)))) + break; + + src = dest ^ ((1 << (32 - index)) - 1); + } + + buffer[i + 1] = (byte)dest; + buffer[i + 2] = (byte)(dest >> 8); + buffer[i + 3] = (byte)(dest >> 16); + buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1)); + i += 4; + } + else + { + prevMask = (prevMask << 1) | 1; + } + } + + prevPos = i - prevPos; + prevMask = ((prevPos & ~3) != 0) ? 0 : prevMask << (prevPos - 1); + + i -= offset; + pos += i; + return i; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Filters/Filter.cs b/src/SharpCompress/Compressor/Filters/Filter.cs similarity index 96% rename from SharpCompress/Compressor/Filters/Filter.cs rename to src/SharpCompress/Compressor/Filters/Filter.cs index 1c2cd9ec..e1961943 100644 --- a/SharpCompress/Compressor/Filters/Filter.cs +++ b/src/SharpCompress/Compressor/Filters/Filter.cs @@ -1,154 +1,154 @@ -using System; -using System.IO; - -namespace SharpCompress.Compressor.Filters -{ - internal abstract class Filter : Stream - { - protected bool isEncoder; - protected Stream baseStream; - - private byte[] tail; - private byte[] window; - private int transformed = 0; - private int read = 0; - private bool endReached = false; - private bool isDisposed; - - protected Filter(bool isEncoder, Stream baseStream, int lookahead) - { - this.isEncoder = isEncoder; - this.baseStream = baseStream; - tail = new byte[lookahead - 1]; - window = new byte[tail.Length * 2]; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - baseStream.Dispose(); - } - - public override bool CanRead - { - get { return !isEncoder; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return isEncoder; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { return baseStream.Length; } - } - - public override long Position - { - get { return baseStream.Position; } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - int size = 0; - - if (transformed > 0) - { - int copySize = transformed; - if (copySize > count) - copySize = count; - Buffer.BlockCopy(tail, 0, buffer, offset, copySize); - transformed -= copySize; - read -= copySize; - offset += copySize; - count -= copySize; - size += copySize; - Buffer.BlockCopy(tail, copySize, tail, 0, read); - } - if (count == 0) - return size; - - int inSize = read; - if (inSize > count) - inSize = count; - Buffer.BlockCopy(tail, 0, buffer, offset, inSize); - read -= inSize; - Buffer.BlockCopy(tail, inSize, tail, 0, read); - while (!endReached && inSize < count) - { - int baseRead = baseStream.Read(buffer, offset + inSize, count - inSize); - inSize += baseRead; - if (baseRead == 0) - endReached = true; - } - while (!endReached && read < tail.Length) - { - int baseRead = baseStream.Read(tail, read, tail.Length - read); - read += baseRead; - if (baseRead == 0) - endReached = true; - } - - if (inSize > tail.Length) - { - transformed = Transform(buffer, offset, inSize); - offset += transformed; - count -= transformed; - size += transformed; - inSize -= transformed; - transformed = 0; - } - - if (count == 0) - return size; - - Buffer.BlockCopy(buffer, offset, window, 0, inSize); - Buffer.BlockCopy(tail, 0, window, inSize, read); - if (inSize + read > tail.Length) - transformed = Transform(window, 0, inSize + read); - else - transformed = inSize + read; - Buffer.BlockCopy(window, 0, buffer, offset, inSize); - Buffer.BlockCopy(window, inSize, tail, 0, read); - size += inSize; - transformed -= inSize; - - return size; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Transform(buffer, offset, count); - baseStream.Write(buffer, offset, count); - } - - protected abstract int Transform(byte[] buffer, int offset, int count); - } +using System; +using System.IO; + +namespace SharpCompress.Compressor.Filters +{ + internal abstract class Filter : Stream + { + protected bool isEncoder; + protected Stream baseStream; + + private byte[] tail; + private byte[] window; + private int transformed = 0; + private int read = 0; + private bool endReached = false; + private bool isDisposed; + + protected Filter(bool isEncoder, Stream baseStream, int lookahead) + { + this.isEncoder = isEncoder; + this.baseStream = baseStream; + tail = new byte[lookahead - 1]; + window = new byte[tail.Length * 2]; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + baseStream.Dispose(); + } + + public override bool CanRead + { + get { return !isEncoder; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return isEncoder; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { return baseStream.Length; } + } + + public override long Position + { + get { return baseStream.Position; } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int size = 0; + + if (transformed > 0) + { + int copySize = transformed; + if (copySize > count) + copySize = count; + Buffer.BlockCopy(tail, 0, buffer, offset, copySize); + transformed -= copySize; + read -= copySize; + offset += copySize; + count -= copySize; + size += copySize; + Buffer.BlockCopy(tail, copySize, tail, 0, read); + } + if (count == 0) + return size; + + int inSize = read; + if (inSize > count) + inSize = count; + Buffer.BlockCopy(tail, 0, buffer, offset, inSize); + read -= inSize; + Buffer.BlockCopy(tail, inSize, tail, 0, read); + while (!endReached && inSize < count) + { + int baseRead = baseStream.Read(buffer, offset + inSize, count - inSize); + inSize += baseRead; + if (baseRead == 0) + endReached = true; + } + while (!endReached && read < tail.Length) + { + int baseRead = baseStream.Read(tail, read, tail.Length - read); + read += baseRead; + if (baseRead == 0) + endReached = true; + } + + if (inSize > tail.Length) + { + transformed = Transform(buffer, offset, inSize); + offset += transformed; + count -= transformed; + size += transformed; + inSize -= transformed; + transformed = 0; + } + + if (count == 0) + return size; + + Buffer.BlockCopy(buffer, offset, window, 0, inSize); + Buffer.BlockCopy(tail, 0, window, inSize, read); + if (inSize + read > tail.Length) + transformed = Transform(window, 0, inSize + read); + else + transformed = inSize + read; + Buffer.BlockCopy(window, 0, buffer, offset, inSize); + Buffer.BlockCopy(window, inSize, tail, 0, read); + size += inSize; + transformed -= inSize; + + return size; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Transform(buffer, offset, count); + baseStream.Write(buffer, offset, count); + } + + protected abstract int Transform(byte[] buffer, int offset, int count); + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/AesDecoderStream.cs b/src/SharpCompress/Compressor/LZMA/AesDecoderStream.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/AesDecoderStream.cs rename to src/SharpCompress/Compressor/LZMA/AesDecoderStream.cs index 56fb020f..7ed1eebd 100644 --- a/SharpCompress/Compressor/LZMA/AesDecoderStream.cs +++ b/src/SharpCompress/Compressor/LZMA/AesDecoderStream.cs @@ -1,232 +1,232 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using Org.BouncyCastle.Crypto.Digests; -using SharpCompress.Compressor.LZMA.Utilites; - -namespace SharpCompress.Compressor.LZMA -{ - internal class AesDecoderStream : DecoderStream2 - { - #region Variables - - private Stream mStream; - private ICryptoTransform mDecoder; - private byte[] mBuffer; - private long mWritten; - private long mLimit; - private int mOffset; - private int mEnding; - private int mUnderflow; - private bool isDisposed; - - #endregion - - #region Stream Methods - - public AesDecoderStream(Stream input, byte[] info, IPasswordProvider pass, long limit) - { - mStream = input; - mLimit = limit; - - if (((uint)input.Length & 15) != 0) - throw new NotSupportedException("AES decoder does not support padding."); - - int numCyclesPower; - byte[] salt, seed; - Init(info, out numCyclesPower, out salt, out seed); - - byte[] password = Encoding.Unicode.GetBytes(pass.CryptoGetTextPassword()); - byte[] key = InitKey(numCyclesPower, salt, password); - - using (var aes = Aes.Create()) - { - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.None; - mDecoder = aes.CreateDecryptor(key, seed); - } - - mBuffer = new byte[4 << 10]; - } - - protected override void Dispose(bool disposing) - { - try - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - mStream.Dispose(); - mDecoder.Dispose(); - } - } - finally - { - base.Dispose(disposing); - } - } - - public override long Position - { - get { return mWritten; } - } - - public override long Length - { - get { return mLimit; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count == 0 || mWritten == mLimit) - return 0; - - if (mUnderflow > 0) - return HandleUnderflow(buffer, offset, count); - - // Need at least 16 bytes to proceed. - if (mEnding - mOffset < 16) - { - Buffer.BlockCopy(mBuffer, mOffset, mBuffer, 0, mEnding - mOffset); - mEnding -= mOffset; - mOffset = 0; - - do - { - int read = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding); - if (read == 0) - { - // We are not done decoding and have less than 16 bytes. - throw new EndOfStreamException(); - } - - mEnding += read; - } while (mEnding - mOffset < 16); - } - - // We shouldn't return more data than we are limited to. - // Currently this is handled by forcing an underflow if - // the stream length is not a multiple of the block size. - if (count > mLimit - mWritten) - count = (int)(mLimit - mWritten); - - // We cannot transform less than 16 bytes into the target buffer, - // but we also cannot return zero, so we need to handle this. - // We transform the data locally and use our own buffer as cache. - if (count < 16) - return HandleUnderflow(buffer, offset, count); - - if (count > mEnding - mOffset) - count = mEnding - mOffset; - - // Otherwise we transform directly into the target buffer. - int processed = mDecoder.TransformBlock(mBuffer, mOffset, count & ~15, buffer, offset); - mOffset += processed; - mWritten += processed; - return processed; - } - - #endregion - - #region Private Methods - - private void Init(byte[] info, out int numCyclesPower, out byte[] salt, out byte[] iv) - { - byte bt = info[0]; - numCyclesPower = bt & 0x3F; - - if ((bt & 0xC0) == 0) - { - salt = new byte[0]; - iv = new byte[0]; - return; - } - - int saltSize = (bt >> 7) & 1; - int ivSize = (bt >> 6) & 1; - if (info.Length == 1) - throw new InvalidOperationException(); - - byte bt2 = info[1]; - saltSize += (bt2 >> 4); - ivSize += (bt2 & 15); - if (info.Length < 2 + saltSize + ivSize) - throw new InvalidOperationException(); - - salt = new byte[saltSize]; - for (int i = 0; i < saltSize; i++) - salt[i] = info[i + 2]; - - iv = new byte[16]; - for (int i = 0; i < ivSize; i++) - iv[i] = info[i + saltSize + 2]; - - if (numCyclesPower > 24) - throw new NotSupportedException(); - } - - private byte[] InitKey(int mNumCyclesPower, byte[] salt, byte[] pass) - { - if (mNumCyclesPower == 0x3F) - { - var key = new byte[32]; - - int pos; - for (pos = 0; pos < salt.Length; pos++) - key[pos] = salt[pos]; - for (int i = 0; i < pass.Length && pos < 32; i++) - key[pos++] = pass[i]; - - return key; - } - else - { - var sha = new Sha256Digest(); - byte[] counter = new byte[8]; - long numRounds = 1L << mNumCyclesPower; - for (long round = 0; round < numRounds; round++) - { - sha.BlockUpdate(salt, 0, salt.Length); - sha.BlockUpdate(pass, 0, pass.Length); - sha.BlockUpdate(counter, 0, counter.Length); - - // This mirrors the counter so we don't have to convert long to byte[] each round. - // (It also ensures the counter is little endian, which BitConverter does not.) - for (int i = 0; i < 8; i++) - if (++counter[i] != 0) - break; - } - - sha.DoFinal(counter, 0); - return counter; - } - } - - private int HandleUnderflow(byte[] buffer, int offset, int count) - { - // If this is zero we were called to create a new underflow buffer. - // Just transform as much as possible so we can feed from it as long as possible. - if (mUnderflow == 0) - { - int blockSize = (mEnding - mOffset) & ~15; - mUnderflow = mDecoder.TransformBlock(mBuffer, mOffset, blockSize, mBuffer, mOffset); - } - - if (count > mUnderflow) - count = mUnderflow; - - Buffer.BlockCopy(mBuffer, mOffset, buffer, offset, count); - mWritten += count; - mOffset += count; - mUnderflow -= count; - return count; - } - - #endregion - } +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Org.BouncyCastle.Crypto.Digests; +using SharpCompress.Compressor.LZMA.Utilites; + +namespace SharpCompress.Compressor.LZMA +{ + internal class AesDecoderStream : DecoderStream2 + { + #region Variables + + private Stream mStream; + private ICryptoTransform mDecoder; + private byte[] mBuffer; + private long mWritten; + private long mLimit; + private int mOffset; + private int mEnding; + private int mUnderflow; + private bool isDisposed; + + #endregion + + #region Stream Methods + + public AesDecoderStream(Stream input, byte[] info, IPasswordProvider pass, long limit) + { + mStream = input; + mLimit = limit; + + if (((uint)input.Length & 15) != 0) + throw new NotSupportedException("AES decoder does not support padding."); + + int numCyclesPower; + byte[] salt, seed; + Init(info, out numCyclesPower, out salt, out seed); + + byte[] password = Encoding.Unicode.GetBytes(pass.CryptoGetTextPassword()); + byte[] key = InitKey(numCyclesPower, salt, password); + + using (var aes = Aes.Create()) + { + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.None; + mDecoder = aes.CreateDecryptor(key, seed); + } + + mBuffer = new byte[4 << 10]; + } + + protected override void Dispose(bool disposing) + { + try + { + if (isDisposed) + { + return; + } + isDisposed = true; + if (disposing) + { + mStream.Dispose(); + mDecoder.Dispose(); + } + } + finally + { + base.Dispose(disposing); + } + } + + public override long Position + { + get { return mWritten; } + } + + public override long Length + { + get { return mLimit; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count == 0 || mWritten == mLimit) + return 0; + + if (mUnderflow > 0) + return HandleUnderflow(buffer, offset, count); + + // Need at least 16 bytes to proceed. + if (mEnding - mOffset < 16) + { + Buffer.BlockCopy(mBuffer, mOffset, mBuffer, 0, mEnding - mOffset); + mEnding -= mOffset; + mOffset = 0; + + do + { + int read = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding); + if (read == 0) + { + // We are not done decoding and have less than 16 bytes. + throw new EndOfStreamException(); + } + + mEnding += read; + } while (mEnding - mOffset < 16); + } + + // We shouldn't return more data than we are limited to. + // Currently this is handled by forcing an underflow if + // the stream length is not a multiple of the block size. + if (count > mLimit - mWritten) + count = (int)(mLimit - mWritten); + + // We cannot transform less than 16 bytes into the target buffer, + // but we also cannot return zero, so we need to handle this. + // We transform the data locally and use our own buffer as cache. + if (count < 16) + return HandleUnderflow(buffer, offset, count); + + if (count > mEnding - mOffset) + count = mEnding - mOffset; + + // Otherwise we transform directly into the target buffer. + int processed = mDecoder.TransformBlock(mBuffer, mOffset, count & ~15, buffer, offset); + mOffset += processed; + mWritten += processed; + return processed; + } + + #endregion + + #region Private Methods + + private void Init(byte[] info, out int numCyclesPower, out byte[] salt, out byte[] iv) + { + byte bt = info[0]; + numCyclesPower = bt & 0x3F; + + if ((bt & 0xC0) == 0) + { + salt = new byte[0]; + iv = new byte[0]; + return; + } + + int saltSize = (bt >> 7) & 1; + int ivSize = (bt >> 6) & 1; + if (info.Length == 1) + throw new InvalidOperationException(); + + byte bt2 = info[1]; + saltSize += (bt2 >> 4); + ivSize += (bt2 & 15); + if (info.Length < 2 + saltSize + ivSize) + throw new InvalidOperationException(); + + salt = new byte[saltSize]; + for (int i = 0; i < saltSize; i++) + salt[i] = info[i + 2]; + + iv = new byte[16]; + for (int i = 0; i < ivSize; i++) + iv[i] = info[i + saltSize + 2]; + + if (numCyclesPower > 24) + throw new NotSupportedException(); + } + + private byte[] InitKey(int mNumCyclesPower, byte[] salt, byte[] pass) + { + if (mNumCyclesPower == 0x3F) + { + var key = new byte[32]; + + int pos; + for (pos = 0; pos < salt.Length; pos++) + key[pos] = salt[pos]; + for (int i = 0; i < pass.Length && pos < 32; i++) + key[pos++] = pass[i]; + + return key; + } + else + { + var sha = new Sha256Digest(); + byte[] counter = new byte[8]; + long numRounds = 1L << mNumCyclesPower; + for (long round = 0; round < numRounds; round++) + { + sha.BlockUpdate(salt, 0, salt.Length); + sha.BlockUpdate(pass, 0, pass.Length); + sha.BlockUpdate(counter, 0, counter.Length); + + // This mirrors the counter so we don't have to convert long to byte[] each round. + // (It also ensures the counter is little endian, which BitConverter does not.) + for (int i = 0; i < 8; i++) + if (++counter[i] != 0) + break; + } + + sha.DoFinal(counter, 0); + return counter; + } + } + + private int HandleUnderflow(byte[] buffer, int offset, int count) + { + // If this is zero we were called to create a new underflow buffer. + // Just transform as much as possible so we can feed from it as long as possible. + if (mUnderflow == 0) + { + int blockSize = (mEnding - mOffset) & ~15; + mUnderflow = mDecoder.TransformBlock(mBuffer, mOffset, blockSize, mBuffer, mOffset); + } + + if (count > mUnderflow) + count = mUnderflow; + + Buffer.BlockCopy(mBuffer, mOffset, buffer, offset, count); + mWritten += count; + mOffset += count; + mUnderflow -= count; + return count; + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs b/src/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs rename to src/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs index c13f34b6..5c748216 100644 --- a/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs +++ b/src/SharpCompress/Compressor/LZMA/Bcj2DecoderStream.cs @@ -1,245 +1,245 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace SharpCompress.Compressor.LZMA -{ - internal class Bcj2DecoderStream : DecoderStream2 - { - private const int kNumTopBits = 24; - private const uint kTopValue = (1 << kNumTopBits); - - private class RangeDecoder - { - internal Stream mStream; - internal uint Range; - internal uint Code; - - public RangeDecoder(Stream stream) - { - mStream = stream; - Range = 0xFFFFFFFF; - for (int i = 0; i < 5; i++) - Code = (Code << 8) | ReadByte(); - } - - public byte ReadByte() - { - int bt = mStream.ReadByte(); - if (bt < 0) - throw new EndOfStreamException(); - - return (byte)bt; - } - - public void Dispose() - { - mStream.Dispose(); - } - } - - private class StatusDecoder - { - private const int numMoveBits = 5; - - private const int kNumBitModelTotalBits = 11; - private const uint kBitModelTotal = 1u << kNumBitModelTotalBits; - - private uint Prob; - - public StatusDecoder() - { - Prob = kBitModelTotal / 2; - } - - private void UpdateModel(uint 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 uint Decode(RangeDecoder decoder) - { - uint newBound = (decoder.Range >> kNumBitModelTotalBits) * Prob; - if (decoder.Code < newBound) - { - decoder.Range = newBound; - Prob += (kBitModelTotal - Prob) >> numMoveBits; - if (decoder.Range < kTopValue) - { - decoder.Code = (decoder.Code << 8) | decoder.ReadByte(); - decoder.Range <<= 8; - } - return 0; - } - else - { - decoder.Range -= newBound; - decoder.Code -= newBound; - Prob -= Prob >> numMoveBits; - if (decoder.Range < kTopValue) - { - decoder.Code = (decoder.Code << 8) | decoder.ReadByte(); - decoder.Range <<= 8; - } - return 1; - } - } - } - - private Stream mMainStream; - private Stream mCallStream; - private Stream mJumpStream; - private RangeDecoder mRangeDecoder; - private StatusDecoder[] mStatusDecoder; - private long mWritten; - private long mLimit; - private IEnumerator mIter; - private bool mFinished; - private bool isDisposed; - - public Bcj2DecoderStream(Stream[] streams, byte[] info, long limit) - { - if (info != null && info.Length > 0) - throw new NotSupportedException(); - - if (streams.Length != 4) - throw new NotSupportedException(); - - mLimit = limit; - mMainStream = streams[0]; - mCallStream = streams[1]; - mJumpStream = streams[2]; - mRangeDecoder = new RangeDecoder(streams[3]); - - mStatusDecoder = new StatusDecoder[256 + 2]; - for (int i = 0; i < mStatusDecoder.Length; i++) - mStatusDecoder[i] = new StatusDecoder(); - - mIter = Run().GetEnumerator(); - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - mMainStream.Dispose(); - mCallStream.Dispose(); - mJumpStream.Dispose(); - } - - private static bool IsJcc(byte b0, byte b1) - { - return b0 == 0x0F - && (b1 & 0xF0) == 0x80; - } - - private static bool IsJ(byte b0, byte b1) - { - return (b1 & 0xFE) == 0xE8 - || IsJcc(b0, b1); - } - - private static int GetIndex(byte b0, byte b1) - { - if (b1 == 0xE8) - return b0; - else if (b1 == 0xE9) - return 256; - else - return 257; - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count == 0 || mFinished) - return 0; - - for (int i = 0; i < count; i++) - { - if (!mIter.MoveNext()) - { - mFinished = true; - return i; - } - - buffer[offset + i] = mIter.Current; - } - - return count; - } - - public IEnumerable Run() - { - const uint kBurstSize = (1u << 18); - - byte prevByte = 0; - uint processedBytes = 0; - for (; ; ) - { - byte b = 0; - uint i; - for (i = 0; i < kBurstSize; i++) - { - int tmp = mMainStream.ReadByte(); - if (tmp < 0) - yield break; - - b = (byte)tmp; - mWritten++; - yield return b; - if (IsJ(prevByte, b)) - break; - - prevByte = b; - } - - processedBytes += i; - if (i == kBurstSize) - continue; - - if (mStatusDecoder[GetIndex(prevByte, b)].Decode(mRangeDecoder) == 1) - { - Stream s = (b == 0xE8) ? mCallStream : mJumpStream; - - uint src = 0; - for (i = 0; i < 4; i++) - { - int b0 = s.ReadByte(); - if (b0 < 0) - throw new EndOfStreamException(); - - src <<= 8; - src |= (uint)b0; - } - - uint dest = src - (uint)(mWritten + 4); - mWritten++; - yield return (byte)dest; - mWritten++; - yield return (byte)(dest >> 8); - mWritten++; - yield return (byte)(dest >> 16); - mWritten++; - yield return (byte)(dest >> 24); - prevByte = (byte)(dest >> 24); - processedBytes += 4; - } - else - { - prevByte = b; - } - } - } - } +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress.Compressor.LZMA +{ + internal class Bcj2DecoderStream : DecoderStream2 + { + private const int kNumTopBits = 24; + private const uint kTopValue = (1 << kNumTopBits); + + private class RangeDecoder + { + internal Stream mStream; + internal uint Range; + internal uint Code; + + public RangeDecoder(Stream stream) + { + mStream = stream; + Range = 0xFFFFFFFF; + for (int i = 0; i < 5; i++) + Code = (Code << 8) | ReadByte(); + } + + public byte ReadByte() + { + int bt = mStream.ReadByte(); + if (bt < 0) + throw new EndOfStreamException(); + + return (byte)bt; + } + + public void Dispose() + { + mStream.Dispose(); + } + } + + private class StatusDecoder + { + private const int numMoveBits = 5; + + private const int kNumBitModelTotalBits = 11; + private const uint kBitModelTotal = 1u << kNumBitModelTotalBits; + + private uint Prob; + + public StatusDecoder() + { + Prob = kBitModelTotal / 2; + } + + private void UpdateModel(uint 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 uint Decode(RangeDecoder decoder) + { + uint newBound = (decoder.Range >> kNumBitModelTotalBits) * Prob; + if (decoder.Code < newBound) + { + decoder.Range = newBound; + Prob += (kBitModelTotal - Prob) >> numMoveBits; + if (decoder.Range < kTopValue) + { + decoder.Code = (decoder.Code << 8) | decoder.ReadByte(); + decoder.Range <<= 8; + } + return 0; + } + else + { + decoder.Range -= newBound; + decoder.Code -= newBound; + Prob -= Prob >> numMoveBits; + if (decoder.Range < kTopValue) + { + decoder.Code = (decoder.Code << 8) | decoder.ReadByte(); + decoder.Range <<= 8; + } + return 1; + } + } + } + + private Stream mMainStream; + private Stream mCallStream; + private Stream mJumpStream; + private RangeDecoder mRangeDecoder; + private StatusDecoder[] mStatusDecoder; + private long mWritten; + private long mLimit; + private IEnumerator mIter; + private bool mFinished; + private bool isDisposed; + + public Bcj2DecoderStream(Stream[] streams, byte[] info, long limit) + { + if (info != null && info.Length > 0) + throw new NotSupportedException(); + + if (streams.Length != 4) + throw new NotSupportedException(); + + mLimit = limit; + mMainStream = streams[0]; + mCallStream = streams[1]; + mJumpStream = streams[2]; + mRangeDecoder = new RangeDecoder(streams[3]); + + mStatusDecoder = new StatusDecoder[256 + 2]; + for (int i = 0; i < mStatusDecoder.Length; i++) + mStatusDecoder[i] = new StatusDecoder(); + + mIter = Run().GetEnumerator(); + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + mMainStream.Dispose(); + mCallStream.Dispose(); + mJumpStream.Dispose(); + } + + private static bool IsJcc(byte b0, byte b1) + { + return b0 == 0x0F + && (b1 & 0xF0) == 0x80; + } + + private static bool IsJ(byte b0, byte b1) + { + return (b1 & 0xFE) == 0xE8 + || IsJcc(b0, b1); + } + + private static int GetIndex(byte b0, byte b1) + { + if (b1 == 0xE8) + return b0; + else if (b1 == 0xE9) + return 256; + else + return 257; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count == 0 || mFinished) + return 0; + + for (int i = 0; i < count; i++) + { + if (!mIter.MoveNext()) + { + mFinished = true; + return i; + } + + buffer[offset + i] = mIter.Current; + } + + return count; + } + + public IEnumerable Run() + { + const uint kBurstSize = (1u << 18); + + byte prevByte = 0; + uint processedBytes = 0; + for (; ; ) + { + byte b = 0; + uint i; + for (i = 0; i < kBurstSize; i++) + { + int tmp = mMainStream.ReadByte(); + if (tmp < 0) + yield break; + + b = (byte)tmp; + mWritten++; + yield return b; + if (IsJ(prevByte, b)) + break; + + prevByte = b; + } + + processedBytes += i; + if (i == kBurstSize) + continue; + + if (mStatusDecoder[GetIndex(prevByte, b)].Decode(mRangeDecoder) == 1) + { + Stream s = (b == 0xE8) ? mCallStream : mJumpStream; + + uint src = 0; + for (i = 0; i < 4; i++) + { + int b0 = s.ReadByte(); + if (b0 < 0) + throw new EndOfStreamException(); + + src <<= 8; + src |= (uint)b0; + } + + uint dest = src - (uint)(mWritten + 4); + mWritten++; + yield return (byte)dest; + mWritten++; + yield return (byte)(dest >> 8); + mWritten++; + yield return (byte)(dest >> 16); + mWritten++; + yield return (byte)(dest >> 24); + prevByte = (byte)(dest >> 24); + processedBytes += 4; + } + else + { + prevByte = b; + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/BitVector.cs b/src/SharpCompress/Compressor/LZMA/BitVector.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/BitVector.cs rename to src/SharpCompress/Compressor/LZMA/BitVector.cs index 181c7d04..ec7443a3 100644 --- a/SharpCompress/Compressor/LZMA/BitVector.cs +++ b/src/SharpCompress/Compressor/LZMA/BitVector.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace SharpCompress.Compressor.LZMA -{ - internal class BitVector - { - private uint[] mBits; - private int mLength; - - public BitVector(int length) - { - mLength = length; - mBits = new uint[(length + 31) >> 5]; - } - - public BitVector(int length, bool initValue) - { - mLength = length; - mBits = new uint[(length + 31) >> 5]; - - if (initValue) - for (int i = 0; i < mBits.Length; i++) - mBits[i] = ~0u; - } - - public BitVector(List bits) - : this(bits.Count) - { - for (int i = 0; i < bits.Count; i++) - if (bits[i]) - SetBit(i); - } - - public bool[] ToArray() - { - bool[] bits = new bool[mLength]; - for (int i = 0; i < bits.Length; i++) - bits[i] = this[i]; - return bits; - } - - public int Length - { - get { return mLength; } - } - - public bool this[int index] - { - get - { - if (index < 0 || index >= mLength) - throw new ArgumentOutOfRangeException("index"); - - return (mBits[index >> 5] & (1u << (index & 31))) != 0; - } - } - - public void SetBit(int index) - { - if (index < 0 || index >= mLength) - throw new ArgumentOutOfRangeException("index"); - - mBits[index >> 5] |= 1u << (index & 31); - } - - internal bool GetAndSet(int index) - { - if (index < 0 || index >= mLength) - throw new ArgumentOutOfRangeException("index"); - - uint bits = mBits[index >> 5]; - uint mask = 1u << (index & 31); - mBits[index >> 5] |= mask; - return (bits & mask) != 0; - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(mLength); - for (int i = 0; i < mLength; i++) - sb.Append(this[i] ? 'x' : '.'); - return sb.ToString(); - } - } +using System; +using System.Collections.Generic; +using System.Text; + +namespace SharpCompress.Compressor.LZMA +{ + internal class BitVector + { + private uint[] mBits; + private int mLength; + + public BitVector(int length) + { + mLength = length; + mBits = new uint[(length + 31) >> 5]; + } + + public BitVector(int length, bool initValue) + { + mLength = length; + mBits = new uint[(length + 31) >> 5]; + + if (initValue) + for (int i = 0; i < mBits.Length; i++) + mBits[i] = ~0u; + } + + public BitVector(List bits) + : this(bits.Count) + { + for (int i = 0; i < bits.Count; i++) + if (bits[i]) + SetBit(i); + } + + public bool[] ToArray() + { + bool[] bits = new bool[mLength]; + for (int i = 0; i < bits.Length; i++) + bits[i] = this[i]; + return bits; + } + + public int Length + { + get { return mLength; } + } + + public bool this[int index] + { + get + { + if (index < 0 || index >= mLength) + throw new ArgumentOutOfRangeException("index"); + + return (mBits[index >> 5] & (1u << (index & 31))) != 0; + } + } + + public void SetBit(int index) + { + if (index < 0 || index >= mLength) + throw new ArgumentOutOfRangeException("index"); + + mBits[index >> 5] |= 1u << (index & 31); + } + + internal bool GetAndSet(int index) + { + if (index < 0 || index >= mLength) + throw new ArgumentOutOfRangeException("index"); + + uint bits = mBits[index >> 5]; + uint mask = 1u << (index & 31); + mBits[index >> 5] |= mask; + return (bits & mask) != 0; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(mLength); + for (int i = 0; i < mLength; i++) + sb.Append(this[i] ? 'x' : '.'); + return sb.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/CRC.cs b/src/SharpCompress/Compressor/LZMA/CRC.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/CRC.cs rename to src/SharpCompress/Compressor/LZMA/CRC.cs index 17ec9f6e..6f261767 100644 --- a/SharpCompress/Compressor/LZMA/CRC.cs +++ b/src/SharpCompress/Compressor/LZMA/CRC.cs @@ -1,83 +1,83 @@ -using System; -using System.IO; - -namespace SharpCompress.Compressor.LZMA -{ - internal static class CRC - { - public const uint kInitCRC = 0xFFFFFFFF; - private static uint[] kTable = new uint[4 * 256]; - - static CRC() - { - const uint kCrcPoly = 0xEDB88320; - - for (uint i = 0; i < 256; i++) - { - uint r = i; - for (int j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); - - kTable[i] = r; - } - - for (uint i = 256; i < kTable.Length; i++) - { - uint r = kTable[i - 256]; - kTable[i] = kTable[r & 0xFF] ^ (r >> 8); - } - } - - public static uint From(Stream stream, long length) - { - uint crc = kInitCRC; - byte[] buffer = new byte[Math.Min(length, 4 << 10)]; - while (length > 0) - { - int delta = stream.Read(buffer, 0, (int)Math.Min(length, buffer.Length)); - if (delta == 0) - throw new EndOfStreamException(); - crc = Update(crc, buffer, 0, delta); - length -= delta; - } - return Finish(crc); - } - - public static uint Finish(uint crc) - { - return ~crc; - } - - public static uint Update(uint crc, byte bt) - { - return kTable[(crc & 0xFF) ^ bt] ^ (crc >> 8); - } - - public static uint Update(uint crc, uint value) - { - crc ^= value; - return kTable[0x300 + (crc & 0xFF)] - ^ kTable[0x200 + ((crc >> 8) & 0xFF)] - ^ kTable[0x100 + ((crc >> 16) & 0xFF)] - ^ kTable[0x000 + (crc >> 24)]; - } - - public static uint Update(uint crc, ulong value) - { - return Update(Update(crc, (uint)value), (uint)(value >> 32)); - } - - public static uint Update(uint crc, long value) - { - return Update(crc, (ulong)value); - } - - public static uint Update(uint crc, byte[] buffer, int offset, int length) - { - for (int i = 0; i < length; i++) - crc = Update(crc, buffer[offset + i]); - - return crc; - } - } +using System; +using System.IO; + +namespace SharpCompress.Compressor.LZMA +{ + internal static class CRC + { + public const uint kInitCRC = 0xFFFFFFFF; + private static uint[] kTable = new uint[4 * 256]; + + static CRC() + { + const uint kCrcPoly = 0xEDB88320; + + for (uint i = 0; i < 256; i++) + { + uint r = i; + for (int j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + + kTable[i] = r; + } + + for (uint i = 256; i < kTable.Length; i++) + { + uint r = kTable[i - 256]; + kTable[i] = kTable[r & 0xFF] ^ (r >> 8); + } + } + + public static uint From(Stream stream, long length) + { + uint crc = kInitCRC; + byte[] buffer = new byte[Math.Min(length, 4 << 10)]; + while (length > 0) + { + int delta = stream.Read(buffer, 0, (int)Math.Min(length, buffer.Length)); + if (delta == 0) + throw new EndOfStreamException(); + crc = Update(crc, buffer, 0, delta); + length -= delta; + } + return Finish(crc); + } + + public static uint Finish(uint crc) + { + return ~crc; + } + + public static uint Update(uint crc, byte bt) + { + return kTable[(crc & 0xFF) ^ bt] ^ (crc >> 8); + } + + public static uint Update(uint crc, uint value) + { + crc ^= value; + return kTable[0x300 + (crc & 0xFF)] + ^ kTable[0x200 + ((crc >> 8) & 0xFF)] + ^ kTable[0x100 + ((crc >> 16) & 0xFF)] + ^ kTable[0x000 + (crc >> 24)]; + } + + public static uint Update(uint crc, ulong value) + { + return Update(Update(crc, (uint)value), (uint)(value >> 32)); + } + + public static uint Update(uint crc, long value) + { + return Update(crc, (ulong)value); + } + + public static uint Update(uint crc, byte[] buffer, int offset, int length) + { + for (int i = 0; i < length; i++) + crc = Update(crc, buffer[offset + i]); + + return crc; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/DecoderStream.cs b/src/SharpCompress/Compressor/LZMA/DecoderStream.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/DecoderStream.cs rename to src/SharpCompress/Compressor/LZMA/DecoderStream.cs index 0427d1fc..47609ee7 100644 --- a/SharpCompress/Compressor/LZMA/DecoderStream.cs +++ b/src/SharpCompress/Compressor/LZMA/DecoderStream.cs @@ -1,176 +1,176 @@ -using System; -using System.IO; -using SharpCompress.Common.SevenZip; -using SharpCompress.Compressor.LZMA.Utilites; -using SharpCompress.IO; - -namespace SharpCompress.Compressor.LZMA -{ - internal abstract class DecoderStream2 : Stream - { - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - } - - internal static class DecoderStreamHelper - { - private static int FindCoderIndexForOutStreamIndex(CFolder folderInfo, int outStreamIndex) - { - for (int coderIndex = 0; coderIndex < folderInfo.Coders.Count; coderIndex++) - { - var coderInfo = folderInfo.Coders[coderIndex]; - outStreamIndex -= coderInfo.NumOutStreams; - if (outStreamIndex < 0) - return coderIndex; - } - - throw new InvalidOperationException("Could not link output stream to coder."); - } - - private static void FindPrimaryOutStreamIndex(CFolder folderInfo, out int primaryCoderIndex, - out int primaryOutStreamIndex) - { - bool foundPrimaryOutStream = false; - primaryCoderIndex = -1; - primaryOutStreamIndex = -1; - - for (int outStreamIndex = 0, coderIndex = 0; - coderIndex < folderInfo.Coders.Count; - coderIndex++) - { - for (int coderOutStreamIndex = 0; - coderOutStreamIndex < folderInfo.Coders[coderIndex].NumOutStreams; - coderOutStreamIndex++, outStreamIndex++) - { - if (folderInfo.FindBindPairForOutStream(outStreamIndex) < 0) - { - if (foundPrimaryOutStream) - throw new NotSupportedException("Multiple output streams."); - - foundPrimaryOutStream = true; - primaryCoderIndex = coderIndex; - primaryOutStreamIndex = outStreamIndex; - } - } - } - - if (!foundPrimaryOutStream) - throw new NotSupportedException("No output stream."); - } - - private static Stream CreateDecoderStream(Stream[] packStreams, long[] packSizes, Stream[] outStreams, - CFolder folderInfo, int coderIndex, IPasswordProvider pass) - { - var coderInfo = folderInfo.Coders[coderIndex]; - if (coderInfo.NumOutStreams != 1) - throw new NotSupportedException("Multiple output streams are not supported."); - - int inStreamId = 0; - for (int i = 0; i < coderIndex; i++) - inStreamId += folderInfo.Coders[i].NumInStreams; - - int outStreamId = 0; - for (int i = 0; i < coderIndex; i++) - outStreamId += folderInfo.Coders[i].NumOutStreams; - - Stream[] inStreams = new Stream[coderInfo.NumInStreams]; - - for (int i = 0; i < inStreams.Length; i++, inStreamId++) - { - int bindPairIndex = folderInfo.FindBindPairForInStream(inStreamId); - if (bindPairIndex >= 0) - { - int pairedOutIndex = folderInfo.BindPairs[bindPairIndex].OutIndex; - - if (outStreams[pairedOutIndex] != null) - throw new NotSupportedException("Overlapping stream bindings are not supported."); - - int otherCoderIndex = FindCoderIndexForOutStreamIndex(folderInfo, pairedOutIndex); - inStreams[i] = CreateDecoderStream(packStreams, packSizes, outStreams, folderInfo, otherCoderIndex, - pass); - //inStreamSizes[i] = folderInfo.UnpackSizes[pairedOutIndex]; - - if (outStreams[pairedOutIndex] != null) - throw new NotSupportedException("Overlapping stream bindings are not supported."); - - outStreams[pairedOutIndex] = inStreams[i]; - } - else - { - int index = folderInfo.FindPackStreamArrayIndex(inStreamId); - if (index < 0) - throw new NotSupportedException("Could not find input stream binding."); - - inStreams[i] = packStreams[index]; - //inStreamSizes[i] = packSizes[index]; - } - } - - long unpackSize = folderInfo.UnpackSizes[outStreamId]; - return DecoderRegistry.CreateDecoderStream(coderInfo.MethodId, inStreams, coderInfo.Props, pass, unpackSize); - } - - internal static Stream CreateDecoderStream(Stream inStream, long startPos, long[] packSizes, CFolder folderInfo, - IPasswordProvider pass) - { - if (!folderInfo.CheckStructure()) - throw new NotSupportedException("Unsupported stream binding structure."); - - Stream[] inStreams = new Stream[folderInfo.PackStreams.Count]; - for (int j = 0; j < folderInfo.PackStreams.Count; j++) - { - inStreams[j] = new ReadOnlySubStream(inStream, startPos, packSizes[j]); - startPos += packSizes[j]; - } - - Stream[] outStreams = new Stream[folderInfo.UnpackSizes.Count]; - - int primaryCoderIndex, primaryOutStreamIndex; - FindPrimaryOutStreamIndex(folderInfo, out primaryCoderIndex, out primaryOutStreamIndex); - return CreateDecoderStream(inStreams, packSizes, outStreams, folderInfo, primaryCoderIndex, pass); - } - } +using System; +using System.IO; +using SharpCompress.Common.SevenZip; +using SharpCompress.Compressor.LZMA.Utilites; +using SharpCompress.IO; + +namespace SharpCompress.Compressor.LZMA +{ + internal abstract class DecoderStream2 : Stream + { + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } + + internal static class DecoderStreamHelper + { + private static int FindCoderIndexForOutStreamIndex(CFolder folderInfo, int outStreamIndex) + { + for (int coderIndex = 0; coderIndex < folderInfo.Coders.Count; coderIndex++) + { + var coderInfo = folderInfo.Coders[coderIndex]; + outStreamIndex -= coderInfo.NumOutStreams; + if (outStreamIndex < 0) + return coderIndex; + } + + throw new InvalidOperationException("Could not link output stream to coder."); + } + + private static void FindPrimaryOutStreamIndex(CFolder folderInfo, out int primaryCoderIndex, + out int primaryOutStreamIndex) + { + bool foundPrimaryOutStream = false; + primaryCoderIndex = -1; + primaryOutStreamIndex = -1; + + for (int outStreamIndex = 0, coderIndex = 0; + coderIndex < folderInfo.Coders.Count; + coderIndex++) + { + for (int coderOutStreamIndex = 0; + coderOutStreamIndex < folderInfo.Coders[coderIndex].NumOutStreams; + coderOutStreamIndex++, outStreamIndex++) + { + if (folderInfo.FindBindPairForOutStream(outStreamIndex) < 0) + { + if (foundPrimaryOutStream) + throw new NotSupportedException("Multiple output streams."); + + foundPrimaryOutStream = true; + primaryCoderIndex = coderIndex; + primaryOutStreamIndex = outStreamIndex; + } + } + } + + if (!foundPrimaryOutStream) + throw new NotSupportedException("No output stream."); + } + + private static Stream CreateDecoderStream(Stream[] packStreams, long[] packSizes, Stream[] outStreams, + CFolder folderInfo, int coderIndex, IPasswordProvider pass) + { + var coderInfo = folderInfo.Coders[coderIndex]; + if (coderInfo.NumOutStreams != 1) + throw new NotSupportedException("Multiple output streams are not supported."); + + int inStreamId = 0; + for (int i = 0; i < coderIndex; i++) + inStreamId += folderInfo.Coders[i].NumInStreams; + + int outStreamId = 0; + for (int i = 0; i < coderIndex; i++) + outStreamId += folderInfo.Coders[i].NumOutStreams; + + Stream[] inStreams = new Stream[coderInfo.NumInStreams]; + + for (int i = 0; i < inStreams.Length; i++, inStreamId++) + { + int bindPairIndex = folderInfo.FindBindPairForInStream(inStreamId); + if (bindPairIndex >= 0) + { + int pairedOutIndex = folderInfo.BindPairs[bindPairIndex].OutIndex; + + if (outStreams[pairedOutIndex] != null) + throw new NotSupportedException("Overlapping stream bindings are not supported."); + + int otherCoderIndex = FindCoderIndexForOutStreamIndex(folderInfo, pairedOutIndex); + inStreams[i] = CreateDecoderStream(packStreams, packSizes, outStreams, folderInfo, otherCoderIndex, + pass); + //inStreamSizes[i] = folderInfo.UnpackSizes[pairedOutIndex]; + + if (outStreams[pairedOutIndex] != null) + throw new NotSupportedException("Overlapping stream bindings are not supported."); + + outStreams[pairedOutIndex] = inStreams[i]; + } + else + { + int index = folderInfo.FindPackStreamArrayIndex(inStreamId); + if (index < 0) + throw new NotSupportedException("Could not find input stream binding."); + + inStreams[i] = packStreams[index]; + //inStreamSizes[i] = packSizes[index]; + } + } + + long unpackSize = folderInfo.UnpackSizes[outStreamId]; + return DecoderRegistry.CreateDecoderStream(coderInfo.MethodId, inStreams, coderInfo.Props, pass, unpackSize); + } + + internal static Stream CreateDecoderStream(Stream inStream, long startPos, long[] packSizes, CFolder folderInfo, + IPasswordProvider pass) + { + if (!folderInfo.CheckStructure()) + throw new NotSupportedException("Unsupported stream binding structure."); + + Stream[] inStreams = new Stream[folderInfo.PackStreams.Count]; + for (int j = 0; j < folderInfo.PackStreams.Count; j++) + { + inStreams[j] = new ReadOnlySubStream(inStream, startPos, packSizes[j]); + startPos += packSizes[j]; + } + + Stream[] outStreams = new Stream[folderInfo.UnpackSizes.Count]; + + int primaryCoderIndex, primaryOutStreamIndex; + FindPrimaryOutStreamIndex(folderInfo, out primaryCoderIndex, out primaryOutStreamIndex); + return CreateDecoderStream(inStreams, packSizes, outStreams, folderInfo, primaryCoderIndex, pass); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/ICoder.cs b/src/SharpCompress/Compressor/LZMA/ICoder.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/ICoder.cs rename to src/SharpCompress/Compressor/LZMA/ICoder.cs index 5d9b8caa..354bd836 100644 --- a/SharpCompress/Compressor/LZMA/ICoder.cs +++ b/src/SharpCompress/Compressor/LZMA/ICoder.cs @@ -1,170 +1,170 @@ -using System; - -namespace SharpCompress.Compressor.LZMA -{ - /// - /// The exception that is thrown when an error in input stream occurs during decoding. - /// - internal class DataErrorException : Exception - { - public DataErrorException() : base("Data Error") - { - } - } - - /// - /// The exception that is thrown when the value of an argument is outside the allowable range. - /// - internal class InvalidParamException : Exception - { - public InvalidParamException() : base("Invalid Parameter") - { - } - } - - internal interface ICodeProgress - { - /// - /// Callback progress. - /// - /// - /// input size. -1 if unknown. - /// - /// - /// output size. -1 if unknown. - /// - void SetProgress(Int64 inSize, Int64 outSize); - }; - - internal interface ICoder - { - /// - /// Codes streams. - /// - /// - /// input Stream. - /// - /// - /// output Stream. - /// - /// - /// input Size. -1 if unknown. - /// - /// - /// output Size. -1 if unknown. - /// - /// - /// callback progress reference. - /// - 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); - }; - */ - - /// - /// Provides the fields that represent properties idenitifiers for compressing. - /// - internal enum CoderPropID - { - /// - /// Specifies default property. - /// - DefaultProp = 0, - - /// - /// Specifies size of dictionary. - /// - DictionarySize, - - /// - /// Specifies size of memory for PPM*. - /// - UsedMemorySize, - - /// - /// Specifies order for PPM methods. - /// - Order, - - /// - /// Specifies Block Size. - /// - BlockSize, - - /// - /// Specifies number of postion state bits for LZMA (0 - x - 4). - /// - PosStateBits, - - /// - /// Specifies number of literal context bits for LZMA (0 - x - 8). - /// - LitContextBits, - - /// - /// Specifies number of literal position bits for LZMA (0 - x - 4). - /// - LitPosBits, - - /// - /// Specifies number of fast bytes for LZ*. - /// - NumFastBytes, - - /// - /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". - /// - MatchFinder, - - /// - /// Specifies the number of match finder cyckes. - /// - MatchFinderCycles, - - /// - /// Specifies number of passes. - /// - NumPasses, - - /// - /// Specifies number of algorithm. - /// - Algorithm, - - /// - /// Specifies the number of threads. - /// - NumThreads, - - /// - /// Specifies mode with end marker. - /// - EndMarker - }; - - - internal interface ISetCoderProperties - { - void SetCoderProperties(CoderPropID[] propIDs, object[] properties); - }; - - internal interface IWriteCoderProperties - { - void WriteCoderProperties(System.IO.Stream outStream); - } - - internal interface ISetDecoderProperties - { - void SetDecoderProperties(byte[] properties); - } +using System; + +namespace SharpCompress.Compressor.LZMA +{ + /// + /// The exception that is thrown when an error in input stream occurs during decoding. + /// + internal class DataErrorException : Exception + { + public DataErrorException() : base("Data Error") + { + } + } + + /// + /// The exception that is thrown when the value of an argument is outside the allowable range. + /// + internal class InvalidParamException : Exception + { + public InvalidParamException() : base("Invalid Parameter") + { + } + } + + internal interface ICodeProgress + { + /// + /// Callback progress. + /// + /// + /// input size. -1 if unknown. + /// + /// + /// output size. -1 if unknown. + /// + void SetProgress(Int64 inSize, Int64 outSize); + }; + + internal interface ICoder + { + /// + /// Codes streams. + /// + /// + /// input Stream. + /// + /// + /// output Stream. + /// + /// + /// input Size. -1 if unknown. + /// + /// + /// output Size. -1 if unknown. + /// + /// + /// callback progress reference. + /// + 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); + }; + */ + + /// + /// Provides the fields that represent properties idenitifiers for compressing. + /// + internal enum CoderPropID + { + /// + /// Specifies default property. + /// + DefaultProp = 0, + + /// + /// Specifies size of dictionary. + /// + DictionarySize, + + /// + /// Specifies size of memory for PPM*. + /// + UsedMemorySize, + + /// + /// Specifies order for PPM methods. + /// + Order, + + /// + /// Specifies Block Size. + /// + BlockSize, + + /// + /// Specifies number of postion state bits for LZMA (0 - x - 4). + /// + PosStateBits, + + /// + /// Specifies number of literal context bits for LZMA (0 - x - 8). + /// + LitContextBits, + + /// + /// Specifies number of literal position bits for LZMA (0 - x - 4). + /// + LitPosBits, + + /// + /// Specifies number of fast bytes for LZ*. + /// + NumFastBytes, + + /// + /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". + /// + MatchFinder, + + /// + /// Specifies the number of match finder cyckes. + /// + MatchFinderCycles, + + /// + /// Specifies number of passes. + /// + NumPasses, + + /// + /// Specifies number of algorithm. + /// + Algorithm, + + /// + /// Specifies the number of threads. + /// + NumThreads, + + /// + /// Specifies mode with end marker. + /// + EndMarker + }; + + + internal interface ISetCoderProperties + { + void SetCoderProperties(CoderPropID[] propIDs, object[] properties); + }; + + internal interface IWriteCoderProperties + { + void WriteCoderProperties(System.IO.Stream outStream); + } + + internal interface ISetDecoderProperties + { + void SetDecoderProperties(byte[] properties); + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LZ/CRC.cs b/src/SharpCompress/Compressor/LZMA/LZ/CRC.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/LZ/CRC.cs rename to src/SharpCompress/Compressor/LZMA/LZ/CRC.cs index 2079c63f..a1775aac 100644 --- a/SharpCompress/Compressor/LZMA/LZ/CRC.cs +++ b/src/SharpCompress/Compressor/LZMA/LZ/CRC.cs @@ -1,59 +1,59 @@ -namespace SharpCompress.Compressor.LZMA.LZ -{ - internal 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; - } - } - - private 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; - } - - private static uint CalculateDigest(byte[] data, uint offset, uint size) - { - CRC crc = new CRC(); - // crc.Init(); - crc.Update(data, offset, size); - return crc.GetDigest(); - } - - private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size) - { - return (CalculateDigest(data, offset, size) == digest); - } - } +namespace SharpCompress.Compressor.LZMA.LZ +{ + internal 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; + } + } + + private 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; + } + + private static uint CalculateDigest(byte[] data, uint offset, uint size) + { + CRC crc = new CRC(); + // crc.Init(); + crc.Update(data, offset, size); + return crc.GetDigest(); + } + + private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size) + { + return (CalculateDigest(data, offset, size) == digest); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LZ/LzBinTree.cs b/src/SharpCompress/Compressor/LZMA/LZ/LzBinTree.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/LZ/LzBinTree.cs rename to src/SharpCompress/Compressor/LZMA/LZ/LzBinTree.cs index 3032d0d8..e7d7f38a 100644 --- a/SharpCompress/Compressor/LZMA/LZ/LzBinTree.cs +++ b/src/SharpCompress/Compressor/LZMA/LZ/LzBinTree.cs @@ -1,382 +1,382 @@ -using System; - -namespace SharpCompress.Compressor.LZMA.LZ -{ - internal class BinTree : InWindow - { - private UInt32 _cyclicBufferPos; - private UInt32 _cyclicBufferSize = 0; - private UInt32 _matchMaxLen; - - private UInt32[] _son; - private UInt32[] _hash; - - private UInt32 _cutValue = 0xFF; - private UInt32 _hashMask; - private UInt32 _hashSizeSum = 0; - - private bool HASH_ARRAY = true; - - private const UInt32 kHash2Size = 1 << 10; - private const UInt32 kHash3Size = 1 << 16; - private const UInt32 kBT2HashSize = 1 << 16; - private const UInt32 kStartMaxLen = 1; - private const UInt32 kHash3Offset = kHash2Size; - private const UInt32 kEmptyHashValue = 0; - private const UInt32 kMaxValForNormalize = ((UInt32) 1 << 31) - 1; - - private UInt32 kNumHashDirectBytes = 0; - private UInt32 kMinMatchCheck = 4; - private 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); - } - - private 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; - } - } - - private 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; - } - } +using System; + +namespace SharpCompress.Compressor.LZMA.LZ +{ + internal class BinTree : InWindow + { + private UInt32 _cyclicBufferPos; + private UInt32 _cyclicBufferSize = 0; + private UInt32 _matchMaxLen; + + private UInt32[] _son; + private UInt32[] _hash; + + private UInt32 _cutValue = 0xFF; + private UInt32 _hashMask; + private UInt32 _hashSizeSum = 0; + + private bool HASH_ARRAY = true; + + private const UInt32 kHash2Size = 1 << 10; + private const UInt32 kHash3Size = 1 << 16; + private const UInt32 kBT2HashSize = 1 << 16; + private const UInt32 kStartMaxLen = 1; + private const UInt32 kHash3Offset = kHash2Size; + private const UInt32 kEmptyHashValue = 0; + private const UInt32 kMaxValForNormalize = ((UInt32) 1 << 31) - 1; + + private UInt32 kNumHashDirectBytes = 0; + private UInt32 kMinMatchCheck = 4; + private 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); + } + + private 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; + } + } + + private 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; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LZ/LzInWindow.cs b/src/SharpCompress/Compressor/LZMA/LZ/LzInWindow.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/LZ/LzInWindow.cs rename to src/SharpCompress/Compressor/LZMA/LZ/LzInWindow.cs index fb2dfc8b..7bc83ec8 100644 --- a/SharpCompress/Compressor/LZMA/LZ/LzInWindow.cs +++ b/src/SharpCompress/Compressor/LZMA/LZ/LzInWindow.cs @@ -1,160 +1,160 @@ -using System; - -namespace SharpCompress.Compressor.LZMA.LZ -{ - internal class InWindow - { - public Byte[] _bufferBase = null; // pointer to buffer with data - private System.IO.Stream _stream; - private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done - private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream - - private UInt32 _pointerToLastSafePosition; - - public UInt32 _bufferOffset; - - public UInt32 _blockSize; // Size of Allocated memory block - public UInt32 _pos; // offset (from _buffer) of curent byte - private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos - private 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 != null - ? _stream.Read(_bufferBase, (int) (_bufferOffset + _streamPos), size) - : 0; - 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; - } - } - - private 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; - _streamEndWasReached = false; - } - - public void SetStream(System.IO.Stream stream) - { - _stream = stream; - if (_streamEndWasReached) - { - _streamEndWasReached = false; - if (IsDataStarved) - ReadBlock(); - } - } - - 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; - } - - public bool IsDataStarved - { - get { return _streamPos - _pos < _keepSizeAfter; } - } - } +using System; + +namespace SharpCompress.Compressor.LZMA.LZ +{ + internal class InWindow + { + public Byte[] _bufferBase = null; // pointer to buffer with data + private System.IO.Stream _stream; + private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done + private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream + + private UInt32 _pointerToLastSafePosition; + + public UInt32 _bufferOffset; + + public UInt32 _blockSize; // Size of Allocated memory block + public UInt32 _pos; // offset (from _buffer) of curent byte + private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos + private 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 != null + ? _stream.Read(_bufferBase, (int) (_bufferOffset + _streamPos), size) + : 0; + 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; + } + } + + private 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; + _streamEndWasReached = false; + } + + public void SetStream(System.IO.Stream stream) + { + _stream = stream; + if (_streamEndWasReached) + { + _streamEndWasReached = false; + if (IsDataStarved) + ReadBlock(); + } + } + + 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; + } + + public bool IsDataStarved + { + get { return _streamPos - _pos < _keepSizeAfter; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LZ/LzOutWindow.cs b/src/SharpCompress/Compressor/LZMA/LZ/LzOutWindow.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/LZ/LzOutWindow.cs rename to src/SharpCompress/Compressor/LZMA/LZ/LzOutWindow.cs index ce91c5d8..4fc6c0cf 100644 --- a/SharpCompress/Compressor/LZMA/LZ/LzOutWindow.cs +++ b/src/SharpCompress/Compressor/LZMA/LZ/LzOutWindow.cs @@ -1,175 +1,175 @@ -namespace SharpCompress.Compressor.LZMA.LZ -{ - internal class OutWindow - { - private byte[] _buffer = null; - private int _windowSize = 0; - private int _pos; - private int _streamPos; - private int _pendingLen; - private int _pendingDist; - private System.IO.Stream _stream; - - public long Total; - public long Limit; - - public void Create(int windowSize) - { - if (_windowSize != windowSize) - _buffer = new byte[windowSize]; - else - _buffer[windowSize - 1] = 0; - _windowSize = windowSize; - _pos = 0; - _streamPos = 0; - _pendingLen = 0; - Total = 0; - Limit = 0; - } - - public void Reset() - { - Create(_windowSize); - } - - public void Init(System.IO.Stream stream) - { - ReleaseStream(); - _stream = stream; - } - - public void Train(System.IO.Stream stream) - { - long len = stream.Length; - int size = (len < _windowSize) ? (int) len : _windowSize; - stream.Position = len - size; - Total = 0; - Limit = size; - _pos = _windowSize - size; - CopyStream(stream, size); - if (_pos == _windowSize) - _pos = 0; - _streamPos = _pos; - } - - public void ReleaseStream() - { - Flush(); - _stream = null; - } - - public void Flush() - { - if (_stream == null) - return; - 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) - { - int size = len; - int pos = _pos - distance - 1; - if (pos < 0) - pos += _windowSize; - for (; size > 0 && _pos < _windowSize && Total < Limit; size--) - { - if (pos >= _windowSize) - pos = 0; - _buffer[_pos++] = _buffer[pos++]; - Total++; - if (_pos >= _windowSize) - Flush(); - } - _pendingLen = size; - _pendingDist = distance; - } - - public void PutByte(byte b) - { - _buffer[_pos++] = b; - Total++; - if (_pos >= _windowSize) - Flush(); - } - - public byte GetByte(int distance) - { - int pos = _pos - distance - 1; - if (pos < 0) - pos += _windowSize; - return _buffer[pos]; - } - - public int CopyStream(System.IO.Stream stream, int len) - { - int size = len; - while (size > 0 && _pos < _windowSize && Total < Limit) - { - int curSize = _windowSize - _pos; - if (curSize > Limit - Total) - curSize = (int) (Limit - Total); - if (curSize > size) - curSize = size; - int numReadBytes = stream.Read(_buffer, _pos, curSize); - if (numReadBytes == 0) - throw new DataErrorException(); - size -= numReadBytes; - _pos += numReadBytes; - Total += numReadBytes; - if (_pos >= _windowSize) - Flush(); - } - return len - size; - } - - public void SetLimit(long size) - { - Limit = Total + size; - } - - public bool HasSpace - { - get { return _pos < _windowSize && Total < Limit; } - } - - public bool HasPending - { - get { return _pendingLen > 0; } - } - - public int Read(byte[] buffer, int offset, int count) - { - if (_streamPos >= _pos) - return 0; - - int size = _pos - _streamPos; - if (size > count) - size = count; - System.Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size); - _streamPos += size; - if (_streamPos >= _windowSize) - { - _pos = 0; - _streamPos = 0; - } - return size; - } - - public void CopyPending() - { - if (_pendingLen > 0) - CopyBlock(_pendingDist, _pendingLen); - } - - public int AvailableBytes - { - get { return _pos - _streamPos; } - } - } +namespace SharpCompress.Compressor.LZMA.LZ +{ + internal class OutWindow + { + private byte[] _buffer = null; + private int _windowSize = 0; + private int _pos; + private int _streamPos; + private int _pendingLen; + private int _pendingDist; + private System.IO.Stream _stream; + + public long Total; + public long Limit; + + public void Create(int windowSize) + { + if (_windowSize != windowSize) + _buffer = new byte[windowSize]; + else + _buffer[windowSize - 1] = 0; + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + _pendingLen = 0; + Total = 0; + Limit = 0; + } + + public void Reset() + { + Create(_windowSize); + } + + public void Init(System.IO.Stream stream) + { + ReleaseStream(); + _stream = stream; + } + + public void Train(System.IO.Stream stream) + { + long len = stream.Length; + int size = (len < _windowSize) ? (int) len : _windowSize; + stream.Position = len - size; + Total = 0; + Limit = size; + _pos = _windowSize - size; + CopyStream(stream, size); + if (_pos == _windowSize) + _pos = 0; + _streamPos = _pos; + } + + public void ReleaseStream() + { + Flush(); + _stream = null; + } + + public void Flush() + { + if (_stream == null) + return; + 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) + { + int size = len; + int pos = _pos - distance - 1; + if (pos < 0) + pos += _windowSize; + for (; size > 0 && _pos < _windowSize && Total < Limit; size--) + { + if (pos >= _windowSize) + pos = 0; + _buffer[_pos++] = _buffer[pos++]; + Total++; + if (_pos >= _windowSize) + Flush(); + } + _pendingLen = size; + _pendingDist = distance; + } + + public void PutByte(byte b) + { + _buffer[_pos++] = b; + Total++; + if (_pos >= _windowSize) + Flush(); + } + + public byte GetByte(int distance) + { + int pos = _pos - distance - 1; + if (pos < 0) + pos += _windowSize; + return _buffer[pos]; + } + + public int CopyStream(System.IO.Stream stream, int len) + { + int size = len; + while (size > 0 && _pos < _windowSize && Total < Limit) + { + int curSize = _windowSize - _pos; + if (curSize > Limit - Total) + curSize = (int) (Limit - Total); + if (curSize > size) + curSize = size; + int numReadBytes = stream.Read(_buffer, _pos, curSize); + if (numReadBytes == 0) + throw new DataErrorException(); + size -= numReadBytes; + _pos += numReadBytes; + Total += numReadBytes; + if (_pos >= _windowSize) + Flush(); + } + return len - size; + } + + public void SetLimit(long size) + { + Limit = Total + size; + } + + public bool HasSpace + { + get { return _pos < _windowSize && Total < Limit; } + } + + public bool HasPending + { + get { return _pendingLen > 0; } + } + + public int Read(byte[] buffer, int offset, int count) + { + if (_streamPos >= _pos) + return 0; + + int size = _pos - _streamPos; + if (size > count) + size = count; + System.Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size); + _streamPos += size; + if (_streamPos >= _windowSize) + { + _pos = 0; + _streamPos = 0; + } + return size; + } + + public void CopyPending() + { + if (_pendingLen > 0) + CopyBlock(_pendingDist, _pendingLen); + } + + public int AvailableBytes + { + get { return _pos - _streamPos; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Log.cs b/src/SharpCompress/Compressor/LZMA/Log.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/Log.cs rename to src/SharpCompress/Compressor/LZMA/Log.cs index b742b0f8..f4231c94 100644 --- a/SharpCompress/Compressor/LZMA/Log.cs +++ b/src/SharpCompress/Compressor/LZMA/Log.cs @@ -1,91 +1,91 @@ -using System; -using System.Collections.Generic; - -namespace SharpCompress.Compressor.LZMA -{ - internal static class Log - { - private static Stack _indent = new Stack(); - private static bool _needsIndent = true; - - static Log() - { - _indent.Push(""); - } - - public static void PushIndent(string indent = " ") - { - _indent.Push(_indent.Peek() + indent); - } - - public static void PopIndent() - { - if (_indent.Count == 1) - throw new InvalidOperationException(); - - _indent.Pop(); - } - - private static void EnsureIndent() - { - if (_needsIndent) - { - _needsIndent = false; -#if !DOTNET51 - System.Diagnostics.Debug.Write(_indent.Peek()); -#endif - } - } - - public static void Write(object value) - { - EnsureIndent(); -#if !DOTNET51 - System.Diagnostics.Debug.Write(value); -#endif - } - - public static void Write(string text) - { - EnsureIndent(); -#if !DOTNET51 - System.Diagnostics.Debug.Write(text); -#endif - } - - public static void Write(string format, params object[] args) - { - EnsureIndent(); -#if !DOTNET51 - System.Diagnostics.Debug.Write(string.Format(format, args)); -#endif - } - - public static void WriteLine() - { - System.Diagnostics.Debug.WriteLine(""); - _needsIndent = true; - } - - public static void WriteLine(object value) - { - EnsureIndent(); - System.Diagnostics.Debug.WriteLine(value); - _needsIndent = true; - } - - public static void WriteLine(string text) - { - EnsureIndent(); - System.Diagnostics.Debug.WriteLine(text); - _needsIndent = true; - } - - public static void WriteLine(string format, params object[] args) - { - EnsureIndent(); - System.Diagnostics.Debug.WriteLine(string.Format(format, args)); - _needsIndent = true; - } - } +using System; +using System.Collections.Generic; + +namespace SharpCompress.Compressor.LZMA +{ + internal static class Log + { + private static Stack _indent = new Stack(); + private static bool _needsIndent = true; + + static Log() + { + _indent.Push(""); + } + + public static void PushIndent(string indent = " ") + { + _indent.Push(_indent.Peek() + indent); + } + + public static void PopIndent() + { + if (_indent.Count == 1) + throw new InvalidOperationException(); + + _indent.Pop(); + } + + private static void EnsureIndent() + { + if (_needsIndent) + { + _needsIndent = false; +#if !DOTNET51 + System.Diagnostics.Debug.Write(_indent.Peek()); +#endif + } + } + + public static void Write(object value) + { + EnsureIndent(); +#if !DOTNET51 + System.Diagnostics.Debug.Write(value); +#endif + } + + public static void Write(string text) + { + EnsureIndent(); +#if !DOTNET51 + System.Diagnostics.Debug.Write(text); +#endif + } + + public static void Write(string format, params object[] args) + { + EnsureIndent(); +#if !DOTNET51 + System.Diagnostics.Debug.Write(string.Format(format, args)); +#endif + } + + public static void WriteLine() + { + System.Diagnostics.Debug.WriteLine(""); + _needsIndent = true; + } + + public static void WriteLine(object value) + { + EnsureIndent(); + System.Diagnostics.Debug.WriteLine(value); + _needsIndent = true; + } + + public static void WriteLine(string text) + { + EnsureIndent(); + System.Diagnostics.Debug.WriteLine(text); + _needsIndent = true; + } + + public static void WriteLine(string format, params object[] args) + { + EnsureIndent(); + System.Diagnostics.Debug.WriteLine(string.Format(format, args)); + _needsIndent = true; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LzmaBase.cs b/src/SharpCompress/Compressor/LZMA/LzmaBase.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/LzmaBase.cs rename to src/SharpCompress/Compressor/LZMA/LzmaBase.cs index 3508ff61..9d1f78a7 100644 --- a/SharpCompress/Compressor/LZMA/LzmaBase.cs +++ b/src/SharpCompress/Compressor/LZMA/LzmaBase.cs @@ -1,97 +1,97 @@ -namespace SharpCompress.Compressor.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; - } +namespace SharpCompress.Compressor.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; + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressor/LZMA/LzmaDecoder.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/LzmaDecoder.cs rename to src/SharpCompress/Compressor/LZMA/LzmaDecoder.cs index ac2d30c2..5de39f3c 100644 --- a/SharpCompress/Compressor/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressor/LZMA/LzmaDecoder.cs @@ -1,418 +1,418 @@ -using System; -using SharpCompress.Compressor.LZMA.RangeCoder; - -namespace SharpCompress.Compressor.LZMA -{ - internal class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream - { - private class LenDecoder - { - private BitDecoder m_Choice = new BitDecoder(); - private BitDecoder m_Choice2 = new BitDecoder(); - private BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; - private BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; - private BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits); - private 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; - } - } - } - - private class LiteralDecoder - { - private struct Decoder2 - { - private 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; - } - } - - private Decoder2[] m_Coders; - private int m_NumPrevBits; - private int m_NumPosBits; - private 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(); - } - - private 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); - } - }; - - private LZ.OutWindow m_OutWindow; - - private BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; - private BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates]; - private BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates]; - private BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates]; - private BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates]; - private BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; - - private BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates]; - private BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; - - private BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits); - - private LenDecoder m_LenDecoder = new LenDecoder(); - private LenDecoder m_RepLenDecoder = new LenDecoder(); - - private LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); - - private int m_DictionarySize; - - private uint m_PosStateMask; - - private Base.State state = new Base.State(); - private uint rep0, rep1, rep2, rep3; - - public Decoder() - { - m_DictionarySize = -1; - for (int i = 0; i < Base.kNumLenToPosStates; i++) - m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); - } - - private void CreateDictionary() - { - if (m_DictionarySize < 0) - throw new InvalidParamException(); - m_OutWindow = new LZ.OutWindow(); - int blockSize = Math.Max(m_DictionarySize, (1 << 12)); - m_OutWindow.Create(blockSize); - } - - private void SetLiteralProperties(int lp, int lc) - { - if (lp > 8) - throw new InvalidParamException(); - if (lc > 8) - throw new InvalidParamException(); - m_LiteralDecoder.Create(lp, lc); - } - - private 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; - } - - private void Init() - { - 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(); - - state.Init(); - rep0 = 0; - rep1 = 0; - rep2 = 0; - rep3 = 0; - } - - public void Code(System.IO.Stream inStream, System.IO.Stream outStream, - Int64 inSize, Int64 outSize, ICodeProgress progress) - { - if (m_OutWindow == null) - CreateDictionary(); - m_OutWindow.Init(outStream); - if (outSize > 0) - m_OutWindow.SetLimit(outSize); - else - m_OutWindow.SetLimit(Int64.MaxValue - m_OutWindow.Total); - - RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder(); - rangeDecoder.Init(inStream); - - Code(m_DictionarySize, m_OutWindow, rangeDecoder); - - m_OutWindow.ReleaseStream(); - rangeDecoder.ReleaseStream(); - - if (!rangeDecoder.IsFinished || (inSize > 0 && rangeDecoder.Total != inSize)) - throw new DataErrorException(); - if (m_OutWindow.HasPending) - throw new DataErrorException(); - m_OutWindow = null; - } - - internal bool Code(int dictionarySize, LZ.OutWindow outWindow, RangeCoder.Decoder rangeDecoder) - { - int dictionarySizeCheck = Math.Max(dictionarySize, 1); - - outWindow.CopyPending(); - - while (outWindow.HasSpace) - { - uint posState = (uint) outWindow.Total & m_PosStateMask; - if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(rangeDecoder) == 0) - { - byte b; - byte prevByte = outWindow.GetByte(0); - if (!state.IsCharState()) - b = m_LiteralDecoder.DecodeWithMatchByte(rangeDecoder, - (uint) outWindow.Total, prevByte, - outWindow.GetByte((int) rep0)); - else - b = m_LiteralDecoder.DecodeNormal(rangeDecoder, (uint) outWindow.Total, prevByte); - outWindow.PutByte(b); - state.UpdateChar(); - } - else - { - uint len; - if (m_IsRepDecoders[state.Index].Decode(rangeDecoder) == 1) - { - if (m_IsRepG0Decoders[state.Index].Decode(rangeDecoder) == 0) - { - if ( - m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode( - rangeDecoder) == 0) - { - state.UpdateShortRep(); - outWindow.PutByte(outWindow.GetByte((int) rep0)); - continue; - } - } - else - { - UInt32 distance; - if (m_IsRepG1Decoders[state.Index].Decode(rangeDecoder) == 0) - { - distance = rep1; - } - else - { - if (m_IsRepG2Decoders[state.Index].Decode(rangeDecoder) == 0) - distance = rep2; - else - { - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - len = m_RepLenDecoder.Decode(rangeDecoder, posState) + Base.kMatchMinLen; - state.UpdateRep(); - } - else - { - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - len = Base.kMatchMinLen + m_LenDecoder.Decode(rangeDecoder, posState); - state.UpdateMatch(); - uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(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, rangeDecoder, numDirectBits); - else - { - rep0 += (rangeDecoder.DecodeDirectBits( - numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits); - rep0 += m_PosAlignDecoder.ReverseDecode(rangeDecoder); - } - } - else - rep0 = posSlot; - } - if (rep0 >= outWindow.Total || rep0 >= dictionarySizeCheck) - { - if (rep0 == 0xFFFFFFFF) - return true; - throw new DataErrorException(); - } - outWindow.CopyBlock((int) rep0, (int) len); - } - } - return false; - } - - public void SetDecoderProperties(byte[] properties) - { - if (properties.Length < 1) - 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(); - SetLiteralProperties(lp, lc); - SetPosBitsProperties(pb); - Init(); - if (properties.Length >= 5) - { - m_DictionarySize = 0; - for (int i = 0; i < 4; i++) - m_DictionarySize += properties[1 + i] << (i*8); - } - } - - public void Train(System.IO.Stream stream) - { - if (m_OutWindow == null) - CreateDictionary(); - 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) {} - */ - } +using System; +using SharpCompress.Compressor.LZMA.RangeCoder; + +namespace SharpCompress.Compressor.LZMA +{ + internal class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream + { + private class LenDecoder + { + private BitDecoder m_Choice = new BitDecoder(); + private BitDecoder m_Choice2 = new BitDecoder(); + private BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; + private BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; + private BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits); + private 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; + } + } + } + + private class LiteralDecoder + { + private struct Decoder2 + { + private 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; + } + } + + private Decoder2[] m_Coders; + private int m_NumPrevBits; + private int m_NumPosBits; + private 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(); + } + + private 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); + } + }; + + private LZ.OutWindow m_OutWindow; + + private BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + private BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates]; + private BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates]; + private BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates]; + private BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates]; + private BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + private BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates]; + private BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; + + private BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits); + + private LenDecoder m_LenDecoder = new LenDecoder(); + private LenDecoder m_RepLenDecoder = new LenDecoder(); + + private LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); + + private int m_DictionarySize; + + private uint m_PosStateMask; + + private Base.State state = new Base.State(); + private uint rep0, rep1, rep2, rep3; + + public Decoder() + { + m_DictionarySize = -1; + for (int i = 0; i < Base.kNumLenToPosStates; i++) + m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); + } + + private void CreateDictionary() + { + if (m_DictionarySize < 0) + throw new InvalidParamException(); + m_OutWindow = new LZ.OutWindow(); + int blockSize = Math.Max(m_DictionarySize, (1 << 12)); + m_OutWindow.Create(blockSize); + } + + private void SetLiteralProperties(int lp, int lc) + { + if (lp > 8) + throw new InvalidParamException(); + if (lc > 8) + throw new InvalidParamException(); + m_LiteralDecoder.Create(lp, lc); + } + + private 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; + } + + private void Init() + { + 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(); + + state.Init(); + rep0 = 0; + rep1 = 0; + rep2 = 0; + rep3 = 0; + } + + public void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress) + { + if (m_OutWindow == null) + CreateDictionary(); + m_OutWindow.Init(outStream); + if (outSize > 0) + m_OutWindow.SetLimit(outSize); + else + m_OutWindow.SetLimit(Int64.MaxValue - m_OutWindow.Total); + + RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder(); + rangeDecoder.Init(inStream); + + Code(m_DictionarySize, m_OutWindow, rangeDecoder); + + m_OutWindow.ReleaseStream(); + rangeDecoder.ReleaseStream(); + + if (!rangeDecoder.IsFinished || (inSize > 0 && rangeDecoder.Total != inSize)) + throw new DataErrorException(); + if (m_OutWindow.HasPending) + throw new DataErrorException(); + m_OutWindow = null; + } + + internal bool Code(int dictionarySize, LZ.OutWindow outWindow, RangeCoder.Decoder rangeDecoder) + { + int dictionarySizeCheck = Math.Max(dictionarySize, 1); + + outWindow.CopyPending(); + + while (outWindow.HasSpace) + { + uint posState = (uint) outWindow.Total & m_PosStateMask; + if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(rangeDecoder) == 0) + { + byte b; + byte prevByte = outWindow.GetByte(0); + if (!state.IsCharState()) + b = m_LiteralDecoder.DecodeWithMatchByte(rangeDecoder, + (uint) outWindow.Total, prevByte, + outWindow.GetByte((int) rep0)); + else + b = m_LiteralDecoder.DecodeNormal(rangeDecoder, (uint) outWindow.Total, prevByte); + outWindow.PutByte(b); + state.UpdateChar(); + } + else + { + uint len; + if (m_IsRepDecoders[state.Index].Decode(rangeDecoder) == 1) + { + if (m_IsRepG0Decoders[state.Index].Decode(rangeDecoder) == 0) + { + if ( + m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode( + rangeDecoder) == 0) + { + state.UpdateShortRep(); + outWindow.PutByte(outWindow.GetByte((int) rep0)); + continue; + } + } + else + { + UInt32 distance; + if (m_IsRepG1Decoders[state.Index].Decode(rangeDecoder) == 0) + { + distance = rep1; + } + else + { + if (m_IsRepG2Decoders[state.Index].Decode(rangeDecoder) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = m_RepLenDecoder.Decode(rangeDecoder, posState) + Base.kMatchMinLen; + state.UpdateRep(); + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + len = Base.kMatchMinLen + m_LenDecoder.Decode(rangeDecoder, posState); + state.UpdateMatch(); + uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(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, rangeDecoder, numDirectBits); + else + { + rep0 += (rangeDecoder.DecodeDirectBits( + numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits); + rep0 += m_PosAlignDecoder.ReverseDecode(rangeDecoder); + } + } + else + rep0 = posSlot; + } + if (rep0 >= outWindow.Total || rep0 >= dictionarySizeCheck) + { + if (rep0 == 0xFFFFFFFF) + return true; + throw new DataErrorException(); + } + outWindow.CopyBlock((int) rep0, (int) len); + } + } + return false; + } + + public void SetDecoderProperties(byte[] properties) + { + if (properties.Length < 1) + 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(); + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + Init(); + if (properties.Length >= 5) + { + m_DictionarySize = 0; + for (int i = 0; i < 4; i++) + m_DictionarySize += properties[1 + i] << (i*8); + } + } + + public void Train(System.IO.Stream stream) + { + if (m_OutWindow == null) + CreateDictionary(); + 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) {} + */ + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressor/LZMA/LzmaEncoder.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/LzmaEncoder.cs rename to src/SharpCompress/Compressor/LZMA/LzmaEncoder.cs index 7026764f..4cd528ba 100644 --- a/SharpCompress/Compressor/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressor/LZMA/LzmaEncoder.cs @@ -1,1605 +1,1605 @@ -using System; -using SharpCompress.Compressor.LZMA.RangeCoder; - -namespace SharpCompress.Compressor.LZMA -{ - internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties - { - private enum EMatchFinderType - { - BT2, - BT4, - }; - - private const UInt32 kIfinityPrice = 0xFFFFFFF; - - private 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; - } - } - - private 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); - } - - private 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); - } - - private Base.State _state = new Base.State(); - private Byte _previousByte; - private UInt32[] _repDistances = new UInt32[Base.kNumRepDistances]; - - private void BaseInit() - { - _state.Init(); - _previousByte = 0; - for (UInt32 i = 0; i < Base.kNumRepDistances; i++) - _repDistances[i] = 0; - } - - private const int kDefaultDictionaryLogSize = 22; - private const UInt32 kNumFastBytesDefault = 0x20; - - private class LiteralEncoder - { - public struct Encoder2 - { - private 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; - } - } - - private Encoder2[] m_Coders; - private int m_NumPrevBits; - private int m_NumPosBits; - private 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))]; - } - } - - private class LenEncoder - { - private RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder(); - private RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder(); - private RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; - private RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; - private 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); - } - }; - - private const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; - - private class LenPriceTableEncoder : LenEncoder - { - private UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax]; - private UInt32 _tableSize; - private 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]; - } - - private 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); - } - } - - private const UInt32 kNumOpts = 1 << 12; - - private 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); - } - }; - - private Optimal[] _optimum = new Optimal[kNumOpts]; - private LZ.BinTree _matchFinder = null; - private RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); - - private RangeCoder.BitEncoder[] _isMatch = - new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; - - private RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates]; - private RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates]; - private RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates]; - private RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates]; - - private RangeCoder.BitEncoder[] _isRep0Long = - new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; - - private RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates]; - - private RangeCoder.BitEncoder[] _posEncoders = - new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; - - private RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits); - - private LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); - private LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); - - private LiteralEncoder _literalEncoder = new LiteralEncoder(); - - private UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen*2 + 2]; - - private UInt32 _numFastBytes = kNumFastBytesDefault; - private UInt32 _longestMatchLength; - private UInt32 _numDistancePairs; - - private UInt32 _additionalOffset; - - private UInt32 _optimumEndIndex; - private UInt32 _optimumCurrentIndex; - - private bool _longestMatchWasFound; - - private UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)]; - private UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits]; - private UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize]; - private UInt32 _alignPriceCount; - - private UInt32 _distTableSize = (kDefaultDictionaryLogSize*2); - - private int _posStateBits = 2; - private UInt32 _posStateMask = (4 - 1); - private int _numLiteralPosStateBits = 0; - private int _numLiteralContextBits = 3; - - private UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize); - private UInt32 _dictionarySizePrev = 0xFFFFFFFF; - private UInt32 _numFastBytesPrev = 0xFFFFFFFF; - - private Int64 nowPos64; - private bool _finished; - private System.IO.Stream _inStream; - - private EMatchFinderType _matchFinderType = EMatchFinderType.BT4; - private bool _writeEndMark = false; - - private bool _needReleaseMFStream; - private bool _processingMode; - - private 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 + kNumOpts); - _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); - } - - private void SetWriteEndMarkerMode(bool writeEndMarker) - { - _writeEndMark = writeEndMarker; - } - - private 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; - } - - private 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++; - } - - - private void MovePos(UInt32 num) - { - if (num > 0) - { - _matchFinder.Skip(num); - _additionalOffset += num; - } - } - - private UInt32 GetRepLen1Price(Base.State state, UInt32 posState) - { - return _isRepG0[state.Index].GetPrice0() + - _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0(); - } - - private 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; - } - - private 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); - } - - private 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); - } - - private 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; - } - - private UInt32[] reps = new UInt32[Base.kNumRepDistances]; - private UInt32[] repLens = new UInt32[Base.kNumRepDistances]; - - - private 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; - } - } - } - } - } - - private bool ChangePair(UInt32 smallDist, UInt32 bigDist) - { - const int kDif = 7; - return (smallDist < ((UInt32) (1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); - } - - private 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); - } - - private 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); - _needReleaseMFStream = true; - _inStream = null; - } - - if (_finished) - return; - _finished = true; - - - Int64 progressPosValuePrev = nowPos64; - if (nowPos64 == 0) - { - if (_trainSize > 0) - { - for (; _trainSize > 0 && (!_processingMode || !_matchFinder.IsDataStarved); _trainSize--) - _matchFinder.Skip(1); - if (_trainSize == 0) - _previousByte = _matchFinder.GetIndexByte(-1); - } - if (_processingMode && _matchFinder.IsDataStarved) - { - _finished = false; - return; - } - 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 (_processingMode && _matchFinder.IsDataStarved) - { - _finished = false; - return; - } - if (_matchFinder.GetNumAvailableBytes() == 0) - { - Flush((UInt32) nowPos64); - return; - } - while (true) - { - if (_processingMode && _matchFinder.IsDataStarved) - { - _finished = false; - return; - } - - 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 (_processingMode && _matchFinder.IsDataStarved) - { - _finished = false; - return; - } - if (_matchFinder.GetNumAvailableBytes() == 0) - { - Flush((UInt32) nowPos64); - return; - } - - if (nowPos64 - progressPosValuePrev >= (1 << 12)) - { - _finished = false; - finished = false; - return; - } - } - } - } - - private void ReleaseMFStream() - { - if (_matchFinder != null && _needReleaseMFStream) - { - _matchFinder.ReleaseStream(); - _needReleaseMFStream = false; - } - } - - private void SetOutStream(System.IO.Stream outStream) - { - _rangeEncoder.SetStream(outStream); - } - - private void ReleaseOutStream() - { - _rangeEncoder.ReleaseStream(); - } - - private void ReleaseStreams() - { - ReleaseMFStream(); - ReleaseOutStream(); - } - - public void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream, - Int64 inSize, Int64 outSize) - { - _inStream = inStream; - _finished = false; - Create(); - SetOutStream(outStream); - Init(); - _matchFinder.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; - _processingMode = 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(); - } - } - - public long Code(System.IO.Stream inStream, bool final) - { - _matchFinder.SetStream(inStream); - _processingMode = !final; - try - { - while (true) - { - Int64 processedInSize; - Int64 processedOutSize; - bool finished; - CodeOneBlock(out processedInSize, out processedOutSize, out finished); - if (finished) - return processedInSize; - } - } - finally - { - _matchFinder.ReleaseStream(); - if (final) - ReleaseStreams(); - } - } - - public void Train(System.IO.Stream trainStream) - { - if (nowPos64 > 0) - throw new InvalidOperationException(); - _trainSize = (uint) trainStream.Length; - if (_trainSize > 0) - { - _matchFinder.SetStream(trainStream); - for (; _trainSize > 0 && !_matchFinder.IsDataStarved; _trainSize--) - _matchFinder.Skip(1); - if (_trainSize == 0) - _previousByte = _matchFinder.GetIndexByte(-1); - _matchFinder.ReleaseStream(); - } - } - - private const int kPropSize = 5; - private 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)) & 0xFF); - outStream.Write(properties, 0, kPropSize); - } - - private UInt32[] tempPrices = new UInt32[Base.kNumFullDistances]; - private UInt32 _matchPriceCount; - - private 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; - } - - private void FillAlignPrices() - { - for (UInt32 i = 0; i < Base.kAlignTableSize; i++) - _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i); - _alignPriceCount = 0; - } - - - private static string[] kMatchFinderIDs = - { - "BT2", - "BT4", - }; - - private 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(); - } - } - } - - private uint _trainSize = 0; - - public void SetTrainSize(uint trainSize) - { - _trainSize = trainSize; - } - } +using System; +using SharpCompress.Compressor.LZMA.RangeCoder; + +namespace SharpCompress.Compressor.LZMA +{ + internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties + { + private enum EMatchFinderType + { + BT2, + BT4, + }; + + private const UInt32 kIfinityPrice = 0xFFFFFFF; + + private 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; + } + } + + private 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); + } + + private 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); + } + + private Base.State _state = new Base.State(); + private Byte _previousByte; + private UInt32[] _repDistances = new UInt32[Base.kNumRepDistances]; + + private void BaseInit() + { + _state.Init(); + _previousByte = 0; + for (UInt32 i = 0; i < Base.kNumRepDistances; i++) + _repDistances[i] = 0; + } + + private const int kDefaultDictionaryLogSize = 22; + private const UInt32 kNumFastBytesDefault = 0x20; + + private class LiteralEncoder + { + public struct Encoder2 + { + private 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; + } + } + + private Encoder2[] m_Coders; + private int m_NumPrevBits; + private int m_NumPosBits; + private 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))]; + } + } + + private class LenEncoder + { + private RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder(); + private RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder(); + private RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; + private RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; + private 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); + } + }; + + private const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; + + private class LenPriceTableEncoder : LenEncoder + { + private UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax]; + private UInt32 _tableSize; + private 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]; + } + + private 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); + } + } + + private const UInt32 kNumOpts = 1 << 12; + + private 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); + } + }; + + private Optimal[] _optimum = new Optimal[kNumOpts]; + private LZ.BinTree _matchFinder = null; + private RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); + + private RangeCoder.BitEncoder[] _isMatch = + new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + private RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates]; + private RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates]; + private RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates]; + private RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates]; + + private RangeCoder.BitEncoder[] _isRep0Long = + new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + private RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates]; + + private RangeCoder.BitEncoder[] _posEncoders = + new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; + + private RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits); + + private LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); + private LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); + + private LiteralEncoder _literalEncoder = new LiteralEncoder(); + + private UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen*2 + 2]; + + private UInt32 _numFastBytes = kNumFastBytesDefault; + private UInt32 _longestMatchLength; + private UInt32 _numDistancePairs; + + private UInt32 _additionalOffset; + + private UInt32 _optimumEndIndex; + private UInt32 _optimumCurrentIndex; + + private bool _longestMatchWasFound; + + private UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)]; + private UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits]; + private UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize]; + private UInt32 _alignPriceCount; + + private UInt32 _distTableSize = (kDefaultDictionaryLogSize*2); + + private int _posStateBits = 2; + private UInt32 _posStateMask = (4 - 1); + private int _numLiteralPosStateBits = 0; + private int _numLiteralContextBits = 3; + + private UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize); + private UInt32 _dictionarySizePrev = 0xFFFFFFFF; + private UInt32 _numFastBytesPrev = 0xFFFFFFFF; + + private Int64 nowPos64; + private bool _finished; + private System.IO.Stream _inStream; + + private EMatchFinderType _matchFinderType = EMatchFinderType.BT4; + private bool _writeEndMark = false; + + private bool _needReleaseMFStream; + private bool _processingMode; + + private 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 + kNumOpts); + _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); + } + + private void SetWriteEndMarkerMode(bool writeEndMarker) + { + _writeEndMark = writeEndMarker; + } + + private 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; + } + + private 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++; + } + + + private void MovePos(UInt32 num) + { + if (num > 0) + { + _matchFinder.Skip(num); + _additionalOffset += num; + } + } + + private UInt32 GetRepLen1Price(Base.State state, UInt32 posState) + { + return _isRepG0[state.Index].GetPrice0() + + _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0(); + } + + private 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; + } + + private 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); + } + + private 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); + } + + private 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; + } + + private UInt32[] reps = new UInt32[Base.kNumRepDistances]; + private UInt32[] repLens = new UInt32[Base.kNumRepDistances]; + + + private 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; + } + } + } + } + } + + private bool ChangePair(UInt32 smallDist, UInt32 bigDist) + { + const int kDif = 7; + return (smallDist < ((UInt32) (1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); + } + + private 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); + } + + private 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); + _needReleaseMFStream = true; + _inStream = null; + } + + if (_finished) + return; + _finished = true; + + + Int64 progressPosValuePrev = nowPos64; + if (nowPos64 == 0) + { + if (_trainSize > 0) + { + for (; _trainSize > 0 && (!_processingMode || !_matchFinder.IsDataStarved); _trainSize--) + _matchFinder.Skip(1); + if (_trainSize == 0) + _previousByte = _matchFinder.GetIndexByte(-1); + } + if (_processingMode && _matchFinder.IsDataStarved) + { + _finished = false; + return; + } + 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 (_processingMode && _matchFinder.IsDataStarved) + { + _finished = false; + return; + } + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32) nowPos64); + return; + } + while (true) + { + if (_processingMode && _matchFinder.IsDataStarved) + { + _finished = false; + return; + } + + 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 (_processingMode && _matchFinder.IsDataStarved) + { + _finished = false; + return; + } + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32) nowPos64); + return; + } + + if (nowPos64 - progressPosValuePrev >= (1 << 12)) + { + _finished = false; + finished = false; + return; + } + } + } + } + + private void ReleaseMFStream() + { + if (_matchFinder != null && _needReleaseMFStream) + { + _matchFinder.ReleaseStream(); + _needReleaseMFStream = false; + } + } + + private void SetOutStream(System.IO.Stream outStream) + { + _rangeEncoder.SetStream(outStream); + } + + private void ReleaseOutStream() + { + _rangeEncoder.ReleaseStream(); + } + + private void ReleaseStreams() + { + ReleaseMFStream(); + ReleaseOutStream(); + } + + public void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize) + { + _inStream = inStream; + _finished = false; + Create(); + SetOutStream(outStream); + Init(); + _matchFinder.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; + _processingMode = 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(); + } + } + + public long Code(System.IO.Stream inStream, bool final) + { + _matchFinder.SetStream(inStream); + _processingMode = !final; + try + { + while (true) + { + Int64 processedInSize; + Int64 processedOutSize; + bool finished; + CodeOneBlock(out processedInSize, out processedOutSize, out finished); + if (finished) + return processedInSize; + } + } + finally + { + _matchFinder.ReleaseStream(); + if (final) + ReleaseStreams(); + } + } + + public void Train(System.IO.Stream trainStream) + { + if (nowPos64 > 0) + throw new InvalidOperationException(); + _trainSize = (uint) trainStream.Length; + if (_trainSize > 0) + { + _matchFinder.SetStream(trainStream); + for (; _trainSize > 0 && !_matchFinder.IsDataStarved; _trainSize--) + _matchFinder.Skip(1); + if (_trainSize == 0) + _previousByte = _matchFinder.GetIndexByte(-1); + _matchFinder.ReleaseStream(); + } + } + + private const int kPropSize = 5; + private 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)) & 0xFF); + outStream.Write(properties, 0, kPropSize); + } + + private UInt32[] tempPrices = new UInt32[Base.kNumFullDistances]; + private UInt32 _matchPriceCount; + + private 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; + } + + private void FillAlignPrices() + { + for (UInt32 i = 0; i < Base.kAlignTableSize; i++) + _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i); + _alignPriceCount = 0; + } + + + private static string[] kMatchFinderIDs = + { + "BT2", + "BT4", + }; + + private 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(); + } + } + } + + private uint _trainSize = 0; + + public void SetTrainSize(uint trainSize) + { + _trainSize = trainSize; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LzmaEncoderProperties.cs b/src/SharpCompress/Compressor/LZMA/LzmaEncoderProperties.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/LzmaEncoderProperties.cs rename to src/SharpCompress/Compressor/LZMA/LzmaEncoderProperties.cs index 07ca6bd2..a34c3e9d 100644 --- a/SharpCompress/Compressor/LZMA/LzmaEncoderProperties.cs +++ b/src/SharpCompress/Compressor/LZMA/LzmaEncoderProperties.cs @@ -1,55 +1,55 @@ -namespace SharpCompress.Compressor.LZMA -{ - public class LzmaEncoderProperties - { - internal CoderPropID[] propIDs; - internal object[] properties; - - public LzmaEncoderProperties() - : this(false) - { - } - - public LzmaEncoderProperties(bool eos) - : this(eos, 1 << 20) - { - } - - public LzmaEncoderProperties(bool eos, int dictionary) - : this(eos, dictionary, 32) - { - } - - public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes) - { - int posStateBits = 2; - int litContextBits = 3; - int litPosBits = 0; - int algorithm = 2; - string mf = "bt4"; - - propIDs = new CoderPropID[] - { - CoderPropID.DictionarySize, - CoderPropID.PosStateBits, - CoderPropID.LitContextBits, - CoderPropID.LitPosBits, - CoderPropID.Algorithm, - CoderPropID.NumFastBytes, - CoderPropID.MatchFinder, - CoderPropID.EndMarker - }; - properties = new object[] - { - dictionary, - posStateBits, - litContextBits, - litPosBits, - algorithm, - numFastBytes, - mf, - eos - }; - } - } +namespace SharpCompress.Compressor.LZMA +{ + public class LzmaEncoderProperties + { + internal CoderPropID[] propIDs; + internal object[] properties; + + public LzmaEncoderProperties() + : this(false) + { + } + + public LzmaEncoderProperties(bool eos) + : this(eos, 1 << 20) + { + } + + public LzmaEncoderProperties(bool eos, int dictionary) + : this(eos, dictionary, 32) + { + } + + public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes) + { + int posStateBits = 2; + int litContextBits = 3; + int litPosBits = 0; + int algorithm = 2; + string mf = "bt4"; + + propIDs = new CoderPropID[] + { + CoderPropID.DictionarySize, + CoderPropID.PosStateBits, + CoderPropID.LitContextBits, + CoderPropID.LitPosBits, + CoderPropID.Algorithm, + CoderPropID.NumFastBytes, + CoderPropID.MatchFinder, + CoderPropID.EndMarker + }; + properties = new object[] + { + dictionary, + posStateBits, + litContextBits, + litPosBits, + algorithm, + numFastBytes, + mf, + eos + }; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/LzmaStream.cs b/src/SharpCompress/Compressor/LZMA/LzmaStream.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/LzmaStream.cs rename to src/SharpCompress/Compressor/LZMA/LzmaStream.cs index 22522f9d..613c71ed 100644 --- a/SharpCompress/Compressor/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressor/LZMA/LzmaStream.cs @@ -1,308 +1,308 @@ -using System; -using System.IO; -using SharpCompress.Compressor.LZMA.LZ; - -namespace SharpCompress.Compressor.LZMA -{ - public class LzmaStream : Stream - { - private Stream inputStream; - private long inputSize; - private long outputSize; - - private int dictionarySize; - private OutWindow outWindow = new OutWindow(); - private RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder(); - private Decoder decoder; - - private long position = 0; - private bool endReached = false; - private long availableBytes; - private long rangeDecoderLimit; - private long inputPosition = 0; - - // LZMA2 - private bool isLZMA2; - private bool uncompressedChunk = false; - private bool needDictReset = true; - private bool needProps = true; - private byte[] props = new byte[5]; - - private Encoder encoder; - private bool isDisposed; - - public LzmaStream(byte[] properties, Stream inputStream) - : this(properties, inputStream, -1, -1, null, properties.Length < 5) - { - } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize) - : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) - { - } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) - : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) - { - } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, - Stream presetDictionary, bool isLZMA2) - { - this.inputStream = inputStream; - this.inputSize = inputSize; - this.outputSize = outputSize; - this.isLZMA2 = isLZMA2; - - if (!isLZMA2) - { - dictionarySize = BitConverter.ToInt32(properties, 1); - outWindow.Create(dictionarySize); - if (presetDictionary != null) - outWindow.Train(presetDictionary); - - rangeDecoder.Init(inputStream); - - decoder = new Decoder(); - decoder.SetDecoderProperties(properties); - props = properties; - - availableBytes = outputSize < 0 ? long.MaxValue : outputSize; - rangeDecoderLimit = inputSize; - } - else - { - dictionarySize = 2 | (properties[0] & 1); - dictionarySize <<= (properties[0] >> 1) + 11; - - outWindow.Create(dictionarySize); - if (presetDictionary != null) - { - outWindow.Train(presetDictionary); - needDictReset = false; - } - - props = new byte[1]; - availableBytes = 0; - } - } - - public LzmaStream(LzmaEncoderProperties properties, bool isLZMA2, Stream outputStream) - : this(properties, isLZMA2, null, outputStream) - { - } - - public LzmaStream(LzmaEncoderProperties properties, bool isLZMA2, Stream presetDictionary, Stream outputStream) - { - this.isLZMA2 = isLZMA2; - availableBytes = 0; - endReached = true; - - if (isLZMA2) - throw new NotImplementedException(); - - encoder = new Encoder(); - encoder.SetCoderProperties(properties.propIDs, properties.properties); - MemoryStream propStream = new MemoryStream(5); - encoder.WriteCoderProperties(propStream); - props = propStream.ToArray(); - - encoder.SetStreams(null, outputStream, -1, -1); - if (presetDictionary != null) - encoder.Train(presetDictionary); - } - - public override bool CanRead - { - get { return encoder == null; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return encoder != null; } - } - - public override void Flush() - { - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - if (encoder != null) - { - position = encoder.Code(null, true); - } - if (inputStream != null) - { - inputStream.Dispose(); - } - } - base.Dispose(disposing); - } - - public override long Length - { - get { return position + availableBytes; } - } - - public override long Position - { - get { return position; } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (endReached) - return 0; - - int total = 0; - while (total < count) - { - if (availableBytes == 0) - { - if (isLZMA2) - decodeChunkHeader(); - else - endReached = true; - if (endReached) - break; - } - - int toProcess = count - total; - if (toProcess > availableBytes) - toProcess = (int)availableBytes; - - outWindow.SetLimit(toProcess); - if (uncompressedChunk) - { - inputPosition += outWindow.CopyStream(inputStream, toProcess); - } - else if (decoder.Code(dictionarySize, outWindow, rangeDecoder) - && outputSize < 0) - { - availableBytes = outWindow.AvailableBytes; - } - - int read = outWindow.Read(buffer, offset, toProcess); - total += read; - offset += read; - position += read; - availableBytes -= read; - - if (availableBytes == 0 && !uncompressedChunk) - { - rangeDecoder.ReleaseStream(); - if (!rangeDecoder.IsFinished || (rangeDecoderLimit >= 0 && rangeDecoder.Total != rangeDecoderLimit)) - throw new DataErrorException(); - inputPosition += rangeDecoder.Total; - if (outWindow.HasPending) - throw new DataErrorException(); - } - } - - if (endReached) - { - if (inputSize >= 0 && inputPosition != inputSize) - throw new DataErrorException(); - if (outputSize >= 0 && position != outputSize) - throw new DataErrorException(); - } - - return total; - } - - private void decodeChunkHeader() - { - int control = inputStream.ReadByte(); - inputPosition++; - - if (control == 0x00) - { - endReached = true; - return; - } - - if (control >= 0xE0 || control == 0x01) - { - needProps = true; - needDictReset = false; - outWindow.Reset(); - } - else if (needDictReset) - throw new DataErrorException(); - - if (control >= 0x80) - { - uncompressedChunk = false; - - availableBytes = (control & 0x1F) << 16; - availableBytes += (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1; - inputPosition += 2; - - rangeDecoderLimit = (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1; - inputPosition += 2; - - if (control >= 0xC0) - { - needProps = false; - props[0] = (byte)inputStream.ReadByte(); - inputPosition++; - - decoder = new Decoder(); - decoder.SetDecoderProperties(props); - } - else if (needProps) - throw new DataErrorException(); - else if (control >= 0xA0) - { - decoder = new Decoder(); - decoder.SetDecoderProperties(props); - } - - rangeDecoder.Init(inputStream); - } - else if (control > 0x02) - throw new DataErrorException(); - else - { - uncompressedChunk = true; - availableBytes = (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1; - inputPosition += 2; - } - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (encoder != null) - position = encoder.Code(new MemoryStream(buffer, offset, count), false); - } - - public byte[] Properties - { - get { return props; } - } - } +using System; +using System.IO; +using SharpCompress.Compressor.LZMA.LZ; + +namespace SharpCompress.Compressor.LZMA +{ + public class LzmaStream : Stream + { + private Stream inputStream; + private long inputSize; + private long outputSize; + + private int dictionarySize; + private OutWindow outWindow = new OutWindow(); + private RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder(); + private Decoder decoder; + + private long position = 0; + private bool endReached = false; + private long availableBytes; + private long rangeDecoderLimit; + private long inputPosition = 0; + + // LZMA2 + private bool isLZMA2; + private bool uncompressedChunk = false; + private bool needDictReset = true; + private bool needProps = true; + private byte[] props = new byte[5]; + + private Encoder encoder; + private bool isDisposed; + + public LzmaStream(byte[] properties, Stream inputStream) + : this(properties, inputStream, -1, -1, null, properties.Length < 5) + { + } + + public LzmaStream(byte[] properties, Stream inputStream, long inputSize) + : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) + { + } + + public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) + : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) + { + } + + public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, + Stream presetDictionary, bool isLZMA2) + { + this.inputStream = inputStream; + this.inputSize = inputSize; + this.outputSize = outputSize; + this.isLZMA2 = isLZMA2; + + if (!isLZMA2) + { + dictionarySize = BitConverter.ToInt32(properties, 1); + outWindow.Create(dictionarySize); + if (presetDictionary != null) + outWindow.Train(presetDictionary); + + rangeDecoder.Init(inputStream); + + decoder = new Decoder(); + decoder.SetDecoderProperties(properties); + props = properties; + + availableBytes = outputSize < 0 ? long.MaxValue : outputSize; + rangeDecoderLimit = inputSize; + } + else + { + dictionarySize = 2 | (properties[0] & 1); + dictionarySize <<= (properties[0] >> 1) + 11; + + outWindow.Create(dictionarySize); + if (presetDictionary != null) + { + outWindow.Train(presetDictionary); + needDictReset = false; + } + + props = new byte[1]; + availableBytes = 0; + } + } + + public LzmaStream(LzmaEncoderProperties properties, bool isLZMA2, Stream outputStream) + : this(properties, isLZMA2, null, outputStream) + { + } + + public LzmaStream(LzmaEncoderProperties properties, bool isLZMA2, Stream presetDictionary, Stream outputStream) + { + this.isLZMA2 = isLZMA2; + availableBytes = 0; + endReached = true; + + if (isLZMA2) + throw new NotImplementedException(); + + encoder = new Encoder(); + encoder.SetCoderProperties(properties.propIDs, properties.properties); + MemoryStream propStream = new MemoryStream(5); + encoder.WriteCoderProperties(propStream); + props = propStream.ToArray(); + + encoder.SetStreams(null, outputStream, -1, -1); + if (presetDictionary != null) + encoder.Train(presetDictionary); + } + + public override bool CanRead + { + get { return encoder == null; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return encoder != null; } + } + + public override void Flush() + { + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + if (disposing) + { + if (encoder != null) + { + position = encoder.Code(null, true); + } + if (inputStream != null) + { + inputStream.Dispose(); + } + } + base.Dispose(disposing); + } + + public override long Length + { + get { return position + availableBytes; } + } + + public override long Position + { + get { return position; } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (endReached) + return 0; + + int total = 0; + while (total < count) + { + if (availableBytes == 0) + { + if (isLZMA2) + decodeChunkHeader(); + else + endReached = true; + if (endReached) + break; + } + + int toProcess = count - total; + if (toProcess > availableBytes) + toProcess = (int)availableBytes; + + outWindow.SetLimit(toProcess); + if (uncompressedChunk) + { + inputPosition += outWindow.CopyStream(inputStream, toProcess); + } + else if (decoder.Code(dictionarySize, outWindow, rangeDecoder) + && outputSize < 0) + { + availableBytes = outWindow.AvailableBytes; + } + + int read = outWindow.Read(buffer, offset, toProcess); + total += read; + offset += read; + position += read; + availableBytes -= read; + + if (availableBytes == 0 && !uncompressedChunk) + { + rangeDecoder.ReleaseStream(); + if (!rangeDecoder.IsFinished || (rangeDecoderLimit >= 0 && rangeDecoder.Total != rangeDecoderLimit)) + throw new DataErrorException(); + inputPosition += rangeDecoder.Total; + if (outWindow.HasPending) + throw new DataErrorException(); + } + } + + if (endReached) + { + if (inputSize >= 0 && inputPosition != inputSize) + throw new DataErrorException(); + if (outputSize >= 0 && position != outputSize) + throw new DataErrorException(); + } + + return total; + } + + private void decodeChunkHeader() + { + int control = inputStream.ReadByte(); + inputPosition++; + + if (control == 0x00) + { + endReached = true; + return; + } + + if (control >= 0xE0 || control == 0x01) + { + needProps = true; + needDictReset = false; + outWindow.Reset(); + } + else if (needDictReset) + throw new DataErrorException(); + + if (control >= 0x80) + { + uncompressedChunk = false; + + availableBytes = (control & 0x1F) << 16; + availableBytes += (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1; + inputPosition += 2; + + rangeDecoderLimit = (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1; + inputPosition += 2; + + if (control >= 0xC0) + { + needProps = false; + props[0] = (byte)inputStream.ReadByte(); + inputPosition++; + + decoder = new Decoder(); + decoder.SetDecoderProperties(props); + } + else if (needProps) + throw new DataErrorException(); + else if (control >= 0xA0) + { + decoder = new Decoder(); + decoder.SetDecoderProperties(props); + } + + rangeDecoder.Init(inputStream); + } + else if (control > 0x02) + throw new DataErrorException(); + else + { + uncompressedChunk = true; + availableBytes = (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1; + inputPosition += 2; + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (encoder != null) + position = encoder.Code(new MemoryStream(buffer, offset, count), false); + } + + public byte[] Properties + { + get { return props; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs b/src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs rename to src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs index bac7eb63..77e401c7 100644 --- a/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs +++ b/src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoder.cs @@ -1,243 +1,243 @@ -using System; - -namespace SharpCompress.Compressor.LZMA.RangeCoder -{ - internal class Encoder - { - public const uint kTopValue = (1 << 24); - - private System.IO.Stream Stream; - - public UInt64 Low; - public uint Range; - private uint _cacheSize; - private 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.Dispose(); - } - - 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 -1; - //return _cacheSize + Stream.Position - StartPosition + 4; - // (long)Stream.GetProcessedSize(); - } - } - - internal class Decoder - { - public const uint kTopValue = (1 << 24); - public uint Range; - public uint Code = 0; - // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); - public System.IO.Stream Stream; - public long Total; - - 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(); - Total = 5; - } - - public void ReleaseStream() - { - // Stream.ReleaseStream(); - Stream = null; - } - - public void CloseStream() - { - Stream.Dispose(); - } - - public void Normalize() - { - while (Range < kTopValue) - { - Code = (Code << 8) | (byte) Stream.ReadByte(); - Range <<= 8; - Total++; - } - } - - public void Normalize2() - { - if (Range < kTopValue) - { - Code = (Code << 8) | (byte) Stream.ReadByte(); - Range <<= 8; - Total++; - } - } - - public uint GetThreshold(uint total) - { - return Code/(Range /= total); - } - - public void Decode(uint start, uint size) - { - 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; - Total++; - } - } - 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; - } - - public bool IsFinished - { - get { return Code == 0; } - } - - // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } - } +using System; + +namespace SharpCompress.Compressor.LZMA.RangeCoder +{ + internal class Encoder + { + public const uint kTopValue = (1 << 24); + + private System.IO.Stream Stream; + + public UInt64 Low; + public uint Range; + private uint _cacheSize; + private 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.Dispose(); + } + + 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 -1; + //return _cacheSize + Stream.Position - StartPosition + 4; + // (long)Stream.GetProcessedSize(); + } + } + + internal class Decoder + { + public const uint kTopValue = (1 << 24); + public uint Range; + public uint Code = 0; + // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); + public System.IO.Stream Stream; + public long Total; + + 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(); + Total = 5; + } + + public void ReleaseStream() + { + // Stream.ReleaseStream(); + Stream = null; + } + + public void CloseStream() + { + Stream.Dispose(); + } + + public void Normalize() + { + while (Range < kTopValue) + { + Code = (Code << 8) | (byte) Stream.ReadByte(); + Range <<= 8; + Total++; + } + } + + public void Normalize2() + { + if (Range < kTopValue) + { + Code = (Code << 8) | (byte) Stream.ReadByte(); + Range <<= 8; + Total++; + } + } + + public uint GetThreshold(uint total) + { + return Code/(Range /= total); + } + + public void Decode(uint start, uint size) + { + 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; + Total++; + } + } + 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; + } + + public bool IsFinished + { + get { return Code == 0; } + } + + // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBit.cs b/src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBit.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBit.cs rename to src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBit.cs index 24767224..8af6185d 100644 --- a/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBit.cs +++ b/src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBit.cs @@ -1,133 +1,133 @@ -using System; - -namespace SharpCompress.Compressor.LZMA.RangeCoder -{ - internal struct BitEncoder - { - public const int kNumBitModelTotalBits = 11; - public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); - private const int kNumMoveBits = 5; - private const int kNumMoveReducingBits = 2; - public const int kNumBitPriceShiftBits = 6; - - private 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]; - } - } - - internal struct BitDecoder - { - public const int kNumBitModelTotalBits = 11; - public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); - private const int kNumMoveBits = 5; - - private 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; - rangeDecoder.Total++; - } - 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; - rangeDecoder.Total++; - } - return 1; - } - } - } +using System; + +namespace SharpCompress.Compressor.LZMA.RangeCoder +{ + internal struct BitEncoder + { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + private const int kNumMoveBits = 5; + private const int kNumMoveReducingBits = 2; + public const int kNumBitPriceShiftBits = 6; + + private 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]; + } + } + + internal struct BitDecoder + { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + private const int kNumMoveBits = 5; + + private 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; + rangeDecoder.Total++; + } + 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; + rangeDecoder.Total++; + } + return 1; + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs b/src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs rename to src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs index b30dab7e..a1856b94 100644 --- a/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs +++ b/src/SharpCompress/Compressor/LZMA/RangeCoder/RangeCoderBitTree.cs @@ -1,157 +1,157 @@ -using System; - -namespace SharpCompress.Compressor.LZMA.RangeCoder -{ - internal struct BitTreeEncoder - { - private BitEncoder[] Models; - private 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; - } - } - } - - internal struct BitTreeDecoder - { - private BitDecoder[] Models; - private 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; - } - } +using System; + +namespace SharpCompress.Compressor.LZMA.RangeCoder +{ + internal struct BitTreeEncoder + { + private BitEncoder[] Models; + private 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; + } + } + } + + internal struct BitTreeDecoder + { + private BitDecoder[] Models; + private 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; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Registry.cs b/src/SharpCompress/Compressor/LZMA/Registry.cs similarity index 97% rename from SharpCompress/Compressor/LZMA/Registry.cs rename to src/SharpCompress/Compressor/LZMA/Registry.cs index d2f6294d..c80b6ab3 100644 --- a/SharpCompress/Compressor/LZMA/Registry.cs +++ b/src/SharpCompress/Compressor/LZMA/Registry.cs @@ -1,53 +1,53 @@ -using System; -using System.IO; -using System.Linq; -using SharpCompress.Common.SevenZip; -using SharpCompress.Compressor.BZip2; -using SharpCompress.Compressor.Filters; -using SharpCompress.Compressor.LZMA.Utilites; -using SharpCompress.Compressor.PPMd; - -namespace SharpCompress.Compressor.LZMA -{ - internal static class DecoderRegistry - { - private const uint k_Copy = 0x0; - private const uint k_Delta = 3; - private const uint k_LZMA2 = 0x21; - private const uint k_LZMA = 0x030101; - private const uint k_PPMD = 0x030401; - private const uint k_BCJ = 0x03030103; - private const uint k_BCJ2 = 0x0303011B; - private const uint k_Deflate = 0x040108; - private const uint k_BZip2 = 0x040202; - - internal static Stream CreateDecoderStream(CMethodId id, Stream[] inStreams, byte[] info, IPasswordProvider pass, - long limit) - { - switch (id.Id) - { - case k_Copy: - if (info != null) - throw new NotSupportedException(); - return inStreams.Single(); - case k_LZMA: - case k_LZMA2: - return new LzmaStream(info, inStreams.Single(), -1, limit); -#if !DOTNET51 - case CMethodId.kAESId: - return new AesDecoderStream(inStreams.Single(), info, pass, limit); -#endif - case k_BCJ: - return new BCJFilter(false, inStreams.Single()); - case k_BCJ2: - return new Bcj2DecoderStream(inStreams, info, limit); - case k_BZip2: - return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, true); - case k_PPMD: - return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false); - default: - throw new NotSupportedException(); - } - } - } +using System; +using System.IO; +using System.Linq; +using SharpCompress.Common.SevenZip; +using SharpCompress.Compressor.BZip2; +using SharpCompress.Compressor.Filters; +using SharpCompress.Compressor.LZMA.Utilites; +using SharpCompress.Compressor.PPMd; + +namespace SharpCompress.Compressor.LZMA +{ + internal static class DecoderRegistry + { + private const uint k_Copy = 0x0; + private const uint k_Delta = 3; + private const uint k_LZMA2 = 0x21; + private const uint k_LZMA = 0x030101; + private const uint k_PPMD = 0x030401; + private const uint k_BCJ = 0x03030103; + private const uint k_BCJ2 = 0x0303011B; + private const uint k_Deflate = 0x040108; + private const uint k_BZip2 = 0x040202; + + internal static Stream CreateDecoderStream(CMethodId id, Stream[] inStreams, byte[] info, IPasswordProvider pass, + long limit) + { + switch (id.Id) + { + case k_Copy: + if (info != null) + throw new NotSupportedException(); + return inStreams.Single(); + case k_LZMA: + case k_LZMA2: + return new LzmaStream(info, inStreams.Single(), -1, limit); +#if !DOTNET51 + case CMethodId.kAESId: + return new AesDecoderStream(inStreams.Single(), info, pass, limit); +#endif + case k_BCJ: + return new BCJFilter(false, inStreams.Single()); + case k_BCJ2: + return new Bcj2DecoderStream(inStreams, info, limit); + case k_BZip2: + return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, true); + case k_PPMD: + return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false); + default: + throw new NotSupportedException(); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Utilites/CrcBuilderStream.cs b/src/SharpCompress/Compressor/LZMA/Utilites/CrcBuilderStream.cs similarity index 95% rename from SharpCompress/Compressor/LZMA/Utilites/CrcBuilderStream.cs rename to src/SharpCompress/Compressor/LZMA/Utilites/CrcBuilderStream.cs index b7baba36..37fcce80 100644 --- a/SharpCompress/Compressor/LZMA/Utilites/CrcBuilderStream.cs +++ b/src/SharpCompress/Compressor/LZMA/Utilites/CrcBuilderStream.cs @@ -1,209 +1,209 @@ -using System; -using System.IO; - -namespace SharpCompress.Compressor.LZMA.Utilites -{ - internal class CrcBuilderStream : Stream - { - private long mProcessed; - private Stream mTarget; - private uint mCRC; - private bool mFinished; - private bool isDisposed; - - public CrcBuilderStream(Stream target) - { - mTarget = target; - mCRC = CRC.kInitCRC; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - mTarget.Dispose(); - base.Dispose(disposing); - } - - public long Processed - { - get { return mProcessed; } - } - - public uint Finish() - { - if (!mFinished) - { - mFinished = true; - mCRC = CRC.Finish(mCRC); - } - - return mCRC; - } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override void Flush() - { - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new InvalidOperationException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (mFinished) - throw new InvalidOperationException("CRC calculation has been finished."); - - mProcessed += count; - mCRC = CRC.Update(mCRC, buffer, offset, count); - mTarget.Write(buffer, offset, count); - } - } - - internal class ReadingCrcBuilderStream : Stream - { - private long mProcessed; - private Stream mSource; - private uint mCRC; - private bool mFinished; - - public ReadingCrcBuilderStream(Stream source) - { - mSource = source; - mCRC = CRC.kInitCRC; - } - - protected override void Dispose(bool disposing) - { - try - { - if (disposing) - mSource.Dispose(); - } - finally - { - base.Dispose(disposing); - } - } - - public long Processed - { - get { return mProcessed; } - } - - public uint Finish() - { - if (!mFinished) - { - mFinished = true; - mCRC = CRC.Finish(mCRC); - } - - return mCRC; - } - - public override bool CanRead - { - get { return mSource.CanRead; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count > 0 && !mFinished) - { - int read = mSource.Read(buffer, offset, count); - if (read > 0) - { - mProcessed += read; - mCRC = CRC.Update(mCRC, buffer, offset, read); - return read; - } - - Finish(); - } - - return 0; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - } +using System; +using System.IO; + +namespace SharpCompress.Compressor.LZMA.Utilites +{ + internal class CrcBuilderStream : Stream + { + private long mProcessed; + private Stream mTarget; + private uint mCRC; + private bool mFinished; + private bool isDisposed; + + public CrcBuilderStream(Stream target) + { + mTarget = target; + mCRC = CRC.kInitCRC; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + mTarget.Dispose(); + base.Dispose(disposing); + } + + public long Processed + { + get { return mProcessed; } + } + + public uint Finish() + { + if (!mFinished) + { + mFinished = true; + mCRC = CRC.Finish(mCRC); + } + + return mCRC; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new InvalidOperationException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (mFinished) + throw new InvalidOperationException("CRC calculation has been finished."); + + mProcessed += count; + mCRC = CRC.Update(mCRC, buffer, offset, count); + mTarget.Write(buffer, offset, count); + } + } + + internal class ReadingCrcBuilderStream : Stream + { + private long mProcessed; + private Stream mSource; + private uint mCRC; + private bool mFinished; + + public ReadingCrcBuilderStream(Stream source) + { + mSource = source; + mCRC = CRC.kInitCRC; + } + + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + mSource.Dispose(); + } + finally + { + base.Dispose(disposing); + } + } + + public long Processed + { + get { return mProcessed; } + } + + public uint Finish() + { + if (!mFinished) + { + mFinished = true; + mCRC = CRC.Finish(mCRC); + } + + return mCRC; + } + + public override bool CanRead + { + get { return mSource.CanRead; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count > 0 && !mFinished) + { + int read = mSource.Read(buffer, offset, count); + if (read > 0) + { + mProcessed += read; + mCRC = CRC.Update(mCRC, buffer, offset, read); + return read; + } + + Finish(); + } + + return 0; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Utilites/CrcCheckStream.cs b/src/SharpCompress/Compressor/LZMA/Utilites/CrcCheckStream.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/Utilites/CrcCheckStream.cs rename to src/SharpCompress/Compressor/LZMA/Utilites/CrcCheckStream.cs index 1cb2070a..2f641175 100644 --- a/SharpCompress/Compressor/LZMA/Utilites/CrcCheckStream.cs +++ b/src/SharpCompress/Compressor/LZMA/Utilites/CrcCheckStream.cs @@ -1,114 +1,114 @@ -using System; -using System.IO; - -namespace SharpCompress.Compressor.LZMA.Utilites -{ - internal class CrcCheckStream : Stream - { - private readonly uint mExpectedCRC; - private uint mCurrentCRC; - private bool mClosed; - - private long[] mBytes = new long[256]; - private long mLength; - - public CrcCheckStream(uint crc) - { - mExpectedCRC = crc; - mCurrentCRC = CRC.kInitCRC; - } - - protected override void Dispose(bool disposing) - { - if (mCurrentCRC != mExpectedCRC) - throw new InvalidOperationException(); - try - { - if (disposing && !mClosed) - { - mClosed = true; - mCurrentCRC = CRC.Finish(mCurrentCRC); -#if DEBUG - if (mCurrentCRC == mExpectedCRC) - System.Diagnostics.Debug.WriteLine("CRC ok: " + mExpectedCRC.ToString("x8")); - else - { - System.Diagnostics.Debugger.Break(); - System.Diagnostics.Debug.WriteLine("bad CRC"); - } - - double lengthInv = 1.0/mLength; - double entropy = 0; - for (int i = 0; i < 256; i++) - { - if (mBytes[i] != 0) - { - double p = lengthInv*mBytes[i]; - entropy -= p*Math.Log(p, 256); - } - } - System.Diagnostics.Debug.WriteLine("entropy: " + (int) (entropy*100) + "%"); -#endif - } - } - finally - { - base.Dispose(disposing); - } - } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override void Flush() - { - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new InvalidOperationException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - mLength += count; - for (int i = 0; i < count; i++) - mBytes[buffer[offset + i]]++; - - mCurrentCRC = CRC.Update(mCurrentCRC, buffer, offset, count); - } - } +using System; +using System.IO; + +namespace SharpCompress.Compressor.LZMA.Utilites +{ + internal class CrcCheckStream : Stream + { + private readonly uint mExpectedCRC; + private uint mCurrentCRC; + private bool mClosed; + + private long[] mBytes = new long[256]; + private long mLength; + + public CrcCheckStream(uint crc) + { + mExpectedCRC = crc; + mCurrentCRC = CRC.kInitCRC; + } + + protected override void Dispose(bool disposing) + { + if (mCurrentCRC != mExpectedCRC) + throw new InvalidOperationException(); + try + { + if (disposing && !mClosed) + { + mClosed = true; + mCurrentCRC = CRC.Finish(mCurrentCRC); +#if DEBUG + if (mCurrentCRC == mExpectedCRC) + System.Diagnostics.Debug.WriteLine("CRC ok: " + mExpectedCRC.ToString("x8")); + else + { + System.Diagnostics.Debugger.Break(); + System.Diagnostics.Debug.WriteLine("bad CRC"); + } + + double lengthInv = 1.0/mLength; + double entropy = 0; + for (int i = 0; i < 256; i++) + { + if (mBytes[i] != 0) + { + double p = lengthInv*mBytes[i]; + entropy -= p*Math.Log(p, 256); + } + } + System.Diagnostics.Debug.WriteLine("entropy: " + (int) (entropy*100) + "%"); +#endif + } + } + finally + { + base.Dispose(disposing); + } + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new InvalidOperationException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + mLength += count; + for (int i = 0; i < count; i++) + mBytes[buffer[offset + i]]++; + + mCurrentCRC = CRC.Update(mCurrentCRC, buffer, offset, count); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs b/src/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs rename to src/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs index f03533a6..691b5546 100644 --- a/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs +++ b/src/SharpCompress/Compressor/LZMA/Utilites/IPasswordProvider.cs @@ -1,7 +1,7 @@ -namespace SharpCompress.Compressor.LZMA.Utilites -{ - internal interface IPasswordProvider - { - string CryptoGetTextPassword(); - } +namespace SharpCompress.Compressor.LZMA.Utilites +{ + internal interface IPasswordProvider + { + string CryptoGetTextPassword(); + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/LZMA/Utilites/Utils.cs b/src/SharpCompress/Compressor/LZMA/Utilites/Utils.cs similarity index 96% rename from SharpCompress/Compressor/LZMA/Utilites/Utils.cs rename to src/SharpCompress/Compressor/LZMA/Utilites/Utils.cs index f535324d..36fb2d09 100644 --- a/SharpCompress/Compressor/LZMA/Utilites/Utils.cs +++ b/src/SharpCompress/Compressor/LZMA/Utilites/Utils.cs @@ -1,80 +1,80 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace SharpCompress.Compressor.LZMA.Utilites -{ - internal enum BlockType : byte - { - #region Constants - - End = 0, - Header = 1, - ArchiveProperties = 2, - AdditionalStreamsInfo = 3, - MainStreamsInfo = 4, - FilesInfo = 5, - PackInfo = 6, - UnpackInfo = 7, - SubStreamsInfo = 8, - Size = 9, - CRC = 10, - Folder = 11, - CodersUnpackSize = 12, - NumUnpackStream = 13, - EmptyStream = 14, - EmptyFile = 15, - Anti = 16, - Name = 17, - CTime = 18, - ATime = 19, - MTime = 20, - WinAttributes = 21, - Comment = 22, - EncodedHeader = 23, - StartPos = 24, - Dummy = 25, - - #endregion - } - - internal static class Utils - { - [Conditional("DEBUG")] - public static void Assert(bool expression) - { - if (!expression) - { - if (Debugger.IsAttached) - Debugger.Break(); - - throw new Exception("Assertion failed."); - } - } - - public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - if (buffer == null) - throw new ArgumentNullException("buffer"); - - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException("offset"); - - if (length < 0 || length > buffer.Length - offset) - throw new ArgumentOutOfRangeException("length"); - - while (length > 0) - { - int fetched = stream.Read(buffer, offset, length); - if (fetched <= 0) - throw new EndOfStreamException(); - - offset += fetched; - length -= fetched; - } - } - } +using System; +using System.Diagnostics; +using System.IO; + +namespace SharpCompress.Compressor.LZMA.Utilites +{ + internal enum BlockType : byte + { + #region Constants + + End = 0, + Header = 1, + ArchiveProperties = 2, + AdditionalStreamsInfo = 3, + MainStreamsInfo = 4, + FilesInfo = 5, + PackInfo = 6, + UnpackInfo = 7, + SubStreamsInfo = 8, + Size = 9, + CRC = 10, + Folder = 11, + CodersUnpackSize = 12, + NumUnpackStream = 13, + EmptyStream = 14, + EmptyFile = 15, + Anti = 16, + Name = 17, + CTime = 18, + ATime = 19, + MTime = 20, + WinAttributes = 21, + Comment = 22, + EncodedHeader = 23, + StartPos = 24, + Dummy = 25, + + #endregion + } + + internal static class Utils + { + [Conditional("DEBUG")] + public static void Assert(bool expression) + { + if (!expression) + { + if (Debugger.IsAttached) + Debugger.Break(); + + throw new Exception("Assertion failed."); + } + } + + public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (buffer == null) + throw new ArgumentNullException("buffer"); + + if (offset < 0 || offset > buffer.Length) + throw new ArgumentOutOfRangeException("offset"); + + if (length < 0 || length > buffer.Length - offset) + throw new ArgumentOutOfRangeException("length"); + + while (length > 0) + { + int fetched = stream.Read(buffer, offset, length); + if (fetched <= 0) + throw new EndOfStreamException(); + + offset += fetched; + length -= fetched; + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/FreqData.cs b/src/SharpCompress/Compressor/PPMd/H/FreqData.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/H/FreqData.cs rename to src/SharpCompress/Compressor/PPMd/H/FreqData.cs index a37ea93a..958587c7 100644 --- a/SharpCompress/Compressor/PPMd/H/FreqData.cs +++ b/src/SharpCompress/Compressor/PPMd/H/FreqData.cs @@ -1,68 +1,68 @@ -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class FreqData : Pointer - { - internal const int Size = 6; - - // struct FreqData - // { - // ushort SummFreq; - // STATE _PACK_ATTR * Stats; - // }; - - internal FreqData(byte[] Memory) - : base(Memory) - { - } - - internal int SummFreq - { - get { return Utility.readShortLittleEndian(Memory, Address) & 0xffff; } - - set { Utility.WriteLittleEndian(Memory, Address, (short) value); } - } - - internal FreqData Initialize(byte[] mem) - { - return base.Initialize(mem); - } - - internal void IncrementSummFreq(int dSummFreq) - { - Utility.incShortLittleEndian(Memory, Address, (short) dSummFreq); - } - - internal int GetStats() - { - return Utility.readIntLittleEndian(Memory, Address + 2); - } - - internal virtual void SetStats(State state) - { - SetStats(state.Address); - } - - internal void SetStats(int state) - { - Utility.WriteLittleEndian(Memory, Address + 2, state); - } - - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("FreqData["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(Size); - buffer.Append("\n summFreq="); - buffer.Append(SummFreq); - buffer.Append("\n stats="); - buffer.Append(GetStats()); - buffer.Append("\n]"); - return buffer.ToString(); - } - } +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class FreqData : Pointer + { + internal const int Size = 6; + + // struct FreqData + // { + // ushort SummFreq; + // STATE _PACK_ATTR * Stats; + // }; + + internal FreqData(byte[] Memory) + : base(Memory) + { + } + + internal int SummFreq + { + get { return Utility.readShortLittleEndian(Memory, Address) & 0xffff; } + + set { Utility.WriteLittleEndian(Memory, Address, (short) value); } + } + + internal FreqData Initialize(byte[] mem) + { + return base.Initialize(mem); + } + + internal void IncrementSummFreq(int dSummFreq) + { + Utility.incShortLittleEndian(Memory, Address, (short) dSummFreq); + } + + internal int GetStats() + { + return Utility.readIntLittleEndian(Memory, Address + 2); + } + + internal virtual void SetStats(State state) + { + SetStats(state.Address); + } + + internal void SetStats(int state) + { + Utility.WriteLittleEndian(Memory, Address + 2, state); + } + + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("FreqData["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(Size); + buffer.Append("\n summFreq="); + buffer.Append(SummFreq); + buffer.Append("\n stats="); + buffer.Append(GetStats()); + buffer.Append("\n]"); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/ModelPPM.cs b/src/SharpCompress/Compressor/PPMd/H/ModelPPM.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/H/ModelPPM.cs rename to src/SharpCompress/Compressor/PPMd/H/ModelPPM.cs index d371d721..4d2b76f5 100644 --- a/SharpCompress/Compressor/PPMd/H/ModelPPM.cs +++ b/src/SharpCompress/Compressor/PPMd/H/ModelPPM.cs @@ -1,928 +1,928 @@ -using System.Text; -using System.IO; -using SharpCompress.Compressor.Rar; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class ModelPPM - { - private void InitBlock() - { - for (int i = 0; i < 25; i++) - { - SEE2Cont[i] = new SEE2Context[16]; - } - for (int i2 = 0; i2 < 128; i2++) - { - binSumm[i2] = new int[64]; - } - } - - public SubAllocator SubAlloc - { - get { return subAlloc; } - } - - public virtual SEE2Context DummySEE2Cont - { - get { return dummySEE2Cont; } - } - - public virtual int InitRL - { - get { return initRL; } - } - - public virtual int EscCount - { - get { return escCount; } - - set { this.escCount = value & 0xff; } - } - - public virtual int[] CharMask - { - get { return charMask; } - } - - public virtual int NumMasked - { - get { return numMasked; } - - set { this.numMasked = value; } - } - - public virtual int PrevSuccess - { - get { return prevSuccess; } - - set { this.prevSuccess = value & 0xff; } - } - - public virtual int InitEsc - { - get { return initEsc; } - - set { this.initEsc = value; } - } - - public virtual int RunLength - { - get { return runLength; } - - set { this.runLength = value; } - } - - public virtual int HiBitsFlag - { - get { return hiBitsFlag; } - - set { this.hiBitsFlag = value & 0xff; } - } - - public virtual int[][] BinSumm - { - get { return binSumm; } - } - - internal RangeCoder Coder - { - get { return coder; } - } - - internal State FoundState - { - get { return foundState; } - } - - public virtual byte[] Heap - { - get { return subAlloc.Heap; } - } - - public virtual int OrderFall - { - get { return orderFall; } - } - - public const int MAX_O = 64; /* maximum allowed model order */ - - public const int INT_BITS = 7; - - public const int PERIOD_BITS = 7; - - //UPGRADE_NOTE: Final was removed from the declaration of 'TOT_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int TOT_BITS = INT_BITS + PERIOD_BITS; - - //UPGRADE_NOTE: Final was removed from the declaration of 'INTERVAL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int INTERVAL = 1 << INT_BITS; - - //UPGRADE_NOTE: Final was removed from the declaration of 'BIN_SCALE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int BIN_SCALE = 1 << TOT_BITS; - - public const int MAX_FREQ = 124; - - private SEE2Context[][] SEE2Cont = new SEE2Context[25][]; - - private SEE2Context dummySEE2Cont; - - private PPMContext minContext; //medContext - - private PPMContext maxContext; - - private State foundState; // found next state transition - - private int numMasked, initEsc, orderFall, maxOrder, runLength, initRL; - - private int[] charMask = new int[256]; - - private int[] NS2Indx = new int[256]; - - private int[] NS2BSIndx = new int[256]; - - private int[] HB2Flag = new int[256]; - - // byte EscCount, PrevSuccess, HiBitsFlag; - private int escCount, prevSuccess, hiBitsFlag; - - private int[][] binSumm = new int[128][]; // binary SEE-contexts - - private RangeCoder coder; - - private SubAllocator subAlloc = new SubAllocator(); - - private static int[] InitBinEsc = new int[] {0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; - - // Temp fields - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState1 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState2 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState3 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState4 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private StateRef tempStateRef1 = new StateRef(); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private StateRef tempStateRef2 = new StateRef(); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private PPMContext tempPPMContext1 = new PPMContext(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private PPMContext tempPPMContext2 = new PPMContext(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private PPMContext tempPPMContext3 = new PPMContext(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private PPMContext tempPPMContext4 = new PPMContext(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] ps = new int[MAX_O]; - - public ModelPPM() - { - InitBlock(); - minContext = null; - maxContext = null; - //medContext = null; - } - - private void restartModelRare() - { - Utility.Fill(charMask, 0); - subAlloc.initSubAllocator(); - initRL = -(maxOrder < 12 ? maxOrder : 12) - 1; - int addr = subAlloc.allocContext(); - minContext.Address = addr; - maxContext.Address = addr; - minContext.setSuffix(0); - orderFall = maxOrder; - minContext.NumStats = 256; - minContext.FreqData.SummFreq = minContext.NumStats + 1; - - addr = subAlloc.allocUnits(256/2); - foundState.Address = addr; - minContext.FreqData.SetStats(addr); - - State state = new State(subAlloc.Heap); - addr = minContext.FreqData.GetStats(); - runLength = initRL; - prevSuccess = 0; - for (int i = 0; i < 256; i++) - { - state.Address = addr + i*State.Size; - state.Symbol = i; - state.Freq = 1; - state.SetSuccessor(0); - } - - for (int i = 0; i < 128; i++) - { - for (int k = 0; k < 8; k++) - { - for (int m = 0; m < 64; m += 8) - { - binSumm[i][k + m] = BIN_SCALE - InitBinEsc[k]/(i + 2); - } - } - } - for (int i = 0; i < 25; i++) - { - for (int k = 0; k < 16; k++) - { - SEE2Cont[i][k].Initialize(5*i + 10); - } - } - } - - private void startModelRare(int MaxOrder) - { - int i, k, m, Step; - escCount = 1; - this.maxOrder = MaxOrder; - restartModelRare(); - // Bug Fixed - NS2BSIndx[0] = 0; - NS2BSIndx[1] = 2; - for (int j = 0; j < 9; j++) - { - NS2BSIndx[2 + j] = 4; - } - for (int j = 0; j < 256 - 11; j++) - { - NS2BSIndx[11 + j] = 6; - } - for (i = 0; i < 3; i++) - { - NS2Indx[i] = i; - } - for (m = i, k = 1, Step = 1; i < 256; i++) - { - NS2Indx[i] = m; - if ((--k) == 0) - { - k = ++Step; - m++; - } - } - for (int j = 0; j < 0x40; j++) - { - HB2Flag[j] = 0; - } - for (int j = 0; j < 0x100 - 0x40; j++) - { - HB2Flag[0x40 + j] = 0x08; - } - dummySEE2Cont.Shift = PERIOD_BITS; - } - - private void clearMask() - { - escCount = 1; - Utility.Fill(charMask, 0); - } - - internal bool decodeInit(Unpack unpackRead, int escChar) - { - int MaxOrder = unpackRead.Char & 0xff; - bool reset = ((MaxOrder & 0x20) != 0); - - int MaxMB = 0; - if (reset) - { - MaxMB = unpackRead.Char; - } - else - { - if (subAlloc.GetAllocatedMemory() == 0) - { - return (false); - } - } - if ((MaxOrder & 0x40) != 0) - { - escChar = unpackRead.Char; - unpackRead.PpmEscChar = escChar; - } - coder = new RangeCoder(unpackRead); - if (reset) - { - MaxOrder = (MaxOrder & 0x1f) + 1; - if (MaxOrder > 16) - { - MaxOrder = 16 + (MaxOrder - 16)*3; - } - if (MaxOrder == 1) - { - subAlloc.stopSubAllocator(); - return (false); - } - subAlloc.startSubAllocator((MaxMB + 1) << 20); - minContext = new PPMContext(Heap); - //medContext = new PPMContext(Heap); - maxContext = new PPMContext(Heap); - foundState = new State(Heap); - dummySEE2Cont = new SEE2Context(); - for (int i = 0; i < 25; i++) - { - for (int j = 0; j < 16; j++) - { - SEE2Cont[i][j] = new SEE2Context(); - } - } - startModelRare(MaxOrder); - } - return (minContext.Address != 0); - } - - public virtual int decodeChar() - { - // Debug - //subAlloc.dumpHeap(); - - if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd) - { - return (-1); - } - - if (minContext.NumStats != 1) - { - if (minContext.FreqData.GetStats() <= subAlloc.PText || - minContext.FreqData.GetStats() > subAlloc.HeapEnd) - { - return (-1); - } - if (!minContext.decodeSymbol1(this)) - { - return (-1); - } - } - else - { - minContext.decodeBinSymbol(this); - } - coder.Decode(); - while (foundState.Address == 0) - { - coder.AriDecNormalize(); - do - { - orderFall++; - minContext.Address = minContext.getSuffix(); // =MinContext->Suffix; - if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd) - { - return (-1); - } - } while (minContext.NumStats == numMasked); - if (!minContext.decodeSymbol2(this)) - { - return (-1); - } - coder.Decode(); - } - int Symbol = foundState.Symbol; - if ((orderFall == 0) && foundState.GetSuccessor() > subAlloc.PText) - { - // MinContext=MaxContext=FoundState->Successor; - int addr = foundState.GetSuccessor(); - minContext.Address = addr; - maxContext.Address = addr; - } - else - { - updateModel(); - //this.foundState.Address=foundState.Address);//TODO just 4 debugging - if (escCount == 0) - { - clearMask(); - } - } - coder.AriDecNormalize(); // ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); - return (Symbol); - } - - public virtual SEE2Context[][] getSEE2Cont() - { - return SEE2Cont; - } - - public virtual void incEscCount(int dEscCount) - { - EscCount = EscCount + dEscCount; - } - - public virtual void incRunLength(int dRunLength) - { - RunLength = RunLength + dRunLength; - } - - public virtual int[] getHB2Flag() - { - return HB2Flag; - } - - public virtual int[] getNS2BSIndx() - { - return NS2BSIndx; - } - - public virtual int[] getNS2Indx() - { - return NS2Indx; - } - - private int createSuccessors(bool Skip, State p1) - { - //State upState = tempState1.Initialize(null); - StateRef upState = tempStateRef2; - State tempState = tempState1.Initialize(Heap); - - // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; - PPMContext pc = tempPPMContext1.Initialize(Heap); - pc.Address = minContext.Address; - PPMContext upBranch = tempPPMContext2.Initialize(Heap); - upBranch.Address = foundState.GetSuccessor(); - - // STATE * p, * ps[MAX_O], ** pps=ps; - State p = tempState2.Initialize(Heap); - int pps = 0; - - bool noLoop = false; - - if (!Skip) - { - ps[pps++] = foundState.Address; // *pps++ = FoundState; - if (pc.getSuffix() == 0) - { - noLoop = true; - } - } - if (!noLoop) - { - bool loopEntry = false; - if (p1.Address != 0) - { - p.Address = p1.Address; - pc.Address = pc.getSuffix(); // =pc->Suffix; - loopEntry = true; - } - do - { - if (!loopEntry) - { - pc.Address = pc.getSuffix(); // pc=pc->Suffix; - if (pc.NumStats != 1) - { - p.Address = pc.FreqData.GetStats(); // p=pc->U.Stats - if (p.Symbol != foundState.Symbol) - { - do - { - p.IncrementAddress(); - } while (p.Symbol != foundState.Symbol); - } - } - else - { - p.Address = pc.getOneState().Address; // p=&(pc->OneState); - } - } // LOOP_ENTRY: - loopEntry = false; - if (p.GetSuccessor() != upBranch.Address) - { - pc.Address = p.GetSuccessor(); // =p->Successor; - break; - } - ps[pps++] = p.Address; - } while (pc.getSuffix() != 0); - } // NO_LOOP: - if (pps == 0) - { - return pc.Address; - } - upState.Symbol = Heap[upBranch.Address]; // UpState.Symbol=*(byte*) - // UpBranch; - // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); - upState.SetSuccessor(upBranch.Address + 1); //TODO check if +1 necessary - if (pc.NumStats != 1) - { - if (pc.Address <= subAlloc.PText) - { - return (0); - } - p.Address = pc.FreqData.GetStats(); - if (p.Symbol != upState.Symbol) - { - do - { - p.IncrementAddress(); - } while (p.Symbol != upState.Symbol); - } - int cf = p.Freq - 1; - int s0 = pc.FreqData.SummFreq - pc.NumStats - cf; - // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); - upState.Freq = 1 + ((2*cf <= s0) ? (5*cf > s0 ? 1 : 0) : ((2*cf + 3*s0 - 1)/(2*s0))); - } - else - { - upState.Freq = pc.getOneState().Freq; // UpState.Freq=pc->OneState.Freq; - } - do - { - // pc = pc->createChild(this,*--pps,UpState); - tempState.Address = ps[--pps]; - pc.Address = pc.createChild(this, tempState, upState); - if (pc.Address == 0) - { - return 0; - } - } while (pps != 0); - return pc.Address; - } - - private void updateModelRestart() - { - restartModelRare(); - escCount = 0; - } - - private void updateModel() - { - //System.out.println("ModelPPM.updateModel()"); - // STATE fs = *FoundState, *p = NULL; - StateRef fs = tempStateRef1; - fs.Values = foundState; - State p = tempState3.Initialize(Heap); - State tempState = tempState4.Initialize(Heap); - - PPMContext pc = tempPPMContext3.Initialize(Heap); - PPMContext successor = tempPPMContext4.Initialize(Heap); - - int ns1, ns, cf, sf, s0; - pc.Address = minContext.getSuffix(); - if (fs.Freq < MAX_FREQ/4 && pc.Address != 0) - { - if (pc.NumStats != 1) - { - p.Address = pc.FreqData.GetStats(); - if (p.Symbol != fs.Symbol) - { - do - { - p.IncrementAddress(); - } while (p.Symbol != fs.Symbol); - tempState.Address = p.Address - State.Size; - if (p.Freq >= tempState.Freq) - { - State.PPMDSwap(p, tempState); - p.DecrementAddress(); - } - } - if (p.Freq < MAX_FREQ - 9) - { - p.IncrementFreq(2); - pc.FreqData.IncrementSummFreq(2); - } - } - else - { - p.Address = pc.getOneState().Address; - if (p.Freq < 32) - { - p.IncrementFreq(1); - } - } - } - if (orderFall == 0) - { - foundState.SetSuccessor(createSuccessors(true, p)); - minContext.Address = foundState.GetSuccessor(); - maxContext.Address = foundState.GetSuccessor(); - if (minContext.Address == 0) - { - updateModelRestart(); - return; - } - return; - } - subAlloc.Heap[subAlloc.PText] = (byte) fs.Symbol; - subAlloc.incPText(); - successor.Address = subAlloc.PText; - if (subAlloc.PText >= subAlloc.FakeUnitsStart) - { - updateModelRestart(); - return; - } - // // Debug - // subAlloc.dumpHeap(); - if (fs.GetSuccessor() != 0) - { - if (fs.GetSuccessor() <= subAlloc.PText) - { - fs.SetSuccessor(createSuccessors(false, p)); - if (fs.GetSuccessor() == 0) - { - updateModelRestart(); - return; - } - } - if (--orderFall == 0) - { - successor.Address = fs.GetSuccessor(); - if (maxContext.Address != minContext.Address) - { - subAlloc.decPText(1); - } - } - } - else - { - foundState.SetSuccessor(successor.Address); - fs.SetSuccessor(minContext); - } - // // Debug - // subAlloc.dumpHeap(); - ns = minContext.NumStats; - s0 = minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1); - for (pc.Address = maxContext.Address; pc.Address != minContext.Address; pc.Address = pc.getSuffix()) - { - if ((ns1 = pc.NumStats) != 1) - { - if ((ns1 & 1) == 0) - { - //System.out.println(ns1); - pc.FreqData.SetStats(subAlloc.expandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1))); - if (pc.FreqData.GetStats() == 0) - { - updateModelRestart(); - return; - } - } - // bug fixed - // int sum = ((2 * ns1 < ns) ? 1 : 0) + - // 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() - // .getSummFreq() <= 8 * ns1) ? 1 : 0)); - int sum = ((2*ns1 < ns) ? 1 : 0) + - 2*(((4*ns1 <= ns) ? 1 : 0) & ((pc.FreqData.SummFreq <= 8*ns1) ? 1 : 0)); - pc.FreqData.IncrementSummFreq(sum); - } - else - { - p.Address = subAlloc.allocUnits(1); - if (p.Address == 0) - { - updateModelRestart(); - return; - } - p.SetValues(pc.getOneState()); - pc.FreqData.SetStats(p); - if (p.Freq < MAX_FREQ/4 - 1) - { - p.IncrementFreq(p.Freq); - } - else - { - p.Freq = MAX_FREQ - 4; - } - pc.FreqData.SummFreq = (p.Freq + initEsc + (ns > 3 ? 1 : 0)); - } - cf = 2*fs.Freq*(pc.FreqData.SummFreq + 6); - sf = s0 + pc.FreqData.SummFreq; - if (cf < 6*sf) - { - cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4*sf ? 1 : 0); - pc.FreqData.IncrementSummFreq(3); - } - else - { - cf = 4 + (cf >= 9*sf ? 1 : 0) + (cf >= 12*sf ? 1 : 0) + (cf >= 15*sf ? 1 : 0); - pc.FreqData.IncrementSummFreq(cf); - } - p.Address = pc.FreqData.GetStats() + ns1*State.Size; - p.SetSuccessor(successor); - p.Symbol = fs.Symbol; - p.Freq = cf; - pc.NumStats = ++ns1; - } - - int address = fs.GetSuccessor(); - maxContext.Address = address; - minContext.Address = address; - //TODO-----debug - // int pos = minContext.getFreqData().getStats(); - // State a = new State(getHeap()); - // a.Address=pos); - // pos+=State.size; - // a.Address=pos); - //--dbg end - return; - } - - // Debug - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("ModelPPM["); - buffer.Append("\n numMasked="); - buffer.Append(numMasked); - buffer.Append("\n initEsc="); - buffer.Append(initEsc); - buffer.Append("\n orderFall="); - buffer.Append(orderFall); - buffer.Append("\n maxOrder="); - buffer.Append(maxOrder); - buffer.Append("\n runLength="); - buffer.Append(runLength); - buffer.Append("\n initRL="); - buffer.Append(initRL); - buffer.Append("\n escCount="); - buffer.Append(escCount); - buffer.Append("\n prevSuccess="); - buffer.Append(prevSuccess); - buffer.Append("\n foundState="); - buffer.Append(foundState); - buffer.Append("\n coder="); - buffer.Append(coder); - buffer.Append("\n subAlloc="); - buffer.Append(subAlloc); - buffer.Append("\n]"); - return buffer.ToString(); - } - - // Debug - // public void dumpHeap() { - // subAlloc.dumpHeap(); - // } - - internal bool decodeInit(Stream stream, int maxOrder, int maxMemory) - { - if (stream != null) - coder = new RangeCoder(stream); - - if (maxOrder == 1) - { - subAlloc.stopSubAllocator(); - return (false); - } - subAlloc.startSubAllocator(maxMemory); - minContext = new PPMContext(Heap); - //medContext = new PPMContext(Heap); - maxContext = new PPMContext(Heap); - foundState = new State(Heap); - dummySEE2Cont = new SEE2Context(); - for (int i = 0; i < 25; i++) - { - for (int j = 0; j < 16; j++) - { - SEE2Cont[i][j] = new SEE2Context(); - } - } - startModelRare(maxOrder); - - return (minContext.Address != 0); - } - - internal void nextContext() - { - int addr = foundState.GetSuccessor(); - if (orderFall == 0 && addr > subAlloc.PText) - { - minContext.Address = addr; - maxContext.Address = addr; - } - else - updateModel(); - } - - public int decodeChar(LZMA.RangeCoder.Decoder decoder) - { - if (minContext.NumStats != 1) - { - State s = tempState1.Initialize(Heap); - s.Address = minContext.FreqData.GetStats(); - int i; - int count, hiCnt; - if ((count = (int) decoder.GetThreshold((uint) minContext.FreqData.SummFreq)) < (hiCnt = s.Freq)) - { - byte symbol; - decoder.Decode(0, (uint) s.Freq); - symbol = (byte) s.Symbol; - minContext.update1_0(this, s.Address); - nextContext(); - return symbol; - } - prevSuccess = 0; - i = minContext.NumStats - 1; - do - { - s.IncrementAddress(); - if ((hiCnt += s.Freq) > count) - { - byte symbol; - decoder.Decode((uint) (hiCnt - s.Freq), (uint) s.Freq); - symbol = (byte) s.Symbol; - minContext.update1(this, s.Address); - nextContext(); - return symbol; - } - } while (--i > 0); - if (count >= minContext.FreqData.SummFreq) - return -2; - hiBitsFlag = HB2Flag[foundState.Symbol]; - decoder.Decode((uint) hiCnt, (uint) (minContext.FreqData.SummFreq - hiCnt)); - for (i = 0; i < 256; i++) - charMask[i] = -1; - charMask[s.Symbol] = 0; - i = minContext.NumStats - 1; - do - { - s.DecrementAddress(); - charMask[s.Symbol] = 0; - } while (--i > 0); - } - else - { - State rs = tempState1.Initialize(Heap); - rs.Address = minContext.getOneState().Address; - hiBitsFlag = getHB2Flag()[foundState.Symbol]; - int off1 = rs.Freq - 1; - int off2 = minContext.getArrayIndex(this, rs); - int bs = binSumm[off1][off2]; - if (decoder.DecodeBit((uint) bs, 14) == 0) - { - byte symbol; - binSumm[off1][off2] = (bs + INTERVAL - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF; - foundState.Address = rs.Address; - symbol = (byte) rs.Symbol; - rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); - prevSuccess = 1; - incRunLength(1); - nextContext(); - return symbol; - } - bs = (bs - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF; - binSumm[off1][off2] = bs; - initEsc = PPMContext.ExpEscape[Utility.URShift(bs, 10)]; - int i; - for (i = 0; i < 256; i++) - charMask[i] = -1; - charMask[rs.Symbol] = 0; - prevSuccess = 0; - } - for (;;) - { - State s = tempState1.Initialize(Heap); - int i; - int freqSum, count, hiCnt; - SEE2Context see; - int num, numMasked = minContext.NumStats; - do - { - orderFall++; - minContext.Address = minContext.getSuffix(); - if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd) - return -1; - } while (minContext.NumStats == numMasked); - hiCnt = 0; - s.Address = minContext.FreqData.GetStats(); - i = 0; - num = minContext.NumStats - numMasked; - do - { - int k = charMask[s.Symbol]; - hiCnt += s.Freq & k; - minContext.ps[i] = s.Address; - s.IncrementAddress(); - i -= k; - } while (i != num); - - see = minContext.makeEscFreq(this, numMasked, out freqSum); - freqSum += hiCnt; - count = (int) decoder.GetThreshold((uint) freqSum); - - if (count < hiCnt) - { - byte symbol; - State ps = tempState2.Initialize(Heap); - for (hiCnt = 0, i = 0, ps.Address = minContext.ps[i]; - (hiCnt += ps.Freq) <= count; - i++, ps.Address = minContext.ps[i]) ; - s.Address = ps.Address; - decoder.Decode((uint) (hiCnt - s.Freq), (uint) s.Freq); - see.update(); - symbol = (byte) s.Symbol; - minContext.update2(this, s.Address); - updateModel(); - return symbol; - } - if (count >= freqSum) - return -2; - decoder.Decode((uint) hiCnt, (uint) (freqSum - hiCnt)); - see.Summ = see.Summ + freqSum; - do - { - s.Address = minContext.ps[--i]; - charMask[s.Symbol] = 0; - } while (i != 0); - } - } - } +using System.Text; +using System.IO; +using SharpCompress.Compressor.Rar; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class ModelPPM + { + private void InitBlock() + { + for (int i = 0; i < 25; i++) + { + SEE2Cont[i] = new SEE2Context[16]; + } + for (int i2 = 0; i2 < 128; i2++) + { + binSumm[i2] = new int[64]; + } + } + + public SubAllocator SubAlloc + { + get { return subAlloc; } + } + + public virtual SEE2Context DummySEE2Cont + { + get { return dummySEE2Cont; } + } + + public virtual int InitRL + { + get { return initRL; } + } + + public virtual int EscCount + { + get { return escCount; } + + set { this.escCount = value & 0xff; } + } + + public virtual int[] CharMask + { + get { return charMask; } + } + + public virtual int NumMasked + { + get { return numMasked; } + + set { this.numMasked = value; } + } + + public virtual int PrevSuccess + { + get { return prevSuccess; } + + set { this.prevSuccess = value & 0xff; } + } + + public virtual int InitEsc + { + get { return initEsc; } + + set { this.initEsc = value; } + } + + public virtual int RunLength + { + get { return runLength; } + + set { this.runLength = value; } + } + + public virtual int HiBitsFlag + { + get { return hiBitsFlag; } + + set { this.hiBitsFlag = value & 0xff; } + } + + public virtual int[][] BinSumm + { + get { return binSumm; } + } + + internal RangeCoder Coder + { + get { return coder; } + } + + internal State FoundState + { + get { return foundState; } + } + + public virtual byte[] Heap + { + get { return subAlloc.Heap; } + } + + public virtual int OrderFall + { + get { return orderFall; } + } + + public const int MAX_O = 64; /* maximum allowed model order */ + + public const int INT_BITS = 7; + + public const int PERIOD_BITS = 7; + + //UPGRADE_NOTE: Final was removed from the declaration of 'TOT_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int TOT_BITS = INT_BITS + PERIOD_BITS; + + //UPGRADE_NOTE: Final was removed from the declaration of 'INTERVAL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int INTERVAL = 1 << INT_BITS; + + //UPGRADE_NOTE: Final was removed from the declaration of 'BIN_SCALE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int BIN_SCALE = 1 << TOT_BITS; + + public const int MAX_FREQ = 124; + + private SEE2Context[][] SEE2Cont = new SEE2Context[25][]; + + private SEE2Context dummySEE2Cont; + + private PPMContext minContext; //medContext + + private PPMContext maxContext; + + private State foundState; // found next state transition + + private int numMasked, initEsc, orderFall, maxOrder, runLength, initRL; + + private int[] charMask = new int[256]; + + private int[] NS2Indx = new int[256]; + + private int[] NS2BSIndx = new int[256]; + + private int[] HB2Flag = new int[256]; + + // byte EscCount, PrevSuccess, HiBitsFlag; + private int escCount, prevSuccess, hiBitsFlag; + + private int[][] binSumm = new int[128][]; // binary SEE-contexts + + private RangeCoder coder; + + private SubAllocator subAlloc = new SubAllocator(); + + private static int[] InitBinEsc = new int[] {0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + + // Temp fields + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState1 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState2 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState3 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState4 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private StateRef tempStateRef1 = new StateRef(); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private StateRef tempStateRef2 = new StateRef(); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private PPMContext tempPPMContext1 = new PPMContext(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private PPMContext tempPPMContext2 = new PPMContext(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private PPMContext tempPPMContext3 = new PPMContext(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private PPMContext tempPPMContext4 = new PPMContext(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private int[] ps = new int[MAX_O]; + + public ModelPPM() + { + InitBlock(); + minContext = null; + maxContext = null; + //medContext = null; + } + + private void restartModelRare() + { + Utility.Fill(charMask, 0); + subAlloc.initSubAllocator(); + initRL = -(maxOrder < 12 ? maxOrder : 12) - 1; + int addr = subAlloc.allocContext(); + minContext.Address = addr; + maxContext.Address = addr; + minContext.setSuffix(0); + orderFall = maxOrder; + minContext.NumStats = 256; + minContext.FreqData.SummFreq = minContext.NumStats + 1; + + addr = subAlloc.allocUnits(256/2); + foundState.Address = addr; + minContext.FreqData.SetStats(addr); + + State state = new State(subAlloc.Heap); + addr = minContext.FreqData.GetStats(); + runLength = initRL; + prevSuccess = 0; + for (int i = 0; i < 256; i++) + { + state.Address = addr + i*State.Size; + state.Symbol = i; + state.Freq = 1; + state.SetSuccessor(0); + } + + for (int i = 0; i < 128; i++) + { + for (int k = 0; k < 8; k++) + { + for (int m = 0; m < 64; m += 8) + { + binSumm[i][k + m] = BIN_SCALE - InitBinEsc[k]/(i + 2); + } + } + } + for (int i = 0; i < 25; i++) + { + for (int k = 0; k < 16; k++) + { + SEE2Cont[i][k].Initialize(5*i + 10); + } + } + } + + private void startModelRare(int MaxOrder) + { + int i, k, m, Step; + escCount = 1; + this.maxOrder = MaxOrder; + restartModelRare(); + // Bug Fixed + NS2BSIndx[0] = 0; + NS2BSIndx[1] = 2; + for (int j = 0; j < 9; j++) + { + NS2BSIndx[2 + j] = 4; + } + for (int j = 0; j < 256 - 11; j++) + { + NS2BSIndx[11 + j] = 6; + } + for (i = 0; i < 3; i++) + { + NS2Indx[i] = i; + } + for (m = i, k = 1, Step = 1; i < 256; i++) + { + NS2Indx[i] = m; + if ((--k) == 0) + { + k = ++Step; + m++; + } + } + for (int j = 0; j < 0x40; j++) + { + HB2Flag[j] = 0; + } + for (int j = 0; j < 0x100 - 0x40; j++) + { + HB2Flag[0x40 + j] = 0x08; + } + dummySEE2Cont.Shift = PERIOD_BITS; + } + + private void clearMask() + { + escCount = 1; + Utility.Fill(charMask, 0); + } + + internal bool decodeInit(Unpack unpackRead, int escChar) + { + int MaxOrder = unpackRead.Char & 0xff; + bool reset = ((MaxOrder & 0x20) != 0); + + int MaxMB = 0; + if (reset) + { + MaxMB = unpackRead.Char; + } + else + { + if (subAlloc.GetAllocatedMemory() == 0) + { + return (false); + } + } + if ((MaxOrder & 0x40) != 0) + { + escChar = unpackRead.Char; + unpackRead.PpmEscChar = escChar; + } + coder = new RangeCoder(unpackRead); + if (reset) + { + MaxOrder = (MaxOrder & 0x1f) + 1; + if (MaxOrder > 16) + { + MaxOrder = 16 + (MaxOrder - 16)*3; + } + if (MaxOrder == 1) + { + subAlloc.stopSubAllocator(); + return (false); + } + subAlloc.startSubAllocator((MaxMB + 1) << 20); + minContext = new PPMContext(Heap); + //medContext = new PPMContext(Heap); + maxContext = new PPMContext(Heap); + foundState = new State(Heap); + dummySEE2Cont = new SEE2Context(); + for (int i = 0; i < 25; i++) + { + for (int j = 0; j < 16; j++) + { + SEE2Cont[i][j] = new SEE2Context(); + } + } + startModelRare(MaxOrder); + } + return (minContext.Address != 0); + } + + public virtual int decodeChar() + { + // Debug + //subAlloc.dumpHeap(); + + if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd) + { + return (-1); + } + + if (minContext.NumStats != 1) + { + if (minContext.FreqData.GetStats() <= subAlloc.PText || + minContext.FreqData.GetStats() > subAlloc.HeapEnd) + { + return (-1); + } + if (!minContext.decodeSymbol1(this)) + { + return (-1); + } + } + else + { + minContext.decodeBinSymbol(this); + } + coder.Decode(); + while (foundState.Address == 0) + { + coder.AriDecNormalize(); + do + { + orderFall++; + minContext.Address = minContext.getSuffix(); // =MinContext->Suffix; + if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd) + { + return (-1); + } + } while (minContext.NumStats == numMasked); + if (!minContext.decodeSymbol2(this)) + { + return (-1); + } + coder.Decode(); + } + int Symbol = foundState.Symbol; + if ((orderFall == 0) && foundState.GetSuccessor() > subAlloc.PText) + { + // MinContext=MaxContext=FoundState->Successor; + int addr = foundState.GetSuccessor(); + minContext.Address = addr; + maxContext.Address = addr; + } + else + { + updateModel(); + //this.foundState.Address=foundState.Address);//TODO just 4 debugging + if (escCount == 0) + { + clearMask(); + } + } + coder.AriDecNormalize(); // ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + return (Symbol); + } + + public virtual SEE2Context[][] getSEE2Cont() + { + return SEE2Cont; + } + + public virtual void incEscCount(int dEscCount) + { + EscCount = EscCount + dEscCount; + } + + public virtual void incRunLength(int dRunLength) + { + RunLength = RunLength + dRunLength; + } + + public virtual int[] getHB2Flag() + { + return HB2Flag; + } + + public virtual int[] getNS2BSIndx() + { + return NS2BSIndx; + } + + public virtual int[] getNS2Indx() + { + return NS2Indx; + } + + private int createSuccessors(bool Skip, State p1) + { + //State upState = tempState1.Initialize(null); + StateRef upState = tempStateRef2; + State tempState = tempState1.Initialize(Heap); + + // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; + PPMContext pc = tempPPMContext1.Initialize(Heap); + pc.Address = minContext.Address; + PPMContext upBranch = tempPPMContext2.Initialize(Heap); + upBranch.Address = foundState.GetSuccessor(); + + // STATE * p, * ps[MAX_O], ** pps=ps; + State p = tempState2.Initialize(Heap); + int pps = 0; + + bool noLoop = false; + + if (!Skip) + { + ps[pps++] = foundState.Address; // *pps++ = FoundState; + if (pc.getSuffix() == 0) + { + noLoop = true; + } + } + if (!noLoop) + { + bool loopEntry = false; + if (p1.Address != 0) + { + p.Address = p1.Address; + pc.Address = pc.getSuffix(); // =pc->Suffix; + loopEntry = true; + } + do + { + if (!loopEntry) + { + pc.Address = pc.getSuffix(); // pc=pc->Suffix; + if (pc.NumStats != 1) + { + p.Address = pc.FreqData.GetStats(); // p=pc->U.Stats + if (p.Symbol != foundState.Symbol) + { + do + { + p.IncrementAddress(); + } while (p.Symbol != foundState.Symbol); + } + } + else + { + p.Address = pc.getOneState().Address; // p=&(pc->OneState); + } + } // LOOP_ENTRY: + loopEntry = false; + if (p.GetSuccessor() != upBranch.Address) + { + pc.Address = p.GetSuccessor(); // =p->Successor; + break; + } + ps[pps++] = p.Address; + } while (pc.getSuffix() != 0); + } // NO_LOOP: + if (pps == 0) + { + return pc.Address; + } + upState.Symbol = Heap[upBranch.Address]; // UpState.Symbol=*(byte*) + // UpBranch; + // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); + upState.SetSuccessor(upBranch.Address + 1); //TODO check if +1 necessary + if (pc.NumStats != 1) + { + if (pc.Address <= subAlloc.PText) + { + return (0); + } + p.Address = pc.FreqData.GetStats(); + if (p.Symbol != upState.Symbol) + { + do + { + p.IncrementAddress(); + } while (p.Symbol != upState.Symbol); + } + int cf = p.Freq - 1; + int s0 = pc.FreqData.SummFreq - pc.NumStats - cf; + // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); + upState.Freq = 1 + ((2*cf <= s0) ? (5*cf > s0 ? 1 : 0) : ((2*cf + 3*s0 - 1)/(2*s0))); + } + else + { + upState.Freq = pc.getOneState().Freq; // UpState.Freq=pc->OneState.Freq; + } + do + { + // pc = pc->createChild(this,*--pps,UpState); + tempState.Address = ps[--pps]; + pc.Address = pc.createChild(this, tempState, upState); + if (pc.Address == 0) + { + return 0; + } + } while (pps != 0); + return pc.Address; + } + + private void updateModelRestart() + { + restartModelRare(); + escCount = 0; + } + + private void updateModel() + { + //System.out.println("ModelPPM.updateModel()"); + // STATE fs = *FoundState, *p = NULL; + StateRef fs = tempStateRef1; + fs.Values = foundState; + State p = tempState3.Initialize(Heap); + State tempState = tempState4.Initialize(Heap); + + PPMContext pc = tempPPMContext3.Initialize(Heap); + PPMContext successor = tempPPMContext4.Initialize(Heap); + + int ns1, ns, cf, sf, s0; + pc.Address = minContext.getSuffix(); + if (fs.Freq < MAX_FREQ/4 && pc.Address != 0) + { + if (pc.NumStats != 1) + { + p.Address = pc.FreqData.GetStats(); + if (p.Symbol != fs.Symbol) + { + do + { + p.IncrementAddress(); + } while (p.Symbol != fs.Symbol); + tempState.Address = p.Address - State.Size; + if (p.Freq >= tempState.Freq) + { + State.PPMDSwap(p, tempState); + p.DecrementAddress(); + } + } + if (p.Freq < MAX_FREQ - 9) + { + p.IncrementFreq(2); + pc.FreqData.IncrementSummFreq(2); + } + } + else + { + p.Address = pc.getOneState().Address; + if (p.Freq < 32) + { + p.IncrementFreq(1); + } + } + } + if (orderFall == 0) + { + foundState.SetSuccessor(createSuccessors(true, p)); + minContext.Address = foundState.GetSuccessor(); + maxContext.Address = foundState.GetSuccessor(); + if (minContext.Address == 0) + { + updateModelRestart(); + return; + } + return; + } + subAlloc.Heap[subAlloc.PText] = (byte) fs.Symbol; + subAlloc.incPText(); + successor.Address = subAlloc.PText; + if (subAlloc.PText >= subAlloc.FakeUnitsStart) + { + updateModelRestart(); + return; + } + // // Debug + // subAlloc.dumpHeap(); + if (fs.GetSuccessor() != 0) + { + if (fs.GetSuccessor() <= subAlloc.PText) + { + fs.SetSuccessor(createSuccessors(false, p)); + if (fs.GetSuccessor() == 0) + { + updateModelRestart(); + return; + } + } + if (--orderFall == 0) + { + successor.Address = fs.GetSuccessor(); + if (maxContext.Address != minContext.Address) + { + subAlloc.decPText(1); + } + } + } + else + { + foundState.SetSuccessor(successor.Address); + fs.SetSuccessor(minContext); + } + // // Debug + // subAlloc.dumpHeap(); + ns = minContext.NumStats; + s0 = minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1); + for (pc.Address = maxContext.Address; pc.Address != minContext.Address; pc.Address = pc.getSuffix()) + { + if ((ns1 = pc.NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + //System.out.println(ns1); + pc.FreqData.SetStats(subAlloc.expandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1))); + if (pc.FreqData.GetStats() == 0) + { + updateModelRestart(); + return; + } + } + // bug fixed + // int sum = ((2 * ns1 < ns) ? 1 : 0) + + // 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() + // .getSummFreq() <= 8 * ns1) ? 1 : 0)); + int sum = ((2*ns1 < ns) ? 1 : 0) + + 2*(((4*ns1 <= ns) ? 1 : 0) & ((pc.FreqData.SummFreq <= 8*ns1) ? 1 : 0)); + pc.FreqData.IncrementSummFreq(sum); + } + else + { + p.Address = subAlloc.allocUnits(1); + if (p.Address == 0) + { + updateModelRestart(); + return; + } + p.SetValues(pc.getOneState()); + pc.FreqData.SetStats(p); + if (p.Freq < MAX_FREQ/4 - 1) + { + p.IncrementFreq(p.Freq); + } + else + { + p.Freq = MAX_FREQ - 4; + } + pc.FreqData.SummFreq = (p.Freq + initEsc + (ns > 3 ? 1 : 0)); + } + cf = 2*fs.Freq*(pc.FreqData.SummFreq + 6); + sf = s0 + pc.FreqData.SummFreq; + if (cf < 6*sf) + { + cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4*sf ? 1 : 0); + pc.FreqData.IncrementSummFreq(3); + } + else + { + cf = 4 + (cf >= 9*sf ? 1 : 0) + (cf >= 12*sf ? 1 : 0) + (cf >= 15*sf ? 1 : 0); + pc.FreqData.IncrementSummFreq(cf); + } + p.Address = pc.FreqData.GetStats() + ns1*State.Size; + p.SetSuccessor(successor); + p.Symbol = fs.Symbol; + p.Freq = cf; + pc.NumStats = ++ns1; + } + + int address = fs.GetSuccessor(); + maxContext.Address = address; + minContext.Address = address; + //TODO-----debug + // int pos = minContext.getFreqData().getStats(); + // State a = new State(getHeap()); + // a.Address=pos); + // pos+=State.size; + // a.Address=pos); + //--dbg end + return; + } + + // Debug + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("ModelPPM["); + buffer.Append("\n numMasked="); + buffer.Append(numMasked); + buffer.Append("\n initEsc="); + buffer.Append(initEsc); + buffer.Append("\n orderFall="); + buffer.Append(orderFall); + buffer.Append("\n maxOrder="); + buffer.Append(maxOrder); + buffer.Append("\n runLength="); + buffer.Append(runLength); + buffer.Append("\n initRL="); + buffer.Append(initRL); + buffer.Append("\n escCount="); + buffer.Append(escCount); + buffer.Append("\n prevSuccess="); + buffer.Append(prevSuccess); + buffer.Append("\n foundState="); + buffer.Append(foundState); + buffer.Append("\n coder="); + buffer.Append(coder); + buffer.Append("\n subAlloc="); + buffer.Append(subAlloc); + buffer.Append("\n]"); + return buffer.ToString(); + } + + // Debug + // public void dumpHeap() { + // subAlloc.dumpHeap(); + // } + + internal bool decodeInit(Stream stream, int maxOrder, int maxMemory) + { + if (stream != null) + coder = new RangeCoder(stream); + + if (maxOrder == 1) + { + subAlloc.stopSubAllocator(); + return (false); + } + subAlloc.startSubAllocator(maxMemory); + minContext = new PPMContext(Heap); + //medContext = new PPMContext(Heap); + maxContext = new PPMContext(Heap); + foundState = new State(Heap); + dummySEE2Cont = new SEE2Context(); + for (int i = 0; i < 25; i++) + { + for (int j = 0; j < 16; j++) + { + SEE2Cont[i][j] = new SEE2Context(); + } + } + startModelRare(maxOrder); + + return (minContext.Address != 0); + } + + internal void nextContext() + { + int addr = foundState.GetSuccessor(); + if (orderFall == 0 && addr > subAlloc.PText) + { + minContext.Address = addr; + maxContext.Address = addr; + } + else + updateModel(); + } + + public int decodeChar(LZMA.RangeCoder.Decoder decoder) + { + if (minContext.NumStats != 1) + { + State s = tempState1.Initialize(Heap); + s.Address = minContext.FreqData.GetStats(); + int i; + int count, hiCnt; + if ((count = (int) decoder.GetThreshold((uint) minContext.FreqData.SummFreq)) < (hiCnt = s.Freq)) + { + byte symbol; + decoder.Decode(0, (uint) s.Freq); + symbol = (byte) s.Symbol; + minContext.update1_0(this, s.Address); + nextContext(); + return symbol; + } + prevSuccess = 0; + i = minContext.NumStats - 1; + do + { + s.IncrementAddress(); + if ((hiCnt += s.Freq) > count) + { + byte symbol; + decoder.Decode((uint) (hiCnt - s.Freq), (uint) s.Freq); + symbol = (byte) s.Symbol; + minContext.update1(this, s.Address); + nextContext(); + return symbol; + } + } while (--i > 0); + if (count >= minContext.FreqData.SummFreq) + return -2; + hiBitsFlag = HB2Flag[foundState.Symbol]; + decoder.Decode((uint) hiCnt, (uint) (minContext.FreqData.SummFreq - hiCnt)); + for (i = 0; i < 256; i++) + charMask[i] = -1; + charMask[s.Symbol] = 0; + i = minContext.NumStats - 1; + do + { + s.DecrementAddress(); + charMask[s.Symbol] = 0; + } while (--i > 0); + } + else + { + State rs = tempState1.Initialize(Heap); + rs.Address = minContext.getOneState().Address; + hiBitsFlag = getHB2Flag()[foundState.Symbol]; + int off1 = rs.Freq - 1; + int off2 = minContext.getArrayIndex(this, rs); + int bs = binSumm[off1][off2]; + if (decoder.DecodeBit((uint) bs, 14) == 0) + { + byte symbol; + binSumm[off1][off2] = (bs + INTERVAL - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF; + foundState.Address = rs.Address; + symbol = (byte) rs.Symbol; + rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); + prevSuccess = 1; + incRunLength(1); + nextContext(); + return symbol; + } + bs = (bs - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF; + binSumm[off1][off2] = bs; + initEsc = PPMContext.ExpEscape[Utility.URShift(bs, 10)]; + int i; + for (i = 0; i < 256; i++) + charMask[i] = -1; + charMask[rs.Symbol] = 0; + prevSuccess = 0; + } + for (;;) + { + State s = tempState1.Initialize(Heap); + int i; + int freqSum, count, hiCnt; + SEE2Context see; + int num, numMasked = minContext.NumStats; + do + { + orderFall++; + minContext.Address = minContext.getSuffix(); + if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd) + return -1; + } while (minContext.NumStats == numMasked); + hiCnt = 0; + s.Address = minContext.FreqData.GetStats(); + i = 0; + num = minContext.NumStats - numMasked; + do + { + int k = charMask[s.Symbol]; + hiCnt += s.Freq & k; + minContext.ps[i] = s.Address; + s.IncrementAddress(); + i -= k; + } while (i != num); + + see = minContext.makeEscFreq(this, numMasked, out freqSum); + freqSum += hiCnt; + count = (int) decoder.GetThreshold((uint) freqSum); + + if (count < hiCnt) + { + byte symbol; + State ps = tempState2.Initialize(Heap); + for (hiCnt = 0, i = 0, ps.Address = minContext.ps[i]; + (hiCnt += ps.Freq) <= count; + i++, ps.Address = minContext.ps[i]) ; + s.Address = ps.Address; + decoder.Decode((uint) (hiCnt - s.Freq), (uint) s.Freq); + see.update(); + symbol = (byte) s.Symbol; + minContext.update2(this, s.Address); + updateModel(); + return symbol; + } + if (count >= freqSum) + return -2; + decoder.Decode((uint) hiCnt, (uint) (freqSum - hiCnt)); + see.Summ = see.Summ + freqSum; + do + { + s.Address = minContext.ps[--i]; + charMask[s.Symbol] = 0; + } while (i != 0); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/PPMContext.cs b/src/SharpCompress/Compressor/PPMd/H/PPMContext.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/H/PPMContext.cs rename to src/SharpCompress/Compressor/PPMd/H/PPMContext.cs index 8b36bf6d..bfe4b7d5 100644 --- a/SharpCompress/Compressor/PPMd/H/PPMContext.cs +++ b/src/SharpCompress/Compressor/PPMd/H/PPMContext.cs @@ -1,548 +1,548 @@ -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class PPMContext : Pointer - { - internal FreqData FreqData - { - get { return freqData; } - - set - { - this.freqData.SummFreq = value.SummFreq; - this.freqData.SetStats(value.GetStats()); - } - } - - public virtual int NumStats - { - get - { - if (Memory != null) - { - numStats = Utility.readShortLittleEndian(Memory, Address) & 0xffff; - } - return numStats; - } - - set - { - this.numStats = value & 0xffff; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address, (short) value); - } - } - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'unionSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: The initialization of 'unionSize' was moved to static method 'SharpCompress.Unpack.PPM.PPMContext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" - private static readonly int unionSize; - - //UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int size = 2 + unionSize + 4; // 12 - - // ushort NumStats; - private int numStats; // determines if feqData or onstate is used - - // (1==onestate) - - //UPGRADE_NOTE: Final was removed from the declaration of 'freqData '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private FreqData freqData; // -\ - - // |-> union - //UPGRADE_NOTE: Final was removed from the declaration of 'oneState '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State oneState; // -/ - - private int suffix; // pointer ppmcontext - - //UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] ExpEscape = new int[] {25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2}; - - // Temp fields - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState1 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState2 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState3 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState4 = new State(null); - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState5 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private State tempState5 = new State(null); - private PPMContext tempPPMContext = null; - //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal int[] ps = new int[256]; - - public PPMContext(byte[] Memory) - : base(Memory) - { - oneState = new State(Memory); - freqData = new FreqData(Memory); - } - - internal PPMContext Initialize(byte[] mem) - { - oneState.Initialize(mem); - freqData.Initialize(mem); - return base.Initialize(mem); - } - - internal State getOneState() - { - return oneState; - } - - internal void setOneState(StateRef oneState) - { - this.oneState.SetValues(oneState); - } - - internal int getSuffix() - { - if (Memory != null) - { - suffix = Utility.readIntLittleEndian(Memory, Address + 8); - } - return suffix; - } - - internal void setSuffix(PPMContext suffix) - { - setSuffix(suffix.Address); - } - - internal void setSuffix(int suffix) - { - this.suffix = suffix; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address + 8, suffix); - } - } - - internal override int Address - { - get { return base.Address; } - set - { - base.Address = value; - oneState.Address = value + 2; - freqData.Address = value + 2; - } - } - - private PPMContext getTempPPMContext(byte[] Memory) - { - if (tempPPMContext == null) - { - tempPPMContext = new PPMContext(null); - } - return tempPPMContext.Initialize(Memory); - } - - internal int createChild(ModelPPM model, State pStats, StateRef firstState) - { - PPMContext pc = getTempPPMContext(model.SubAlloc.Heap); - pc.Address = model.SubAlloc.allocContext(); - if (pc != null) - { - pc.NumStats = 1; - pc.setOneState(firstState); - pc.setSuffix(this); - pStats.SetSuccessor(pc); - } - return pc.Address; - } - - internal void rescale(ModelPPM model) - { - int OldNS = NumStats, i = NumStats - 1, Adder, EscFreq; - // STATE* p1, * p; - State p1 = new State(model.Heap); - State p = new State(model.Heap); - State temp = new State(model.Heap); - - for (p.Address = model.FoundState.Address; p.Address != freqData.GetStats(); p.DecrementAddress()) - { - temp.Address = p.Address - State.Size; - State.PPMDSwap(p, temp); - } - temp.Address = freqData.GetStats(); - temp.IncrementFreq(4); - freqData.IncrementSummFreq(4); - EscFreq = freqData.SummFreq - p.Freq; - Adder = (model.OrderFall != 0) ? 1 : 0; - p.Freq = Utility.URShift((p.Freq + Adder), 1); - freqData.SummFreq = p.Freq; - do - { - p.IncrementAddress(); - EscFreq -= p.Freq; - p.Freq = Utility.URShift((p.Freq + Adder), 1); - freqData.IncrementSummFreq(p.Freq); - temp.Address = p.Address - State.Size; - if (p.Freq > temp.Freq) - { - p1.Address = p.Address; - StateRef tmp = new StateRef(); - tmp.Values = p1; - State temp2 = new State(model.Heap); - State temp3 = new State(model.Heap); - do - { - // p1[0]=p1[-1]; - temp2.Address = p1.Address - State.Size; - p1.SetValues(temp2); - p1.DecrementAddress(); - temp3.Address = p1.Address - State.Size; - } while (p1.Address != freqData.GetStats() && tmp.Freq > temp3.Freq); - p1.SetValues(tmp); - } - } while (--i != 0); - if (p.Freq == 0) - { - do - { - i++; - p.DecrementAddress(); - } while (p.Freq == 0); - EscFreq += i; - NumStats = NumStats - i; - if (NumStats == 1) - { - StateRef tmp = new StateRef(); - temp.Address = freqData.GetStats(); - tmp.Values = temp; - // STATE tmp=*U.Stats; - do - { - // tmp.Freq-=(tmp.Freq >> 1) - tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1)); - EscFreq = Utility.URShift(EscFreq, 1); - } while (EscFreq > 1); - model.SubAlloc.freeUnits(freqData.GetStats(), Utility.URShift((OldNS + 1), 1)); - oneState.SetValues(tmp); - model.FoundState.Address = oneState.Address; - return; - } - } - EscFreq -= Utility.URShift(EscFreq, 1); - freqData.IncrementSummFreq(EscFreq); - int n0 = Utility.URShift((OldNS + 1), 1), n1 = Utility.URShift((NumStats + 1), 1); - if (n0 != n1) - { - freqData.SetStats(model.SubAlloc.shrinkUnits(freqData.GetStats(), n0, n1)); - } - model.FoundState.Address = freqData.GetStats(); - } - - internal int getArrayIndex(ModelPPM Model, State rs) - { - PPMContext tempSuffix = getTempPPMContext(Model.SubAlloc.Heap); - tempSuffix.Address = getSuffix(); - int ret = 0; - ret += Model.PrevSuccess; - ret += Model.getNS2BSIndx()[tempSuffix.NumStats - 1]; - ret += Model.HiBitsFlag + 2*Model.getHB2Flag()[rs.Symbol]; - ret += ((Utility.URShift(Model.RunLength, 26)) & 0x20); - return ret; - } - - internal int getMean(int summ, int shift, int round) - { - return (Utility.URShift((summ + (1 << (shift - round))), (shift))); - } - - internal void decodeBinSymbol(ModelPPM model) - { - State rs = tempState1.Initialize(model.Heap); - rs.Address = oneState.Address; // State& - model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol]; - int off1 = rs.Freq - 1; - int off2 = getArrayIndex(model, rs); - int bs = model.BinSumm[off1][off2]; - if (model.Coder.GetCurrentShiftCount(ModelPPM.TOT_BITS) < bs) - { - model.FoundState.Address = rs.Address; - rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); - model.Coder.SubRange.LowCount = 0; - model.Coder.SubRange.HighCount = bs; - bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff); - model.BinSumm[off1][off2] = bs; - model.PrevSuccess = 1; - model.incRunLength(1); - } - else - { - model.Coder.SubRange.LowCount = bs; - bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF; - model.BinSumm[off1][off2] = bs; - model.Coder.SubRange.HighCount = ModelPPM.BIN_SCALE; - model.InitEsc = ExpEscape[Utility.URShift(bs, 10)]; - model.NumMasked = 1; - model.CharMask[rs.Symbol] = model.EscCount; - model.PrevSuccess = 0; - model.FoundState.Address = 0; - } - //int a = 0;//TODO just 4 debugging - } - - // public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2) - // { - // byte[] bytes = model.getSubAlloc().getHeap(); - // int p1 = state1.Address; - // int p2 = state2.Address; - // - // for (int i = 0; i < StatePtr.size; i++) { - // byte temp = bytes[p1+i]; - // bytes[p1+i] = bytes[p2+i]; - // bytes[p2+i] = temp; - // } - // state1.Address=p1); - // state2.Address=p2); - // } - - internal void update1(ModelPPM model, int p) - { - model.FoundState.Address = p; - model.FoundState.IncrementFreq(4); - freqData.IncrementSummFreq(4); - State p0 = tempState3.Initialize(model.Heap); - State p1 = tempState4.Initialize(model.Heap); - p0.Address = p; - p1.Address = p - State.Size; - if (p0.Freq > p1.Freq) - { - State.PPMDSwap(p0, p1); - model.FoundState.Address = p1.Address; - if (p1.Freq > ModelPPM.MAX_FREQ) - rescale(model); - } - } - - internal void update1_0(ModelPPM model, int p) - { - model.FoundState.Address = p; - model.PrevSuccess = 2*model.FoundState.Freq > freqData.SummFreq ? 1 : 0; - model.incRunLength(model.PrevSuccess); - freqData.IncrementSummFreq(4); - model.FoundState.IncrementFreq(4); - if (model.FoundState.Freq > ModelPPM.MAX_FREQ) - rescale(model); - } - - internal bool decodeSymbol2(ModelPPM model) - { - long count; - int hiCnt, i = NumStats - model.NumMasked; - SEE2Context psee2c = makeEscFreq2(model, i); - RangeCoder coder = model.Coder; - // STATE* ps[256], ** pps=ps, * p=U.Stats-1; - State p = tempState1.Initialize(model.Heap); - State temp = tempState2.Initialize(model.Heap); - p.Address = freqData.GetStats() - State.Size; - int pps = 0; - hiCnt = 0; - - do - { - do - { - p.IncrementAddress(); // p++; - } while (model.CharMask[p.Symbol] == model.EscCount); - hiCnt += p.Freq; - ps[pps++] = p.Address; - } while (--i != 0); - coder.SubRange.incScale(hiCnt); - count = coder.CurrentCount; - if (count >= coder.SubRange.Scale) - { - return false; - } - pps = 0; - p.Address = ps[pps]; - if (count < hiCnt) - { - hiCnt = 0; - while ((hiCnt += p.Freq) <= count) - { - p.Address = ps[++pps]; // p=*++pps; - } - coder.SubRange.HighCount = hiCnt; - coder.SubRange.LowCount = hiCnt - p.Freq; - psee2c.update(); - update2(model, p.Address); - } - else - { - coder.SubRange.LowCount = hiCnt; - coder.SubRange.HighCount = coder.SubRange.Scale; - i = NumStats - model.NumMasked; // ->NumMasked; - pps--; - do - { - temp.Address = ps[++pps]; // (*++pps) - model.CharMask[temp.Symbol] = model.EscCount; - } while (--i != 0); - psee2c.incSumm((int) coder.SubRange.Scale); - model.NumMasked = NumStats; - } - return (true); - } - - internal void update2(ModelPPM model, int p) - { - State temp = tempState5.Initialize(model.Heap); - temp.Address = p; - model.FoundState.Address = p; - model.FoundState.IncrementFreq(4); - freqData.IncrementSummFreq(4); - if (temp.Freq > ModelPPM.MAX_FREQ) - { - rescale(model); - } - model.incEscCount(1); - model.RunLength = model.InitRL; - } - - private SEE2Context makeEscFreq2(ModelPPM model, int Diff) - { - SEE2Context psee2c; - int numStats = NumStats; - if (numStats != 256) - { - PPMContext suff = getTempPPMContext(model.Heap); - suff.Address = getSuffix(); - int idx1 = model.getNS2Indx()[Diff - 1]; - int idx2 = 0; - idx2 += ((Diff < suff.NumStats - numStats) ? 1 : 0); - idx2 += 2*((freqData.SummFreq < 11*numStats) ? 1 : 0); - idx2 += 4*((model.NumMasked > Diff) ? 1 : 0); - idx2 += model.HiBitsFlag; - psee2c = model.getSEE2Cont()[idx1][idx2]; - model.Coder.SubRange.Scale = psee2c.Mean; - } - else - { - psee2c = model.DummySEE2Cont; - model.Coder.SubRange.Scale = 1; - } - return psee2c; - } - - internal SEE2Context makeEscFreq(ModelPPM model, int numMasked, out int escFreq) - { - SEE2Context psee2c; - int numStats = NumStats; - int nonMasked = numStats - numMasked; - if (numStats != 256) - { - PPMContext suff = getTempPPMContext(model.Heap); - suff.Address = getSuffix(); - int idx1 = model.getNS2Indx()[nonMasked - 1]; - int idx2 = 0; - idx2 += ((nonMasked < suff.NumStats - numStats) ? 1 : 0); - idx2 += 2*((freqData.SummFreq < 11*numStats) ? 1 : 0); - idx2 += 4*((numMasked > nonMasked) ? 1 : 0); - idx2 += model.HiBitsFlag; - psee2c = model.getSEE2Cont()[idx1][idx2]; - escFreq = psee2c.Mean; - } - else - { - psee2c = model.DummySEE2Cont; - escFreq = 1; - } - return psee2c; - } - - internal bool decodeSymbol1(ModelPPM model) - { - RangeCoder coder = model.Coder; - coder.SubRange.Scale = freqData.SummFreq; - State p = new State(model.Heap); - p.Address = freqData.GetStats(); - int i, HiCnt; - long count = coder.CurrentCount; - if (count >= coder.SubRange.Scale) - { - return false; - } - if (count < (HiCnt = p.Freq)) - { - coder.SubRange.HighCount = HiCnt; - model.PrevSuccess = (2*HiCnt > coder.SubRange.Scale) ? 1 : 0; - model.incRunLength(model.PrevSuccess); - HiCnt += 4; - model.FoundState.Address = p.Address; - model.FoundState.Freq = HiCnt; - freqData.IncrementSummFreq(4); - if (HiCnt > ModelPPM.MAX_FREQ) - { - rescale(model); - } - coder.SubRange.LowCount = 0; - return true; - } - else - { - if (model.FoundState.Address == 0) - { - return (false); - } - } - model.PrevSuccess = 0; - int numStats = NumStats; - i = numStats - 1; - while ((HiCnt += p.IncrementAddress().Freq) <= count) - { - if (--i == 0) - { - model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol]; - coder.SubRange.LowCount = HiCnt; - model.CharMask[p.Symbol] = model.EscCount; - model.NumMasked = numStats; - i = numStats - 1; - model.FoundState.Address = 0; - do - { - model.CharMask[p.DecrementAddress().Symbol] = model.EscCount; - } while (--i != 0); - coder.SubRange.HighCount = coder.SubRange.Scale; - return (true); - } - } - coder.SubRange.LowCount = HiCnt - p.Freq; - coder.SubRange.HighCount = HiCnt; - update1(model, p.Address); - return (true); - } - - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("PPMContext["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(size); - buffer.Append("\n numStats="); - buffer.Append(NumStats); - buffer.Append("\n Suffix="); - buffer.Append(getSuffix()); - buffer.Append("\n freqData="); - buffer.Append(freqData); - buffer.Append("\n oneState="); - buffer.Append(oneState); - buffer.Append("\n]"); - return buffer.ToString(); - } - - static PPMContext() - { - unionSize = System.Math.Max(FreqData.Size, State.Size); - } - } +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class PPMContext : Pointer + { + internal FreqData FreqData + { + get { return freqData; } + + set + { + this.freqData.SummFreq = value.SummFreq; + this.freqData.SetStats(value.GetStats()); + } + } + + public virtual int NumStats + { + get + { + if (Memory != null) + { + numStats = Utility.readShortLittleEndian(Memory, Address) & 0xffff; + } + return numStats; + } + + set + { + this.numStats = value & 0xffff; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address, (short) value); + } + } + } + + //UPGRADE_NOTE: Final was removed from the declaration of 'unionSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + //UPGRADE_NOTE: The initialization of 'unionSize' was moved to static method 'SharpCompress.Unpack.PPM.PPMContext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" + private static readonly int unionSize; + + //UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int size = 2 + unionSize + 4; // 12 + + // ushort NumStats; + private int numStats; // determines if feqData or onstate is used + + // (1==onestate) + + //UPGRADE_NOTE: Final was removed from the declaration of 'freqData '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private FreqData freqData; // -\ + + // |-> union + //UPGRADE_NOTE: Final was removed from the declaration of 'oneState '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State oneState; // -/ + + private int suffix; // pointer ppmcontext + + //UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] ExpEscape = new int[] {25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2}; + + // Temp fields + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState1 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState2 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState3 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState4 = new State(null); + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState5 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private State tempState5 = new State(null); + private PPMContext tempPPMContext = null; + //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal int[] ps = new int[256]; + + public PPMContext(byte[] Memory) + : base(Memory) + { + oneState = new State(Memory); + freqData = new FreqData(Memory); + } + + internal PPMContext Initialize(byte[] mem) + { + oneState.Initialize(mem); + freqData.Initialize(mem); + return base.Initialize(mem); + } + + internal State getOneState() + { + return oneState; + } + + internal void setOneState(StateRef oneState) + { + this.oneState.SetValues(oneState); + } + + internal int getSuffix() + { + if (Memory != null) + { + suffix = Utility.readIntLittleEndian(Memory, Address + 8); + } + return suffix; + } + + internal void setSuffix(PPMContext suffix) + { + setSuffix(suffix.Address); + } + + internal void setSuffix(int suffix) + { + this.suffix = suffix; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address + 8, suffix); + } + } + + internal override int Address + { + get { return base.Address; } + set + { + base.Address = value; + oneState.Address = value + 2; + freqData.Address = value + 2; + } + } + + private PPMContext getTempPPMContext(byte[] Memory) + { + if (tempPPMContext == null) + { + tempPPMContext = new PPMContext(null); + } + return tempPPMContext.Initialize(Memory); + } + + internal int createChild(ModelPPM model, State pStats, StateRef firstState) + { + PPMContext pc = getTempPPMContext(model.SubAlloc.Heap); + pc.Address = model.SubAlloc.allocContext(); + if (pc != null) + { + pc.NumStats = 1; + pc.setOneState(firstState); + pc.setSuffix(this); + pStats.SetSuccessor(pc); + } + return pc.Address; + } + + internal void rescale(ModelPPM model) + { + int OldNS = NumStats, i = NumStats - 1, Adder, EscFreq; + // STATE* p1, * p; + State p1 = new State(model.Heap); + State p = new State(model.Heap); + State temp = new State(model.Heap); + + for (p.Address = model.FoundState.Address; p.Address != freqData.GetStats(); p.DecrementAddress()) + { + temp.Address = p.Address - State.Size; + State.PPMDSwap(p, temp); + } + temp.Address = freqData.GetStats(); + temp.IncrementFreq(4); + freqData.IncrementSummFreq(4); + EscFreq = freqData.SummFreq - p.Freq; + Adder = (model.OrderFall != 0) ? 1 : 0; + p.Freq = Utility.URShift((p.Freq + Adder), 1); + freqData.SummFreq = p.Freq; + do + { + p.IncrementAddress(); + EscFreq -= p.Freq; + p.Freq = Utility.URShift((p.Freq + Adder), 1); + freqData.IncrementSummFreq(p.Freq); + temp.Address = p.Address - State.Size; + if (p.Freq > temp.Freq) + { + p1.Address = p.Address; + StateRef tmp = new StateRef(); + tmp.Values = p1; + State temp2 = new State(model.Heap); + State temp3 = new State(model.Heap); + do + { + // p1[0]=p1[-1]; + temp2.Address = p1.Address - State.Size; + p1.SetValues(temp2); + p1.DecrementAddress(); + temp3.Address = p1.Address - State.Size; + } while (p1.Address != freqData.GetStats() && tmp.Freq > temp3.Freq); + p1.SetValues(tmp); + } + } while (--i != 0); + if (p.Freq == 0) + { + do + { + i++; + p.DecrementAddress(); + } while (p.Freq == 0); + EscFreq += i; + NumStats = NumStats - i; + if (NumStats == 1) + { + StateRef tmp = new StateRef(); + temp.Address = freqData.GetStats(); + tmp.Values = temp; + // STATE tmp=*U.Stats; + do + { + // tmp.Freq-=(tmp.Freq >> 1) + tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1)); + EscFreq = Utility.URShift(EscFreq, 1); + } while (EscFreq > 1); + model.SubAlloc.freeUnits(freqData.GetStats(), Utility.URShift((OldNS + 1), 1)); + oneState.SetValues(tmp); + model.FoundState.Address = oneState.Address; + return; + } + } + EscFreq -= Utility.URShift(EscFreq, 1); + freqData.IncrementSummFreq(EscFreq); + int n0 = Utility.URShift((OldNS + 1), 1), n1 = Utility.URShift((NumStats + 1), 1); + if (n0 != n1) + { + freqData.SetStats(model.SubAlloc.shrinkUnits(freqData.GetStats(), n0, n1)); + } + model.FoundState.Address = freqData.GetStats(); + } + + internal int getArrayIndex(ModelPPM Model, State rs) + { + PPMContext tempSuffix = getTempPPMContext(Model.SubAlloc.Heap); + tempSuffix.Address = getSuffix(); + int ret = 0; + ret += Model.PrevSuccess; + ret += Model.getNS2BSIndx()[tempSuffix.NumStats - 1]; + ret += Model.HiBitsFlag + 2*Model.getHB2Flag()[rs.Symbol]; + ret += ((Utility.URShift(Model.RunLength, 26)) & 0x20); + return ret; + } + + internal int getMean(int summ, int shift, int round) + { + return (Utility.URShift((summ + (1 << (shift - round))), (shift))); + } + + internal void decodeBinSymbol(ModelPPM model) + { + State rs = tempState1.Initialize(model.Heap); + rs.Address = oneState.Address; // State& + model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol]; + int off1 = rs.Freq - 1; + int off2 = getArrayIndex(model, rs); + int bs = model.BinSumm[off1][off2]; + if (model.Coder.GetCurrentShiftCount(ModelPPM.TOT_BITS) < bs) + { + model.FoundState.Address = rs.Address; + rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); + model.Coder.SubRange.LowCount = 0; + model.Coder.SubRange.HighCount = bs; + bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff); + model.BinSumm[off1][off2] = bs; + model.PrevSuccess = 1; + model.incRunLength(1); + } + else + { + model.Coder.SubRange.LowCount = bs; + bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF; + model.BinSumm[off1][off2] = bs; + model.Coder.SubRange.HighCount = ModelPPM.BIN_SCALE; + model.InitEsc = ExpEscape[Utility.URShift(bs, 10)]; + model.NumMasked = 1; + model.CharMask[rs.Symbol] = model.EscCount; + model.PrevSuccess = 0; + model.FoundState.Address = 0; + } + //int a = 0;//TODO just 4 debugging + } + + // public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2) + // { + // byte[] bytes = model.getSubAlloc().getHeap(); + // int p1 = state1.Address; + // int p2 = state2.Address; + // + // for (int i = 0; i < StatePtr.size; i++) { + // byte temp = bytes[p1+i]; + // bytes[p1+i] = bytes[p2+i]; + // bytes[p2+i] = temp; + // } + // state1.Address=p1); + // state2.Address=p2); + // } + + internal void update1(ModelPPM model, int p) + { + model.FoundState.Address = p; + model.FoundState.IncrementFreq(4); + freqData.IncrementSummFreq(4); + State p0 = tempState3.Initialize(model.Heap); + State p1 = tempState4.Initialize(model.Heap); + p0.Address = p; + p1.Address = p - State.Size; + if (p0.Freq > p1.Freq) + { + State.PPMDSwap(p0, p1); + model.FoundState.Address = p1.Address; + if (p1.Freq > ModelPPM.MAX_FREQ) + rescale(model); + } + } + + internal void update1_0(ModelPPM model, int p) + { + model.FoundState.Address = p; + model.PrevSuccess = 2*model.FoundState.Freq > freqData.SummFreq ? 1 : 0; + model.incRunLength(model.PrevSuccess); + freqData.IncrementSummFreq(4); + model.FoundState.IncrementFreq(4); + if (model.FoundState.Freq > ModelPPM.MAX_FREQ) + rescale(model); + } + + internal bool decodeSymbol2(ModelPPM model) + { + long count; + int hiCnt, i = NumStats - model.NumMasked; + SEE2Context psee2c = makeEscFreq2(model, i); + RangeCoder coder = model.Coder; + // STATE* ps[256], ** pps=ps, * p=U.Stats-1; + State p = tempState1.Initialize(model.Heap); + State temp = tempState2.Initialize(model.Heap); + p.Address = freqData.GetStats() - State.Size; + int pps = 0; + hiCnt = 0; + + do + { + do + { + p.IncrementAddress(); // p++; + } while (model.CharMask[p.Symbol] == model.EscCount); + hiCnt += p.Freq; + ps[pps++] = p.Address; + } while (--i != 0); + coder.SubRange.incScale(hiCnt); + count = coder.CurrentCount; + if (count >= coder.SubRange.Scale) + { + return false; + } + pps = 0; + p.Address = ps[pps]; + if (count < hiCnt) + { + hiCnt = 0; + while ((hiCnt += p.Freq) <= count) + { + p.Address = ps[++pps]; // p=*++pps; + } + coder.SubRange.HighCount = hiCnt; + coder.SubRange.LowCount = hiCnt - p.Freq; + psee2c.update(); + update2(model, p.Address); + } + else + { + coder.SubRange.LowCount = hiCnt; + coder.SubRange.HighCount = coder.SubRange.Scale; + i = NumStats - model.NumMasked; // ->NumMasked; + pps--; + do + { + temp.Address = ps[++pps]; // (*++pps) + model.CharMask[temp.Symbol] = model.EscCount; + } while (--i != 0); + psee2c.incSumm((int) coder.SubRange.Scale); + model.NumMasked = NumStats; + } + return (true); + } + + internal void update2(ModelPPM model, int p) + { + State temp = tempState5.Initialize(model.Heap); + temp.Address = p; + model.FoundState.Address = p; + model.FoundState.IncrementFreq(4); + freqData.IncrementSummFreq(4); + if (temp.Freq > ModelPPM.MAX_FREQ) + { + rescale(model); + } + model.incEscCount(1); + model.RunLength = model.InitRL; + } + + private SEE2Context makeEscFreq2(ModelPPM model, int Diff) + { + SEE2Context psee2c; + int numStats = NumStats; + if (numStats != 256) + { + PPMContext suff = getTempPPMContext(model.Heap); + suff.Address = getSuffix(); + int idx1 = model.getNS2Indx()[Diff - 1]; + int idx2 = 0; + idx2 += ((Diff < suff.NumStats - numStats) ? 1 : 0); + idx2 += 2*((freqData.SummFreq < 11*numStats) ? 1 : 0); + idx2 += 4*((model.NumMasked > Diff) ? 1 : 0); + idx2 += model.HiBitsFlag; + psee2c = model.getSEE2Cont()[idx1][idx2]; + model.Coder.SubRange.Scale = psee2c.Mean; + } + else + { + psee2c = model.DummySEE2Cont; + model.Coder.SubRange.Scale = 1; + } + return psee2c; + } + + internal SEE2Context makeEscFreq(ModelPPM model, int numMasked, out int escFreq) + { + SEE2Context psee2c; + int numStats = NumStats; + int nonMasked = numStats - numMasked; + if (numStats != 256) + { + PPMContext suff = getTempPPMContext(model.Heap); + suff.Address = getSuffix(); + int idx1 = model.getNS2Indx()[nonMasked - 1]; + int idx2 = 0; + idx2 += ((nonMasked < suff.NumStats - numStats) ? 1 : 0); + idx2 += 2*((freqData.SummFreq < 11*numStats) ? 1 : 0); + idx2 += 4*((numMasked > nonMasked) ? 1 : 0); + idx2 += model.HiBitsFlag; + psee2c = model.getSEE2Cont()[idx1][idx2]; + escFreq = psee2c.Mean; + } + else + { + psee2c = model.DummySEE2Cont; + escFreq = 1; + } + return psee2c; + } + + internal bool decodeSymbol1(ModelPPM model) + { + RangeCoder coder = model.Coder; + coder.SubRange.Scale = freqData.SummFreq; + State p = new State(model.Heap); + p.Address = freqData.GetStats(); + int i, HiCnt; + long count = coder.CurrentCount; + if (count >= coder.SubRange.Scale) + { + return false; + } + if (count < (HiCnt = p.Freq)) + { + coder.SubRange.HighCount = HiCnt; + model.PrevSuccess = (2*HiCnt > coder.SubRange.Scale) ? 1 : 0; + model.incRunLength(model.PrevSuccess); + HiCnt += 4; + model.FoundState.Address = p.Address; + model.FoundState.Freq = HiCnt; + freqData.IncrementSummFreq(4); + if (HiCnt > ModelPPM.MAX_FREQ) + { + rescale(model); + } + coder.SubRange.LowCount = 0; + return true; + } + else + { + if (model.FoundState.Address == 0) + { + return (false); + } + } + model.PrevSuccess = 0; + int numStats = NumStats; + i = numStats - 1; + while ((HiCnt += p.IncrementAddress().Freq) <= count) + { + if (--i == 0) + { + model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol]; + coder.SubRange.LowCount = HiCnt; + model.CharMask[p.Symbol] = model.EscCount; + model.NumMasked = numStats; + i = numStats - 1; + model.FoundState.Address = 0; + do + { + model.CharMask[p.DecrementAddress().Symbol] = model.EscCount; + } while (--i != 0); + coder.SubRange.HighCount = coder.SubRange.Scale; + return (true); + } + } + coder.SubRange.LowCount = HiCnt - p.Freq; + coder.SubRange.HighCount = HiCnt; + update1(model, p.Address); + return (true); + } + + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("PPMContext["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(size); + buffer.Append("\n numStats="); + buffer.Append(NumStats); + buffer.Append("\n Suffix="); + buffer.Append(getSuffix()); + buffer.Append("\n freqData="); + buffer.Append(freqData); + buffer.Append("\n oneState="); + buffer.Append(oneState); + buffer.Append("\n]"); + return buffer.ToString(); + } + + static PPMContext() + { + unionSize = System.Math.Max(FreqData.Size, State.Size); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/Pointer.cs b/src/SharpCompress/Compressor/PPMd/H/Pointer.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/H/Pointer.cs rename to src/SharpCompress/Compressor/PPMd/H/Pointer.cs index c5230c87..75b3916f 100644 --- a/SharpCompress/Compressor/PPMd/H/Pointer.cs +++ b/src/SharpCompress/Compressor/PPMd/H/Pointer.cs @@ -1,25 +1,25 @@ -namespace SharpCompress.Compressor.PPMd.H -{ - internal abstract class Pointer - { - /// Initialize the object with the array (may be null) - /// the byte array - /// - internal Pointer(byte[] mem) - { - Memory = mem; - } - - internal byte[] Memory { get; private set; } - - internal virtual int Address { get; set; } - - protected T Initialize(byte[] mem) - where T : Pointer - { - Memory = mem; - Address = 0; - return this as T; - } - } +namespace SharpCompress.Compressor.PPMd.H +{ + internal abstract class Pointer + { + /// Initialize the object with the array (may be null) + /// the byte array + /// + internal Pointer(byte[] mem) + { + Memory = mem; + } + + internal byte[] Memory { get; private set; } + + internal virtual int Address { get; set; } + + protected T Initialize(byte[] mem) + where T : Pointer + { + Memory = mem; + Address = 0; + return this as T; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/RangeCoder.cs b/src/SharpCompress/Compressor/PPMd/H/RangeCoder.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/H/RangeCoder.cs rename to src/SharpCompress/Compressor/PPMd/H/RangeCoder.cs index e3b48200..39c11897 100644 --- a/SharpCompress/Compressor/PPMd/H/RangeCoder.cs +++ b/src/SharpCompress/Compressor/PPMd/H/RangeCoder.cs @@ -1,166 +1,166 @@ -using System.Text; -using System.IO; -using SharpCompress.Compressor.Rar; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class RangeCoder - { - internal const int TOP = 1 << 24; - internal const int BOT = 1 << 15; - internal const long UintMask = 0xFFFFffffL; - - // uint low, code, range; - private long low, code, range; - private Unpack unpackRead; - private Stream stream; - - internal RangeCoder(Unpack unpackRead) - { - this.unpackRead = unpackRead; - Init(); - } - - internal RangeCoder(Stream stream) - { - this.stream = stream; - Init(); - } - - private void Init() - { - this.SubRange = new SubRange(); - - low = code = 0L; - range = 0xFFFFffffL; - for (int i = 0; i < 4; i++) - { - code = ((code << 8) | Char) & UintMask; - } - } - - internal int CurrentCount - { - get - { - range = (range/SubRange.Scale) & UintMask; - return (int) ((code - low)/(range)); - } - } - - private long Char - { - get - { - if (unpackRead != null) - return (unpackRead.Char); - if (stream != null) - return stream.ReadByte(); - return -1; - } - } - - internal SubRange SubRange { get; private set; } - - - internal long GetCurrentShiftCount(int SHIFT) - { - range = Utility.URShift(range, SHIFT); - return ((code - low)/(range)) & UintMask; - } - - internal void Decode() - { - low = (low + (range*SubRange.LowCount)) & UintMask; - range = (range*(SubRange.HighCount - SubRange.LowCount)) & UintMask; - } - - internal void AriDecNormalize() - { - // while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true)) - // { - // code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask; - // range = (range << 8)&uintMask; - // low = (low << 8)&uintMask; - // } - - // Rewrote for clarity - bool c2 = false; - while ((low ^ (low + range)) < TOP || (c2 = range < BOT)) - { - if (c2) - { - range = (-low & (BOT - 1)) & UintMask; - c2 = false; - } - code = ((code << 8) | Char) & UintMask; - range = (range << 8) & UintMask; - low = (low << 8) & UintMask; - } - } - - // Debug - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("RangeCoder["); - buffer.Append("\n low="); - buffer.Append(low); - buffer.Append("\n code="); - buffer.Append(code); - buffer.Append("\n range="); - buffer.Append(range); - buffer.Append("\n subrange="); - buffer.Append(SubRange); - buffer.Append("]"); - return buffer.ToString(); - } - } - - internal class SubRange - { - // uint LowCount, HighCount, scale; - private long lowCount, highCount, scale; - - internal void incScale(int dScale) - { - Scale = Scale + dScale; - } - - internal long HighCount - { - get { return highCount; } - - set { this.highCount = value & RangeCoder.UintMask; } - } - - internal long LowCount - { - get { return lowCount & RangeCoder.UintMask; } - - set { this.lowCount = value & RangeCoder.UintMask; } - } - - internal long Scale - { - get { return scale; } - - set { this.scale = value & RangeCoder.UintMask; } - } - - // Debug - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("SubRange["); - buffer.Append("\n lowCount="); - buffer.Append(lowCount); - buffer.Append("\n highCount="); - buffer.Append(highCount); - buffer.Append("\n scale="); - buffer.Append(scale); - buffer.Append("]"); - return buffer.ToString(); - } - } +using System.Text; +using System.IO; +using SharpCompress.Compressor.Rar; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class RangeCoder + { + internal const int TOP = 1 << 24; + internal const int BOT = 1 << 15; + internal const long UintMask = 0xFFFFffffL; + + // uint low, code, range; + private long low, code, range; + private Unpack unpackRead; + private Stream stream; + + internal RangeCoder(Unpack unpackRead) + { + this.unpackRead = unpackRead; + Init(); + } + + internal RangeCoder(Stream stream) + { + this.stream = stream; + Init(); + } + + private void Init() + { + this.SubRange = new SubRange(); + + low = code = 0L; + range = 0xFFFFffffL; + for (int i = 0; i < 4; i++) + { + code = ((code << 8) | Char) & UintMask; + } + } + + internal int CurrentCount + { + get + { + range = (range/SubRange.Scale) & UintMask; + return (int) ((code - low)/(range)); + } + } + + private long Char + { + get + { + if (unpackRead != null) + return (unpackRead.Char); + if (stream != null) + return stream.ReadByte(); + return -1; + } + } + + internal SubRange SubRange { get; private set; } + + + internal long GetCurrentShiftCount(int SHIFT) + { + range = Utility.URShift(range, SHIFT); + return ((code - low)/(range)) & UintMask; + } + + internal void Decode() + { + low = (low + (range*SubRange.LowCount)) & UintMask; + range = (range*(SubRange.HighCount - SubRange.LowCount)) & UintMask; + } + + internal void AriDecNormalize() + { + // while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true)) + // { + // code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask; + // range = (range << 8)&uintMask; + // low = (low << 8)&uintMask; + // } + + // Rewrote for clarity + bool c2 = false; + while ((low ^ (low + range)) < TOP || (c2 = range < BOT)) + { + if (c2) + { + range = (-low & (BOT - 1)) & UintMask; + c2 = false; + } + code = ((code << 8) | Char) & UintMask; + range = (range << 8) & UintMask; + low = (low << 8) & UintMask; + } + } + + // Debug + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("RangeCoder["); + buffer.Append("\n low="); + buffer.Append(low); + buffer.Append("\n code="); + buffer.Append(code); + buffer.Append("\n range="); + buffer.Append(range); + buffer.Append("\n subrange="); + buffer.Append(SubRange); + buffer.Append("]"); + return buffer.ToString(); + } + } + + internal class SubRange + { + // uint LowCount, HighCount, scale; + private long lowCount, highCount, scale; + + internal void incScale(int dScale) + { + Scale = Scale + dScale; + } + + internal long HighCount + { + get { return highCount; } + + set { this.highCount = value & RangeCoder.UintMask; } + } + + internal long LowCount + { + get { return lowCount & RangeCoder.UintMask; } + + set { this.lowCount = value & RangeCoder.UintMask; } + } + + internal long Scale + { + get { return scale; } + + set { this.scale = value & RangeCoder.UintMask; } + } + + // Debug + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("SubRange["); + buffer.Append("\n lowCount="); + buffer.Append(lowCount); + buffer.Append("\n highCount="); + buffer.Append(highCount); + buffer.Append("\n scale="); + buffer.Append(scale); + buffer.Append("]"); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs b/src/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/H/RarMemBlock.cs rename to src/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs index 52f601d8..a295792d 100644 --- a/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs +++ b/src/SharpCompress/Compressor/PPMd/H/RarMemBlock.cs @@ -1,123 +1,123 @@ -namespace SharpCompress.Compressor.PPMd.H -{ - internal class RarMemBlock : Pointer - { - public const int size = 12; - - private int stamp, NU; - - private int next, prev; // Pointer RarMemBlock - - public RarMemBlock(byte[] Memory) - : base(Memory) - { - } - - internal int Stamp - { - get - { - if (Memory != null) - { - stamp = Utility.readShortLittleEndian(Memory, Address) & 0xffff; - } - return stamp; - } - - set - { - this.stamp = value; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address, (short) value); - } - } - } - - internal void InsertAt(RarMemBlock p) - { - RarMemBlock temp = new RarMemBlock(Memory); - SetPrev(p.Address); - temp.Address = GetPrev(); - SetNext(temp.GetNext()); // prev.getNext(); - temp.SetNext(this); // prev.setNext(this); - temp.Address = GetNext(); - temp.SetPrev(this); // next.setPrev(this); - } - - internal void Remove() - { - RarMemBlock temp = new RarMemBlock(Memory); - temp.Address = GetPrev(); - temp.SetNext(GetNext()); // prev.setNext(next); - temp.Address = GetNext(); - temp.SetPrev(GetPrev()); // next.setPrev(prev); - // next = -1; - // prev = -1; - } - - internal int GetNext() - { - if (Memory != null) - { - next = Utility.readIntLittleEndian(Memory, Address + 4); - } - return next; - } - - internal void SetNext(RarMemBlock next) - { - SetNext(next.Address); - } - - internal void SetNext(int next) - { - this.next = next; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address + 4, next); - } - } - - internal int GetNU() - { - if (Memory != null) - { - NU = Utility.readShortLittleEndian(Memory, Address + 2) & 0xffff; - } - return NU; - } - - internal void SetNU(int nu) - { - NU = nu & 0xffff; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address + 2, (short) nu); - } - } - - internal int GetPrev() - { - if (Memory != null) - { - prev = Utility.readIntLittleEndian(Memory, Address + 8); - } - return prev; - } - - internal void SetPrev(RarMemBlock prev) - { - SetPrev(prev.Address); - } - - internal void SetPrev(int prev) - { - this.prev = prev; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address + 8, prev); - } - } - } +namespace SharpCompress.Compressor.PPMd.H +{ + internal class RarMemBlock : Pointer + { + public const int size = 12; + + private int stamp, NU; + + private int next, prev; // Pointer RarMemBlock + + public RarMemBlock(byte[] Memory) + : base(Memory) + { + } + + internal int Stamp + { + get + { + if (Memory != null) + { + stamp = Utility.readShortLittleEndian(Memory, Address) & 0xffff; + } + return stamp; + } + + set + { + this.stamp = value; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address, (short) value); + } + } + } + + internal void InsertAt(RarMemBlock p) + { + RarMemBlock temp = new RarMemBlock(Memory); + SetPrev(p.Address); + temp.Address = GetPrev(); + SetNext(temp.GetNext()); // prev.getNext(); + temp.SetNext(this); // prev.setNext(this); + temp.Address = GetNext(); + temp.SetPrev(this); // next.setPrev(this); + } + + internal void Remove() + { + RarMemBlock temp = new RarMemBlock(Memory); + temp.Address = GetPrev(); + temp.SetNext(GetNext()); // prev.setNext(next); + temp.Address = GetNext(); + temp.SetPrev(GetPrev()); // next.setPrev(prev); + // next = -1; + // prev = -1; + } + + internal int GetNext() + { + if (Memory != null) + { + next = Utility.readIntLittleEndian(Memory, Address + 4); + } + return next; + } + + internal void SetNext(RarMemBlock next) + { + SetNext(next.Address); + } + + internal void SetNext(int next) + { + this.next = next; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address + 4, next); + } + } + + internal int GetNU() + { + if (Memory != null) + { + NU = Utility.readShortLittleEndian(Memory, Address + 2) & 0xffff; + } + return NU; + } + + internal void SetNU(int nu) + { + NU = nu & 0xffff; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address + 2, (short) nu); + } + } + + internal int GetPrev() + { + if (Memory != null) + { + prev = Utility.readIntLittleEndian(Memory, Address + 8); + } + return prev; + } + + internal void SetPrev(RarMemBlock prev) + { + SetPrev(prev.Address); + } + + internal void SetPrev(int prev) + { + this.prev = prev; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address + 8, prev); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/RarNode.cs b/src/SharpCompress/Compressor/PPMd/H/RarNode.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/H/RarNode.cs rename to src/SharpCompress/Compressor/PPMd/H/RarNode.cs index 2369fb5a..7f503a00 100644 --- a/SharpCompress/Compressor/PPMd/H/RarNode.cs +++ b/src/SharpCompress/Compressor/PPMd/H/RarNode.cs @@ -1,53 +1,53 @@ -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class RarNode : Pointer - { - private int next; //rarnode pointer - - public const int size = 4; - - public RarNode(byte[] Memory) - : base(Memory) - { - } - - internal int GetNext() - { - if (Memory != null) - { - next = Utility.readIntLittleEndian(Memory, Address); - } - return next; - } - - internal void SetNext(RarNode next) - { - SetNext(next.Address); - } - - internal void SetNext(int next) - { - this.next = next; - if (Memory != null) - { - Utility.WriteLittleEndian(Memory, Address, next); - } - } - - public override string ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("State["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(size); - buffer.Append("\n next="); - buffer.Append(GetNext()); - buffer.Append("\n]"); - return buffer.ToString(); - } - } +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class RarNode : Pointer + { + private int next; //rarnode pointer + + public const int size = 4; + + public RarNode(byte[] Memory) + : base(Memory) + { + } + + internal int GetNext() + { + if (Memory != null) + { + next = Utility.readIntLittleEndian(Memory, Address); + } + return next; + } + + internal void SetNext(RarNode next) + { + SetNext(next.Address); + } + + internal void SetNext(int next) + { + this.next = next; + if (Memory != null) + { + Utility.WriteLittleEndian(Memory, Address, next); + } + } + + public override string ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("State["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(size); + buffer.Append("\n next="); + buffer.Append(GetNext()); + buffer.Append("\n]"); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/SEE2Context.cs b/src/SharpCompress/Compressor/PPMd/H/SEE2Context.cs similarity index 95% rename from SharpCompress/Compressor/PPMd/H/SEE2Context.cs rename to src/SharpCompress/Compressor/PPMd/H/SEE2Context.cs index c9688124..a5aabe10 100644 --- a/SharpCompress/Compressor/PPMd/H/SEE2Context.cs +++ b/src/SharpCompress/Compressor/PPMd/H/SEE2Context.cs @@ -1,89 +1,89 @@ -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class SEE2Context - { - public virtual int Mean - { - get - { - int retVal = Utility.URShift(summ, shift); - summ -= retVal; - return retVal + ((retVal == 0) ? 1 : 0); - } - } - - public virtual int Count - { - get { return count; } - - set { this.count = value & 0xff; } - } - - public virtual int Shift - { - get { return shift; } - - set { this.shift = value & 0xff; } - } - - public virtual int Summ - { - get { return summ; } - - set { this.summ = value & 0xffff; } - } - - public const int size = 4; - - // ushort Summ; - private int summ; - - // byte Shift; - private int shift; - - // byte Count; - private int count; - - public void Initialize(int initVal) - { - shift = (ModelPPM.PERIOD_BITS - 4) & 0xff; - summ = (initVal << shift) & 0xffff; - count = 4; - } - - public virtual void update() - { - if (shift < ModelPPM.PERIOD_BITS && --count == 0) - { - summ += summ; - count = (3 << shift++); - } - summ &= 0xffff; - count &= 0xff; - shift &= 0xff; - } - - public virtual void incSumm(int dSumm) - { - Summ = Summ + dSumm; - } - - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("SEE2Context["); - buffer.Append("\n size="); - buffer.Append(size); - buffer.Append("\n summ="); - buffer.Append(summ); - buffer.Append("\n shift="); - buffer.Append(shift); - buffer.Append("\n count="); - buffer.Append(count); - buffer.Append("\n]"); - return buffer.ToString(); - } - } +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class SEE2Context + { + public virtual int Mean + { + get + { + int retVal = Utility.URShift(summ, shift); + summ -= retVal; + return retVal + ((retVal == 0) ? 1 : 0); + } + } + + public virtual int Count + { + get { return count; } + + set { this.count = value & 0xff; } + } + + public virtual int Shift + { + get { return shift; } + + set { this.shift = value & 0xff; } + } + + public virtual int Summ + { + get { return summ; } + + set { this.summ = value & 0xffff; } + } + + public const int size = 4; + + // ushort Summ; + private int summ; + + // byte Shift; + private int shift; + + // byte Count; + private int count; + + public void Initialize(int initVal) + { + shift = (ModelPPM.PERIOD_BITS - 4) & 0xff; + summ = (initVal << shift) & 0xffff; + count = 4; + } + + public virtual void update() + { + if (shift < ModelPPM.PERIOD_BITS && --count == 0) + { + summ += summ; + count = (3 << shift++); + } + summ &= 0xffff; + count &= 0xff; + shift &= 0xff; + } + + public virtual void incSumm(int dSumm) + { + Summ = Summ + dSumm; + } + + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("SEE2Context["); + buffer.Append("\n size="); + buffer.Append(size); + buffer.Append("\n summ="); + buffer.Append(summ); + buffer.Append("\n shift="); + buffer.Append(shift); + buffer.Append("\n count="); + buffer.Append(count); + buffer.Append("\n]"); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/State.cs b/src/SharpCompress/Compressor/PPMd/H/State.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/H/State.cs rename to src/SharpCompress/Compressor/PPMd/H/State.cs index a459321e..20f616d7 100644 --- a/SharpCompress/Compressor/PPMd/H/State.cs +++ b/src/SharpCompress/Compressor/PPMd/H/State.cs @@ -1,107 +1,107 @@ -using System; -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class State : Pointer - { - internal const int Size = 6; - - internal State(byte[] Memory) - : base(Memory) - { - } - - internal int Symbol - { - get { return Memory[Address] & 0xff; } - - set { Memory[Address] = (byte) value; } - } - - internal int Freq - { - get { return Memory[Address + 1] & 0xff; } - - set { Memory[Address + 1] = (byte) value; } - } - - internal State Initialize(byte[] mem) - { - return base.Initialize(mem); - } - - internal void IncrementFreq(int dFreq) - { - Memory[Address + 1] = (byte) (Memory[Address + 1] + dFreq); - } - - internal int GetSuccessor() - { - return Utility.readIntLittleEndian(Memory, Address + 2); - } - - internal void SetSuccessor(PPMContext successor) - { - SetSuccessor(successor.Address); - } - - internal void SetSuccessor(int successor) - { - Utility.WriteLittleEndian(Memory, Address + 2, successor); - } - - internal void SetValues(StateRef state) - { - Symbol = state.Symbol; - Freq = state.Freq; - SetSuccessor(state.GetSuccessor()); - } - - internal void SetValues(State ptr) - { - Array.Copy(ptr.Memory, ptr.Address, Memory, Address, Size); - } - - internal State DecrementAddress() - { - Address = Address - Size; - return this; - } - - internal State IncrementAddress() - { - Address = Address + Size; - return this; - } - - internal static void PPMDSwap(State ptr1, State ptr2) - { - byte[] mem1 = ptr1.Memory, mem2 = ptr2.Memory; - for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < Size; i++, pos1++, pos2++) - { - byte temp = mem1[pos1]; - mem1[pos1] = mem2[pos2]; - mem2[pos2] = temp; - } - } - - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("State["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(Size); - buffer.Append("\n symbol="); - buffer.Append(Symbol); - buffer.Append("\n freq="); - buffer.Append(Freq); - buffer.Append("\n successor="); - buffer.Append(GetSuccessor()); - buffer.Append("\n]"); - return buffer.ToString(); - } - } +using System; +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class State : Pointer + { + internal const int Size = 6; + + internal State(byte[] Memory) + : base(Memory) + { + } + + internal int Symbol + { + get { return Memory[Address] & 0xff; } + + set { Memory[Address] = (byte) value; } + } + + internal int Freq + { + get { return Memory[Address + 1] & 0xff; } + + set { Memory[Address + 1] = (byte) value; } + } + + internal State Initialize(byte[] mem) + { + return base.Initialize(mem); + } + + internal void IncrementFreq(int dFreq) + { + Memory[Address + 1] = (byte) (Memory[Address + 1] + dFreq); + } + + internal int GetSuccessor() + { + return Utility.readIntLittleEndian(Memory, Address + 2); + } + + internal void SetSuccessor(PPMContext successor) + { + SetSuccessor(successor.Address); + } + + internal void SetSuccessor(int successor) + { + Utility.WriteLittleEndian(Memory, Address + 2, successor); + } + + internal void SetValues(StateRef state) + { + Symbol = state.Symbol; + Freq = state.Freq; + SetSuccessor(state.GetSuccessor()); + } + + internal void SetValues(State ptr) + { + Array.Copy(ptr.Memory, ptr.Address, Memory, Address, Size); + } + + internal State DecrementAddress() + { + Address = Address - Size; + return this; + } + + internal State IncrementAddress() + { + Address = Address + Size; + return this; + } + + internal static void PPMDSwap(State ptr1, State ptr2) + { + byte[] mem1 = ptr1.Memory, mem2 = ptr2.Memory; + for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < Size; i++, pos1++, pos2++) + { + byte temp = mem1[pos1]; + mem1[pos1] = mem2[pos2]; + mem2[pos2] = temp; + } + } + + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("State["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(Size); + buffer.Append("\n symbol="); + buffer.Append(Symbol); + buffer.Append("\n freq="); + buffer.Append(Freq); + buffer.Append("\n successor="); + buffer.Append(GetSuccessor()); + buffer.Append("\n]"); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/StateRef.cs b/src/SharpCompress/Compressor/PPMd/H/StateRef.cs similarity index 95% rename from SharpCompress/Compressor/PPMd/H/StateRef.cs rename to src/SharpCompress/Compressor/PPMd/H/StateRef.cs index ee2eb37b..4f9b9d75 100644 --- a/SharpCompress/Compressor/PPMd/H/StateRef.cs +++ b/src/SharpCompress/Compressor/PPMd/H/StateRef.cs @@ -1,77 +1,77 @@ -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class StateRef - { - private int symbol; - - private int freq; - - private int successor; // pointer ppmcontext - - internal int Symbol - { - get { return symbol; } - - set { this.symbol = value & 0xff; } - } - - internal int Freq - { - get { return freq; } - - set { this.freq = value & 0xff; } - } - - internal State Values - { - set - { - Freq = value.Freq; - SetSuccessor(value.GetSuccessor()); - Symbol = value.Symbol; - } - } - - - public virtual void IncrementFreq(int dFreq) - { - freq = (freq + dFreq) & 0xff; - } - - public virtual void DecrementFreq(int dFreq) - { - freq = (freq - dFreq) & 0xff; - } - - public virtual int GetSuccessor() - { - return successor; - } - - public virtual void SetSuccessor(PPMContext successor) - { - SetSuccessor(successor.Address); - } - - public virtual void SetSuccessor(int successor) - { - this.successor = successor; - } - - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("State["); - buffer.Append("\n symbol="); - buffer.Append(Symbol); - buffer.Append("\n freq="); - buffer.Append(Freq); - buffer.Append("\n successor="); - buffer.Append(GetSuccessor()); - buffer.Append("\n]"); - return buffer.ToString(); - } - } +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class StateRef + { + private int symbol; + + private int freq; + + private int successor; // pointer ppmcontext + + internal int Symbol + { + get { return symbol; } + + set { this.symbol = value & 0xff; } + } + + internal int Freq + { + get { return freq; } + + set { this.freq = value & 0xff; } + } + + internal State Values + { + set + { + Freq = value.Freq; + SetSuccessor(value.GetSuccessor()); + Symbol = value.Symbol; + } + } + + + public virtual void IncrementFreq(int dFreq) + { + freq = (freq + dFreq) & 0xff; + } + + public virtual void DecrementFreq(int dFreq) + { + freq = (freq - dFreq) & 0xff; + } + + public virtual int GetSuccessor() + { + return successor; + } + + public virtual void SetSuccessor(PPMContext successor) + { + SetSuccessor(successor.Address); + } + + public virtual void SetSuccessor(int successor) + { + this.successor = successor; + } + + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("State["); + buffer.Append("\n symbol="); + buffer.Append(Symbol); + buffer.Append("\n freq="); + buffer.Append(Freq); + buffer.Append("\n successor="); + buffer.Append(GetSuccessor()); + buffer.Append("\n]"); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/H/SubAllocator.cs b/src/SharpCompress/Compressor/PPMd/H/SubAllocator.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/H/SubAllocator.cs rename to src/SharpCompress/Compressor/PPMd/H/SubAllocator.cs index dd209cb7..8b5c6e57 100644 --- a/SharpCompress/Compressor/PPMd/H/SubAllocator.cs +++ b/src/SharpCompress/Compressor/PPMd/H/SubAllocator.cs @@ -1,466 +1,466 @@ -using System; -using System.Text; - -namespace SharpCompress.Compressor.PPMd.H -{ - internal class SubAllocator - { - public virtual int FakeUnitsStart - { - get { return fakeUnitsStart; } - - set { this.fakeUnitsStart = value; } - } - - public virtual int HeapEnd - { - get { return heapEnd; } - } - - public virtual int PText - { - get { return pText; } - - set { pText = value; } - } - - public virtual int UnitsStart - { - get { return unitsStart; } - - set { this.unitsStart = value; } - } - - public virtual byte[] Heap - { - get { return heap; } - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'N4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public const int N1 = 4; - public const int N2 = 4; - public const int N3 = 4; - public static readonly int N4 = (128 + 3 - 1*N1 - 2*N2 - 3*N3)/4; - - //UPGRADE_NOTE: Final was removed from the declaration of 'N_INDEXES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int N_INDEXES = N1 + N2 + N3 + N4; - - //UPGRADE_NOTE: Final was removed from the declaration of 'UNIT_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: The initialization of 'UNIT_SIZE' was moved to static method 'SharpCompress.Unpack.PPM.SubAllocator'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" - public static readonly int UNIT_SIZE; - - public const int FIXED_UNIT_SIZE = 12; - - private int subAllocatorSize; - - // byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; - private int[] indx2Units = new int[N_INDEXES]; - private int[] units2Indx = new int[128]; - private int glueCount; - - // byte *HeapStart,*LoUnit, *HiUnit; - private int heapStart, loUnit, hiUnit; - - //UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private RarNode[] freeList = new RarNode[N_INDEXES]; - - // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; - private int pText, unitsStart, heapEnd, fakeUnitsStart; - - private byte[] heap; - - private int freeListPos; - - private int tempMemBlockPos; - - // Temp fields - private RarNode tempRarNode = null; - private RarMemBlock tempRarMemBlock1 = null; - private RarMemBlock tempRarMemBlock2 = null; - private RarMemBlock tempRarMemBlock3 = null; - - public SubAllocator() - { - clean(); - } - - public virtual void clean() - { - subAllocatorSize = 0; - } - - private void insertNode(int p, int indx) - { - RarNode temp = tempRarNode; - temp.Address = p; - temp.SetNext(freeList[indx].GetNext()); - freeList[indx].SetNext(temp); - } - - public virtual void incPText() - { - pText++; - } - - private int removeNode(int indx) - { - int retVal = freeList[indx].GetNext(); - RarNode temp = tempRarNode; - temp.Address = retVal; - freeList[indx].SetNext(temp.GetNext()); - return retVal; - } - - private int U2B(int NU) - { - return UNIT_SIZE*NU; - } - - /* memblockptr */ - - private int MBPtr(int BasePtr, int Items) - { - return (BasePtr + U2B(Items)); - } - - private void splitBlock(int pv, int oldIndx, int newIndx) - { - int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx]; - int p = pv + U2B(indx2Units[newIndx]); - if (indx2Units[i = units2Indx[uDiff - 1]] != uDiff) - { - insertNode(p, --i); - p += U2B(i = indx2Units[i]); - uDiff -= i; - } - insertNode(p, units2Indx[uDiff - 1]); - } - - public virtual void stopSubAllocator() - { - if (subAllocatorSize != 0) - { - subAllocatorSize = 0; - //ArrayFactory.BYTES_FACTORY.recycle(heap); - heap = null; - heapStart = 1; - // rarfree(HeapStart); - // Free temp fields - tempRarNode = null; - tempRarMemBlock1 = null; - tempRarMemBlock2 = null; - tempRarMemBlock3 = null; - } - } - - public virtual int GetAllocatedMemory() - { - return subAllocatorSize; - } - - - public virtual bool startSubAllocator(int SASize) - { - int t = SASize; - if (subAllocatorSize == t) - { - return true; - } - stopSubAllocator(); - int allocSize = t/FIXED_UNIT_SIZE*UNIT_SIZE + UNIT_SIZE; - - // adding space for freelist (needed for poiters) - // 1+ for null pointer - int realAllocSize = 1 + allocSize + 4*N_INDEXES; - // adding space for an additional memblock - tempMemBlockPos = realAllocSize; - realAllocSize += RarMemBlock.size; - - heap = new byte[realAllocSize]; - heapStart = 1; - heapEnd = heapStart + allocSize - UNIT_SIZE; - subAllocatorSize = t; - // Bug fixed - freeListPos = heapStart + allocSize; - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - //assert(realAllocSize - tempMemBlockPos == RarMemBlock.size): realAllocSize - //+ + tempMemBlockPos + + RarMemBlock.size; - - // Init freeList - for (int i = 0, pos = freeListPos; i < freeList.Length; i++, pos += RarNode.size) - { - freeList[i] = new RarNode(heap); - freeList[i].Address = pos; - } - - // Init temp fields - tempRarNode = new RarNode(heap); - tempRarMemBlock1 = new RarMemBlock(heap); - tempRarMemBlock2 = new RarMemBlock(heap); - tempRarMemBlock3 = new RarMemBlock(heap); - - return true; - } - - private void glueFreeBlocks() - { - RarMemBlock s0 = tempRarMemBlock1; - s0.Address = tempMemBlockPos; - RarMemBlock p = tempRarMemBlock2; - RarMemBlock p1 = tempRarMemBlock3; - int i, k, sz; - if (loUnit != hiUnit) - { - heap[loUnit] = 0; - } - for (i = 0, s0.SetPrev(s0), s0.SetNext(s0); i < N_INDEXES; i++) - { - while (freeList[i].GetNext() != 0) - { - p.Address = removeNode(i); // =(RAR_MEM_BLK*)RemoveNode(i); - p.InsertAt(s0); // p->insertAt(&s0); - p.Stamp = 0xFFFF; // p->Stamp=0xFFFF; - p.SetNU(indx2Units[i]); // p->NU=Indx2Units[i]; - } - } - for (p.Address = s0.GetNext(); p.Address != s0.Address; p.Address = p.GetNext()) - { - // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU - // < 0x10000) - // Bug fixed - p1.Address = MBPtr(p.Address, p.GetNU()); - while (p1.Stamp == 0xFFFF && p.GetNU() + p1.GetNU() < 0x10000) - { - p1.Remove(); - p.SetNU(p.GetNU() + p1.GetNU()); // ->NU += p1->NU; - p1.Address = MBPtr(p.Address, p.GetNU()); - } - } - // while ((p=s0.next) != &s0) - // Bug fixed - p.Address = s0.GetNext(); - while (p.Address != s0.Address) - { - for (p.Remove(), sz = p.GetNU(); sz > 128; sz -= 128, p.Address = MBPtr(p.Address, 128)) - { - insertNode(p.Address, N_INDEXES - 1); - } - if (indx2Units[i = units2Indx[sz - 1]] != sz) - { - k = sz - indx2Units[--i]; - insertNode(MBPtr(p.Address, sz - k), k - 1); - } - insertNode(p.Address, i); - p.Address = s0.GetNext(); - } - } - - private int allocUnitsRare(int indx) - { - if (glueCount == 0) - { - glueCount = 255; - glueFreeBlocks(); - if (freeList[indx].GetNext() != 0) - { - return removeNode(indx); - } - } - int i = indx; - do - { - if (++i == N_INDEXES) - { - glueCount--; - i = U2B(indx2Units[indx]); - int j = FIXED_UNIT_SIZE*indx2Units[indx]; - if (fakeUnitsStart - pText > j) - { - fakeUnitsStart -= j; - unitsStart -= i; - return unitsStart; - } - return (0); - } - } while (freeList[i].GetNext() == 0); - int retVal = removeNode(i); - splitBlock(retVal, i, indx); - return retVal; - } - - public virtual int allocUnits(int NU) - { - int indx = units2Indx[NU - 1]; - if (freeList[indx].GetNext() != 0) - { - return removeNode(indx); - } - int retVal = loUnit; - loUnit += U2B(indx2Units[indx]); - if (loUnit <= hiUnit) - { - return retVal; - } - loUnit -= U2B(indx2Units[indx]); - return allocUnitsRare(indx); - } - - public virtual int allocContext() - { - if (hiUnit != loUnit) - return (hiUnit -= UNIT_SIZE); - if (freeList[0].GetNext() != 0) - { - return removeNode(0); - } - return allocUnitsRare(0); - } - - public virtual int expandUnits(int oldPtr, int OldNU) - { - int i0 = units2Indx[OldNU - 1]; - int i1 = units2Indx[OldNU - 1 + 1]; - if (i0 == i1) - { - return oldPtr; - } - int ptr = allocUnits(OldNU + 1); - if (ptr != 0) - { - // memcpy(ptr,OldPtr,U2B(OldNU)); - Array.Copy(heap, oldPtr, heap, ptr, U2B(OldNU)); - insertNode(oldPtr, i0); - } - return ptr; - } - - public virtual int shrinkUnits(int oldPtr, int oldNU, int newNU) - { - // System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " + - // OldNU + ", " + NewNU + ")"); - int i0 = units2Indx[oldNU - 1]; - int i1 = units2Indx[newNU - 1]; - if (i0 == i1) - { - return oldPtr; - } - if (freeList[i1].GetNext() != 0) - { - int ptr = removeNode(i1); - // memcpy(ptr,OldPtr,U2B(NewNU)); - // for (int i = 0; i < U2B(NewNU); i++) { - // heap[ptr + i] = heap[OldPtr + i]; - // } - Array.Copy(heap, oldPtr, heap, ptr, U2B(newNU)); - insertNode(oldPtr, i0); - return ptr; - } - else - { - splitBlock(oldPtr, i0, i1); - return oldPtr; - } - } - - public virtual void freeUnits(int ptr, int OldNU) - { - insertNode(ptr, units2Indx[OldNU - 1]); - } - - public virtual void decPText(int dPText) - { - PText = PText - dPText; - } - - public virtual void initSubAllocator() - { - int i, k; - Utility.Fill(heap, freeListPos, freeListPos + sizeOfFreeList(), (byte) 0); - - pText = heapStart; - - int size2 = FIXED_UNIT_SIZE*(subAllocatorSize/8/FIXED_UNIT_SIZE*7); - int realSize2 = size2/FIXED_UNIT_SIZE*UNIT_SIZE; - int size1 = subAllocatorSize - size2; - int realSize1 = size1/FIXED_UNIT_SIZE*UNIT_SIZE + size1%FIXED_UNIT_SIZE; - hiUnit = heapStart + subAllocatorSize; - loUnit = unitsStart = heapStart + realSize1; - fakeUnitsStart = heapStart + size1; - hiUnit = loUnit + realSize2; - - for (i = 0, k = 1; i < N1; i++, k += 1) - { - indx2Units[i] = k & 0xff; - } - for (k++; i < N1 + N2; i++, k += 2) - { - indx2Units[i] = k & 0xff; - } - for (k++; i < N1 + N2 + N3; i++, k += 3) - { - indx2Units[i] = k & 0xff; - } - for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4) - { - indx2Units[i] = k & 0xff; - } - - for (glueCount = 0, k = 0, i = 0; k < 128; k++) - { - i += ((indx2Units[i] < (k + 1)) ? 1 : 0); - units2Indx[k] = i & 0xff; - } - } - - private int sizeOfFreeList() - { - return freeList.Length*RarNode.size; - } - - // Debug - // public void dumpHeap() { - // File file = new File("P:\\test\\heapdumpj"); - // OutputStream out = null; - // try { - // out = new FileOutputStream(file); - // out.write(heap, heapStart, heapEnd - heapStart); - // out.flush(); - // System.out.println("Heap dumped to " + file.getAbsolutePath()); - // } - // catch (IOException e) { - // e.printStackTrace(); - // } - // finally { - // FileUtil.close(out); - // } - // } - - // Debug - public override System.String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("SubAllocator["); - buffer.Append("\n subAllocatorSize="); - buffer.Append(subAllocatorSize); - buffer.Append("\n glueCount="); - buffer.Append(glueCount); - buffer.Append("\n heapStart="); - buffer.Append(heapStart); - buffer.Append("\n loUnit="); - buffer.Append(loUnit); - buffer.Append("\n hiUnit="); - buffer.Append(hiUnit); - buffer.Append("\n pText="); - buffer.Append(pText); - buffer.Append("\n unitsStart="); - buffer.Append(unitsStart); - buffer.Append("\n]"); - return buffer.ToString(); - } - - static SubAllocator() - { - UNIT_SIZE = System.Math.Max(PPMContext.size, RarMemBlock.size); - } - } +using System; +using System.Text; + +namespace SharpCompress.Compressor.PPMd.H +{ + internal class SubAllocator + { + public virtual int FakeUnitsStart + { + get { return fakeUnitsStart; } + + set { this.fakeUnitsStart = value; } + } + + public virtual int HeapEnd + { + get { return heapEnd; } + } + + public virtual int PText + { + get { return pText; } + + set { pText = value; } + } + + public virtual int UnitsStart + { + get { return unitsStart; } + + set { this.unitsStart = value; } + } + + public virtual byte[] Heap + { + get { return heap; } + } + + //UPGRADE_NOTE: Final was removed from the declaration of 'N4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public const int N1 = 4; + public const int N2 = 4; + public const int N3 = 4; + public static readonly int N4 = (128 + 3 - 1*N1 - 2*N2 - 3*N3)/4; + + //UPGRADE_NOTE: Final was removed from the declaration of 'N_INDEXES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int N_INDEXES = N1 + N2 + N3 + N4; + + //UPGRADE_NOTE: Final was removed from the declaration of 'UNIT_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + //UPGRADE_NOTE: The initialization of 'UNIT_SIZE' was moved to static method 'SharpCompress.Unpack.PPM.SubAllocator'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" + public static readonly int UNIT_SIZE; + + public const int FIXED_UNIT_SIZE = 12; + + private int subAllocatorSize; + + // byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; + private int[] indx2Units = new int[N_INDEXES]; + private int[] units2Indx = new int[128]; + private int glueCount; + + // byte *HeapStart,*LoUnit, *HiUnit; + private int heapStart, loUnit, hiUnit; + + //UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private RarNode[] freeList = new RarNode[N_INDEXES]; + + // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; + private int pText, unitsStart, heapEnd, fakeUnitsStart; + + private byte[] heap; + + private int freeListPos; + + private int tempMemBlockPos; + + // Temp fields + private RarNode tempRarNode = null; + private RarMemBlock tempRarMemBlock1 = null; + private RarMemBlock tempRarMemBlock2 = null; + private RarMemBlock tempRarMemBlock3 = null; + + public SubAllocator() + { + clean(); + } + + public virtual void clean() + { + subAllocatorSize = 0; + } + + private void insertNode(int p, int indx) + { + RarNode temp = tempRarNode; + temp.Address = p; + temp.SetNext(freeList[indx].GetNext()); + freeList[indx].SetNext(temp); + } + + public virtual void incPText() + { + pText++; + } + + private int removeNode(int indx) + { + int retVal = freeList[indx].GetNext(); + RarNode temp = tempRarNode; + temp.Address = retVal; + freeList[indx].SetNext(temp.GetNext()); + return retVal; + } + + private int U2B(int NU) + { + return UNIT_SIZE*NU; + } + + /* memblockptr */ + + private int MBPtr(int BasePtr, int Items) + { + return (BasePtr + U2B(Items)); + } + + private void splitBlock(int pv, int oldIndx, int newIndx) + { + int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx]; + int p = pv + U2B(indx2Units[newIndx]); + if (indx2Units[i = units2Indx[uDiff - 1]] != uDiff) + { + insertNode(p, --i); + p += U2B(i = indx2Units[i]); + uDiff -= i; + } + insertNode(p, units2Indx[uDiff - 1]); + } + + public virtual void stopSubAllocator() + { + if (subAllocatorSize != 0) + { + subAllocatorSize = 0; + //ArrayFactory.BYTES_FACTORY.recycle(heap); + heap = null; + heapStart = 1; + // rarfree(HeapStart); + // Free temp fields + tempRarNode = null; + tempRarMemBlock1 = null; + tempRarMemBlock2 = null; + tempRarMemBlock3 = null; + } + } + + public virtual int GetAllocatedMemory() + { + return subAllocatorSize; + } + + + public virtual bool startSubAllocator(int SASize) + { + int t = SASize; + if (subAllocatorSize == t) + { + return true; + } + stopSubAllocator(); + int allocSize = t/FIXED_UNIT_SIZE*UNIT_SIZE + UNIT_SIZE; + + // adding space for freelist (needed for poiters) + // 1+ for null pointer + int realAllocSize = 1 + allocSize + 4*N_INDEXES; + // adding space for an additional memblock + tempMemBlockPos = realAllocSize; + realAllocSize += RarMemBlock.size; + + heap = new byte[realAllocSize]; + heapStart = 1; + heapEnd = heapStart + allocSize - UNIT_SIZE; + subAllocatorSize = t; + // Bug fixed + freeListPos = heapStart + allocSize; + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + //assert(realAllocSize - tempMemBlockPos == RarMemBlock.size): realAllocSize + //+ + tempMemBlockPos + + RarMemBlock.size; + + // Init freeList + for (int i = 0, pos = freeListPos; i < freeList.Length; i++, pos += RarNode.size) + { + freeList[i] = new RarNode(heap); + freeList[i].Address = pos; + } + + // Init temp fields + tempRarNode = new RarNode(heap); + tempRarMemBlock1 = new RarMemBlock(heap); + tempRarMemBlock2 = new RarMemBlock(heap); + tempRarMemBlock3 = new RarMemBlock(heap); + + return true; + } + + private void glueFreeBlocks() + { + RarMemBlock s0 = tempRarMemBlock1; + s0.Address = tempMemBlockPos; + RarMemBlock p = tempRarMemBlock2; + RarMemBlock p1 = tempRarMemBlock3; + int i, k, sz; + if (loUnit != hiUnit) + { + heap[loUnit] = 0; + } + for (i = 0, s0.SetPrev(s0), s0.SetNext(s0); i < N_INDEXES; i++) + { + while (freeList[i].GetNext() != 0) + { + p.Address = removeNode(i); // =(RAR_MEM_BLK*)RemoveNode(i); + p.InsertAt(s0); // p->insertAt(&s0); + p.Stamp = 0xFFFF; // p->Stamp=0xFFFF; + p.SetNU(indx2Units[i]); // p->NU=Indx2Units[i]; + } + } + for (p.Address = s0.GetNext(); p.Address != s0.Address; p.Address = p.GetNext()) + { + // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU + // < 0x10000) + // Bug fixed + p1.Address = MBPtr(p.Address, p.GetNU()); + while (p1.Stamp == 0xFFFF && p.GetNU() + p1.GetNU() < 0x10000) + { + p1.Remove(); + p.SetNU(p.GetNU() + p1.GetNU()); // ->NU += p1->NU; + p1.Address = MBPtr(p.Address, p.GetNU()); + } + } + // while ((p=s0.next) != &s0) + // Bug fixed + p.Address = s0.GetNext(); + while (p.Address != s0.Address) + { + for (p.Remove(), sz = p.GetNU(); sz > 128; sz -= 128, p.Address = MBPtr(p.Address, 128)) + { + insertNode(p.Address, N_INDEXES - 1); + } + if (indx2Units[i = units2Indx[sz - 1]] != sz) + { + k = sz - indx2Units[--i]; + insertNode(MBPtr(p.Address, sz - k), k - 1); + } + insertNode(p.Address, i); + p.Address = s0.GetNext(); + } + } + + private int allocUnitsRare(int indx) + { + if (glueCount == 0) + { + glueCount = 255; + glueFreeBlocks(); + if (freeList[indx].GetNext() != 0) + { + return removeNode(indx); + } + } + int i = indx; + do + { + if (++i == N_INDEXES) + { + glueCount--; + i = U2B(indx2Units[indx]); + int j = FIXED_UNIT_SIZE*indx2Units[indx]; + if (fakeUnitsStart - pText > j) + { + fakeUnitsStart -= j; + unitsStart -= i; + return unitsStart; + } + return (0); + } + } while (freeList[i].GetNext() == 0); + int retVal = removeNode(i); + splitBlock(retVal, i, indx); + return retVal; + } + + public virtual int allocUnits(int NU) + { + int indx = units2Indx[NU - 1]; + if (freeList[indx].GetNext() != 0) + { + return removeNode(indx); + } + int retVal = loUnit; + loUnit += U2B(indx2Units[indx]); + if (loUnit <= hiUnit) + { + return retVal; + } + loUnit -= U2B(indx2Units[indx]); + return allocUnitsRare(indx); + } + + public virtual int allocContext() + { + if (hiUnit != loUnit) + return (hiUnit -= UNIT_SIZE); + if (freeList[0].GetNext() != 0) + { + return removeNode(0); + } + return allocUnitsRare(0); + } + + public virtual int expandUnits(int oldPtr, int OldNU) + { + int i0 = units2Indx[OldNU - 1]; + int i1 = units2Indx[OldNU - 1 + 1]; + if (i0 == i1) + { + return oldPtr; + } + int ptr = allocUnits(OldNU + 1); + if (ptr != 0) + { + // memcpy(ptr,OldPtr,U2B(OldNU)); + Array.Copy(heap, oldPtr, heap, ptr, U2B(OldNU)); + insertNode(oldPtr, i0); + } + return ptr; + } + + public virtual int shrinkUnits(int oldPtr, int oldNU, int newNU) + { + // System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " + + // OldNU + ", " + NewNU + ")"); + int i0 = units2Indx[oldNU - 1]; + int i1 = units2Indx[newNU - 1]; + if (i0 == i1) + { + return oldPtr; + } + if (freeList[i1].GetNext() != 0) + { + int ptr = removeNode(i1); + // memcpy(ptr,OldPtr,U2B(NewNU)); + // for (int i = 0; i < U2B(NewNU); i++) { + // heap[ptr + i] = heap[OldPtr + i]; + // } + Array.Copy(heap, oldPtr, heap, ptr, U2B(newNU)); + insertNode(oldPtr, i0); + return ptr; + } + else + { + splitBlock(oldPtr, i0, i1); + return oldPtr; + } + } + + public virtual void freeUnits(int ptr, int OldNU) + { + insertNode(ptr, units2Indx[OldNU - 1]); + } + + public virtual void decPText(int dPText) + { + PText = PText - dPText; + } + + public virtual void initSubAllocator() + { + int i, k; + Utility.Fill(heap, freeListPos, freeListPos + sizeOfFreeList(), (byte) 0); + + pText = heapStart; + + int size2 = FIXED_UNIT_SIZE*(subAllocatorSize/8/FIXED_UNIT_SIZE*7); + int realSize2 = size2/FIXED_UNIT_SIZE*UNIT_SIZE; + int size1 = subAllocatorSize - size2; + int realSize1 = size1/FIXED_UNIT_SIZE*UNIT_SIZE + size1%FIXED_UNIT_SIZE; + hiUnit = heapStart + subAllocatorSize; + loUnit = unitsStart = heapStart + realSize1; + fakeUnitsStart = heapStart + size1; + hiUnit = loUnit + realSize2; + + for (i = 0, k = 1; i < N1; i++, k += 1) + { + indx2Units[i] = k & 0xff; + } + for (k++; i < N1 + N2; i++, k += 2) + { + indx2Units[i] = k & 0xff; + } + for (k++; i < N1 + N2 + N3; i++, k += 3) + { + indx2Units[i] = k & 0xff; + } + for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4) + { + indx2Units[i] = k & 0xff; + } + + for (glueCount = 0, k = 0, i = 0; k < 128; k++) + { + i += ((indx2Units[i] < (k + 1)) ? 1 : 0); + units2Indx[k] = i & 0xff; + } + } + + private int sizeOfFreeList() + { + return freeList.Length*RarNode.size; + } + + // Debug + // public void dumpHeap() { + // File file = new File("P:\\test\\heapdumpj"); + // OutputStream out = null; + // try { + // out = new FileOutputStream(file); + // out.write(heap, heapStart, heapEnd - heapStart); + // out.flush(); + // System.out.println("Heap dumped to " + file.getAbsolutePath()); + // } + // catch (IOException e) { + // e.printStackTrace(); + // } + // finally { + // FileUtil.close(out); + // } + // } + + // Debug + public override System.String ToString() + { + StringBuilder buffer = new StringBuilder(); + buffer.Append("SubAllocator["); + buffer.Append("\n subAllocatorSize="); + buffer.Append(subAllocatorSize); + buffer.Append("\n glueCount="); + buffer.Append(glueCount); + buffer.Append("\n heapStart="); + buffer.Append(heapStart); + buffer.Append("\n loUnit="); + buffer.Append(loUnit); + buffer.Append("\n hiUnit="); + buffer.Append(hiUnit); + buffer.Append("\n pText="); + buffer.Append(pText); + buffer.Append("\n unitsStart="); + buffer.Append(unitsStart); + buffer.Append("\n]"); + return buffer.ToString(); + } + + static SubAllocator() + { + UNIT_SIZE = System.Math.Max(PPMContext.size, RarMemBlock.size); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/Allocator.cs b/src/SharpCompress/Compressor/PPMd/I1/Allocator.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/I1/Allocator.cs rename to src/SharpCompress/Compressor/PPMd/I1/Allocator.cs index f47ca24a..ff50a7bd 100644 --- a/SharpCompress/Compressor/PPMd/I1/Allocator.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/Allocator.cs @@ -1,458 +1,458 @@ -#region Using - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with - /// instances of (which simply contain a single address value, representing a location - /// in the large array). Callers can then cast to one of the following structures (all - /// of which also simply contain a single address value): - internal class Allocator - { - private const uint UnitSize = 12; - private const uint LocalOffset = 4; // reserve the first four bytes for Pointer.Zero - private const uint NodeOffset = LocalOffset + MemoryNode.Size; // reserve space for a single memory node - - private const uint HeapOffset = NodeOffset + IndexCount*MemoryNode.Size; - // reserve space for the array of memory nodes - - private const uint N1 = 4; - private const uint N2 = 4; - private const uint N3 = 4; - private const uint N4 = (128 + 3 - 1*N1 - 2*N2 - 3*N3)/4; - private const uint IndexCount = N1 + N2 + N3 + N4; - - private static readonly byte[] indexToUnits; - private static readonly byte[] unitsToIndex; - - public uint AllocatorSize; - public uint GlueCount; - public Pointer BaseUnit; - public Pointer LowUnit; - public Pointer HighUnit; - public Pointer Text; - public Pointer Heap; - public MemoryNode[] MemoryNodes; - - public byte[] Memory; - - /// - /// Initializes static read-only arrays used by the . - /// - static Allocator() - { - // Construct the static index to units lookup array. It will contain the following values. - // - // 1 2 3 4 6 8 10 12 15 18 21 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 - // 112 116 120 124 128 - - uint index; - uint unitCount; - - indexToUnits = new byte[IndexCount]; - - for (index = 0, unitCount = 1; index < N1; index++, unitCount += 1) - indexToUnits[index] = (byte) unitCount; - - for (unitCount++; index < N1 + N2; index++, unitCount += 2) - indexToUnits[index] = (byte) unitCount; - - for (unitCount++; index < N1 + N2 + N3; index++, unitCount += 3) - indexToUnits[index] = (byte) unitCount; - - for (unitCount++; index < N1 + N2 + N3 + N4; index++, unitCount += 4) - indexToUnits[index] = (byte) unitCount; - - // Construct the static units to index lookup array. It will contain the following values. - // - // 00 01 02 03 04 04 05 05 06 06 07 07 08 08 08 09 09 09 10 10 10 11 11 11 12 12 12 12 13 13 13 13 - // 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 19 20 20 20 20 21 21 21 21 - // 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 27 27 27 27 28 28 28 28 29 29 29 29 - // 30 30 30 30 31 31 31 31 32 32 32 32 33 33 33 33 34 34 34 34 35 35 35 35 36 36 36 36 37 37 37 37 - - unitsToIndex = new byte[128]; - - for (unitCount = index = 0; unitCount < 128; unitCount++) - { - index += (uint) ((indexToUnits[index] < unitCount + 1) ? 1 : 0); - unitsToIndex[unitCount] = (byte) index; - } - } - - #region Public Methods - - public Allocator() - { - MemoryNodes = new MemoryNode[IndexCount]; - } - - /// - /// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying - /// and re-creating it). - /// - public void Initialize() - { - for (int index = 0; index < IndexCount; index++) - { - MemoryNodes[index] = new MemoryNode((uint) (NodeOffset + index*MemoryNode.Size), Memory); - MemoryNodes[index].Stamp = 0; - MemoryNodes[index].Next = MemoryNode.Zero; - MemoryNodes[index].UnitCount = 0; - } - - Text = Heap; - - uint difference = UnitSize*(AllocatorSize/8/UnitSize*7); - - HighUnit = Heap + AllocatorSize; - LowUnit = HighUnit - difference; - BaseUnit = HighUnit - difference; - - GlueCount = 0; - } - - /// - /// Start the allocator (create a single, large array of bytes). - /// - /// - /// Note that .NET will create that array on the large object heap (because it is so large). - /// - /// - public void Start(int allocatorSize) - { - uint size = (uint) allocatorSize; - if (AllocatorSize != size) - { - Stop(); - Memory = new byte[HeapOffset + size]; // the single, large array of bytes - Heap = new Pointer(HeapOffset, Memory); // reserve bytes in the range 0 .. HeapOffset - 1 - AllocatorSize = size; - } - } - - /// - /// Stop the allocator (free the single, large array of bytes). This can safely be called multiple times (without - /// intervening calls to ). - /// - /// - /// Because the array is on the large object heap it may not be freed immediately. - /// - public void Stop() - { - if (AllocatorSize != 0) - { - AllocatorSize = 0; - Memory = null; - Heap = Pointer.Zero; - } - } - - /// - /// Determine how much memory (from the single, large array) is currenly in use. - /// - /// - public uint GetMemoryUsed() - { - uint memoryUsed = AllocatorSize - (HighUnit - LowUnit) - (BaseUnit - Text); - for (uint index = 0; index < IndexCount; index++) - memoryUsed -= UnitSize*indexToUnits[index]*MemoryNodes[index].Stamp; - return memoryUsed; - } - - /// - /// Allocate a given number of units from the single, large array. Each unit is bytes - /// in size. - /// - /// - /// - public Pointer AllocateUnits(uint unitCount) - { - uint index = unitsToIndex[unitCount - 1]; - if (MemoryNodes[index].Available) - return MemoryNodes[index].Remove(); - - Pointer allocatedBlock = LowUnit; - LowUnit += indexToUnits[index]*UnitSize; - if (LowUnit <= HighUnit) - return allocatedBlock; - - LowUnit -= indexToUnits[index]*UnitSize; - return AllocateUnitsRare(index); - } - - /// - /// Allocate enough space for a PpmContext instance in the single, large array. - /// - /// - public Pointer AllocateContext() - { - if (HighUnit != LowUnit) - return (HighUnit -= UnitSize); - else if (MemoryNodes[0].Available) - return MemoryNodes[0].Remove(); - else - return AllocateUnitsRare(0); - } - - /// - /// Increase the size of an existing allocation (represented by a ). - /// - /// - /// - /// - public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount) - { - uint oldIndex = unitsToIndex[oldUnitCount - 1]; - uint newIndex = unitsToIndex[oldUnitCount]; - - if (oldIndex == newIndex) - return oldPointer; - - Pointer pointer = AllocateUnits(oldUnitCount + 1); - - if (pointer != Pointer.Zero) - { - CopyUnits(pointer, oldPointer, oldUnitCount); - MemoryNodes[oldIndex].Insert(oldPointer, oldUnitCount); - } - - return pointer; - } - - /// - /// Decrease the size of an existing allocation (represented by a ). - /// - /// - /// - /// - /// - public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount) - { - uint oldIndex = unitsToIndex[oldUnitCount - 1]; - uint newIndex = unitsToIndex[newUnitCount - 1]; - - if (oldIndex == newIndex) - return oldPointer; - - if (MemoryNodes[newIndex].Available) - { - Pointer pointer = MemoryNodes[newIndex].Remove(); - CopyUnits(pointer, oldPointer, newUnitCount); - MemoryNodes[oldIndex].Insert(oldPointer, indexToUnits[oldIndex]); - return pointer; - } - else - { - SplitBlock(oldPointer, oldIndex, newIndex); - return oldPointer; - } - } - - /// - /// Free previously allocated space (the location and amount of space to free must be specified by using - /// a to indicate the location and a number of units to indicate the amount). - /// - /// - /// - public void FreeUnits(Pointer pointer, uint unitCount) - { - uint index = unitsToIndex[unitCount - 1]; - MemoryNodes[index].Insert(pointer, indexToUnits[index]); - } - - public void SpecialFreeUnits(Pointer pointer) - { - if (pointer != BaseUnit) - { - MemoryNodes[0].Insert(pointer, 1); - } - else - { - MemoryNode memoryNode = pointer; - memoryNode.Stamp = uint.MaxValue; - BaseUnit += UnitSize; - } - } - - public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount) - { - uint index = unitsToIndex[unitCount - 1]; - - if (oldPointer > BaseUnit + 16*1024 || oldPointer > MemoryNodes[index].Next) - return oldPointer; - - Pointer pointer = MemoryNodes[index].Remove(); - CopyUnits(pointer, oldPointer, unitCount); - unitCount = indexToUnits[index]; - - if (oldPointer != BaseUnit) - MemoryNodes[index].Insert(oldPointer, unitCount); - else - BaseUnit += unitCount*UnitSize; - - return pointer; - } - - /// - /// Expand the space allocated (in the single, large array) for the bytes of the data (ie. the "text") that is - /// being encoded or decoded. - /// - public void ExpandText() - { - MemoryNode memoryNode; - uint[] counts = new uint[IndexCount]; - - while ((memoryNode = BaseUnit).Stamp == uint.MaxValue) - { - BaseUnit = memoryNode + memoryNode.UnitCount; - counts[unitsToIndex[memoryNode.UnitCount - 1]]++; - memoryNode.Stamp = 0; - } - - for (uint index = 0; index < IndexCount; index++) - { - for (memoryNode = MemoryNodes[index]; counts[index] != 0; memoryNode = memoryNode.Next) - { - while (memoryNode.Next.Stamp == 0) - { - memoryNode.Unlink(); - MemoryNodes[index].Stamp--; - if (--counts[index] == 0) - break; - } - } - } - } - - #endregion - - #region Private Methods - - private Pointer AllocateUnitsRare(uint index) - { - if (GlueCount == 0) - { - GlueFreeBlocks(); - if (MemoryNodes[index].Available) - return MemoryNodes[index].Remove(); - } - - uint oldIndex = index; - do - { - if (++oldIndex == IndexCount) - { - GlueCount--; - oldIndex = indexToUnits[index]*UnitSize; - return (BaseUnit - Text > oldIndex) ? (BaseUnit -= oldIndex) : Pointer.Zero; - } - } while (!MemoryNodes[oldIndex].Available); - - Pointer allocatedBlock = MemoryNodes[oldIndex].Remove(); - SplitBlock(allocatedBlock, oldIndex, index); - return allocatedBlock; - } - - private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex) - { - uint unitCountDifference = (uint) (indexToUnits[oldIndex] - indexToUnits[newIndex]); - Pointer newPointer = pointer + indexToUnits[newIndex]*UnitSize; - - uint index = unitsToIndex[unitCountDifference - 1]; - if (indexToUnits[index] != unitCountDifference) - { - uint unitCount = indexToUnits[--index]; - MemoryNodes[index].Insert(newPointer, unitCount); - newPointer += unitCount*UnitSize; - unitCountDifference -= unitCount; - } - - MemoryNodes[unitsToIndex[unitCountDifference - 1]].Insert(newPointer, unitCountDifference); - } - - private void GlueFreeBlocks() - { - MemoryNode memoryNode = new MemoryNode(LocalOffset, Memory); - memoryNode.Stamp = 0; - memoryNode.Next = MemoryNode.Zero; - memoryNode.UnitCount = 0; - - MemoryNode memoryNode0; - MemoryNode memoryNode1; - MemoryNode memoryNode2; - - if (LowUnit != HighUnit) - LowUnit[0] = 0; - - // Find all unused memory nodes. - - memoryNode1 = memoryNode; - for (uint index = 0; index < IndexCount; index++) - { - while (MemoryNodes[index].Available) - { - memoryNode0 = MemoryNodes[index].Remove(); - if (memoryNode0.UnitCount != 0) - { - while ((memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp == uint.MaxValue) - { - memoryNode0.UnitCount = memoryNode0.UnitCount + memoryNode2.UnitCount; - memoryNode2.UnitCount = 0; - } - memoryNode1.Link(memoryNode0); - memoryNode1 = memoryNode0; - } - } - } - - // Coalesce the memory represented by the unused memory nodes. - - while (memoryNode.Available) - { - memoryNode0 = memoryNode.Remove(); - uint unitCount = memoryNode0.UnitCount; - if (unitCount != 0) - { - for (; unitCount > 128; unitCount -= 128, memoryNode0 += 128) - MemoryNodes[IndexCount - 1].Insert(memoryNode0, 128); - - uint index = unitsToIndex[unitCount - 1]; - if (indexToUnits[index] != unitCount) - { - uint unitCountDifference = unitCount - indexToUnits[--index]; - MemoryNodes[unitCountDifference - 1].Insert(memoryNode0 + (unitCount - unitCountDifference), - unitCountDifference); - } - - MemoryNodes[index].Insert(memoryNode0, indexToUnits[index]); - } - } - - GlueCount = 1 << 13; - } - - private void CopyUnits(Pointer target, Pointer source, uint unitCount) - { - do - { - target[0] = source[0]; - target[1] = source[1]; - target[2] = source[2]; - target[3] = source[3]; - target[4] = source[4]; - target[5] = source[5]; - target[6] = source[6]; - target[7] = source[7]; - target[8] = source[8]; - target[9] = source[9]; - target[10] = source[10]; - target[11] = source[11]; - target += UnitSize; - source += UnitSize; - } while (--unitCount != 0); - } - - #endregion - } +#region Using + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with + /// instances of (which simply contain a single address value, representing a location + /// in the large array). Callers can then cast to one of the following structures (all + /// of which also simply contain a single address value): + internal class Allocator + { + private const uint UnitSize = 12; + private const uint LocalOffset = 4; // reserve the first four bytes for Pointer.Zero + private const uint NodeOffset = LocalOffset + MemoryNode.Size; // reserve space for a single memory node + + private const uint HeapOffset = NodeOffset + IndexCount*MemoryNode.Size; + // reserve space for the array of memory nodes + + private const uint N1 = 4; + private const uint N2 = 4; + private const uint N3 = 4; + private const uint N4 = (128 + 3 - 1*N1 - 2*N2 - 3*N3)/4; + private const uint IndexCount = N1 + N2 + N3 + N4; + + private static readonly byte[] indexToUnits; + private static readonly byte[] unitsToIndex; + + public uint AllocatorSize; + public uint GlueCount; + public Pointer BaseUnit; + public Pointer LowUnit; + public Pointer HighUnit; + public Pointer Text; + public Pointer Heap; + public MemoryNode[] MemoryNodes; + + public byte[] Memory; + + /// + /// Initializes static read-only arrays used by the . + /// + static Allocator() + { + // Construct the static index to units lookup array. It will contain the following values. + // + // 1 2 3 4 6 8 10 12 15 18 21 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 + // 112 116 120 124 128 + + uint index; + uint unitCount; + + indexToUnits = new byte[IndexCount]; + + for (index = 0, unitCount = 1; index < N1; index++, unitCount += 1) + indexToUnits[index] = (byte) unitCount; + + for (unitCount++; index < N1 + N2; index++, unitCount += 2) + indexToUnits[index] = (byte) unitCount; + + for (unitCount++; index < N1 + N2 + N3; index++, unitCount += 3) + indexToUnits[index] = (byte) unitCount; + + for (unitCount++; index < N1 + N2 + N3 + N4; index++, unitCount += 4) + indexToUnits[index] = (byte) unitCount; + + // Construct the static units to index lookup array. It will contain the following values. + // + // 00 01 02 03 04 04 05 05 06 06 07 07 08 08 08 09 09 09 10 10 10 11 11 11 12 12 12 12 13 13 13 13 + // 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 19 20 20 20 20 21 21 21 21 + // 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 27 27 27 27 28 28 28 28 29 29 29 29 + // 30 30 30 30 31 31 31 31 32 32 32 32 33 33 33 33 34 34 34 34 35 35 35 35 36 36 36 36 37 37 37 37 + + unitsToIndex = new byte[128]; + + for (unitCount = index = 0; unitCount < 128; unitCount++) + { + index += (uint) ((indexToUnits[index] < unitCount + 1) ? 1 : 0); + unitsToIndex[unitCount] = (byte) index; + } + } + + #region Public Methods + + public Allocator() + { + MemoryNodes = new MemoryNode[IndexCount]; + } + + /// + /// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying + /// and re-creating it). + /// + public void Initialize() + { + for (int index = 0; index < IndexCount; index++) + { + MemoryNodes[index] = new MemoryNode((uint) (NodeOffset + index*MemoryNode.Size), Memory); + MemoryNodes[index].Stamp = 0; + MemoryNodes[index].Next = MemoryNode.Zero; + MemoryNodes[index].UnitCount = 0; + } + + Text = Heap; + + uint difference = UnitSize*(AllocatorSize/8/UnitSize*7); + + HighUnit = Heap + AllocatorSize; + LowUnit = HighUnit - difference; + BaseUnit = HighUnit - difference; + + GlueCount = 0; + } + + /// + /// Start the allocator (create a single, large array of bytes). + /// + /// + /// Note that .NET will create that array on the large object heap (because it is so large). + /// + /// + public void Start(int allocatorSize) + { + uint size = (uint) allocatorSize; + if (AllocatorSize != size) + { + Stop(); + Memory = new byte[HeapOffset + size]; // the single, large array of bytes + Heap = new Pointer(HeapOffset, Memory); // reserve bytes in the range 0 .. HeapOffset - 1 + AllocatorSize = size; + } + } + + /// + /// Stop the allocator (free the single, large array of bytes). This can safely be called multiple times (without + /// intervening calls to ). + /// + /// + /// Because the array is on the large object heap it may not be freed immediately. + /// + public void Stop() + { + if (AllocatorSize != 0) + { + AllocatorSize = 0; + Memory = null; + Heap = Pointer.Zero; + } + } + + /// + /// Determine how much memory (from the single, large array) is currenly in use. + /// + /// + public uint GetMemoryUsed() + { + uint memoryUsed = AllocatorSize - (HighUnit - LowUnit) - (BaseUnit - Text); + for (uint index = 0; index < IndexCount; index++) + memoryUsed -= UnitSize*indexToUnits[index]*MemoryNodes[index].Stamp; + return memoryUsed; + } + + /// + /// Allocate a given number of units from the single, large array. Each unit is bytes + /// in size. + /// + /// + /// + public Pointer AllocateUnits(uint unitCount) + { + uint index = unitsToIndex[unitCount - 1]; + if (MemoryNodes[index].Available) + return MemoryNodes[index].Remove(); + + Pointer allocatedBlock = LowUnit; + LowUnit += indexToUnits[index]*UnitSize; + if (LowUnit <= HighUnit) + return allocatedBlock; + + LowUnit -= indexToUnits[index]*UnitSize; + return AllocateUnitsRare(index); + } + + /// + /// Allocate enough space for a PpmContext instance in the single, large array. + /// + /// + public Pointer AllocateContext() + { + if (HighUnit != LowUnit) + return (HighUnit -= UnitSize); + else if (MemoryNodes[0].Available) + return MemoryNodes[0].Remove(); + else + return AllocateUnitsRare(0); + } + + /// + /// Increase the size of an existing allocation (represented by a ). + /// + /// + /// + /// + public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount) + { + uint oldIndex = unitsToIndex[oldUnitCount - 1]; + uint newIndex = unitsToIndex[oldUnitCount]; + + if (oldIndex == newIndex) + return oldPointer; + + Pointer pointer = AllocateUnits(oldUnitCount + 1); + + if (pointer != Pointer.Zero) + { + CopyUnits(pointer, oldPointer, oldUnitCount); + MemoryNodes[oldIndex].Insert(oldPointer, oldUnitCount); + } + + return pointer; + } + + /// + /// Decrease the size of an existing allocation (represented by a ). + /// + /// + /// + /// + /// + public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount) + { + uint oldIndex = unitsToIndex[oldUnitCount - 1]; + uint newIndex = unitsToIndex[newUnitCount - 1]; + + if (oldIndex == newIndex) + return oldPointer; + + if (MemoryNodes[newIndex].Available) + { + Pointer pointer = MemoryNodes[newIndex].Remove(); + CopyUnits(pointer, oldPointer, newUnitCount); + MemoryNodes[oldIndex].Insert(oldPointer, indexToUnits[oldIndex]); + return pointer; + } + else + { + SplitBlock(oldPointer, oldIndex, newIndex); + return oldPointer; + } + } + + /// + /// Free previously allocated space (the location and amount of space to free must be specified by using + /// a to indicate the location and a number of units to indicate the amount). + /// + /// + /// + public void FreeUnits(Pointer pointer, uint unitCount) + { + uint index = unitsToIndex[unitCount - 1]; + MemoryNodes[index].Insert(pointer, indexToUnits[index]); + } + + public void SpecialFreeUnits(Pointer pointer) + { + if (pointer != BaseUnit) + { + MemoryNodes[0].Insert(pointer, 1); + } + else + { + MemoryNode memoryNode = pointer; + memoryNode.Stamp = uint.MaxValue; + BaseUnit += UnitSize; + } + } + + public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount) + { + uint index = unitsToIndex[unitCount - 1]; + + if (oldPointer > BaseUnit + 16*1024 || oldPointer > MemoryNodes[index].Next) + return oldPointer; + + Pointer pointer = MemoryNodes[index].Remove(); + CopyUnits(pointer, oldPointer, unitCount); + unitCount = indexToUnits[index]; + + if (oldPointer != BaseUnit) + MemoryNodes[index].Insert(oldPointer, unitCount); + else + BaseUnit += unitCount*UnitSize; + + return pointer; + } + + /// + /// Expand the space allocated (in the single, large array) for the bytes of the data (ie. the "text") that is + /// being encoded or decoded. + /// + public void ExpandText() + { + MemoryNode memoryNode; + uint[] counts = new uint[IndexCount]; + + while ((memoryNode = BaseUnit).Stamp == uint.MaxValue) + { + BaseUnit = memoryNode + memoryNode.UnitCount; + counts[unitsToIndex[memoryNode.UnitCount - 1]]++; + memoryNode.Stamp = 0; + } + + for (uint index = 0; index < IndexCount; index++) + { + for (memoryNode = MemoryNodes[index]; counts[index] != 0; memoryNode = memoryNode.Next) + { + while (memoryNode.Next.Stamp == 0) + { + memoryNode.Unlink(); + MemoryNodes[index].Stamp--; + if (--counts[index] == 0) + break; + } + } + } + } + + #endregion + + #region Private Methods + + private Pointer AllocateUnitsRare(uint index) + { + if (GlueCount == 0) + { + GlueFreeBlocks(); + if (MemoryNodes[index].Available) + return MemoryNodes[index].Remove(); + } + + uint oldIndex = index; + do + { + if (++oldIndex == IndexCount) + { + GlueCount--; + oldIndex = indexToUnits[index]*UnitSize; + return (BaseUnit - Text > oldIndex) ? (BaseUnit -= oldIndex) : Pointer.Zero; + } + } while (!MemoryNodes[oldIndex].Available); + + Pointer allocatedBlock = MemoryNodes[oldIndex].Remove(); + SplitBlock(allocatedBlock, oldIndex, index); + return allocatedBlock; + } + + private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex) + { + uint unitCountDifference = (uint) (indexToUnits[oldIndex] - indexToUnits[newIndex]); + Pointer newPointer = pointer + indexToUnits[newIndex]*UnitSize; + + uint index = unitsToIndex[unitCountDifference - 1]; + if (indexToUnits[index] != unitCountDifference) + { + uint unitCount = indexToUnits[--index]; + MemoryNodes[index].Insert(newPointer, unitCount); + newPointer += unitCount*UnitSize; + unitCountDifference -= unitCount; + } + + MemoryNodes[unitsToIndex[unitCountDifference - 1]].Insert(newPointer, unitCountDifference); + } + + private void GlueFreeBlocks() + { + MemoryNode memoryNode = new MemoryNode(LocalOffset, Memory); + memoryNode.Stamp = 0; + memoryNode.Next = MemoryNode.Zero; + memoryNode.UnitCount = 0; + + MemoryNode memoryNode0; + MemoryNode memoryNode1; + MemoryNode memoryNode2; + + if (LowUnit != HighUnit) + LowUnit[0] = 0; + + // Find all unused memory nodes. + + memoryNode1 = memoryNode; + for (uint index = 0; index < IndexCount; index++) + { + while (MemoryNodes[index].Available) + { + memoryNode0 = MemoryNodes[index].Remove(); + if (memoryNode0.UnitCount != 0) + { + while ((memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp == uint.MaxValue) + { + memoryNode0.UnitCount = memoryNode0.UnitCount + memoryNode2.UnitCount; + memoryNode2.UnitCount = 0; + } + memoryNode1.Link(memoryNode0); + memoryNode1 = memoryNode0; + } + } + } + + // Coalesce the memory represented by the unused memory nodes. + + while (memoryNode.Available) + { + memoryNode0 = memoryNode.Remove(); + uint unitCount = memoryNode0.UnitCount; + if (unitCount != 0) + { + for (; unitCount > 128; unitCount -= 128, memoryNode0 += 128) + MemoryNodes[IndexCount - 1].Insert(memoryNode0, 128); + + uint index = unitsToIndex[unitCount - 1]; + if (indexToUnits[index] != unitCount) + { + uint unitCountDifference = unitCount - indexToUnits[--index]; + MemoryNodes[unitCountDifference - 1].Insert(memoryNode0 + (unitCount - unitCountDifference), + unitCountDifference); + } + + MemoryNodes[index].Insert(memoryNode0, indexToUnits[index]); + } + } + + GlueCount = 1 << 13; + } + + private void CopyUnits(Pointer target, Pointer source, uint unitCount) + { + do + { + target[0] = source[0]; + target[1] = source[1]; + target[2] = source[2]; + target[3] = source[3]; + target[4] = source[4]; + target[5] = source[5]; + target[6] = source[6]; + target[7] = source[7]; + target[8] = source[8]; + target[9] = source[9]; + target[10] = source[10]; + target[11] = source[11]; + target += UnitSize; + source += UnitSize; + } while (--unitCount != 0); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/Coder.cs b/src/SharpCompress/Compressor/PPMd/I1/Coder.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/I1/Coder.cs rename to src/SharpCompress/Compressor/PPMd/I1/Coder.cs index 005bb08e..90adb6a8 100644 --- a/SharpCompress/Compressor/PPMd/I1/Coder.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/Coder.cs @@ -1,103 +1,103 @@ -#region Using - -using System; -using System.IO; - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// A simple range coder. - /// - /// - /// Note that in most cases fields are used rather than properties for performance reasons (for example, - /// is a field rather than a property). - /// - internal class Coder - { - private const uint RangeTop = 1 << 24; - private const uint RangeBottom = 1 << 15; - private uint low; - private uint code; - private uint range; - - public uint LowCount; - public uint HighCount; - public uint Scale; - - public void RangeEncoderInitialize() - { - low = 0; - range = uint.MaxValue; - } - - public void RangeEncoderNormalize(Stream stream) - { - while ((low ^ (low + range)) < RangeTop || - range < RangeBottom && ((range = (uint) -low & (RangeBottom - 1)) != 0 || true)) - { - stream.WriteByte((byte) (low >> 24)); - range <<= 8; - low <<= 8; - } - } - - public void RangeEncodeSymbol() - { - low += LowCount*(range /= Scale); - range *= HighCount - LowCount; - } - - public void RangeShiftEncodeSymbol(int rangeShift) - { - low += LowCount*(range >>= rangeShift); - range *= HighCount - LowCount; - } - - public void RangeEncoderFlush(Stream stream) - { - for (uint index = 0; index < 4; index++) - { - stream.WriteByte((byte) (low >> 24)); - low <<= 8; - } - } - - public void RangeDecoderInitialize(Stream stream) - { - low = 0; - code = 0; - range = uint.MaxValue; - for (uint index = 0; index < 4; index++) - code = (code << 8) | (byte) stream.ReadByte(); - } - - public void RangeDecoderNormalize(Stream stream) - { - while ((low ^ (low + range)) < RangeTop || - range < RangeBottom && ((range = (uint) -low & (RangeBottom - 1)) != 0 || true)) - { - code = (code << 8) | (byte) stream.ReadByte(); - range <<= 8; - low <<= 8; - } - } - - public uint RangeGetCurrentCount() - { - return (code - low)/(range /= Scale); - } - - public uint RangeGetCurrentShiftCount(int rangeShift) - { - return (code - low)/(range >>= rangeShift); - } - - public void RangeRemoveSubrange() - { - low += range*LowCount; - range *= HighCount - LowCount; - } - } +#region Using + +using System; +using System.IO; + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// A simple range coder. + /// + /// + /// Note that in most cases fields are used rather than properties for performance reasons (for example, + /// is a field rather than a property). + /// + internal class Coder + { + private const uint RangeTop = 1 << 24; + private const uint RangeBottom = 1 << 15; + private uint low; + private uint code; + private uint range; + + public uint LowCount; + public uint HighCount; + public uint Scale; + + public void RangeEncoderInitialize() + { + low = 0; + range = uint.MaxValue; + } + + public void RangeEncoderNormalize(Stream stream) + { + while ((low ^ (low + range)) < RangeTop || + range < RangeBottom && ((range = (uint) -low & (RangeBottom - 1)) != 0 || true)) + { + stream.WriteByte((byte) (low >> 24)); + range <<= 8; + low <<= 8; + } + } + + public void RangeEncodeSymbol() + { + low += LowCount*(range /= Scale); + range *= HighCount - LowCount; + } + + public void RangeShiftEncodeSymbol(int rangeShift) + { + low += LowCount*(range >>= rangeShift); + range *= HighCount - LowCount; + } + + public void RangeEncoderFlush(Stream stream) + { + for (uint index = 0; index < 4; index++) + { + stream.WriteByte((byte) (low >> 24)); + low <<= 8; + } + } + + public void RangeDecoderInitialize(Stream stream) + { + low = 0; + code = 0; + range = uint.MaxValue; + for (uint index = 0; index < 4; index++) + code = (code << 8) | (byte) stream.ReadByte(); + } + + public void RangeDecoderNormalize(Stream stream) + { + while ((low ^ (low + range)) < RangeTop || + range < RangeBottom && ((range = (uint) -low & (RangeBottom - 1)) != 0 || true)) + { + code = (code << 8) | (byte) stream.ReadByte(); + range <<= 8; + low <<= 8; + } + } + + public uint RangeGetCurrentCount() + { + return (code - low)/(range /= Scale); + } + + public uint RangeGetCurrentShiftCount(int rangeShift) + { + return (code - low)/(range >>= rangeShift); + } + + public void RangeRemoveSubrange() + { + low += range*LowCount; + range *= HighCount - LowCount; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/MemoryNode.cs b/src/SharpCompress/Compressor/PPMd/I1/MemoryNode.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/I1/MemoryNode.cs rename to src/SharpCompress/Compressor/PPMd/I1/MemoryNode.cs index 7bb99f2b..8aa440d2 100644 --- a/SharpCompress/Compressor/PPMd/I1/MemoryNode.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/MemoryNode.cs @@ -1,260 +1,260 @@ -#region Using - -using System; - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// A structure containing a single address. The address represents a location in the - /// array. That location in the array contains information itself describing a section - /// of the array (ie. a block of memory). - /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of - /// the instance rather than just copying a reference to the same instance). - /// - /// - /// MemoryNode - /// 4 Stamp - /// 4 Next - /// 4 UnitCount - /// - /// - /// Note that is a field rather than a property for performance reasons. - /// - /// - internal struct MemoryNode - { - public uint Address; - public byte[] Memory; - public static readonly MemoryNode Zero = new MemoryNode(0, null); - public const int Size = 12; - - /// - /// Initializes a new instance of the structure. - /// - public MemoryNode(uint address, byte[] memory) - { - Address = address; - Memory = memory; - } - - /// - /// Gets or sets the stamp. - /// - public uint Stamp - { - get - { - return ((uint) Memory[Address]) | ((uint) Memory[Address + 1]) << 8 | ((uint) Memory[Address + 2]) << 16 | - ((uint) Memory[Address + 3]) << 24; - } - set - { - Memory[Address] = (byte) value; - Memory[Address + 1] = (byte) (value >> 8); - Memory[Address + 2] = (byte) (value >> 16); - Memory[Address + 3] = (byte) (value >> 24); - } - } - - /// - /// Gets or sets the next memory node. - /// - public MemoryNode Next - { - get - { - return - new MemoryNode( - ((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | - ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); - } - set - { - Memory[Address + 4] = (byte) value.Address; - Memory[Address + 5] = (byte) (value.Address >> 8); - Memory[Address + 6] = (byte) (value.Address >> 16); - Memory[Address + 7] = (byte) (value.Address >> 24); - } - } - - /// - /// Gets or sets the unit count. - /// - public uint UnitCount - { - get - { - return ((uint) Memory[Address + 8]) | ((uint) Memory[Address + 9]) << 8 | - ((uint) Memory[Address + 10]) << 16 | ((uint) Memory[Address + 11]) << 24; - } - set - { - Memory[Address + 8] = (byte) value; - Memory[Address + 9] = (byte) (value >> 8); - Memory[Address + 10] = (byte) (value >> 16); - Memory[Address + 11] = (byte) (value >> 24); - } - } - - /// - /// Gets whether there is a next memory node available. - /// - public bool Available - { - get { return Next.Address != 0; } - } - - /// - /// Link in the provided memory node. - /// - /// - public void Link(MemoryNode memoryNode) - { - memoryNode.Next = Next; - Next = memoryNode; - } - - /// - /// Unlink this memory node. - /// - public void Unlink() - { - Next = Next.Next; - } - - /// - /// Insert the memory node into the linked list. - /// - /// - /// - public void Insert(MemoryNode memoryNode, uint unitCount) - { - Link(memoryNode); - memoryNode.Stamp = uint.MaxValue; - memoryNode.UnitCount = unitCount; - Stamp++; - } - - /// - /// Remove this memory node from the linked list. - /// - /// - public MemoryNode Remove() - { - MemoryNode next = Next; - Unlink(); - Stamp--; - return next; - } - - /// - /// Allow a pointer to be implicitly converted to a memory node. - /// - /// - /// - public static implicit operator MemoryNode(Pointer pointer) - { - return new MemoryNode(pointer.Address, pointer.Memory); - } - - /// - /// Allow pointer-like addition on a memory node. - /// - /// - /// - /// - public static MemoryNode operator +(MemoryNode memoryNode, int offset) - { - memoryNode.Address = (uint) (memoryNode.Address + offset*Size); - return memoryNode; - } - - /// - /// Allow pointer-like addition on a memory node. - /// - /// - /// - /// - public static MemoryNode operator +(MemoryNode memoryNode, uint offset) - { - memoryNode.Address += offset*Size; - return memoryNode; - } - - /// - /// Allow pointer-like subtraction on a memory node. - /// - /// - /// - /// - public static MemoryNode operator -(MemoryNode memoryNode, int offset) - { - memoryNode.Address = (uint) (memoryNode.Address - offset*Size); - return memoryNode; - } - - /// - /// Allow pointer-like subtraction on a memory node. - /// - /// - /// - /// - public static MemoryNode operator -(MemoryNode memoryNode, uint offset) - { - memoryNode.Address -= offset*Size; - return memoryNode; - } - - /// - /// Compare two memory nodes. - /// - /// - /// - /// - public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) - { - return memoryNode1.Address == memoryNode2.Address; - } - - /// - /// Compare two memory nodes. - /// - /// - /// - /// - public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) - { - return memoryNode1.Address != memoryNode2.Address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is MemoryNode) - { - MemoryNode memoryNode = (MemoryNode) obj; - return memoryNode.Address == Address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return Address.GetHashCode(); - } - } +#region Using + +using System; + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// A structure containing a single address. The address represents a location in the + /// array. That location in the array contains information itself describing a section + /// of the array (ie. a block of memory). + /// + /// + /// + /// This must be a structure rather than a class because several places in the associated code assume that + /// is a value type (meaning that assignment creates a completely new copy of + /// the instance rather than just copying a reference to the same instance). + /// + /// + /// MemoryNode + /// 4 Stamp + /// 4 Next + /// 4 UnitCount + /// + /// + /// Note that is a field rather than a property for performance reasons. + /// + /// + internal struct MemoryNode + { + public uint Address; + public byte[] Memory; + public static readonly MemoryNode Zero = new MemoryNode(0, null); + public const int Size = 12; + + /// + /// Initializes a new instance of the structure. + /// + public MemoryNode(uint address, byte[] memory) + { + Address = address; + Memory = memory; + } + + /// + /// Gets or sets the stamp. + /// + public uint Stamp + { + get + { + return ((uint) Memory[Address]) | ((uint) Memory[Address + 1]) << 8 | ((uint) Memory[Address + 2]) << 16 | + ((uint) Memory[Address + 3]) << 24; + } + set + { + Memory[Address] = (byte) value; + Memory[Address + 1] = (byte) (value >> 8); + Memory[Address + 2] = (byte) (value >> 16); + Memory[Address + 3] = (byte) (value >> 24); + } + } + + /// + /// Gets or sets the next memory node. + /// + public MemoryNode Next + { + get + { + return + new MemoryNode( + ((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | + ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); + } + set + { + Memory[Address + 4] = (byte) value.Address; + Memory[Address + 5] = (byte) (value.Address >> 8); + Memory[Address + 6] = (byte) (value.Address >> 16); + Memory[Address + 7] = (byte) (value.Address >> 24); + } + } + + /// + /// Gets or sets the unit count. + /// + public uint UnitCount + { + get + { + return ((uint) Memory[Address + 8]) | ((uint) Memory[Address + 9]) << 8 | + ((uint) Memory[Address + 10]) << 16 | ((uint) Memory[Address + 11]) << 24; + } + set + { + Memory[Address + 8] = (byte) value; + Memory[Address + 9] = (byte) (value >> 8); + Memory[Address + 10] = (byte) (value >> 16); + Memory[Address + 11] = (byte) (value >> 24); + } + } + + /// + /// Gets whether there is a next memory node available. + /// + public bool Available + { + get { return Next.Address != 0; } + } + + /// + /// Link in the provided memory node. + /// + /// + public void Link(MemoryNode memoryNode) + { + memoryNode.Next = Next; + Next = memoryNode; + } + + /// + /// Unlink this memory node. + /// + public void Unlink() + { + Next = Next.Next; + } + + /// + /// Insert the memory node into the linked list. + /// + /// + /// + public void Insert(MemoryNode memoryNode, uint unitCount) + { + Link(memoryNode); + memoryNode.Stamp = uint.MaxValue; + memoryNode.UnitCount = unitCount; + Stamp++; + } + + /// + /// Remove this memory node from the linked list. + /// + /// + public MemoryNode Remove() + { + MemoryNode next = Next; + Unlink(); + Stamp--; + return next; + } + + /// + /// Allow a pointer to be implicitly converted to a memory node. + /// + /// + /// + public static implicit operator MemoryNode(Pointer pointer) + { + return new MemoryNode(pointer.Address, pointer.Memory); + } + + /// + /// Allow pointer-like addition on a memory node. + /// + /// + /// + /// + public static MemoryNode operator +(MemoryNode memoryNode, int offset) + { + memoryNode.Address = (uint) (memoryNode.Address + offset*Size); + return memoryNode; + } + + /// + /// Allow pointer-like addition on a memory node. + /// + /// + /// + /// + public static MemoryNode operator +(MemoryNode memoryNode, uint offset) + { + memoryNode.Address += offset*Size; + return memoryNode; + } + + /// + /// Allow pointer-like subtraction on a memory node. + /// + /// + /// + /// + public static MemoryNode operator -(MemoryNode memoryNode, int offset) + { + memoryNode.Address = (uint) (memoryNode.Address - offset*Size); + return memoryNode; + } + + /// + /// Allow pointer-like subtraction on a memory node. + /// + /// + /// + /// + public static MemoryNode operator -(MemoryNode memoryNode, uint offset) + { + memoryNode.Address -= offset*Size; + return memoryNode; + } + + /// + /// Compare two memory nodes. + /// + /// + /// + /// + public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) + { + return memoryNode1.Address == memoryNode2.Address; + } + + /// + /// Compare two memory nodes. + /// + /// + /// + /// + public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) + { + return memoryNode1.Address != memoryNode2.Address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is MemoryNode) + { + MemoryNode memoryNode = (MemoryNode) obj; + return memoryNode.Address == Address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return Address.GetHashCode(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/Model.cs b/src/SharpCompress/Compressor/PPMd/I1/Model.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/I1/Model.cs rename to src/SharpCompress/Compressor/PPMd/I1/Model.cs index 0b536b7b..bffd15c5 100644 --- a/SharpCompress/Compressor/PPMd/I1/Model.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/Model.cs @@ -1,832 +1,832 @@ -#region Using - -using System; -using System.IO; - -#endregion - -// This is a port of Dmitry Shkarin's PPMd Variant I Revision 1. -// Ported by Michael Bone (mjbone03@yahoo.com.au). - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// The model. - /// - internal partial class Model - { - public const uint Signature = 0x84acaf8fU; - public const char Variant = 'I'; - public const int MaximumOrder = 16; // maximum allowed model order - - private const byte UpperFrequency = 5; - private const byte IntervalBitCount = 7; - private const byte PeriodBitCount = 7; - private const byte TotalBitCount = IntervalBitCount + PeriodBitCount; - private const uint Interval = 1 << IntervalBitCount; - private const uint BinaryScale = 1 << TotalBitCount; - private const uint MaximumFrequency = 124; - private const uint OrderBound = 9; - - private See2Context[,] see2Contexts; - private See2Context emptySee2Context; - private PpmContext maximumContext; - private ushort[,] binarySummary = new ushort[25,64]; // binary SEE-contexts - private byte[] numberStatisticsToBinarySummaryIndex = new byte[256]; - private byte[] probabilities = new byte[260]; - private byte[] characterMask = new byte[256]; - private byte escapeCount; - private int modelOrder; - private int orderFall; - private int initialEscape; - private int initialRunLength; - private int runLength; - private byte previousSuccess; - private byte numberMasked; - private ModelRestorationMethod method; - private PpmState foundState; // found next state transition - - private Allocator Allocator; - private Coder Coder; - private PpmContext minimumContext; - private byte numberStatistics; - private PpmState[] decodeStates = new PpmState[256]; - - private static readonly ushort[] InitialBinaryEscapes = - { - 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, - 0x6051 - }; - - private static readonly byte[] ExponentialEscapes = {25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2}; - - #region Public Methods - - public Model() - { - // Construct the conversion table for number statistics. Initially it will contain the following values. - // - // 0 2 4 4 4 4 4 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - - numberStatisticsToBinarySummaryIndex[0] = 2*0; - numberStatisticsToBinarySummaryIndex[1] = 2*1; - for (int index = 2; index < 11; index++) - numberStatisticsToBinarySummaryIndex[index] = 2*2; - for (int index = 11; index < 256; index++) - numberStatisticsToBinarySummaryIndex[index] = 2*3; - - // Construct the probability table. Initially it will contain the following values (depending on the value of - // the upper frequency). - // - // 00 01 02 03 04 05 06 06 07 07 07 08 08 08 08 09 09 09 09 09 10 10 10 10 10 10 11 11 11 11 11 11 - // 11 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 15 15 15 15 - // 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17 17 17 17 17 - // 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 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 21 22 22 - // 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 - // 23 23 23 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 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 - // 26 26 27 27 - - uint count = 1; - uint step = 1; - uint probability = UpperFrequency; - - for (int index = 0; index < UpperFrequency; index++) - probabilities[index] = (byte) index; - - for (int index = UpperFrequency; index < 260; index++) - { - probabilities[index] = (byte) probability; - count--; - if (count == 0) - { - step++; - count = step; - probability++; - } - } - - // Create the context array. - - see2Contexts = new See2Context[24,32]; - for (int index1 = 0; index1 < 24; index1++) - for (int index2 = 0; index2 < 32; index2++) - see2Contexts[index1, index2] = new See2Context(); - - // Set the signature (identifying the algorithm). - - emptySee2Context = new See2Context(); - emptySee2Context.Summary = (ushort) (Signature & 0x0000ffff); - emptySee2Context.Shift = (byte) ((Signature >> 16) & 0x000000ff); - emptySee2Context.Count = (byte) (Signature >> 24); - } - - /// - /// Encode (ie. compress) a given source stream, writing the encoded result to the target stream. - /// - public void Encode(Stream target, Stream source, PpmdProperties properties) - { - if (target == null) - throw new ArgumentNullException("target"); - - if (source == null) - throw new ArgumentNullException("source"); - - EncodeStart(properties); - EncodeBlock(target, source, true); - } - - internal Coder EncodeStart(PpmdProperties properties) - { - Allocator = properties.Allocator; - Coder = new Coder(); - Coder.RangeEncoderInitialize(); - StartModel(properties.ModelOrder, properties.ModelRestorationMethod); - return Coder; - } - - internal void EncodeBlock(Stream target, Stream source, bool final) - { - while (true) - { - minimumContext = maximumContext; - numberStatistics = minimumContext.NumberStatistics; - - int c = source.ReadByte(); - if (c < 0 && !final) - return; - - if (numberStatistics != 0) - { - EncodeSymbol1(c, minimumContext); - Coder.RangeEncodeSymbol(); - } - else - { - EncodeBinarySymbol(c, minimumContext); - Coder.RangeShiftEncodeSymbol(TotalBitCount); - } - - while (foundState == PpmState.Zero) - { - Coder.RangeEncoderNormalize(target); - do - { - orderFall++; - minimumContext = minimumContext.Suffix; - if (minimumContext == PpmContext.Zero) - goto StopEncoding; - } while (minimumContext.NumberStatistics == numberMasked); - EncodeSymbol2(c, minimumContext); - Coder.RangeEncodeSymbol(); - } - - if (orderFall == 0 && (Pointer) foundState.Successor >= Allocator.BaseUnit) - { - maximumContext = foundState.Successor; - } - else - { - UpdateModel(minimumContext); - if (escapeCount == 0) - ClearMask(); - } - - Coder.RangeEncoderNormalize(target); - } - - StopEncoding: - Coder.RangeEncoderFlush(target); - } - - - /// - /// Dencode (ie. decompress) a given source stream, writing the decoded result to the target stream. - /// - public void Decode(Stream target, Stream source, PpmdProperties properties) - { - if (target == null) - throw new ArgumentNullException("target"); - - if (source == null) - throw new ArgumentNullException("source"); - - DecodeStart(source, properties); - byte[] buffer = new byte[65536]; - int read; - while ((read = DecodeBlock(source, buffer, 0, buffer.Length)) != 0) - target.Write(buffer, 0, read); - - return; - } - - internal Coder DecodeStart(Stream source, PpmdProperties properties) - { - Allocator = properties.Allocator; - Coder = new Coder(); - Coder.RangeDecoderInitialize(source); - StartModel(properties.ModelOrder, properties.ModelRestorationMethod); - minimumContext = maximumContext; - numberStatistics = minimumContext.NumberStatistics; - return Coder; - } - - internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count) - { - if (minimumContext == PpmContext.Zero) - return 0; - - int total = 0; - while (total < count) - { - if (numberStatistics != 0) - DecodeSymbol1(minimumContext); - else - DecodeBinarySymbol(minimumContext); - - Coder.RangeRemoveSubrange(); - - while (foundState == PpmState.Zero) - { - Coder.RangeDecoderNormalize(source); - do - { - orderFall++; - minimumContext = minimumContext.Suffix; - if (minimumContext == PpmContext.Zero) - goto StopDecoding; - } while (minimumContext.NumberStatistics == numberMasked); - DecodeSymbol2(minimumContext); - Coder.RangeRemoveSubrange(); - } - - buffer[offset] = foundState.Symbol; - offset++; - total++; - - if (orderFall == 0 && (Pointer) foundState.Successor >= Allocator.BaseUnit) - { - maximumContext = foundState.Successor; - } - else - { - UpdateModel(minimumContext); - if (escapeCount == 0) - ClearMask(); - } - - minimumContext = maximumContext; - numberStatistics = minimumContext.NumberStatistics; - Coder.RangeDecoderNormalize(source); - } - - StopDecoding: - return total; - } - - #endregion - - #region Private Methods - - /// - /// Initialise the model (unless the model order is set to 1 in which case the model should be cleared so that - /// the statistics are carried over, allowing "solid" mode compression). - /// - private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod) - { - Array.Clear(characterMask, 0, characterMask.Length); - escapeCount = 1; - - // Compress in "solid" mode if the model order value is set to 1 (this will examine the current PPM context - // structures to determine the value of orderFall). - - if (modelOrder < 2) - { - orderFall = this.modelOrder; - for (PpmContext context = maximumContext; context.Suffix != PpmContext.Zero; context = context.Suffix) - orderFall--; - return; - } - - this.modelOrder = modelOrder; - orderFall = modelOrder; - method = modelRestorationMethod; - Allocator.Initialize(); - initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1; - runLength = initialRunLength; - - // Allocate the context structure. - - maximumContext = Allocator.AllocateContext(); - maximumContext.Suffix = PpmContext.Zero; - maximumContext.NumberStatistics = 255; - maximumContext.SummaryFrequency = (ushort) (maximumContext.NumberStatistics + 2); - maximumContext.Statistics = Allocator.AllocateUnits(256/2); - // allocates enough space for 256 PPM states (each is 6 bytes) - - previousSuccess = 0; - for (int index = 0; index < 256; index++) - { - PpmState state = maximumContext.Statistics[index]; - state.Symbol = (byte) index; - state.Frequency = 1; - state.Successor = PpmContext.Zero; - } - - uint probability = 0; - for (int index1 = 0; probability < 25; probability++) - { - while (probabilities[index1] == probability) - index1++; - for (int index2 = 0; index2 < 8; index2++) - binarySummary[probability, index2] = - (ushort) (BinaryScale - InitialBinaryEscapes[index2]/(index1 + 1)); - for (int index2 = 8; index2 < 64; index2 += 8) - for (int index3 = 0; index3 < 8; index3++) - binarySummary[probability, index2 + index3] = binarySummary[probability, index3]; - } - - probability = 0; - for (uint index1 = 0; probability < 24; probability++) - { - while (probabilities[index1 + 3] == probability + 3) - index1++; - for (int index2 = 0; index2 < 32; index2++) - see2Contexts[probability, index2].Initialize(2*index1 + 5); - } - } - - private void UpdateModel(PpmContext minimumContext) - { - PpmState state = PpmState.Zero; - PpmContext Successor; - PpmContext currentContext = maximumContext; - uint numberStatistics; - uint ns1; - uint cf; - uint sf; - uint s0; - uint foundStateFrequency = foundState.Frequency; - byte foundStateSymbol = foundState.Symbol; - byte symbol; - byte flag; - - PpmContext foundStateSuccessor = foundState.Successor; - PpmContext context = minimumContext.Suffix; - - if ((foundStateFrequency < MaximumFrequency/4) && (context != PpmContext.Zero)) - { - if (context.NumberStatistics != 0) - { - state = context.Statistics; - if (state.Symbol != foundStateSymbol) - { - do - { - symbol = state[1].Symbol; - state++; - } while (symbol != foundStateSymbol); - if (state[0].Frequency >= state[-1].Frequency) - { - Swap(state[0], state[-1]); - state--; - } - } - cf = (uint) ((state.Frequency < MaximumFrequency - 9) ? 2 : 0); - state.Frequency += (byte) cf; - context.SummaryFrequency += (byte) cf; - } - else - { - state = context.FirstState; - state.Frequency += (byte) ((state.Frequency < 32) ? 1 : 0); - } - } - - if (orderFall == 0 && foundStateSuccessor != PpmContext.Zero) - { - foundState.Successor = CreateSuccessors(true, state, minimumContext); - if (foundState.Successor == PpmContext.Zero) - goto RestartModel; - maximumContext = foundState.Successor; - return; - } - - Allocator.Text[0] = foundStateSymbol; - Allocator.Text++; - Successor = Allocator.Text; - - if (Allocator.Text >= Allocator.BaseUnit) - goto RestartModel; - - if (foundStateSuccessor != PpmContext.Zero) - { - if (foundStateSuccessor < Allocator.BaseUnit) - foundStateSuccessor = CreateSuccessors(false, state, minimumContext); - } - else - { - foundStateSuccessor = ReduceOrder(state, minimumContext); - } - - if (foundStateSuccessor == PpmContext.Zero) - goto RestartModel; - - if (--orderFall == 0) - { - Successor = foundStateSuccessor; - Allocator.Text -= (maximumContext != minimumContext) ? 1 : 0; - } - else if (method > ModelRestorationMethod.Freeze) - { - Successor = foundStateSuccessor; - Allocator.Text = Allocator.Heap; - orderFall = 0; - } - - numberStatistics = minimumContext.NumberStatistics; - s0 = minimumContext.SummaryFrequency - numberStatistics - foundStateFrequency; - flag = (byte) ((foundStateSymbol >= 0x40) ? 0x08 : 0x00); - for (; currentContext != minimumContext; currentContext = currentContext.Suffix) - { - ns1 = currentContext.NumberStatistics; - if (ns1 != 0) - { - if ((ns1 & 1) != 0) - { - state = Allocator.ExpandUnits(currentContext.Statistics, (ns1 + 1) >> 1); - if (state == PpmState.Zero) - goto RestartModel; - currentContext.Statistics = state; - } - currentContext.SummaryFrequency += (ushort) ((3*ns1 + 1 < numberStatistics) ? 1 : 0); - } - else - { - state = Allocator.AllocateUnits(1); - if (state == PpmState.Zero) - goto RestartModel; - Copy(state, currentContext.FirstState); - currentContext.Statistics = state; - if (state.Frequency < MaximumFrequency/4 - 1) - state.Frequency += state.Frequency; - else - state.Frequency = (byte) (MaximumFrequency - 4); - currentContext.SummaryFrequency = - (ushort) (state.Frequency + initialEscape + ((numberStatistics > 2) ? 1 : 0)); - } - - cf = (uint) (2*foundStateFrequency*(currentContext.SummaryFrequency + 6)); - sf = s0 + currentContext.SummaryFrequency; - - if (cf < 6*sf) - { - cf = (uint) (1 + ((cf > sf) ? 1 : 0) + ((cf >= 4*sf) ? 1 : 0)); - currentContext.SummaryFrequency += 4; - } - else - { - cf = (uint) (4 + ((cf > 9*sf) ? 1 : 0) + ((cf > 12*sf) ? 1 : 0) + ((cf > 15*sf) ? 1 : 0)); - currentContext.SummaryFrequency += (ushort) cf; - } - - state = currentContext.Statistics + (++currentContext.NumberStatistics); - state.Successor = Successor; - state.Symbol = foundStateSymbol; - state.Frequency = (byte) cf; - currentContext.Flags |= flag; - } - - maximumContext = foundStateSuccessor; - return; - - RestartModel: - RestoreModel(currentContext, minimumContext, foundStateSuccessor); - } - - private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context) - { - PpmContext upBranch = foundState.Successor; - PpmState[] states = new PpmState[MaximumOrder]; - uint stateIndex = 0; - byte symbol = foundState.Symbol; - - if (!skip) - { - states[stateIndex++] = foundState; - if (context.Suffix == PpmContext.Zero) - goto NoLoop; - } - - bool gotoLoopEntry = false; - if (state != PpmState.Zero) - { - context = context.Suffix; - gotoLoopEntry = true; - } - - do - { - if (gotoLoopEntry) - { - gotoLoopEntry = false; - goto LoopEntry; - } - - context = context.Suffix; - if (context.NumberStatistics != 0) - { - byte temporary; - state = context.Statistics; - if (state.Symbol != symbol) - { - do - { - temporary = state[1].Symbol; - state++; - } while (temporary != symbol); - } - temporary = (byte) ((state.Frequency < MaximumFrequency - 9) ? 1 : 0); - state.Frequency += temporary; - context.SummaryFrequency += temporary; - } - else - { - state = context.FirstState; - state.Frequency += - (byte) (((context.Suffix.NumberStatistics == 0) ? 1 : 0) & ((state.Frequency < 24) ? 1 : 0)); - } - - LoopEntry: - if (state.Successor != upBranch) - { - context = state.Successor; - break; - } - states[stateIndex++] = state; - } while (context.Suffix != PpmContext.Zero); - - NoLoop: - if (stateIndex == 0) - return context; - - byte localNumberStatistics = 0; - byte localFlags = (byte) ((symbol >= 0x40) ? 0x10 : 0x00); - symbol = upBranch.NumberStatistics; - byte localSymbol = symbol; - byte localFrequency; - PpmContext localSuccessor = ((Pointer) upBranch) + 1; - localFlags |= (byte) ((symbol >= 0x40) ? 0x08 : 0x00); - - if (context.NumberStatistics != 0) - { - state = context.Statistics; - if (state.Symbol != symbol) - { - byte temporary; - do - { - temporary = state[1].Symbol; - state++; - } while (temporary != symbol); - } - uint cf = (uint) (state.Frequency - 1); - uint s0 = (uint) (context.SummaryFrequency - context.NumberStatistics - cf); - localFrequency = (byte) (1 + ((2*cf <= s0) ? (uint) ((5*cf > s0) ? 1 : 0) : ((cf + 2*s0 - 3)/s0))); - } - else - { - localFrequency = context.FirstStateFrequency; - } - - do - { - PpmContext currentContext = Allocator.AllocateContext(); - if (currentContext == PpmContext.Zero) - return PpmContext.Zero; - currentContext.NumberStatistics = localNumberStatistics; - currentContext.Flags = localFlags; - currentContext.FirstStateSymbol = localSymbol; - currentContext.FirstStateFrequency = localFrequency; - currentContext.FirstStateSuccessor = localSuccessor; - currentContext.Suffix = context; - context = currentContext; - states[--stateIndex].Successor = context; - } while (stateIndex != 0); - - return context; - } - - private PpmContext ReduceOrder(PpmState state, PpmContext context) - { - PpmState currentState; - PpmState[] states = new PpmState[MaximumOrder]; - uint stateIndex = 0; - PpmContext currentContext = context; - PpmContext UpBranch = Allocator.Text; - byte temporary; - byte symbol = foundState.Symbol; - - states[stateIndex++] = foundState; - foundState.Successor = UpBranch; - orderFall++; - - bool gotoLoopEntry = false; - if (state != PpmState.Zero) - { - context = context.Suffix; - gotoLoopEntry = true; - } - - while (true) - { - if (gotoLoopEntry) - { - gotoLoopEntry = false; - goto LoopEntry; - } - - if (context.Suffix == PpmContext.Zero) - { - if (method > ModelRestorationMethod.Freeze) - { - do - { - states[--stateIndex].Successor = context; - } while (stateIndex != 0); - Allocator.Text = Allocator.Heap + 1; - orderFall = 1; - } - return context; - } - - context = context.Suffix; - if (context.NumberStatistics != 0) - { - state = context.Statistics; - if (state.Symbol != symbol) - { - do - { - temporary = state[1].Symbol; - state++; - } while (temporary != symbol); - } - temporary = (byte) ((state.Frequency < MaximumFrequency - 9) ? 2 : 0); - state.Frequency += temporary; - context.SummaryFrequency += temporary; - } - else - { - state = context.FirstState; - state.Frequency += (byte) ((state.Frequency < 32) ? 1 : 0); - } - - LoopEntry: - if (state.Successor != PpmContext.Zero) - break; - states[stateIndex++] = state; - state.Successor = UpBranch; - orderFall++; - } - - if (method > ModelRestorationMethod.Freeze) - { - context = state.Successor; - do - { - states[--stateIndex].Successor = context; - } while (stateIndex != 0); - Allocator.Text = Allocator.Heap + 1; - orderFall = 1; - return context; - } - else if (state.Successor <= UpBranch) - { - currentState = foundState; - foundState = state; - state.Successor = CreateSuccessors(false, PpmState.Zero, context); - foundState = currentState; - } - - if (orderFall == 1 && currentContext == maximumContext) - { - foundState.Successor = state.Successor; - Allocator.Text--; - } - - return state.Successor; - } - - private void RestoreModel(PpmContext context, PpmContext minimumContext, PpmContext foundStateSuccessor) - { - PpmContext currentContext; - - Allocator.Text = Allocator.Heap; - for (currentContext = maximumContext; currentContext != context; currentContext = currentContext.Suffix) - { - if (--currentContext.NumberStatistics == 0) - { - currentContext.Flags = - (byte) - ((currentContext.Flags & 0x10) + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00)); - PpmState state = currentContext.Statistics; - Copy(currentContext.FirstState, state); - Allocator.SpecialFreeUnits(state); - currentContext.FirstStateFrequency = (byte) ((currentContext.FirstStateFrequency + 11) >> 3); - } - else - { - Refresh((uint) ((currentContext.NumberStatistics + 3) >> 1), false, currentContext); - } - } - - for (; currentContext != minimumContext; currentContext = currentContext.Suffix) - { - if (currentContext.NumberStatistics == 0) - currentContext.FirstStateFrequency -= (byte) (currentContext.FirstStateFrequency >> 1); - else if ((currentContext.SummaryFrequency += 4) > 128 + 4*currentContext.NumberStatistics) - Refresh((uint) ((currentContext.NumberStatistics + 2) >> 1), true, currentContext); - } - - if (method > ModelRestorationMethod.Freeze) - { - maximumContext = foundStateSuccessor; - Allocator.GlueCount += (uint) (((Allocator.MemoryNodes[1].Stamp & 1) == 0) ? 1 : 0); - } - else if (method == ModelRestorationMethod.Freeze) - { - while (maximumContext.Suffix != PpmContext.Zero) - maximumContext = maximumContext.Suffix; - - RemoveBinaryContexts(0, maximumContext); - method = (ModelRestorationMethod) (method + 1); - Allocator.GlueCount = 0; - orderFall = modelOrder; - } - else if (method == ModelRestorationMethod.Restart || - Allocator.GetMemoryUsed() < (Allocator.AllocatorSize >> 1)) - { - StartModel(modelOrder, method); - escapeCount = 0; - } - else - { - while (maximumContext.Suffix != PpmContext.Zero) - maximumContext = maximumContext.Suffix; - - do - { - CutOff(0, maximumContext); - Allocator.ExpandText(); - } while (Allocator.GetMemoryUsed() > 3*(Allocator.AllocatorSize >> 2)); - - Allocator.GlueCount = 0; - orderFall = modelOrder; - } - } - - private static void Swap(PpmState state1, PpmState state2) - { - byte swapSymbol = state1.Symbol; - byte swapFrequency = state1.Frequency; - PpmContext swapSuccessor = state1.Successor; - - state1.Symbol = state2.Symbol; - state1.Frequency = state2.Frequency; - state1.Successor = state2.Successor; - - state2.Symbol = swapSymbol; - state2.Frequency = swapFrequency; - state2.Successor = swapSuccessor; - } - - private static void Copy(PpmState state1, PpmState state2) - { - state1.Symbol = state2.Symbol; - state1.Frequency = state2.Frequency; - state1.Successor = state2.Successor; - } - - private static int Mean(int sum, int shift, int round) - { - return (sum + (1 << (shift - round))) >> shift; - } - - private void ClearMask() - { - escapeCount = 1; - Array.Clear(characterMask, 0, characterMask.Length); - } - - #endregion - } +#region Using + +using System; +using System.IO; + +#endregion + +// This is a port of Dmitry Shkarin's PPMd Variant I Revision 1. +// Ported by Michael Bone (mjbone03@yahoo.com.au). + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// The model. + /// + internal partial class Model + { + public const uint Signature = 0x84acaf8fU; + public const char Variant = 'I'; + public const int MaximumOrder = 16; // maximum allowed model order + + private const byte UpperFrequency = 5; + private const byte IntervalBitCount = 7; + private const byte PeriodBitCount = 7; + private const byte TotalBitCount = IntervalBitCount + PeriodBitCount; + private const uint Interval = 1 << IntervalBitCount; + private const uint BinaryScale = 1 << TotalBitCount; + private const uint MaximumFrequency = 124; + private const uint OrderBound = 9; + + private See2Context[,] see2Contexts; + private See2Context emptySee2Context; + private PpmContext maximumContext; + private ushort[,] binarySummary = new ushort[25,64]; // binary SEE-contexts + private byte[] numberStatisticsToBinarySummaryIndex = new byte[256]; + private byte[] probabilities = new byte[260]; + private byte[] characterMask = new byte[256]; + private byte escapeCount; + private int modelOrder; + private int orderFall; + private int initialEscape; + private int initialRunLength; + private int runLength; + private byte previousSuccess; + private byte numberMasked; + private ModelRestorationMethod method; + private PpmState foundState; // found next state transition + + private Allocator Allocator; + private Coder Coder; + private PpmContext minimumContext; + private byte numberStatistics; + private PpmState[] decodeStates = new PpmState[256]; + + private static readonly ushort[] InitialBinaryEscapes = + { + 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, + 0x6051 + }; + + private static readonly byte[] ExponentialEscapes = {25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2}; + + #region Public Methods + + public Model() + { + // Construct the conversion table for number statistics. Initially it will contain the following values. + // + // 0 2 4 4 4 4 4 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + + numberStatisticsToBinarySummaryIndex[0] = 2*0; + numberStatisticsToBinarySummaryIndex[1] = 2*1; + for (int index = 2; index < 11; index++) + numberStatisticsToBinarySummaryIndex[index] = 2*2; + for (int index = 11; index < 256; index++) + numberStatisticsToBinarySummaryIndex[index] = 2*3; + + // Construct the probability table. Initially it will contain the following values (depending on the value of + // the upper frequency). + // + // 00 01 02 03 04 05 06 06 07 07 07 08 08 08 08 09 09 09 09 09 10 10 10 10 10 10 11 11 11 11 11 11 + // 11 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 15 15 15 15 + // 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17 17 17 17 17 + // 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 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 21 22 22 + // 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 + // 23 23 23 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 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 + // 26 26 27 27 + + uint count = 1; + uint step = 1; + uint probability = UpperFrequency; + + for (int index = 0; index < UpperFrequency; index++) + probabilities[index] = (byte) index; + + for (int index = UpperFrequency; index < 260; index++) + { + probabilities[index] = (byte) probability; + count--; + if (count == 0) + { + step++; + count = step; + probability++; + } + } + + // Create the context array. + + see2Contexts = new See2Context[24,32]; + for (int index1 = 0; index1 < 24; index1++) + for (int index2 = 0; index2 < 32; index2++) + see2Contexts[index1, index2] = new See2Context(); + + // Set the signature (identifying the algorithm). + + emptySee2Context = new See2Context(); + emptySee2Context.Summary = (ushort) (Signature & 0x0000ffff); + emptySee2Context.Shift = (byte) ((Signature >> 16) & 0x000000ff); + emptySee2Context.Count = (byte) (Signature >> 24); + } + + /// + /// Encode (ie. compress) a given source stream, writing the encoded result to the target stream. + /// + public void Encode(Stream target, Stream source, PpmdProperties properties) + { + if (target == null) + throw new ArgumentNullException("target"); + + if (source == null) + throw new ArgumentNullException("source"); + + EncodeStart(properties); + EncodeBlock(target, source, true); + } + + internal Coder EncodeStart(PpmdProperties properties) + { + Allocator = properties.Allocator; + Coder = new Coder(); + Coder.RangeEncoderInitialize(); + StartModel(properties.ModelOrder, properties.ModelRestorationMethod); + return Coder; + } + + internal void EncodeBlock(Stream target, Stream source, bool final) + { + while (true) + { + minimumContext = maximumContext; + numberStatistics = minimumContext.NumberStatistics; + + int c = source.ReadByte(); + if (c < 0 && !final) + return; + + if (numberStatistics != 0) + { + EncodeSymbol1(c, minimumContext); + Coder.RangeEncodeSymbol(); + } + else + { + EncodeBinarySymbol(c, minimumContext); + Coder.RangeShiftEncodeSymbol(TotalBitCount); + } + + while (foundState == PpmState.Zero) + { + Coder.RangeEncoderNormalize(target); + do + { + orderFall++; + minimumContext = minimumContext.Suffix; + if (minimumContext == PpmContext.Zero) + goto StopEncoding; + } while (minimumContext.NumberStatistics == numberMasked); + EncodeSymbol2(c, minimumContext); + Coder.RangeEncodeSymbol(); + } + + if (orderFall == 0 && (Pointer) foundState.Successor >= Allocator.BaseUnit) + { + maximumContext = foundState.Successor; + } + else + { + UpdateModel(minimumContext); + if (escapeCount == 0) + ClearMask(); + } + + Coder.RangeEncoderNormalize(target); + } + + StopEncoding: + Coder.RangeEncoderFlush(target); + } + + + /// + /// Dencode (ie. decompress) a given source stream, writing the decoded result to the target stream. + /// + public void Decode(Stream target, Stream source, PpmdProperties properties) + { + if (target == null) + throw new ArgumentNullException("target"); + + if (source == null) + throw new ArgumentNullException("source"); + + DecodeStart(source, properties); + byte[] buffer = new byte[65536]; + int read; + while ((read = DecodeBlock(source, buffer, 0, buffer.Length)) != 0) + target.Write(buffer, 0, read); + + return; + } + + internal Coder DecodeStart(Stream source, PpmdProperties properties) + { + Allocator = properties.Allocator; + Coder = new Coder(); + Coder.RangeDecoderInitialize(source); + StartModel(properties.ModelOrder, properties.ModelRestorationMethod); + minimumContext = maximumContext; + numberStatistics = minimumContext.NumberStatistics; + return Coder; + } + + internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count) + { + if (minimumContext == PpmContext.Zero) + return 0; + + int total = 0; + while (total < count) + { + if (numberStatistics != 0) + DecodeSymbol1(minimumContext); + else + DecodeBinarySymbol(minimumContext); + + Coder.RangeRemoveSubrange(); + + while (foundState == PpmState.Zero) + { + Coder.RangeDecoderNormalize(source); + do + { + orderFall++; + minimumContext = minimumContext.Suffix; + if (minimumContext == PpmContext.Zero) + goto StopDecoding; + } while (minimumContext.NumberStatistics == numberMasked); + DecodeSymbol2(minimumContext); + Coder.RangeRemoveSubrange(); + } + + buffer[offset] = foundState.Symbol; + offset++; + total++; + + if (orderFall == 0 && (Pointer) foundState.Successor >= Allocator.BaseUnit) + { + maximumContext = foundState.Successor; + } + else + { + UpdateModel(minimumContext); + if (escapeCount == 0) + ClearMask(); + } + + minimumContext = maximumContext; + numberStatistics = minimumContext.NumberStatistics; + Coder.RangeDecoderNormalize(source); + } + + StopDecoding: + return total; + } + + #endregion + + #region Private Methods + + /// + /// Initialise the model (unless the model order is set to 1 in which case the model should be cleared so that + /// the statistics are carried over, allowing "solid" mode compression). + /// + private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod) + { + Array.Clear(characterMask, 0, characterMask.Length); + escapeCount = 1; + + // Compress in "solid" mode if the model order value is set to 1 (this will examine the current PPM context + // structures to determine the value of orderFall). + + if (modelOrder < 2) + { + orderFall = this.modelOrder; + for (PpmContext context = maximumContext; context.Suffix != PpmContext.Zero; context = context.Suffix) + orderFall--; + return; + } + + this.modelOrder = modelOrder; + orderFall = modelOrder; + method = modelRestorationMethod; + Allocator.Initialize(); + initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1; + runLength = initialRunLength; + + // Allocate the context structure. + + maximumContext = Allocator.AllocateContext(); + maximumContext.Suffix = PpmContext.Zero; + maximumContext.NumberStatistics = 255; + maximumContext.SummaryFrequency = (ushort) (maximumContext.NumberStatistics + 2); + maximumContext.Statistics = Allocator.AllocateUnits(256/2); + // allocates enough space for 256 PPM states (each is 6 bytes) + + previousSuccess = 0; + for (int index = 0; index < 256; index++) + { + PpmState state = maximumContext.Statistics[index]; + state.Symbol = (byte) index; + state.Frequency = 1; + state.Successor = PpmContext.Zero; + } + + uint probability = 0; + for (int index1 = 0; probability < 25; probability++) + { + while (probabilities[index1] == probability) + index1++; + for (int index2 = 0; index2 < 8; index2++) + binarySummary[probability, index2] = + (ushort) (BinaryScale - InitialBinaryEscapes[index2]/(index1 + 1)); + for (int index2 = 8; index2 < 64; index2 += 8) + for (int index3 = 0; index3 < 8; index3++) + binarySummary[probability, index2 + index3] = binarySummary[probability, index3]; + } + + probability = 0; + for (uint index1 = 0; probability < 24; probability++) + { + while (probabilities[index1 + 3] == probability + 3) + index1++; + for (int index2 = 0; index2 < 32; index2++) + see2Contexts[probability, index2].Initialize(2*index1 + 5); + } + } + + private void UpdateModel(PpmContext minimumContext) + { + PpmState state = PpmState.Zero; + PpmContext Successor; + PpmContext currentContext = maximumContext; + uint numberStatistics; + uint ns1; + uint cf; + uint sf; + uint s0; + uint foundStateFrequency = foundState.Frequency; + byte foundStateSymbol = foundState.Symbol; + byte symbol; + byte flag; + + PpmContext foundStateSuccessor = foundState.Successor; + PpmContext context = minimumContext.Suffix; + + if ((foundStateFrequency < MaximumFrequency/4) && (context != PpmContext.Zero)) + { + if (context.NumberStatistics != 0) + { + state = context.Statistics; + if (state.Symbol != foundStateSymbol) + { + do + { + symbol = state[1].Symbol; + state++; + } while (symbol != foundStateSymbol); + if (state[0].Frequency >= state[-1].Frequency) + { + Swap(state[0], state[-1]); + state--; + } + } + cf = (uint) ((state.Frequency < MaximumFrequency - 9) ? 2 : 0); + state.Frequency += (byte) cf; + context.SummaryFrequency += (byte) cf; + } + else + { + state = context.FirstState; + state.Frequency += (byte) ((state.Frequency < 32) ? 1 : 0); + } + } + + if (orderFall == 0 && foundStateSuccessor != PpmContext.Zero) + { + foundState.Successor = CreateSuccessors(true, state, minimumContext); + if (foundState.Successor == PpmContext.Zero) + goto RestartModel; + maximumContext = foundState.Successor; + return; + } + + Allocator.Text[0] = foundStateSymbol; + Allocator.Text++; + Successor = Allocator.Text; + + if (Allocator.Text >= Allocator.BaseUnit) + goto RestartModel; + + if (foundStateSuccessor != PpmContext.Zero) + { + if (foundStateSuccessor < Allocator.BaseUnit) + foundStateSuccessor = CreateSuccessors(false, state, minimumContext); + } + else + { + foundStateSuccessor = ReduceOrder(state, minimumContext); + } + + if (foundStateSuccessor == PpmContext.Zero) + goto RestartModel; + + if (--orderFall == 0) + { + Successor = foundStateSuccessor; + Allocator.Text -= (maximumContext != minimumContext) ? 1 : 0; + } + else if (method > ModelRestorationMethod.Freeze) + { + Successor = foundStateSuccessor; + Allocator.Text = Allocator.Heap; + orderFall = 0; + } + + numberStatistics = minimumContext.NumberStatistics; + s0 = minimumContext.SummaryFrequency - numberStatistics - foundStateFrequency; + flag = (byte) ((foundStateSymbol >= 0x40) ? 0x08 : 0x00); + for (; currentContext != minimumContext; currentContext = currentContext.Suffix) + { + ns1 = currentContext.NumberStatistics; + if (ns1 != 0) + { + if ((ns1 & 1) != 0) + { + state = Allocator.ExpandUnits(currentContext.Statistics, (ns1 + 1) >> 1); + if (state == PpmState.Zero) + goto RestartModel; + currentContext.Statistics = state; + } + currentContext.SummaryFrequency += (ushort) ((3*ns1 + 1 < numberStatistics) ? 1 : 0); + } + else + { + state = Allocator.AllocateUnits(1); + if (state == PpmState.Zero) + goto RestartModel; + Copy(state, currentContext.FirstState); + currentContext.Statistics = state; + if (state.Frequency < MaximumFrequency/4 - 1) + state.Frequency += state.Frequency; + else + state.Frequency = (byte) (MaximumFrequency - 4); + currentContext.SummaryFrequency = + (ushort) (state.Frequency + initialEscape + ((numberStatistics > 2) ? 1 : 0)); + } + + cf = (uint) (2*foundStateFrequency*(currentContext.SummaryFrequency + 6)); + sf = s0 + currentContext.SummaryFrequency; + + if (cf < 6*sf) + { + cf = (uint) (1 + ((cf > sf) ? 1 : 0) + ((cf >= 4*sf) ? 1 : 0)); + currentContext.SummaryFrequency += 4; + } + else + { + cf = (uint) (4 + ((cf > 9*sf) ? 1 : 0) + ((cf > 12*sf) ? 1 : 0) + ((cf > 15*sf) ? 1 : 0)); + currentContext.SummaryFrequency += (ushort) cf; + } + + state = currentContext.Statistics + (++currentContext.NumberStatistics); + state.Successor = Successor; + state.Symbol = foundStateSymbol; + state.Frequency = (byte) cf; + currentContext.Flags |= flag; + } + + maximumContext = foundStateSuccessor; + return; + + RestartModel: + RestoreModel(currentContext, minimumContext, foundStateSuccessor); + } + + private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context) + { + PpmContext upBranch = foundState.Successor; + PpmState[] states = new PpmState[MaximumOrder]; + uint stateIndex = 0; + byte symbol = foundState.Symbol; + + if (!skip) + { + states[stateIndex++] = foundState; + if (context.Suffix == PpmContext.Zero) + goto NoLoop; + } + + bool gotoLoopEntry = false; + if (state != PpmState.Zero) + { + context = context.Suffix; + gotoLoopEntry = true; + } + + do + { + if (gotoLoopEntry) + { + gotoLoopEntry = false; + goto LoopEntry; + } + + context = context.Suffix; + if (context.NumberStatistics != 0) + { + byte temporary; + state = context.Statistics; + if (state.Symbol != symbol) + { + do + { + temporary = state[1].Symbol; + state++; + } while (temporary != symbol); + } + temporary = (byte) ((state.Frequency < MaximumFrequency - 9) ? 1 : 0); + state.Frequency += temporary; + context.SummaryFrequency += temporary; + } + else + { + state = context.FirstState; + state.Frequency += + (byte) (((context.Suffix.NumberStatistics == 0) ? 1 : 0) & ((state.Frequency < 24) ? 1 : 0)); + } + + LoopEntry: + if (state.Successor != upBranch) + { + context = state.Successor; + break; + } + states[stateIndex++] = state; + } while (context.Suffix != PpmContext.Zero); + + NoLoop: + if (stateIndex == 0) + return context; + + byte localNumberStatistics = 0; + byte localFlags = (byte) ((symbol >= 0x40) ? 0x10 : 0x00); + symbol = upBranch.NumberStatistics; + byte localSymbol = symbol; + byte localFrequency; + PpmContext localSuccessor = ((Pointer) upBranch) + 1; + localFlags |= (byte) ((symbol >= 0x40) ? 0x08 : 0x00); + + if (context.NumberStatistics != 0) + { + state = context.Statistics; + if (state.Symbol != symbol) + { + byte temporary; + do + { + temporary = state[1].Symbol; + state++; + } while (temporary != symbol); + } + uint cf = (uint) (state.Frequency - 1); + uint s0 = (uint) (context.SummaryFrequency - context.NumberStatistics - cf); + localFrequency = (byte) (1 + ((2*cf <= s0) ? (uint) ((5*cf > s0) ? 1 : 0) : ((cf + 2*s0 - 3)/s0))); + } + else + { + localFrequency = context.FirstStateFrequency; + } + + do + { + PpmContext currentContext = Allocator.AllocateContext(); + if (currentContext == PpmContext.Zero) + return PpmContext.Zero; + currentContext.NumberStatistics = localNumberStatistics; + currentContext.Flags = localFlags; + currentContext.FirstStateSymbol = localSymbol; + currentContext.FirstStateFrequency = localFrequency; + currentContext.FirstStateSuccessor = localSuccessor; + currentContext.Suffix = context; + context = currentContext; + states[--stateIndex].Successor = context; + } while (stateIndex != 0); + + return context; + } + + private PpmContext ReduceOrder(PpmState state, PpmContext context) + { + PpmState currentState; + PpmState[] states = new PpmState[MaximumOrder]; + uint stateIndex = 0; + PpmContext currentContext = context; + PpmContext UpBranch = Allocator.Text; + byte temporary; + byte symbol = foundState.Symbol; + + states[stateIndex++] = foundState; + foundState.Successor = UpBranch; + orderFall++; + + bool gotoLoopEntry = false; + if (state != PpmState.Zero) + { + context = context.Suffix; + gotoLoopEntry = true; + } + + while (true) + { + if (gotoLoopEntry) + { + gotoLoopEntry = false; + goto LoopEntry; + } + + if (context.Suffix == PpmContext.Zero) + { + if (method > ModelRestorationMethod.Freeze) + { + do + { + states[--stateIndex].Successor = context; + } while (stateIndex != 0); + Allocator.Text = Allocator.Heap + 1; + orderFall = 1; + } + return context; + } + + context = context.Suffix; + if (context.NumberStatistics != 0) + { + state = context.Statistics; + if (state.Symbol != symbol) + { + do + { + temporary = state[1].Symbol; + state++; + } while (temporary != symbol); + } + temporary = (byte) ((state.Frequency < MaximumFrequency - 9) ? 2 : 0); + state.Frequency += temporary; + context.SummaryFrequency += temporary; + } + else + { + state = context.FirstState; + state.Frequency += (byte) ((state.Frequency < 32) ? 1 : 0); + } + + LoopEntry: + if (state.Successor != PpmContext.Zero) + break; + states[stateIndex++] = state; + state.Successor = UpBranch; + orderFall++; + } + + if (method > ModelRestorationMethod.Freeze) + { + context = state.Successor; + do + { + states[--stateIndex].Successor = context; + } while (stateIndex != 0); + Allocator.Text = Allocator.Heap + 1; + orderFall = 1; + return context; + } + else if (state.Successor <= UpBranch) + { + currentState = foundState; + foundState = state; + state.Successor = CreateSuccessors(false, PpmState.Zero, context); + foundState = currentState; + } + + if (orderFall == 1 && currentContext == maximumContext) + { + foundState.Successor = state.Successor; + Allocator.Text--; + } + + return state.Successor; + } + + private void RestoreModel(PpmContext context, PpmContext minimumContext, PpmContext foundStateSuccessor) + { + PpmContext currentContext; + + Allocator.Text = Allocator.Heap; + for (currentContext = maximumContext; currentContext != context; currentContext = currentContext.Suffix) + { + if (--currentContext.NumberStatistics == 0) + { + currentContext.Flags = + (byte) + ((currentContext.Flags & 0x10) + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00)); + PpmState state = currentContext.Statistics; + Copy(currentContext.FirstState, state); + Allocator.SpecialFreeUnits(state); + currentContext.FirstStateFrequency = (byte) ((currentContext.FirstStateFrequency + 11) >> 3); + } + else + { + Refresh((uint) ((currentContext.NumberStatistics + 3) >> 1), false, currentContext); + } + } + + for (; currentContext != minimumContext; currentContext = currentContext.Suffix) + { + if (currentContext.NumberStatistics == 0) + currentContext.FirstStateFrequency -= (byte) (currentContext.FirstStateFrequency >> 1); + else if ((currentContext.SummaryFrequency += 4) > 128 + 4*currentContext.NumberStatistics) + Refresh((uint) ((currentContext.NumberStatistics + 2) >> 1), true, currentContext); + } + + if (method > ModelRestorationMethod.Freeze) + { + maximumContext = foundStateSuccessor; + Allocator.GlueCount += (uint) (((Allocator.MemoryNodes[1].Stamp & 1) == 0) ? 1 : 0); + } + else if (method == ModelRestorationMethod.Freeze) + { + while (maximumContext.Suffix != PpmContext.Zero) + maximumContext = maximumContext.Suffix; + + RemoveBinaryContexts(0, maximumContext); + method = (ModelRestorationMethod) (method + 1); + Allocator.GlueCount = 0; + orderFall = modelOrder; + } + else if (method == ModelRestorationMethod.Restart || + Allocator.GetMemoryUsed() < (Allocator.AllocatorSize >> 1)) + { + StartModel(modelOrder, method); + escapeCount = 0; + } + else + { + while (maximumContext.Suffix != PpmContext.Zero) + maximumContext = maximumContext.Suffix; + + do + { + CutOff(0, maximumContext); + Allocator.ExpandText(); + } while (Allocator.GetMemoryUsed() > 3*(Allocator.AllocatorSize >> 2)); + + Allocator.GlueCount = 0; + orderFall = modelOrder; + } + } + + private static void Swap(PpmState state1, PpmState state2) + { + byte swapSymbol = state1.Symbol; + byte swapFrequency = state1.Frequency; + PpmContext swapSuccessor = state1.Successor; + + state1.Symbol = state2.Symbol; + state1.Frequency = state2.Frequency; + state1.Successor = state2.Successor; + + state2.Symbol = swapSymbol; + state2.Frequency = swapFrequency; + state2.Successor = swapSuccessor; + } + + private static void Copy(PpmState state1, PpmState state2) + { + state1.Symbol = state2.Symbol; + state1.Frequency = state2.Frequency; + state1.Successor = state2.Successor; + } + + private static int Mean(int sum, int shift, int round) + { + return (sum + (1 << (shift - round))) >> shift; + } + + private void ClearMask() + { + escapeCount = 1; + Array.Clear(characterMask, 0, characterMask.Length); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/ModelRestorationMethod.cs b/src/SharpCompress/Compressor/PPMd/I1/ModelRestorationMethod.cs similarity index 95% rename from SharpCompress/Compressor/PPMd/I1/ModelRestorationMethod.cs rename to src/SharpCompress/Compressor/PPMd/I1/ModelRestorationMethod.cs index c0c2a2fb..cfcd6465 100644 --- a/SharpCompress/Compressor/PPMd/I1/ModelRestorationMethod.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/ModelRestorationMethod.cs @@ -1,29 +1,29 @@ -#region Using - -using System; - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// The method used to adjust the model when the memory limit is reached. - /// - internal enum ModelRestorationMethod - { - /// - /// Restart the model from scratch (this is the default). - /// - Restart = 0, - - /// - /// Cut off the model (nearly twice as slow). - /// - CutOff = 1, - - /// - /// Freeze the context tree (in some cases may result in poor compression). - /// - Freeze = 2 - } +#region Using + +using System; + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// The method used to adjust the model when the memory limit is reached. + /// + internal enum ModelRestorationMethod + { + /// + /// Restart the model from scratch (this is the default). + /// + Restart = 0, + + /// + /// Cut off the model (nearly twice as slow). + /// + CutOff = 1, + + /// + /// Freeze the context tree (in some cases may result in poor compression). + /// + Freeze = 2 + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/Pointer.cs b/src/SharpCompress/Compressor/PPMd/I1/Pointer.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/I1/Pointer.cs rename to src/SharpCompress/Compressor/PPMd/I1/Pointer.cs index 2e696484..6e43e902 100644 --- a/SharpCompress/Compressor/PPMd/I1/Pointer.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/Pointer.cs @@ -1,329 +1,329 @@ -#region Using - -using System; - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// A structure containing a single address representing a position in the array. This - /// is intended to mimic the behaviour of a pointer in C/C++. - /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of the - /// instance rather than just copying a reference to the same instance). - /// - /// - /// Note that is a field rather than a property for performance reasons. - /// - /// - internal struct Pointer - { - public uint Address; - public byte[] Memory; - public static readonly Pointer Zero = new Pointer(0, null); - public const int Size = 1; - - /// - /// Initializes a new instance of the structure. - /// - public Pointer(uint address, byte[] memory) - { - Address = address; - Memory = memory; - } - - /// - /// Gets or sets the byte at the given . - /// - /// - /// - public byte this[int offset] - { - get - { -#if DEBUG - if (Address == 0) - throw new InvalidOperationException("The pointer being indexed is a null pointer."); -#endif - return Memory[Address + offset]; - } - set - { -#if DEBUG - if (Address == 0) - throw new InvalidOperationException("The pointer being indexed is a null pointer."); -#endif - Memory[Address + offset] = value; - } - } - - /// - /// Allow a to be implicitly converted to a . - /// - /// - /// - public static implicit operator Pointer(MemoryNode memoryNode) - { - return new Pointer(memoryNode.Address, memoryNode.Memory); - } - - /// - /// Allow a to be implicitly converted to a . - /// - /// - /// - public static implicit operator Pointer(Model.PpmContext context) - { - return new Pointer(context.Address, context.Memory); - } - - /// - /// Allow a to be implicitly converted to a . - /// - /// - /// - public static implicit operator Pointer(PpmState state) - { - return new Pointer(state.Address, state.Memory); - } - - /// - /// Increase the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator +(Pointer pointer, int offset) - { -#if DEBUG - if (pointer.Address == 0) - throw new InvalidOperationException("The pointer is a null pointer."); -#endif - pointer.Address = (uint) (pointer.Address + offset); - return pointer; - } - - /// - /// Increase the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator +(Pointer pointer, uint offset) - { -#if DEBUG - if (pointer.Address == 0) - throw new InvalidOperationException("The pointer is a null pointer."); -#endif - pointer.Address += offset; - return pointer; - } - - /// - /// Increment the address of a pointer. - /// - /// - /// - public static Pointer operator ++(Pointer pointer) - { -#if DEBUG - if (pointer.Address == 0) - throw new InvalidOperationException("The pointer being incremented is a null pointer."); -#endif - pointer.Address++; - return pointer; - } - - /// - /// Decrease the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator -(Pointer pointer, int offset) - { -#if DEBUG - if (pointer.Address == 0) - throw new InvalidOperationException("The pointer is a null pointer."); -#endif - pointer.Address = (uint) (pointer.Address - offset); - return pointer; - } - - /// - /// Decrease the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator -(Pointer pointer, uint offset) - { -#if DEBUG - if (pointer.Address == 0) - throw new InvalidOperationException("The pointer is a null pointer."); -#endif - pointer.Address -= offset; - return pointer; - } - - /// - /// Decrement the address of a pointer. - /// - /// - /// - public static Pointer operator --(Pointer pointer) - { -#if DEBUG - if (pointer.Address == 0) - throw new InvalidOperationException("The pointer being decremented is a null pointer."); -#endif - pointer.Address--; - return pointer; - } - - /// - /// Subtract two pointers. - /// - /// - /// - /// The number of bytes between the two pointers. - public static uint operator -(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1.Address == 0) - throw new InvalidOperationException( - "The pointer to the left of the subtraction operator is a null pointer."); - if (pointer2.Address == 0) - throw new InvalidOperationException( - "The pointer to the right of the subtraction operator is a null pointer."); -#endif - return pointer1.Address - pointer2.Address; - } - - /// - /// Compare pointers. - /// - /// - /// - /// - public static bool operator <(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1.Address == 0) - throw new InvalidOperationException( - "The pointer to the left of the less than operator is a null pointer."); - if (pointer2.Address == 0) - throw new InvalidOperationException( - "The pointer to the right of the less than operator is a null pointer."); -#endif - return pointer1.Address < pointer2.Address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator <=(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1.Address == 0) - throw new InvalidOperationException( - "The pointer to the left of the less than or equal to operator is a null pointer."); - if (pointer2.Address == 0) - throw new InvalidOperationException( - "The pointer to the right of the less than or equal to operator is a null pointer."); -#endif - return pointer1.Address <= pointer2.Address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator >(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1.Address == 0) - throw new InvalidOperationException( - "The pointer to the left of the greater than operator is a null pointer."); - if (pointer2.Address == 0) - throw new InvalidOperationException( - "The pointer to the right of the greater than operator is a null pointer."); -#endif - return pointer1.Address > pointer2.Address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator >=(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1.Address == 0) - throw new InvalidOperationException( - "The pointer to the left of the greater than or equal to operator is a null pointer."); - if (pointer2.Address == 0) - throw new InvalidOperationException( - "The pointer to the right of the greater than or equal to operator is a null pointer."); -#endif - return pointer1.Address >= pointer2.Address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator ==(Pointer pointer1, Pointer pointer2) - { - return pointer1.Address == pointer2.Address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator !=(Pointer pointer1, Pointer pointer2) - { - return pointer1.Address != pointer2.Address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is Pointer) - { - Pointer pointer = (Pointer) obj; - return pointer.Address == Address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return Address.GetHashCode(); - } - } +#region Using + +using System; + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// A structure containing a single address representing a position in the array. This + /// is intended to mimic the behaviour of a pointer in C/C++. + /// + /// + /// + /// This must be a structure rather than a class because several places in the associated code assume that + /// is a value type (meaning that assignment creates a completely new copy of the + /// instance rather than just copying a reference to the same instance). + /// + /// + /// Note that is a field rather than a property for performance reasons. + /// + /// + internal struct Pointer + { + public uint Address; + public byte[] Memory; + public static readonly Pointer Zero = new Pointer(0, null); + public const int Size = 1; + + /// + /// Initializes a new instance of the structure. + /// + public Pointer(uint address, byte[] memory) + { + Address = address; + Memory = memory; + } + + /// + /// Gets or sets the byte at the given . + /// + /// + /// + public byte this[int offset] + { + get + { +#if DEBUG + if (Address == 0) + throw new InvalidOperationException("The pointer being indexed is a null pointer."); +#endif + return Memory[Address + offset]; + } + set + { +#if DEBUG + if (Address == 0) + throw new InvalidOperationException("The pointer being indexed is a null pointer."); +#endif + Memory[Address + offset] = value; + } + } + + /// + /// Allow a to be implicitly converted to a . + /// + /// + /// + public static implicit operator Pointer(MemoryNode memoryNode) + { + return new Pointer(memoryNode.Address, memoryNode.Memory); + } + + /// + /// Allow a to be implicitly converted to a . + /// + /// + /// + public static implicit operator Pointer(Model.PpmContext context) + { + return new Pointer(context.Address, context.Memory); + } + + /// + /// Allow a to be implicitly converted to a . + /// + /// + /// + public static implicit operator Pointer(PpmState state) + { + return new Pointer(state.Address, state.Memory); + } + + /// + /// Increase the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator +(Pointer pointer, int offset) + { +#if DEBUG + if (pointer.Address == 0) + throw new InvalidOperationException("The pointer is a null pointer."); +#endif + pointer.Address = (uint) (pointer.Address + offset); + return pointer; + } + + /// + /// Increase the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator +(Pointer pointer, uint offset) + { +#if DEBUG + if (pointer.Address == 0) + throw new InvalidOperationException("The pointer is a null pointer."); +#endif + pointer.Address += offset; + return pointer; + } + + /// + /// Increment the address of a pointer. + /// + /// + /// + public static Pointer operator ++(Pointer pointer) + { +#if DEBUG + if (pointer.Address == 0) + throw new InvalidOperationException("The pointer being incremented is a null pointer."); +#endif + pointer.Address++; + return pointer; + } + + /// + /// Decrease the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator -(Pointer pointer, int offset) + { +#if DEBUG + if (pointer.Address == 0) + throw new InvalidOperationException("The pointer is a null pointer."); +#endif + pointer.Address = (uint) (pointer.Address - offset); + return pointer; + } + + /// + /// Decrease the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator -(Pointer pointer, uint offset) + { +#if DEBUG + if (pointer.Address == 0) + throw new InvalidOperationException("The pointer is a null pointer."); +#endif + pointer.Address -= offset; + return pointer; + } + + /// + /// Decrement the address of a pointer. + /// + /// + /// + public static Pointer operator --(Pointer pointer) + { +#if DEBUG + if (pointer.Address == 0) + throw new InvalidOperationException("The pointer being decremented is a null pointer."); +#endif + pointer.Address--; + return pointer; + } + + /// + /// Subtract two pointers. + /// + /// + /// + /// The number of bytes between the two pointers. + public static uint operator -(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1.Address == 0) + throw new InvalidOperationException( + "The pointer to the left of the subtraction operator is a null pointer."); + if (pointer2.Address == 0) + throw new InvalidOperationException( + "The pointer to the right of the subtraction operator is a null pointer."); +#endif + return pointer1.Address - pointer2.Address; + } + + /// + /// Compare pointers. + /// + /// + /// + /// + public static bool operator <(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1.Address == 0) + throw new InvalidOperationException( + "The pointer to the left of the less than operator is a null pointer."); + if (pointer2.Address == 0) + throw new InvalidOperationException( + "The pointer to the right of the less than operator is a null pointer."); +#endif + return pointer1.Address < pointer2.Address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator <=(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1.Address == 0) + throw new InvalidOperationException( + "The pointer to the left of the less than or equal to operator is a null pointer."); + if (pointer2.Address == 0) + throw new InvalidOperationException( + "The pointer to the right of the less than or equal to operator is a null pointer."); +#endif + return pointer1.Address <= pointer2.Address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator >(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1.Address == 0) + throw new InvalidOperationException( + "The pointer to the left of the greater than operator is a null pointer."); + if (pointer2.Address == 0) + throw new InvalidOperationException( + "The pointer to the right of the greater than operator is a null pointer."); +#endif + return pointer1.Address > pointer2.Address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator >=(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1.Address == 0) + throw new InvalidOperationException( + "The pointer to the left of the greater than or equal to operator is a null pointer."); + if (pointer2.Address == 0) + throw new InvalidOperationException( + "The pointer to the right of the greater than or equal to operator is a null pointer."); +#endif + return pointer1.Address >= pointer2.Address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator ==(Pointer pointer1, Pointer pointer2) + { + return pointer1.Address == pointer2.Address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator !=(Pointer pointer1, Pointer pointer2) + { + return pointer1.Address != pointer2.Address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is Pointer) + { + Pointer pointer = (Pointer) obj; + return pointer.Address == Address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return Address.GetHashCode(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/PpmContext.cs b/src/SharpCompress/Compressor/PPMd/I1/PpmContext.cs similarity index 97% rename from SharpCompress/Compressor/PPMd/I1/PpmContext.cs rename to src/SharpCompress/Compressor/PPMd/I1/PpmContext.cs index 192bfad6..d4625600 100644 --- a/SharpCompress/Compressor/PPMd/I1/PpmContext.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/PpmContext.cs @@ -1,810 +1,810 @@ -#region Using - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// The PPM context structure. This is tightly coupled with . - /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of - /// the instance rather than just copying a reference to the same instance). - /// - /// - internal partial class Model - { - /// - /// The structure which represents the current PPM context. This is 12 bytes in size. - /// - internal struct PpmContext - { - public uint Address; - public byte[] Memory; - public static readonly PpmContext Zero = new PpmContext(0, null); - public const int Size = 12; - - /// - /// Initializes a new instance of the structure. - /// - public PpmContext(uint address, byte[] memory) - { - Address = address; - Memory = memory; - } - - /// - /// Gets or sets the number statistics. - /// - public byte NumberStatistics - { - get { return Memory[Address]; } - set { Memory[Address] = value; } - } - - /// - /// Gets or sets the flags. - /// - public byte Flags - { - get { return Memory[Address + 1]; } - set { Memory[Address + 1] = value; } - } - - /// - /// Gets or sets the summary frequency. - /// - public ushort SummaryFrequency - { - get { return (ushort) (((ushort) Memory[Address + 2]) | ((ushort) Memory[Address + 3]) << 8); } - set - { - Memory[Address + 2] = (byte) value; - Memory[Address + 3] = (byte) (value >> 8); - } - } - - /// - /// Gets or sets the statistics. - /// - public PpmState Statistics - { - get - { - return - new PpmState( - ((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | - ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); - } - set - { - Memory[Address + 4] = (byte) value.Address; - Memory[Address + 5] = (byte) (value.Address >> 8); - Memory[Address + 6] = (byte) (value.Address >> 16); - Memory[Address + 7] = (byte) (value.Address >> 24); - } - } - - /// - /// Gets or sets the suffix. - /// - public PpmContext Suffix - { - get - { - return - new PpmContext( - ((uint) Memory[Address + 8]) | ((uint) Memory[Address + 9]) << 8 | - ((uint) Memory[Address + 10]) << 16 | ((uint) Memory[Address + 11]) << 24, Memory); - } - set - { - Memory[Address + 8] = (byte) value.Address; - Memory[Address + 9] = (byte) (value.Address >> 8); - Memory[Address + 10] = (byte) (value.Address >> 16); - Memory[Address + 11] = (byte) (value.Address >> 24); - } - } - - /// - /// The first PPM state associated with the PPM context. - /// - /// - /// - /// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members - /// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and - /// Successor members of PpmState, since they also add up to 6 bytes). - /// - /// - /// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes) - /// 1 context.NumberStatistics - /// 1 context.Flags - /// 2 context.SummaryFrequency - /// 4 context.Statistics (pointer to PpmState) - /// 4 context.Suffix (pointer to PpmContext) - /// - /// - /// PpmState (total of 6 bytes) - /// 1 Symbol - /// 1 Frequency - /// 4 Successor (pointer to PpmContext) - /// - /// - /// - public PpmState FirstState - { - get { return new PpmState(Address + 2, Memory); } - } - - /// - /// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same - /// information can be obtained using the Symbol property on the PPM state provided by the - /// property. - /// - public byte FirstStateSymbol - { - get { return Memory[Address + 2]; } - set { Memory[Address + 2] = value; } - } - - /// - /// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same - /// information can be obtained using the Frequency property on the PPM state provided by the - ///context.FirstState property. - /// - public byte FirstStateFrequency - { - get { return Memory[Address + 3]; } - set { Memory[Address + 3] = value; } - } - - /// - /// Gets or sets the successor of the first PPM state. This is provided for convenience. The same - /// information can be obtained using the Successor property on the PPM state provided by the - /// - public PpmContext FirstStateSuccessor - { - get - { - return - new PpmContext( - ((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | - ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); - } - set - { - Memory[Address + 4] = (byte) value.Address; - Memory[Address + 5] = (byte) (value.Address >> 8); - Memory[Address + 6] = (byte) (value.Address >> 16); - Memory[Address + 7] = (byte) (value.Address >> 24); - } - } - - /// - /// Allow a pointer to be implicitly converted to a PPM context. - /// - /// - /// - public static implicit operator PpmContext(Pointer pointer) - { - return new PpmContext(pointer.Address, pointer.Memory); - } - - /// - /// Allow pointer-like addition on a PPM context. - /// - /// - /// - /// - public static PpmContext operator +(PpmContext context, int offset) - { - context.Address = (uint) (context.Address + offset*Size); - return context; - } - - /// - /// Allow pointer-like subtraction on a PPM context. - /// - /// - /// - /// - public static PpmContext operator -(PpmContext context, int offset) - { - context.Address = (uint) (context.Address - offset*Size); - return context; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator <=(PpmContext context1, PpmContext context2) - { - return context1.Address <= context2.Address; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator >=(PpmContext context1, PpmContext context2) - { - return context1.Address >= context2.Address; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator ==(PpmContext context1, PpmContext context2) - { - return context1.Address == context2.Address; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator !=(PpmContext context1, PpmContext context2) - { - return context1.Address != context2.Address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is PpmContext) - { - PpmContext context = (PpmContext) obj; - return context.Address == Address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return Address.GetHashCode(); - } - } - - private void EncodeBinarySymbol(int symbol, PpmContext context) - { - PpmState state = context.FirstState; - int index1 = probabilities[state.Frequency - 1]; - int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + - context.Flags + ((runLength >> 26) & 0x20); - - if (state.Symbol == symbol) - { - foundState = state; - state.Frequency += (byte) ((state.Frequency < 196) ? 1 : 0); - Coder.LowCount = 0; - Coder.HighCount = binarySummary[index1, index2]; - binarySummary[index1, index2] += - (ushort) (Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2)); - previousSuccess = 1; - runLength++; - } - else - { - Coder.LowCount = binarySummary[index1, index2]; - binarySummary[index1, index2] -= (ushort) Mean(binarySummary[index1, index2], PeriodBitCount, 2); - Coder.HighCount = BinaryScale; - initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10]; - characterMask[state.Symbol] = escapeCount; - previousSuccess = 0; - numberMasked = 0; - foundState = PpmState.Zero; - } - } - - private void EncodeSymbol1(int symbol, PpmContext context) - { - uint lowCount; - uint index = context.Statistics.Symbol; - PpmState state = context.Statistics; - Coder.Scale = context.SummaryFrequency; - if (index == symbol) - { - Coder.HighCount = state.Frequency; - previousSuccess = (byte) ((2*Coder.HighCount >= Coder.Scale) ? 1 : 0); - foundState = state; - foundState.Frequency += 4; - context.SummaryFrequency += 4; - runLength += previousSuccess; - if (state.Frequency > MaximumFrequency) - Rescale(context); - Coder.LowCount = 0; - return; - } - - lowCount = state.Frequency; - index = context.NumberStatistics; - previousSuccess = 0; - while ((++state).Symbol != symbol) - { - lowCount += state.Frequency; - if (--index == 0) - { - Coder.LowCount = lowCount; - characterMask[state.Symbol] = escapeCount; - numberMasked = context.NumberStatistics; - index = context.NumberStatistics; - foundState = PpmState.Zero; - do - { - characterMask[(--state).Symbol] = escapeCount; - } while (--index != 0); - Coder.HighCount = Coder.Scale; - return; - } - } - Coder.HighCount = (Coder.LowCount = lowCount) + state.Frequency; - Update1(state, context); - } - - private void EncodeSymbol2(int symbol, PpmContext context) - { - See2Context see2Context = MakeEscapeFrequency(context); - uint currentSymbol; - uint lowCount = 0; - uint index = (uint) (context.NumberStatistics - numberMasked); - PpmState state = context.Statistics - 1; - - do - { - do - { - currentSymbol = state[1].Symbol; - state++; - } while (characterMask[currentSymbol] == escapeCount); - characterMask[currentSymbol] = escapeCount; - if (currentSymbol == symbol) - goto SymbolFound; - lowCount += state.Frequency; - } while (--index != 0); - - Coder.LowCount = lowCount; - Coder.Scale += Coder.LowCount; - Coder.HighCount = Coder.Scale; - see2Context.Summary += (ushort) Coder.Scale; - numberMasked = context.NumberStatistics; - return; - - SymbolFound: - Coder.LowCount = lowCount; - lowCount += state.Frequency; - Coder.HighCount = lowCount; - for (PpmState p1 = state; --index != 0;) - { - do - { - currentSymbol = p1[1].Symbol; - p1++; - } while (characterMask[currentSymbol] == escapeCount); - lowCount += p1.Frequency; - } - Coder.Scale += lowCount; - see2Context.Update(); - Update2(state, context); - } - - private void DecodeBinarySymbol(PpmContext context) - { - PpmState state = context.FirstState; - int index1 = probabilities[state.Frequency - 1]; - int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + - context.Flags + ((runLength >> 26) & 0x20); - - if (Coder.RangeGetCurrentShiftCount(TotalBitCount) < binarySummary[index1, index2]) - { - foundState = state; - state.Frequency += (byte) ((state.Frequency < 196) ? 1 : 0); - Coder.LowCount = 0; - Coder.HighCount = binarySummary[index1, index2]; - binarySummary[index1, index2] += - (ushort) (Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2)); - previousSuccess = 1; - runLength++; - } - else - { - Coder.LowCount = binarySummary[index1, index2]; - binarySummary[index1, index2] -= (ushort) Mean(binarySummary[index1, index2], PeriodBitCount, 2); - Coder.HighCount = BinaryScale; - initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10]; - characterMask[state.Symbol] = escapeCount; - previousSuccess = 0; - numberMasked = 0; - foundState = PpmState.Zero; - } - } - - private void DecodeSymbol1(PpmContext context) - { - uint index; - uint count; - uint highCount = context.Statistics.Frequency; - PpmState state = context.Statistics; - Coder.Scale = context.SummaryFrequency; - - count = Coder.RangeGetCurrentCount(); - if (count < highCount) - { - Coder.HighCount = highCount; - previousSuccess = (byte) ((2*Coder.HighCount >= Coder.Scale) ? 1 : 0); - foundState = state; - highCount += 4; - foundState.Frequency = (byte) highCount; - context.SummaryFrequency += 4; - runLength += previousSuccess; - if (highCount > MaximumFrequency) - Rescale(context); - Coder.LowCount = 0; - return; - } - - index = context.NumberStatistics; - previousSuccess = 0; - while ((highCount += (++state).Frequency) <= count) - { - if (--index == 0) - { - Coder.LowCount = highCount; - characterMask[state.Symbol] = escapeCount; - numberMasked = context.NumberStatistics; - index = context.NumberStatistics; - foundState = PpmState.Zero; - do - { - characterMask[(--state).Symbol] = escapeCount; - } while (--index != 0); - Coder.HighCount = Coder.Scale; - return; - } - } - Coder.HighCount = highCount; - Coder.LowCount = Coder.HighCount - state.Frequency; - Update1(state, context); - } - - private void DecodeSymbol2(PpmContext context) - { - See2Context see2Context = MakeEscapeFrequency(context); - uint currentSymbol; - uint count; - uint highCount = 0; - uint index = (uint) (context.NumberStatistics - numberMasked); - uint stateIndex = 0; - PpmState state = context.Statistics - 1; - - do - { - do - { - currentSymbol = state[1].Symbol; - state++; - } while (characterMask[currentSymbol] == escapeCount); - highCount += state.Frequency; - decodeStates[stateIndex++] = state; - // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons) - } while (--index != 0); - - Coder.Scale += highCount; - count = Coder.RangeGetCurrentCount(); - stateIndex = 0; - state = decodeStates[stateIndex]; - if (count < highCount) - { - highCount = 0; - while ((highCount += state.Frequency) <= count) - state = decodeStates[++stateIndex]; - Coder.HighCount = highCount; - Coder.LowCount = Coder.HighCount - state.Frequency; - see2Context.Update(); - Update2(state, context); - } - else - { - Coder.LowCount = highCount; - Coder.HighCount = Coder.Scale; - index = (uint) (context.NumberStatistics - numberMasked); - numberMasked = context.NumberStatistics; - do - { - characterMask[decodeStates[stateIndex].Symbol] = escapeCount; - stateIndex++; - } while (--index != 0); - see2Context.Summary += (ushort) Coder.Scale; - } - } - - private void Update1(PpmState state, PpmContext context) - { - foundState = state; - foundState.Frequency += 4; - context.SummaryFrequency += 4; - if (state[0].Frequency > state[-1].Frequency) - { - Swap(state[0], state[-1]); - foundState = --state; - if (state.Frequency > MaximumFrequency) - Rescale(context); - } - } - - private void Update2(PpmState state, PpmContext context) - { - foundState = state; - foundState.Frequency += 4; - context.SummaryFrequency += 4; - if (state.Frequency > MaximumFrequency) - Rescale(context); - escapeCount++; - runLength = initialRunLength; - } - - private See2Context MakeEscapeFrequency(PpmContext context) - { - uint numberStatistics = (uint) 2*context.NumberStatistics; - See2Context see2Context; - - if (context.NumberStatistics != 0xff) - { - // Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second - // dimension of the see2Contexts array is always in the range 0 .. 31). - - numberStatistics = context.Suffix.NumberStatistics; - int index1 = probabilities[context.NumberStatistics + 2] - 3; - int index2 = ((context.SummaryFrequency > 11*(context.NumberStatistics + 1)) ? 1 : 0) + - ((2*context.NumberStatistics < numberStatistics + numberMasked) ? 2 : 0) + context.Flags; - see2Context = see2Contexts[index1, index2]; - Coder.Scale = see2Context.Mean(); - } - else - { - see2Context = emptySee2Context; - Coder.Scale = 1; - } - - return see2Context; - } - - private void Rescale(PpmContext context) - { - uint oldUnitCount; - int adder; - uint escapeFrequency; - uint index = context.NumberStatistics; - - byte localSymbol; - byte localFrequency; - PpmContext localSuccessor; - PpmState p1; - PpmState state; - - for (state = foundState; state != context.Statistics; state--) - Swap(state[0], state[-1]); - - state.Frequency += 4; - context.SummaryFrequency += 4; - escapeFrequency = (uint) (context.SummaryFrequency - state.Frequency); - adder = (orderFall != 0 || method > ModelRestorationMethod.Freeze) ? 1 : 0; - state.Frequency = (byte) ((state.Frequency + adder) >> 1); - context.SummaryFrequency = state.Frequency; - - do - { - escapeFrequency -= (++state).Frequency; - state.Frequency = (byte) ((state.Frequency + adder) >> 1); - context.SummaryFrequency += state.Frequency; - if (state[0].Frequency > state[-1].Frequency) - { - p1 = state; - localSymbol = p1.Symbol; - localFrequency = p1.Frequency; - localSuccessor = p1.Successor; - do - { - Copy(p1[0], p1[-1]); - } while (localFrequency > (--p1)[-1].Frequency); - p1.Symbol = localSymbol; - p1.Frequency = localFrequency; - p1.Successor = localSuccessor; - } - } while (--index != 0); - - if (state.Frequency == 0) - { - do - { - index++; - } while ((--state).Frequency == 0); - - escapeFrequency += index; - oldUnitCount = (uint) ((context.NumberStatistics + 2) >> 1); - context.NumberStatistics -= (byte) index; - if (context.NumberStatistics == 0) - { - localSymbol = context.Statistics.Symbol; - localFrequency = context.Statistics.Frequency; - localSuccessor = context.Statistics.Successor; - localFrequency = (byte) ((2*localFrequency + escapeFrequency - 1)/escapeFrequency); - if (localFrequency > MaximumFrequency/3) - localFrequency = (byte) (MaximumFrequency/3); - Allocator.FreeUnits(context.Statistics, oldUnitCount); - context.FirstStateSymbol = localSymbol; - context.FirstStateFrequency = localFrequency; - context.FirstStateSuccessor = localSuccessor; - context.Flags = (byte) ((context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00)); - foundState = context.FirstState; - return; - } - - context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, - (uint) ((context.NumberStatistics + 2) >> 1)); - context.Flags &= 0xf7; - index = context.NumberStatistics; - state = context.Statistics; - context.Flags |= (byte) ((state.Symbol >= 0x40) ? 0x08 : 0x00); - do - { - context.Flags |= (byte) (((++state).Symbol >= 0x40) ? 0x08 : 0x00); - } while (--index != 0); - } - - escapeFrequency -= (escapeFrequency >> 1); - context.SummaryFrequency += (ushort) escapeFrequency; - context.Flags |= 0x04; - foundState = context.Statistics; - } - - private void Refresh(uint oldUnitCount, bool scale, PpmContext context) - { - int index = context.NumberStatistics; - int escapeFrequency; - int scaleValue = (scale ? 1 : 0); - - context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint) ((index + 2) >> 1)); - PpmState statistics = context.Statistics; - context.Flags = - (byte) ((context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00)); - escapeFrequency = context.SummaryFrequency - statistics.Frequency; - statistics.Frequency = (byte) ((statistics.Frequency + scaleValue) >> scaleValue); - context.SummaryFrequency = statistics.Frequency; - - do - { - escapeFrequency -= (++statistics).Frequency; - statistics.Frequency = (byte) ((statistics.Frequency + scaleValue) >> scaleValue); - context.SummaryFrequency += statistics.Frequency; - context.Flags |= (byte) ((statistics.Symbol >= 0x40) ? 0x08 : 0x00); - } while (--index != 0); - - escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue; - context.SummaryFrequency += (ushort) escapeFrequency; - } - - private PpmContext CutOff(int order, PpmContext context) - { - int index; - PpmState state; - - if (context.NumberStatistics == 0) - { - state = context.FirstState; - if ((Pointer) state.Successor >= Allocator.BaseUnit) - { - if (order < modelOrder) - state.Successor = CutOff(order + 1, state.Successor); - else - state.Successor = PpmContext.Zero; - - if (state.Successor == PpmContext.Zero && order > OrderBound) - { - Allocator.SpecialFreeUnits(context); - return PpmContext.Zero; - } - - return context; - } - else - { - Allocator.SpecialFreeUnits(context); - return PpmContext.Zero; - } - } - - uint unitCount = (uint) ((context.NumberStatistics + 2) >> 1); - context.Statistics = Allocator.MoveUnitsUp(context.Statistics, unitCount); - index = context.NumberStatistics; - for (state = context.Statistics + index; state >= context.Statistics; state--) - { - if (state.Successor < Allocator.BaseUnit) - { - state.Successor = PpmContext.Zero; - Swap(state, context.Statistics[index--]); - } - else if (order < modelOrder) - state.Successor = CutOff(order + 1, state.Successor); - else - state.Successor = PpmContext.Zero; - } - - if (index != context.NumberStatistics && order != 0) - { - context.NumberStatistics = (byte) index; - state = context.Statistics; - if (index < 0) - { - Allocator.FreeUnits(state, unitCount); - Allocator.SpecialFreeUnits(context); - return PpmContext.Zero; - } - else if (index == 0) - { - context.Flags = (byte) ((context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00)); - Copy(context.FirstState, state); - Allocator.FreeUnits(state, unitCount); - context.FirstStateFrequency = (byte) ((context.FirstStateFrequency + 11) >> 3); - } - else - { - Refresh(unitCount, context.SummaryFrequency > 16*index, context); - } - } - - return context; - } - - private PpmContext RemoveBinaryContexts(int order, PpmContext context) - { - if (context.NumberStatistics == 0) - { - PpmState state = context.FirstState; - if ((Pointer) state.Successor >= Allocator.BaseUnit && order < modelOrder) - state.Successor = RemoveBinaryContexts(order + 1, state.Successor); - else - state.Successor = PpmContext.Zero; - if ((state.Successor == PpmContext.Zero) && - (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff)) - { - Allocator.FreeUnits(context, 1); - return PpmContext.Zero; - } - else - { - return context; - } - } - - for (PpmState state = context.Statistics + context.NumberStatistics; state >= context.Statistics; state--) - { - if ((Pointer) state.Successor >= Allocator.BaseUnit && order < modelOrder) - state.Successor = RemoveBinaryContexts(order + 1, state.Successor); - else - state.Successor = PpmContext.Zero; - } - - return context; - } - } +#region Using + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// The PPM context structure. This is tightly coupled with . + /// + /// + /// + /// This must be a structure rather than a class because several places in the associated code assume that + /// is a value type (meaning that assignment creates a completely new copy of + /// the instance rather than just copying a reference to the same instance). + /// + /// + internal partial class Model + { + /// + /// The structure which represents the current PPM context. This is 12 bytes in size. + /// + internal struct PpmContext + { + public uint Address; + public byte[] Memory; + public static readonly PpmContext Zero = new PpmContext(0, null); + public const int Size = 12; + + /// + /// Initializes a new instance of the structure. + /// + public PpmContext(uint address, byte[] memory) + { + Address = address; + Memory = memory; + } + + /// + /// Gets or sets the number statistics. + /// + public byte NumberStatistics + { + get { return Memory[Address]; } + set { Memory[Address] = value; } + } + + /// + /// Gets or sets the flags. + /// + public byte Flags + { + get { return Memory[Address + 1]; } + set { Memory[Address + 1] = value; } + } + + /// + /// Gets or sets the summary frequency. + /// + public ushort SummaryFrequency + { + get { return (ushort) (((ushort) Memory[Address + 2]) | ((ushort) Memory[Address + 3]) << 8); } + set + { + Memory[Address + 2] = (byte) value; + Memory[Address + 3] = (byte) (value >> 8); + } + } + + /// + /// Gets or sets the statistics. + /// + public PpmState Statistics + { + get + { + return + new PpmState( + ((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | + ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); + } + set + { + Memory[Address + 4] = (byte) value.Address; + Memory[Address + 5] = (byte) (value.Address >> 8); + Memory[Address + 6] = (byte) (value.Address >> 16); + Memory[Address + 7] = (byte) (value.Address >> 24); + } + } + + /// + /// Gets or sets the suffix. + /// + public PpmContext Suffix + { + get + { + return + new PpmContext( + ((uint) Memory[Address + 8]) | ((uint) Memory[Address + 9]) << 8 | + ((uint) Memory[Address + 10]) << 16 | ((uint) Memory[Address + 11]) << 24, Memory); + } + set + { + Memory[Address + 8] = (byte) value.Address; + Memory[Address + 9] = (byte) (value.Address >> 8); + Memory[Address + 10] = (byte) (value.Address >> 16); + Memory[Address + 11] = (byte) (value.Address >> 24); + } + } + + /// + /// The first PPM state associated with the PPM context. + /// + /// + /// + /// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members + /// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and + /// Successor members of PpmState, since they also add up to 6 bytes). + /// + /// + /// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes) + /// 1 context.NumberStatistics + /// 1 context.Flags + /// 2 context.SummaryFrequency + /// 4 context.Statistics (pointer to PpmState) + /// 4 context.Suffix (pointer to PpmContext) + /// + /// + /// PpmState (total of 6 bytes) + /// 1 Symbol + /// 1 Frequency + /// 4 Successor (pointer to PpmContext) + /// + /// + /// + public PpmState FirstState + { + get { return new PpmState(Address + 2, Memory); } + } + + /// + /// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same + /// information can be obtained using the Symbol property on the PPM state provided by the + /// property. + /// + public byte FirstStateSymbol + { + get { return Memory[Address + 2]; } + set { Memory[Address + 2] = value; } + } + + /// + /// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same + /// information can be obtained using the Frequency property on the PPM state provided by the + ///context.FirstState property. + /// + public byte FirstStateFrequency + { + get { return Memory[Address + 3]; } + set { Memory[Address + 3] = value; } + } + + /// + /// Gets or sets the successor of the first PPM state. This is provided for convenience. The same + /// information can be obtained using the Successor property on the PPM state provided by the + /// + public PpmContext FirstStateSuccessor + { + get + { + return + new PpmContext( + ((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | + ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); + } + set + { + Memory[Address + 4] = (byte) value.Address; + Memory[Address + 5] = (byte) (value.Address >> 8); + Memory[Address + 6] = (byte) (value.Address >> 16); + Memory[Address + 7] = (byte) (value.Address >> 24); + } + } + + /// + /// Allow a pointer to be implicitly converted to a PPM context. + /// + /// + /// + public static implicit operator PpmContext(Pointer pointer) + { + return new PpmContext(pointer.Address, pointer.Memory); + } + + /// + /// Allow pointer-like addition on a PPM context. + /// + /// + /// + /// + public static PpmContext operator +(PpmContext context, int offset) + { + context.Address = (uint) (context.Address + offset*Size); + return context; + } + + /// + /// Allow pointer-like subtraction on a PPM context. + /// + /// + /// + /// + public static PpmContext operator -(PpmContext context, int offset) + { + context.Address = (uint) (context.Address - offset*Size); + return context; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator <=(PpmContext context1, PpmContext context2) + { + return context1.Address <= context2.Address; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator >=(PpmContext context1, PpmContext context2) + { + return context1.Address >= context2.Address; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator ==(PpmContext context1, PpmContext context2) + { + return context1.Address == context2.Address; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator !=(PpmContext context1, PpmContext context2) + { + return context1.Address != context2.Address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is PpmContext) + { + PpmContext context = (PpmContext) obj; + return context.Address == Address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return Address.GetHashCode(); + } + } + + private void EncodeBinarySymbol(int symbol, PpmContext context) + { + PpmState state = context.FirstState; + int index1 = probabilities[state.Frequency - 1]; + int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + + context.Flags + ((runLength >> 26) & 0x20); + + if (state.Symbol == symbol) + { + foundState = state; + state.Frequency += (byte) ((state.Frequency < 196) ? 1 : 0); + Coder.LowCount = 0; + Coder.HighCount = binarySummary[index1, index2]; + binarySummary[index1, index2] += + (ushort) (Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2)); + previousSuccess = 1; + runLength++; + } + else + { + Coder.LowCount = binarySummary[index1, index2]; + binarySummary[index1, index2] -= (ushort) Mean(binarySummary[index1, index2], PeriodBitCount, 2); + Coder.HighCount = BinaryScale; + initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10]; + characterMask[state.Symbol] = escapeCount; + previousSuccess = 0; + numberMasked = 0; + foundState = PpmState.Zero; + } + } + + private void EncodeSymbol1(int symbol, PpmContext context) + { + uint lowCount; + uint index = context.Statistics.Symbol; + PpmState state = context.Statistics; + Coder.Scale = context.SummaryFrequency; + if (index == symbol) + { + Coder.HighCount = state.Frequency; + previousSuccess = (byte) ((2*Coder.HighCount >= Coder.Scale) ? 1 : 0); + foundState = state; + foundState.Frequency += 4; + context.SummaryFrequency += 4; + runLength += previousSuccess; + if (state.Frequency > MaximumFrequency) + Rescale(context); + Coder.LowCount = 0; + return; + } + + lowCount = state.Frequency; + index = context.NumberStatistics; + previousSuccess = 0; + while ((++state).Symbol != symbol) + { + lowCount += state.Frequency; + if (--index == 0) + { + Coder.LowCount = lowCount; + characterMask[state.Symbol] = escapeCount; + numberMasked = context.NumberStatistics; + index = context.NumberStatistics; + foundState = PpmState.Zero; + do + { + characterMask[(--state).Symbol] = escapeCount; + } while (--index != 0); + Coder.HighCount = Coder.Scale; + return; + } + } + Coder.HighCount = (Coder.LowCount = lowCount) + state.Frequency; + Update1(state, context); + } + + private void EncodeSymbol2(int symbol, PpmContext context) + { + See2Context see2Context = MakeEscapeFrequency(context); + uint currentSymbol; + uint lowCount = 0; + uint index = (uint) (context.NumberStatistics - numberMasked); + PpmState state = context.Statistics - 1; + + do + { + do + { + currentSymbol = state[1].Symbol; + state++; + } while (characterMask[currentSymbol] == escapeCount); + characterMask[currentSymbol] = escapeCount; + if (currentSymbol == symbol) + goto SymbolFound; + lowCount += state.Frequency; + } while (--index != 0); + + Coder.LowCount = lowCount; + Coder.Scale += Coder.LowCount; + Coder.HighCount = Coder.Scale; + see2Context.Summary += (ushort) Coder.Scale; + numberMasked = context.NumberStatistics; + return; + + SymbolFound: + Coder.LowCount = lowCount; + lowCount += state.Frequency; + Coder.HighCount = lowCount; + for (PpmState p1 = state; --index != 0;) + { + do + { + currentSymbol = p1[1].Symbol; + p1++; + } while (characterMask[currentSymbol] == escapeCount); + lowCount += p1.Frequency; + } + Coder.Scale += lowCount; + see2Context.Update(); + Update2(state, context); + } + + private void DecodeBinarySymbol(PpmContext context) + { + PpmState state = context.FirstState; + int index1 = probabilities[state.Frequency - 1]; + int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + + context.Flags + ((runLength >> 26) & 0x20); + + if (Coder.RangeGetCurrentShiftCount(TotalBitCount) < binarySummary[index1, index2]) + { + foundState = state; + state.Frequency += (byte) ((state.Frequency < 196) ? 1 : 0); + Coder.LowCount = 0; + Coder.HighCount = binarySummary[index1, index2]; + binarySummary[index1, index2] += + (ushort) (Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2)); + previousSuccess = 1; + runLength++; + } + else + { + Coder.LowCount = binarySummary[index1, index2]; + binarySummary[index1, index2] -= (ushort) Mean(binarySummary[index1, index2], PeriodBitCount, 2); + Coder.HighCount = BinaryScale; + initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10]; + characterMask[state.Symbol] = escapeCount; + previousSuccess = 0; + numberMasked = 0; + foundState = PpmState.Zero; + } + } + + private void DecodeSymbol1(PpmContext context) + { + uint index; + uint count; + uint highCount = context.Statistics.Frequency; + PpmState state = context.Statistics; + Coder.Scale = context.SummaryFrequency; + + count = Coder.RangeGetCurrentCount(); + if (count < highCount) + { + Coder.HighCount = highCount; + previousSuccess = (byte) ((2*Coder.HighCount >= Coder.Scale) ? 1 : 0); + foundState = state; + highCount += 4; + foundState.Frequency = (byte) highCount; + context.SummaryFrequency += 4; + runLength += previousSuccess; + if (highCount > MaximumFrequency) + Rescale(context); + Coder.LowCount = 0; + return; + } + + index = context.NumberStatistics; + previousSuccess = 0; + while ((highCount += (++state).Frequency) <= count) + { + if (--index == 0) + { + Coder.LowCount = highCount; + characterMask[state.Symbol] = escapeCount; + numberMasked = context.NumberStatistics; + index = context.NumberStatistics; + foundState = PpmState.Zero; + do + { + characterMask[(--state).Symbol] = escapeCount; + } while (--index != 0); + Coder.HighCount = Coder.Scale; + return; + } + } + Coder.HighCount = highCount; + Coder.LowCount = Coder.HighCount - state.Frequency; + Update1(state, context); + } + + private void DecodeSymbol2(PpmContext context) + { + See2Context see2Context = MakeEscapeFrequency(context); + uint currentSymbol; + uint count; + uint highCount = 0; + uint index = (uint) (context.NumberStatistics - numberMasked); + uint stateIndex = 0; + PpmState state = context.Statistics - 1; + + do + { + do + { + currentSymbol = state[1].Symbol; + state++; + } while (characterMask[currentSymbol] == escapeCount); + highCount += state.Frequency; + decodeStates[stateIndex++] = state; + // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons) + } while (--index != 0); + + Coder.Scale += highCount; + count = Coder.RangeGetCurrentCount(); + stateIndex = 0; + state = decodeStates[stateIndex]; + if (count < highCount) + { + highCount = 0; + while ((highCount += state.Frequency) <= count) + state = decodeStates[++stateIndex]; + Coder.HighCount = highCount; + Coder.LowCount = Coder.HighCount - state.Frequency; + see2Context.Update(); + Update2(state, context); + } + else + { + Coder.LowCount = highCount; + Coder.HighCount = Coder.Scale; + index = (uint) (context.NumberStatistics - numberMasked); + numberMasked = context.NumberStatistics; + do + { + characterMask[decodeStates[stateIndex].Symbol] = escapeCount; + stateIndex++; + } while (--index != 0); + see2Context.Summary += (ushort) Coder.Scale; + } + } + + private void Update1(PpmState state, PpmContext context) + { + foundState = state; + foundState.Frequency += 4; + context.SummaryFrequency += 4; + if (state[0].Frequency > state[-1].Frequency) + { + Swap(state[0], state[-1]); + foundState = --state; + if (state.Frequency > MaximumFrequency) + Rescale(context); + } + } + + private void Update2(PpmState state, PpmContext context) + { + foundState = state; + foundState.Frequency += 4; + context.SummaryFrequency += 4; + if (state.Frequency > MaximumFrequency) + Rescale(context); + escapeCount++; + runLength = initialRunLength; + } + + private See2Context MakeEscapeFrequency(PpmContext context) + { + uint numberStatistics = (uint) 2*context.NumberStatistics; + See2Context see2Context; + + if (context.NumberStatistics != 0xff) + { + // Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second + // dimension of the see2Contexts array is always in the range 0 .. 31). + + numberStatistics = context.Suffix.NumberStatistics; + int index1 = probabilities[context.NumberStatistics + 2] - 3; + int index2 = ((context.SummaryFrequency > 11*(context.NumberStatistics + 1)) ? 1 : 0) + + ((2*context.NumberStatistics < numberStatistics + numberMasked) ? 2 : 0) + context.Flags; + see2Context = see2Contexts[index1, index2]; + Coder.Scale = see2Context.Mean(); + } + else + { + see2Context = emptySee2Context; + Coder.Scale = 1; + } + + return see2Context; + } + + private void Rescale(PpmContext context) + { + uint oldUnitCount; + int adder; + uint escapeFrequency; + uint index = context.NumberStatistics; + + byte localSymbol; + byte localFrequency; + PpmContext localSuccessor; + PpmState p1; + PpmState state; + + for (state = foundState; state != context.Statistics; state--) + Swap(state[0], state[-1]); + + state.Frequency += 4; + context.SummaryFrequency += 4; + escapeFrequency = (uint) (context.SummaryFrequency - state.Frequency); + adder = (orderFall != 0 || method > ModelRestorationMethod.Freeze) ? 1 : 0; + state.Frequency = (byte) ((state.Frequency + adder) >> 1); + context.SummaryFrequency = state.Frequency; + + do + { + escapeFrequency -= (++state).Frequency; + state.Frequency = (byte) ((state.Frequency + adder) >> 1); + context.SummaryFrequency += state.Frequency; + if (state[0].Frequency > state[-1].Frequency) + { + p1 = state; + localSymbol = p1.Symbol; + localFrequency = p1.Frequency; + localSuccessor = p1.Successor; + do + { + Copy(p1[0], p1[-1]); + } while (localFrequency > (--p1)[-1].Frequency); + p1.Symbol = localSymbol; + p1.Frequency = localFrequency; + p1.Successor = localSuccessor; + } + } while (--index != 0); + + if (state.Frequency == 0) + { + do + { + index++; + } while ((--state).Frequency == 0); + + escapeFrequency += index; + oldUnitCount = (uint) ((context.NumberStatistics + 2) >> 1); + context.NumberStatistics -= (byte) index; + if (context.NumberStatistics == 0) + { + localSymbol = context.Statistics.Symbol; + localFrequency = context.Statistics.Frequency; + localSuccessor = context.Statistics.Successor; + localFrequency = (byte) ((2*localFrequency + escapeFrequency - 1)/escapeFrequency); + if (localFrequency > MaximumFrequency/3) + localFrequency = (byte) (MaximumFrequency/3); + Allocator.FreeUnits(context.Statistics, oldUnitCount); + context.FirstStateSymbol = localSymbol; + context.FirstStateFrequency = localFrequency; + context.FirstStateSuccessor = localSuccessor; + context.Flags = (byte) ((context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00)); + foundState = context.FirstState; + return; + } + + context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, + (uint) ((context.NumberStatistics + 2) >> 1)); + context.Flags &= 0xf7; + index = context.NumberStatistics; + state = context.Statistics; + context.Flags |= (byte) ((state.Symbol >= 0x40) ? 0x08 : 0x00); + do + { + context.Flags |= (byte) (((++state).Symbol >= 0x40) ? 0x08 : 0x00); + } while (--index != 0); + } + + escapeFrequency -= (escapeFrequency >> 1); + context.SummaryFrequency += (ushort) escapeFrequency; + context.Flags |= 0x04; + foundState = context.Statistics; + } + + private void Refresh(uint oldUnitCount, bool scale, PpmContext context) + { + int index = context.NumberStatistics; + int escapeFrequency; + int scaleValue = (scale ? 1 : 0); + + context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint) ((index + 2) >> 1)); + PpmState statistics = context.Statistics; + context.Flags = + (byte) ((context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00)); + escapeFrequency = context.SummaryFrequency - statistics.Frequency; + statistics.Frequency = (byte) ((statistics.Frequency + scaleValue) >> scaleValue); + context.SummaryFrequency = statistics.Frequency; + + do + { + escapeFrequency -= (++statistics).Frequency; + statistics.Frequency = (byte) ((statistics.Frequency + scaleValue) >> scaleValue); + context.SummaryFrequency += statistics.Frequency; + context.Flags |= (byte) ((statistics.Symbol >= 0x40) ? 0x08 : 0x00); + } while (--index != 0); + + escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue; + context.SummaryFrequency += (ushort) escapeFrequency; + } + + private PpmContext CutOff(int order, PpmContext context) + { + int index; + PpmState state; + + if (context.NumberStatistics == 0) + { + state = context.FirstState; + if ((Pointer) state.Successor >= Allocator.BaseUnit) + { + if (order < modelOrder) + state.Successor = CutOff(order + 1, state.Successor); + else + state.Successor = PpmContext.Zero; + + if (state.Successor == PpmContext.Zero && order > OrderBound) + { + Allocator.SpecialFreeUnits(context); + return PpmContext.Zero; + } + + return context; + } + else + { + Allocator.SpecialFreeUnits(context); + return PpmContext.Zero; + } + } + + uint unitCount = (uint) ((context.NumberStatistics + 2) >> 1); + context.Statistics = Allocator.MoveUnitsUp(context.Statistics, unitCount); + index = context.NumberStatistics; + for (state = context.Statistics + index; state >= context.Statistics; state--) + { + if (state.Successor < Allocator.BaseUnit) + { + state.Successor = PpmContext.Zero; + Swap(state, context.Statistics[index--]); + } + else if (order < modelOrder) + state.Successor = CutOff(order + 1, state.Successor); + else + state.Successor = PpmContext.Zero; + } + + if (index != context.NumberStatistics && order != 0) + { + context.NumberStatistics = (byte) index; + state = context.Statistics; + if (index < 0) + { + Allocator.FreeUnits(state, unitCount); + Allocator.SpecialFreeUnits(context); + return PpmContext.Zero; + } + else if (index == 0) + { + context.Flags = (byte) ((context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00)); + Copy(context.FirstState, state); + Allocator.FreeUnits(state, unitCount); + context.FirstStateFrequency = (byte) ((context.FirstStateFrequency + 11) >> 3); + } + else + { + Refresh(unitCount, context.SummaryFrequency > 16*index, context); + } + } + + return context; + } + + private PpmContext RemoveBinaryContexts(int order, PpmContext context) + { + if (context.NumberStatistics == 0) + { + PpmState state = context.FirstState; + if ((Pointer) state.Successor >= Allocator.BaseUnit && order < modelOrder) + state.Successor = RemoveBinaryContexts(order + 1, state.Successor); + else + state.Successor = PpmContext.Zero; + if ((state.Successor == PpmContext.Zero) && + (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff)) + { + Allocator.FreeUnits(context, 1); + return PpmContext.Zero; + } + else + { + return context; + } + } + + for (PpmState state = context.Statistics + context.NumberStatistics; state >= context.Statistics; state--) + { + if ((Pointer) state.Successor >= Allocator.BaseUnit && order < modelOrder) + state.Successor = RemoveBinaryContexts(order + 1, state.Successor); + else + state.Successor = PpmContext.Zero; + } + + return context; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/PpmState.cs b/src/SharpCompress/Compressor/PPMd/I1/PpmState.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/I1/PpmState.cs rename to src/SharpCompress/Compressor/PPMd/I1/PpmState.cs index 3ba2a936..08c0173f 100644 --- a/SharpCompress/Compressor/PPMd/I1/PpmState.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/PpmState.cs @@ -1,212 +1,212 @@ -#region Using - -using System; - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// PPM state. - /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of the - /// instance rather than just copying a reference to the same instance). - /// - /// - /// Note that is a field rather than a property for performance reasons. - /// - /// - internal struct PpmState - { - public uint Address; - public byte[] Memory; - public static readonly PpmState Zero = new PpmState(0, null); - public const int Size = 6; - - /// - /// Initializes a new instance of the structure. - /// - public PpmState(uint address, byte[] memory) - { - Address = address; - Memory = memory; - } - - /// - /// Gets or sets the symbol. - /// - public byte Symbol - { - get { return Memory[Address]; } - set { Memory[Address] = value; } - } - - /// - /// Gets or sets the frequency. - /// - public byte Frequency - { - get { return Memory[Address + 1]; } - set { Memory[Address + 1] = value; } - } - - /// - /// Gets or sets the successor. - /// - public Model.PpmContext Successor - { - get - { - return - new Model.PpmContext( - ((uint) Memory[Address + 2]) | ((uint) Memory[Address + 3]) << 8 | - ((uint) Memory[Address + 4]) << 16 | ((uint) Memory[Address + 5]) << 24, Memory); - } - set - { - Memory[Address + 2] = (byte) value.Address; - Memory[Address + 3] = (byte) (value.Address >> 8); - Memory[Address + 4] = (byte) (value.Address >> 16); - Memory[Address + 5] = (byte) (value.Address >> 24); - } - } - - /// - /// Gets the at the relative to this - /// . - /// - /// - /// - public PpmState this[int offset] - { - get { return new PpmState((uint) (Address + offset*Size), Memory); } - } - - /// - /// Allow a pointer to be implicitly converted to a PPM state. - /// - /// - /// - public static implicit operator PpmState(Pointer pointer) - { - return new PpmState(pointer.Address, pointer.Memory); - } - - /// - /// Allow pointer-like addition on a PPM state. - /// - /// - /// - /// - public static PpmState operator +(PpmState state, int offset) - { - state.Address = (uint) (state.Address + offset*Size); - return state; - } - - /// - /// Allow pointer-like incrementing on a PPM state. - /// - /// - /// - public static PpmState operator ++(PpmState state) - { - state.Address += Size; - return state; - } - - /// - /// Allow pointer-like subtraction on a PPM state. - /// - /// - /// - /// - public static PpmState operator -(PpmState state, int offset) - { - state.Address = (uint) (state.Address - offset*Size); - return state; - } - - /// - /// Allow pointer-like decrementing on a PPM state. - /// - /// - /// - public static PpmState operator --(PpmState state) - { - state.Address -= Size; - return state; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator <=(PpmState state1, PpmState state2) - { - return state1.Address <= state2.Address; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator >=(PpmState state1, PpmState state2) - { - return state1.Address >= state2.Address; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator ==(PpmState state1, PpmState state2) - { - return state1.Address == state2.Address; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator !=(PpmState state1, PpmState state2) - { - return state1.Address != state2.Address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is PpmState) - { - PpmState state = (PpmState) obj; - return state.Address == Address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return Address.GetHashCode(); - } - } +#region Using + +using System; + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// PPM state. + /// + /// + /// + /// This must be a structure rather than a class because several places in the associated code assume that + /// is a value type (meaning that assignment creates a completely new copy of the + /// instance rather than just copying a reference to the same instance). + /// + /// + /// Note that is a field rather than a property for performance reasons. + /// + /// + internal struct PpmState + { + public uint Address; + public byte[] Memory; + public static readonly PpmState Zero = new PpmState(0, null); + public const int Size = 6; + + /// + /// Initializes a new instance of the structure. + /// + public PpmState(uint address, byte[] memory) + { + Address = address; + Memory = memory; + } + + /// + /// Gets or sets the symbol. + /// + public byte Symbol + { + get { return Memory[Address]; } + set { Memory[Address] = value; } + } + + /// + /// Gets or sets the frequency. + /// + public byte Frequency + { + get { return Memory[Address + 1]; } + set { Memory[Address + 1] = value; } + } + + /// + /// Gets or sets the successor. + /// + public Model.PpmContext Successor + { + get + { + return + new Model.PpmContext( + ((uint) Memory[Address + 2]) | ((uint) Memory[Address + 3]) << 8 | + ((uint) Memory[Address + 4]) << 16 | ((uint) Memory[Address + 5]) << 24, Memory); + } + set + { + Memory[Address + 2] = (byte) value.Address; + Memory[Address + 3] = (byte) (value.Address >> 8); + Memory[Address + 4] = (byte) (value.Address >> 16); + Memory[Address + 5] = (byte) (value.Address >> 24); + } + } + + /// + /// Gets the at the relative to this + /// . + /// + /// + /// + public PpmState this[int offset] + { + get { return new PpmState((uint) (Address + offset*Size), Memory); } + } + + /// + /// Allow a pointer to be implicitly converted to a PPM state. + /// + /// + /// + public static implicit operator PpmState(Pointer pointer) + { + return new PpmState(pointer.Address, pointer.Memory); + } + + /// + /// Allow pointer-like addition on a PPM state. + /// + /// + /// + /// + public static PpmState operator +(PpmState state, int offset) + { + state.Address = (uint) (state.Address + offset*Size); + return state; + } + + /// + /// Allow pointer-like incrementing on a PPM state. + /// + /// + /// + public static PpmState operator ++(PpmState state) + { + state.Address += Size; + return state; + } + + /// + /// Allow pointer-like subtraction on a PPM state. + /// + /// + /// + /// + public static PpmState operator -(PpmState state, int offset) + { + state.Address = (uint) (state.Address - offset*Size); + return state; + } + + /// + /// Allow pointer-like decrementing on a PPM state. + /// + /// + /// + public static PpmState operator --(PpmState state) + { + state.Address -= Size; + return state; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator <=(PpmState state1, PpmState state2) + { + return state1.Address <= state2.Address; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator >=(PpmState state1, PpmState state2) + { + return state1.Address >= state2.Address; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator ==(PpmState state1, PpmState state2) + { + return state1.Address == state2.Address; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator !=(PpmState state1, PpmState state2) + { + return state1.Address != state2.Address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is PpmState) + { + PpmState state = (PpmState) obj; + return state.Address == Address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return Address.GetHashCode(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/I1/See2Context.cs b/src/SharpCompress/Compressor/PPMd/I1/See2Context.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/I1/See2Context.cs rename to src/SharpCompress/Compressor/PPMd/I1/See2Context.cs index 17685edd..7eec77e7 100644 --- a/SharpCompress/Compressor/PPMd/I1/See2Context.cs +++ b/src/SharpCompress/Compressor/PPMd/I1/See2Context.cs @@ -1,55 +1,55 @@ -#region Using - -using System; - -#endregion - -namespace SharpCompress.Compressor.PPMd.I1 -{ - /// - /// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols. - /// - /// - /// - /// This must be a class rather than a structure because MakeEscapeFrequency returns a See2Context - /// instance from the see2Contexts array. The caller (for example, EncodeSymbol2) then updates the - /// returned See2Context instance and expects the updates to be reflected in the see2Contexts array. - /// This would not happen if this were a structure. - /// - /// - /// Note that in most cases fields are used rather than properties for performance reasons (for example, - /// is a field rather than a property). - /// - /// - internal class See2Context - { - private const byte PeriodBitCount = 7; - - public ushort Summary; - public byte Shift; - public byte Count; - - public void Initialize(uint initialValue) - { - Shift = PeriodBitCount - 4; - Summary = (ushort) (initialValue << Shift); - Count = 7; - } - - public uint Mean() - { - uint value = (uint) (Summary >> Shift); - Summary = (ushort) (Summary - value); - return (uint) (value + ((value == 0) ? 1 : 0)); - } - - public void Update() - { - if (Shift < PeriodBitCount && --Count == 0) - { - Summary += Summary; - Count = (byte) (3 << Shift++); - } - } - } +#region Using + +using System; + +#endregion + +namespace SharpCompress.Compressor.PPMd.I1 +{ + /// + /// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols. + /// + /// + /// + /// This must be a class rather than a structure because MakeEscapeFrequency returns a See2Context + /// instance from the see2Contexts array. The caller (for example, EncodeSymbol2) then updates the + /// returned See2Context instance and expects the updates to be reflected in the see2Contexts array. + /// This would not happen if this were a structure. + /// + /// + /// Note that in most cases fields are used rather than properties for performance reasons (for example, + /// is a field rather than a property). + /// + /// + internal class See2Context + { + private const byte PeriodBitCount = 7; + + public ushort Summary; + public byte Shift; + public byte Count; + + public void Initialize(uint initialValue) + { + Shift = PeriodBitCount - 4; + Summary = (ushort) (initialValue << Shift); + Count = 7; + } + + public uint Mean() + { + uint value = (uint) (Summary >> Shift); + Summary = (ushort) (Summary - value); + return (uint) (value + ((value == 0) ? 1 : 0)); + } + + public void Update() + { + if (Shift < PeriodBitCount && --Count == 0) + { + Summary += Summary; + Count = (byte) (3 << Shift++); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/PpmdProperties.cs b/src/SharpCompress/Compressor/PPMd/PpmdProperties.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/PpmdProperties.cs rename to src/SharpCompress/Compressor/PPMd/PpmdProperties.cs index 9527835b..d7c33b8f 100644 --- a/SharpCompress/Compressor/PPMd/PpmdProperties.cs +++ b/src/SharpCompress/Compressor/PPMd/PpmdProperties.cs @@ -1,81 +1,81 @@ -using System; - -namespace SharpCompress.Compressor.PPMd -{ - public enum PpmdVersion - { - H, - H7z, - I1, - } - - public class PpmdProperties - { - public PpmdVersion Version = PpmdVersion.I1; - public int ModelOrder; - internal I1.ModelRestorationMethod ModelRestorationMethod; - - private int allocatorSize; - internal I1.Allocator Allocator; - - public PpmdProperties() - : this(16 << 20, 6) - { - } - - public PpmdProperties(int allocatorSize, int modelOrder) - : this(allocatorSize, modelOrder, I1.ModelRestorationMethod.Restart) - { - } - - internal PpmdProperties(int allocatorSize, int modelOrder, I1.ModelRestorationMethod modelRestorationMethod) - { - AllocatorSize = allocatorSize; - ModelOrder = modelOrder; - ModelRestorationMethod = modelRestorationMethod; - } - - public PpmdProperties(byte[] properties) - { - if (properties.Length == 2) - { - ushort props = BitConverter.ToUInt16(properties, 0); - AllocatorSize = (((props >> 4) & 0xff) + 1) << 20; - ModelOrder = (props & 0x0f) + 1; - ModelRestorationMethod = (I1.ModelRestorationMethod) (props >> 12); - } - else if (properties.Length == 5) - { - Version = PpmdVersion.H7z; - AllocatorSize = BitConverter.ToInt32(properties, 1); - ModelOrder = properties[0]; - } - } - - public int AllocatorSize - { - get { return allocatorSize; } - set - { - allocatorSize = value; - if (Version == PpmdVersion.I1) - { - if (Allocator == null) - Allocator = new I1.Allocator(); - Allocator.Start(allocatorSize); - } - } - } - - public byte[] Properties - { - get - { - return - BitConverter.GetBytes( - (ushort) - ((ModelOrder - 1) + (((AllocatorSize >> 20) - 1) << 4) + ((ushort) ModelRestorationMethod << 12))); - } - } - } +using System; + +namespace SharpCompress.Compressor.PPMd +{ + public enum PpmdVersion + { + H, + H7z, + I1, + } + + public class PpmdProperties + { + public PpmdVersion Version = PpmdVersion.I1; + public int ModelOrder; + internal I1.ModelRestorationMethod ModelRestorationMethod; + + private int allocatorSize; + internal I1.Allocator Allocator; + + public PpmdProperties() + : this(16 << 20, 6) + { + } + + public PpmdProperties(int allocatorSize, int modelOrder) + : this(allocatorSize, modelOrder, I1.ModelRestorationMethod.Restart) + { + } + + internal PpmdProperties(int allocatorSize, int modelOrder, I1.ModelRestorationMethod modelRestorationMethod) + { + AllocatorSize = allocatorSize; + ModelOrder = modelOrder; + ModelRestorationMethod = modelRestorationMethod; + } + + public PpmdProperties(byte[] properties) + { + if (properties.Length == 2) + { + ushort props = BitConverter.ToUInt16(properties, 0); + AllocatorSize = (((props >> 4) & 0xff) + 1) << 20; + ModelOrder = (props & 0x0f) + 1; + ModelRestorationMethod = (I1.ModelRestorationMethod) (props >> 12); + } + else if (properties.Length == 5) + { + Version = PpmdVersion.H7z; + AllocatorSize = BitConverter.ToInt32(properties, 1); + ModelOrder = properties[0]; + } + } + + public int AllocatorSize + { + get { return allocatorSize; } + set + { + allocatorSize = value; + if (Version == PpmdVersion.I1) + { + if (Allocator == null) + Allocator = new I1.Allocator(); + Allocator.Start(allocatorSize); + } + } + } + + public byte[] Properties + { + get + { + return + BitConverter.GetBytes( + (ushort) + ((ModelOrder - 1) + (((AllocatorSize >> 20) - 1) << 4) + ((ushort) ModelRestorationMethod << 12))); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/PPMd/PpmdStream.cs b/src/SharpCompress/Compressor/PPMd/PpmdStream.cs similarity index 96% rename from SharpCompress/Compressor/PPMd/PpmdStream.cs rename to src/SharpCompress/Compressor/PPMd/PpmdStream.cs index 938f3a3b..efe29b56 100644 --- a/SharpCompress/Compressor/PPMd/PpmdStream.cs +++ b/src/SharpCompress/Compressor/PPMd/PpmdStream.cs @@ -1,142 +1,142 @@ -using System; -using System.IO; -using SharpCompress.Compressor.Rar.PPM; - -namespace SharpCompress.Compressor.PPMd -{ - public class PpmdStream : Stream - { - private PpmdProperties properties; - private Stream stream; - private bool compress; - private I1.Model model; - private H.ModelPPM modelH; - private LZMA.RangeCoder.Decoder decoder; - private long position = 0; - private bool isDisposed; - - public PpmdStream(PpmdProperties properties, Stream stream, bool compress) - { - this.properties = properties; - this.stream = stream; - this.compress = compress; - - if (properties.Version == PpmdVersion.I1) - { - model = new I1.Model(); - if (compress) - model.EncodeStart(properties); - else - model.DecodeStart(stream, properties); - } - if (properties.Version == PpmdVersion.H) - { - modelH = new H.ModelPPM(); - if (compress) - throw new NotImplementedException(); - else - modelH.decodeInit(stream, properties.ModelOrder, properties.AllocatorSize); - } - if (properties.Version == PpmdVersion.H7z) - { - modelH = new H.ModelPPM(); - if (compress) - throw new NotImplementedException(); - else - modelH.decodeInit(null, properties.ModelOrder, properties.AllocatorSize); - decoder = new LZMA.RangeCoder.Decoder(); - decoder.Init(stream); - } - } - - public override bool CanRead - { - get { return !compress; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return compress; } - } - - public override void Flush() - { - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (isDisposing) - { - if (compress) - model.EncodeBlock(stream, new MemoryStream(), true); - } - base.Dispose(isDisposing); - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { return position; } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (compress) - return 0; - int size = 0; - if (properties.Version == PpmdVersion.I1) - size = model.DecodeBlock(stream, buffer, offset, count); - if (properties.Version == PpmdVersion.H) - { - int c; - while (size < count && (c = modelH.decodeChar()) >= 0) - { - buffer[offset++] = (byte) c; - size++; - } - } - if (properties.Version == PpmdVersion.H7z) - { - int c; - while (size < count && (c = modelH.decodeChar(decoder)) >= 0) - { - buffer[offset++] = (byte) c; - size++; - } - } - position += size; - return size; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (compress) - model.EncodeBlock(stream, new MemoryStream(buffer, offset, count), false); - } - } +using System; +using System.IO; +using SharpCompress.Compressor.Rar.PPM; + +namespace SharpCompress.Compressor.PPMd +{ + public class PpmdStream : Stream + { + private PpmdProperties properties; + private Stream stream; + private bool compress; + private I1.Model model; + private H.ModelPPM modelH; + private LZMA.RangeCoder.Decoder decoder; + private long position = 0; + private bool isDisposed; + + public PpmdStream(PpmdProperties properties, Stream stream, bool compress) + { + this.properties = properties; + this.stream = stream; + this.compress = compress; + + if (properties.Version == PpmdVersion.I1) + { + model = new I1.Model(); + if (compress) + model.EncodeStart(properties); + else + model.DecodeStart(stream, properties); + } + if (properties.Version == PpmdVersion.H) + { + modelH = new H.ModelPPM(); + if (compress) + throw new NotImplementedException(); + else + modelH.decodeInit(stream, properties.ModelOrder, properties.AllocatorSize); + } + if (properties.Version == PpmdVersion.H7z) + { + modelH = new H.ModelPPM(); + if (compress) + throw new NotImplementedException(); + else + modelH.decodeInit(null, properties.ModelOrder, properties.AllocatorSize); + decoder = new LZMA.RangeCoder.Decoder(); + decoder.Init(stream); + } + } + + public override bool CanRead + { + get { return !compress; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return compress; } + } + + public override void Flush() + { + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + if (isDisposing) + { + if (compress) + model.EncodeBlock(stream, new MemoryStream(), true); + } + base.Dispose(isDisposing); + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { return position; } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (compress) + return 0; + int size = 0; + if (properties.Version == PpmdVersion.I1) + size = model.DecodeBlock(stream, buffer, offset, count); + if (properties.Version == PpmdVersion.H) + { + int c; + while (size < count && (c = modelH.decodeChar()) >= 0) + { + buffer[offset++] = (byte) c; + size++; + } + } + if (properties.Version == PpmdVersion.H7z) + { + int c; + while (size < count && (c = modelH.decodeChar(decoder)) >= 0) + { + buffer[offset++] = (byte) c; + size++; + } + } + position += size; + return size; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (compress) + model.EncodeBlock(stream, new MemoryStream(buffer, offset, count), false); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/AudioVariables.cs b/src/SharpCompress/Compressor/Rar/Decode/AudioVariables.cs similarity index 96% rename from SharpCompress/Compressor/Rar/Decode/AudioVariables.cs rename to src/SharpCompress/Compressor/Rar/Decode/AudioVariables.cs index 49a39aae..d064cccb 100644 --- a/SharpCompress/Compressor/Rar/Decode/AudioVariables.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/AudioVariables.cs @@ -1,26 +1,26 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class AudioVariables - { - internal AudioVariables() - { - Dif = new int[11]; - } - - internal int[] Dif { get; private set; } - internal int ByteCount { get; set; } - internal int D1 { get; set; } - - internal int D2 { get; set; } - internal int D3 { get; set; } - internal int D4 { get; set; } - - internal int K1 { get; set; } - internal int K2 { get; set; } - internal int K3 { get; set; } - internal int K4 { get; set; } - internal int K5 { get; set; } - internal int LastChar { get; set; } - internal int LastDelta { get; set; } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class AudioVariables + { + internal AudioVariables() + { + Dif = new int[11]; + } + + internal int[] Dif { get; private set; } + internal int ByteCount { get; set; } + internal int D1 { get; set; } + + internal int D2 { get; set; } + internal int D3 { get; set; } + internal int D4 { get; set; } + + internal int K1 { get; set; } + internal int K2 { get; set; } + internal int K3 { get; set; } + internal int K4 { get; set; } + internal int K5 { get; set; } + internal int LastChar { get; set; } + internal int LastDelta { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/BitDecode.cs b/src/SharpCompress/Compressor/Rar/Decode/BitDecode.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/BitDecode.cs rename to src/SharpCompress/Compressor/Rar/Decode/BitDecode.cs index 6f9d7b2e..bf3fc0f1 100644 --- a/SharpCompress/Compressor/Rar/Decode/BitDecode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/BitDecode.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class BitDecode : Decode - { - internal BitDecode() - : base(new int[Compress.BC]) - { - } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class BitDecode : Decode + { + internal BitDecode() + : base(new int[Compress.BC]) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/CodeType.cs b/src/SharpCompress/Compressor/Rar/Decode/CodeType.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/CodeType.cs rename to src/SharpCompress/Compressor/Rar/Decode/CodeType.cs index 5fa87fa7..90ce4df5 100644 --- a/SharpCompress/Compressor/Rar/Decode/CodeType.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/CodeType.cs @@ -1,15 +1,15 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal enum CodeType - { - CODE_HUFFMAN, - CODE_LZ, - CODE_LZ2, - CODE_REPEATLZ, - CODE_CACHELZ, - CODE_STARTFILE, - CODE_ENDFILE, - CODE_VM, - CODE_VMDATA - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal enum CodeType + { + CODE_HUFFMAN, + CODE_LZ, + CODE_LZ2, + CODE_REPEATLZ, + CODE_CACHELZ, + CODE_STARTFILE, + CODE_ENDFILE, + CODE_VM, + CODE_VMDATA + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/Compress.cs b/src/SharpCompress/Compressor/Rar/Decode/Compress.cs similarity index 97% rename from SharpCompress/Compressor/Rar/Decode/Compress.cs rename to src/SharpCompress/Compressor/Rar/Decode/Compress.cs index 1388b350..8a23c7d0 100644 --- a/SharpCompress/Compressor/Rar/Decode/Compress.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/Compress.cs @@ -1,26 +1,26 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class Compress - { - public const int CODEBUFSIZE = 0x4000; - public const int MAXWINSIZE = 0x400000; - //UPGRADE_NOTE: Final was removed from the declaration of 'MAXWINMASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int MAXWINMASK = (MAXWINSIZE - 1); - - public const int LOW_DIST_REP_COUNT = 16; - - public const int NC = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const int DC = 60; - public const int LDC = 17; - public const int RC = 28; - //UPGRADE_NOTE: Final was removed from the declaration of 'HUFF_TABLE_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int HUFF_TABLE_SIZE = (NC + DC + RC + LDC); - public const int BC = 20; - - public const int NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const int DC20 = 48; - public const int RC20 = 28; - public const int BC20 = 19; - public const int MC20 = 257; - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class Compress + { + public const int CODEBUFSIZE = 0x4000; + public const int MAXWINSIZE = 0x400000; + //UPGRADE_NOTE: Final was removed from the declaration of 'MAXWINMASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int MAXWINMASK = (MAXWINSIZE - 1); + + public const int LOW_DIST_REP_COUNT = 16; + + public const int NC = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const int DC = 60; + public const int LDC = 17; + public const int RC = 28; + //UPGRADE_NOTE: Final was removed from the declaration of 'HUFF_TABLE_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int HUFF_TABLE_SIZE = (NC + DC + RC + LDC); + public const int BC = 20; + + public const int NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const int DC20 = 48; + public const int RC20 = 28; + public const int BC20 = 19; + public const int MC20 = 257; + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/Decode.cs b/src/SharpCompress/Compressor/Rar/Decode/Decode.cs similarity index 96% rename from SharpCompress/Compressor/Rar/Decode/Decode.cs rename to src/SharpCompress/Compressor/Rar/Decode/Decode.cs index e4feec74..ad3079c5 100644 --- a/SharpCompress/Compressor/Rar/Decode/Decode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/Decode.cs @@ -1,34 +1,34 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class Decode - { - internal Decode() - : this(new int[2]) - { - } - - protected Decode(int[] customDecodeNum) - { - DecodeLen = new int[16]; - DecodePos = new int[16]; - DecodeNum = customDecodeNum; - } - - /// returns the decode Length array - /// decodeLength - /// - internal int[] DecodeLen { get; private set; } - - /// returns the decode num array - /// decodeNum - /// - internal int[] DecodeNum { get; private set; } - - /// returns the decodePos array - /// decodePos - /// - internal int[] DecodePos { get; private set; } - - internal int MaxNum { get; set; } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class Decode + { + internal Decode() + : this(new int[2]) + { + } + + protected Decode(int[] customDecodeNum) + { + DecodeLen = new int[16]; + DecodePos = new int[16]; + DecodeNum = customDecodeNum; + } + + /// returns the decode Length array + /// decodeLength + /// + internal int[] DecodeLen { get; private set; } + + /// returns the decode num array + /// decodeNum + /// + internal int[] DecodeNum { get; private set; } + + /// returns the decodePos array + /// decodePos + /// + internal int[] DecodePos { get; private set; } + + internal int MaxNum { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/DistDecode.cs b/src/SharpCompress/Compressor/Rar/Decode/DistDecode.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/DistDecode.cs rename to src/SharpCompress/Compressor/Rar/Decode/DistDecode.cs index 1b1f1968..d4f70a29 100644 --- a/SharpCompress/Compressor/Rar/Decode/DistDecode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/DistDecode.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class DistDecode : Decode - { - internal DistDecode() - : base(new int[Compress.DC]) - { - } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class DistDecode : Decode + { + internal DistDecode() + : base(new int[Compress.DC]) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/FilterType.cs b/src/SharpCompress/Compressor/Rar/Decode/FilterType.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/FilterType.cs rename to src/SharpCompress/Compressor/Rar/Decode/FilterType.cs index 64b91d7e..23966e4f 100644 --- a/SharpCompress/Compressor/Rar/Decode/FilterType.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/FilterType.cs @@ -1,16 +1,16 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal enum FilterType - { - FILTER_NONE, - FILTER_PPM, - FILTER_E8, - FILTER_E8E9, - FILTER_UPCASETOLOW, - FILTER_AUDIO, - FILTER_RGB, - FILTER_DELTA, - FILTER_ITANIUM, - FILTER_E8E9V2, - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal enum FilterType + { + FILTER_NONE, + FILTER_PPM, + FILTER_E8, + FILTER_E8E9, + FILTER_UPCASETOLOW, + FILTER_AUDIO, + FILTER_RGB, + FILTER_DELTA, + FILTER_ITANIUM, + FILTER_E8E9V2, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/LitDecode.cs b/src/SharpCompress/Compressor/Rar/Decode/LitDecode.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/LitDecode.cs rename to src/SharpCompress/Compressor/Rar/Decode/LitDecode.cs index 48c0de51..88099d4c 100644 --- a/SharpCompress/Compressor/Rar/Decode/LitDecode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/LitDecode.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class LitDecode : Decode - { - internal LitDecode() - : base(new int[Compress.NC]) - { - } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class LitDecode : Decode + { + internal LitDecode() + : base(new int[Compress.NC]) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/LowDistDecode.cs b/src/SharpCompress/Compressor/Rar/Decode/LowDistDecode.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/LowDistDecode.cs rename to src/SharpCompress/Compressor/Rar/Decode/LowDistDecode.cs index b88f127a..57009771 100644 --- a/SharpCompress/Compressor/Rar/Decode/LowDistDecode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/LowDistDecode.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class LowDistDecode : Decode - { - internal LowDistDecode() - : base(new int[Compress.LDC]) - { - } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class LowDistDecode : Decode + { + internal LowDistDecode() + : base(new int[Compress.LDC]) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/MultDecode.cs b/src/SharpCompress/Compressor/Rar/Decode/MultDecode.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/MultDecode.cs rename to src/SharpCompress/Compressor/Rar/Decode/MultDecode.cs index bc91a04b..e9f892ce 100644 --- a/SharpCompress/Compressor/Rar/Decode/MultDecode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/MultDecode.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class MultDecode : Decode - { - internal MultDecode() - : base(new int[Compress.MC20]) - { - } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class MultDecode : Decode + { + internal MultDecode() + : base(new int[Compress.MC20]) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Decode/RepDecode.cs b/src/SharpCompress/Compressor/Rar/Decode/RepDecode.cs similarity index 95% rename from SharpCompress/Compressor/Rar/Decode/RepDecode.cs rename to src/SharpCompress/Compressor/Rar/Decode/RepDecode.cs index bc66361f..a36bd9f7 100644 --- a/SharpCompress/Compressor/Rar/Decode/RepDecode.cs +++ b/src/SharpCompress/Compressor/Rar/Decode/RepDecode.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.decode -{ - internal class RepDecode : Decode - { - internal RepDecode() - : base(new int[Compress.RC]) - { - } - } +namespace SharpCompress.Compressor.Rar.decode +{ + internal class RepDecode : Decode + { + internal RepDecode() + : base(new int[Compress.RC]) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs similarity index 97% rename from SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs rename to src/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs index dbbea0d6..374fdcef 100644 --- a/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs @@ -1,162 +1,162 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Compressor.Rar -{ - internal class MultiVolumeReadOnlyStream : Stream - { - private long currentPosition; - private long maxPosition; - - private IEnumerator filePartEnumerator; - private Stream currentStream; - - private readonly IExtractionListener streamListener; - - private long currentPartTotalReadBytes; - private long currentEntryTotalReadBytes; - - internal MultiVolumeReadOnlyStream(IEnumerable parts, IExtractionListener streamListener) - { - this.streamListener = streamListener; - - filePartEnumerator = parts.GetEnumerator(); - filePartEnumerator.MoveNext(); - InitializeNextFilePart(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - if (filePartEnumerator != null) - { - filePartEnumerator.Dispose(); - filePartEnumerator = null; - } - if (currentStream != null) - { - currentStream.Dispose(); - currentStream = null; - } - } - } - - private void InitializeNextFilePart() - { - maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize; - currentPosition = 0; - if (currentStream != null) - { - currentStream.Dispose(); - } - currentStream = filePartEnumerator.Current.GetCompressedStream(); - - currentPartTotalReadBytes = 0; - - streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName, - filePartEnumerator.Current.FileHeader.CompressedSize, - filePartEnumerator.Current.FileHeader.UncompressedSize); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int totalRead = 0; - int currentOffset = offset; - int currentCount = count; - while (currentCount > 0) - { - int readSize = currentCount; - if (currentCount > maxPosition - currentPosition) - { - readSize = (int) (maxPosition - currentPosition); - } - - int read = currentStream.Read(buffer, currentOffset, readSize); - if (read < 0) - { - throw new EndOfStreamException(); - } - - currentPosition += read; - currentOffset += read; - currentCount -= read; - totalRead += read; - if (((maxPosition - currentPosition) == 0) - && filePartEnumerator.Current.FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)) - { - if (filePartEnumerator.Current.FileHeader.Salt != null) - { - throw new InvalidFormatException("Sharpcompress currently does not support multi-volume decryption."); - } - string fileName = filePartEnumerator.Current.FileHeader.FileName; - if (!filePartEnumerator.MoveNext()) - { - throw new InvalidFormatException( - "Multi-part rar file is incomplete. Entry expects a new volume: " + fileName); - } - InitializeNextFilePart(); - } - else - { - break; - } - } - currentPartTotalReadBytes += totalRead; - currentEntryTotalReadBytes += totalRead; - streamListener.FireCompressedBytesRead(currentPartTotalReadBytes, currentEntryTotalReadBytes); - return totalRead; - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Compressor.Rar +{ + internal class MultiVolumeReadOnlyStream : Stream + { + private long currentPosition; + private long maxPosition; + + private IEnumerator filePartEnumerator; + private Stream currentStream; + + private readonly IExtractionListener streamListener; + + private long currentPartTotalReadBytes; + private long currentEntryTotalReadBytes; + + internal MultiVolumeReadOnlyStream(IEnumerable parts, IExtractionListener streamListener) + { + this.streamListener = streamListener; + + filePartEnumerator = parts.GetEnumerator(); + filePartEnumerator.MoveNext(); + InitializeNextFilePart(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + if (filePartEnumerator != null) + { + filePartEnumerator.Dispose(); + filePartEnumerator = null; + } + if (currentStream != null) + { + currentStream.Dispose(); + currentStream = null; + } + } + } + + private void InitializeNextFilePart() + { + maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize; + currentPosition = 0; + if (currentStream != null) + { + currentStream.Dispose(); + } + currentStream = filePartEnumerator.Current.GetCompressedStream(); + + currentPartTotalReadBytes = 0; + + streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName, + filePartEnumerator.Current.FileHeader.CompressedSize, + filePartEnumerator.Current.FileHeader.UncompressedSize); + } + + public override int Read(byte[] buffer, int offset, int count) + { + int totalRead = 0; + int currentOffset = offset; + int currentCount = count; + while (currentCount > 0) + { + int readSize = currentCount; + if (currentCount > maxPosition - currentPosition) + { + readSize = (int) (maxPosition - currentPosition); + } + + int read = currentStream.Read(buffer, currentOffset, readSize); + if (read < 0) + { + throw new EndOfStreamException(); + } + + currentPosition += read; + currentOffset += read; + currentCount -= read; + totalRead += read; + if (((maxPosition - currentPosition) == 0) + && filePartEnumerator.Current.FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)) + { + if (filePartEnumerator.Current.FileHeader.Salt != null) + { + throw new InvalidFormatException("Sharpcompress currently does not support multi-volume decryption."); + } + string fileName = filePartEnumerator.Current.FileHeader.FileName; + if (!filePartEnumerator.MoveNext()) + { + throw new InvalidFormatException( + "Multi-part rar file is incomplete. Entry expects a new volume: " + fileName); + } + InitializeNextFilePart(); + } + else + { + break; + } + } + currentPartTotalReadBytes += totalRead; + currentEntryTotalReadBytes += totalRead; + streamListener.FireCompressedBytesRead(currentPartTotalReadBytes, currentEntryTotalReadBytes); + return totalRead; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/PPM/BlockTypes.cs b/src/SharpCompress/Compressor/Rar/PPM/BlockTypes.cs similarity index 94% rename from SharpCompress/Compressor/Rar/PPM/BlockTypes.cs rename to src/SharpCompress/Compressor/Rar/PPM/BlockTypes.cs index 29c9affd..cf3c4889 100644 --- a/SharpCompress/Compressor/Rar/PPM/BlockTypes.cs +++ b/src/SharpCompress/Compressor/Rar/PPM/BlockTypes.cs @@ -1,8 +1,8 @@ -namespace SharpCompress.Compressor.Rar.PPM -{ - internal enum BlockTypes - { - BLOCK_LZ = 0, - BLOCK_PPM = 1, - } +namespace SharpCompress.Compressor.Rar.PPM +{ + internal enum BlockTypes + { + BLOCK_LZ = 0, + BLOCK_PPM = 1, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/RarCRC.cs b/src/SharpCompress/Compressor/Rar/RarCRC.cs similarity index 96% rename from SharpCompress/Compressor/Rar/RarCRC.cs rename to src/SharpCompress/Compressor/Rar/RarCRC.cs index b680434f..1870bb85 100644 --- a/SharpCompress/Compressor/Rar/RarCRC.cs +++ b/src/SharpCompress/Compressor/Rar/RarCRC.cs @@ -1,44 +1,44 @@ -using System; - -namespace SharpCompress.Compressor.Rar -{ - internal static class RarCRC - { - private static uint[] crcTab; - - public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) - { - int size = Math.Min(data.Length - offset, count); - - for (int i = 0; i < size; i++) - { - startCrc = (crcTab[((int) ((int) startCrc ^ (int) data[offset + i])) & 0xff] ^ (startCrc >> 8)); - } - return (startCrc); - } - - static RarCRC() - { - { - crcTab = new uint[256]; - for (uint i = 0; i < 256; i++) - { - uint c = i; - for (int j = 0; j < 8; j++) - { - if ((c & 1) != 0) - { - c = c >> 1; - c ^= 0xEDB88320; - } - else - { - c = c >> 1; - } - } - crcTab[i] = c; - } - } - } - } +using System; + +namespace SharpCompress.Compressor.Rar +{ + internal static class RarCRC + { + private static uint[] crcTab; + + public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) + { + int size = Math.Min(data.Length - offset, count); + + for (int i = 0; i < size; i++) + { + startCrc = (crcTab[((int) ((int) startCrc ^ (int) data[offset + i])) & 0xff] ^ (startCrc >> 8)); + } + return (startCrc); + } + + static RarCRC() + { + { + crcTab = new uint[256]; + for (uint i = 0; i < 256; i++) + { + uint c = i; + for (int j = 0; j < 8; j++) + { + if ((c & 1) != 0) + { + c = c >> 1; + c ^= 0xEDB88320; + } + else + { + c = c >> 1; + } + } + crcTab[i] = c; + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/RarStream.cs b/src/SharpCompress/Compressor/Rar/RarStream.cs similarity index 96% rename from SharpCompress/Compressor/Rar/RarStream.cs rename to src/SharpCompress/Compressor/Rar/RarStream.cs index c9e70bbc..fefabc1a 100644 --- a/SharpCompress/Compressor/Rar/RarStream.cs +++ b/src/SharpCompress/Compressor/Rar/RarStream.cs @@ -1,154 +1,154 @@ -using System; -using System.IO; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Compressor.Rar -{ - internal class RarStream : Stream - { - private readonly Unpack unpack; - private readonly FileHeader fileHeader; - private readonly Stream readStream; - - private bool fetch = false; - - private byte[] tmpBuffer = new byte[65536]; - private int tmpOffset = 0; - private int tmpCount = 0; - - private byte[] outBuffer; - private int outOffset; - private int outCount = 0; - private int outTotal; - private bool isDisposed; - - public RarStream(Unpack unpack, FileHeader fileHeader, Stream readStream) - { - this.unpack = unpack; - this.fileHeader = fileHeader; - this.readStream = readStream; - fetch = true; - unpack.doUnpack(fileHeader, readStream, this); - fetch = false; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - readStream.Dispose(); - } - - public override bool CanRead - { - get - { - return true; - } - } - - public override bool CanSeek - { - get - { - return false; - } - } - - public override bool CanWrite - { - get - { - return false; - } - } - - public override void Flush() - { - } - - public override long Length - { - get { return fileHeader.UncompressedSize; } - } - - public override long Position - { - get { return fileHeader.UncompressedSize - unpack.DestSize; } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - outTotal = 0; - if (tmpCount > 0) - { - int toCopy = tmpCount < count ? tmpCount : count; - Buffer.BlockCopy(tmpBuffer, tmpOffset, buffer, offset, toCopy); - tmpOffset += toCopy; - tmpCount -= toCopy; - offset += toCopy; - count -= toCopy; - outTotal += toCopy; - } - if (count > 0 && unpack.DestSize > 0) - { - outBuffer = buffer; - outOffset = offset; - outCount = count; - fetch = true; - unpack.doUnpack(); - fetch = false; - } - return outTotal; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (!fetch) - { - throw new NotSupportedException(); - } - if (outCount > 0) - { - int toCopy = outCount < count ? outCount : count; - Buffer.BlockCopy(buffer, offset, outBuffer, outOffset, toCopy); - outOffset += toCopy; - outCount -= toCopy; - offset += toCopy; - count -= toCopy; - outTotal += toCopy; - } - if (count > 0) - { - if (tmpBuffer.Length < tmpCount + count) - { - byte[] newBuffer = - new byte[tmpBuffer.Length * 2 > tmpCount + count ? tmpBuffer.Length * 2 : tmpCount + count]; - Buffer.BlockCopy(tmpBuffer, 0, newBuffer, 0, tmpCount); - tmpBuffer = newBuffer; - } - Buffer.BlockCopy(buffer, offset, tmpBuffer, tmpCount, count); - tmpCount += count; - tmpOffset = 0; - unpack.Suspended = true; - } - else - unpack.Suspended = false; - } - } +using System; +using System.IO; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Compressor.Rar +{ + internal class RarStream : Stream + { + private readonly Unpack unpack; + private readonly FileHeader fileHeader; + private readonly Stream readStream; + + private bool fetch = false; + + private byte[] tmpBuffer = new byte[65536]; + private int tmpOffset = 0; + private int tmpCount = 0; + + private byte[] outBuffer; + private int outOffset; + private int outCount = 0; + private int outTotal; + private bool isDisposed; + + public RarStream(Unpack unpack, FileHeader fileHeader, Stream readStream) + { + this.unpack = unpack; + this.fileHeader = fileHeader; + this.readStream = readStream; + fetch = true; + unpack.doUnpack(fileHeader, readStream, this); + fetch = false; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + readStream.Dispose(); + } + + public override bool CanRead + { + get + { + return true; + } + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanWrite + { + get + { + return false; + } + } + + public override void Flush() + { + } + + public override long Length + { + get { return fileHeader.UncompressedSize; } + } + + public override long Position + { + get { return fileHeader.UncompressedSize - unpack.DestSize; } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + outTotal = 0; + if (tmpCount > 0) + { + int toCopy = tmpCount < count ? tmpCount : count; + Buffer.BlockCopy(tmpBuffer, tmpOffset, buffer, offset, toCopy); + tmpOffset += toCopy; + tmpCount -= toCopy; + offset += toCopy; + count -= toCopy; + outTotal += toCopy; + } + if (count > 0 && unpack.DestSize > 0) + { + outBuffer = buffer; + outOffset = offset; + outCount = count; + fetch = true; + unpack.doUnpack(); + fetch = false; + } + return outTotal; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (!fetch) + { + throw new NotSupportedException(); + } + if (outCount > 0) + { + int toCopy = outCount < count ? outCount : count; + Buffer.BlockCopy(buffer, offset, outBuffer, outOffset, toCopy); + outOffset += toCopy; + outCount -= toCopy; + offset += toCopy; + count -= toCopy; + outTotal += toCopy; + } + if (count > 0) + { + if (tmpBuffer.Length < tmpCount + count) + { + byte[] newBuffer = + new byte[tmpBuffer.Length * 2 > tmpCount + count ? tmpBuffer.Length * 2 : tmpCount + count]; + Buffer.BlockCopy(tmpBuffer, 0, newBuffer, 0, tmpCount); + tmpBuffer = newBuffer; + } + Buffer.BlockCopy(buffer, offset, tmpBuffer, tmpCount, count); + tmpCount += count; + tmpOffset = 0; + unpack.Suspended = true; + } + else + unpack.Suspended = false; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Unpack.cs b/src/SharpCompress/Compressor/Rar/Unpack.cs similarity index 97% rename from SharpCompress/Compressor/Rar/Unpack.cs rename to src/SharpCompress/Compressor/Rar/Unpack.cs index 106a01b5..4b6ebd9d 100644 --- a/SharpCompress/Compressor/Rar/Unpack.cs +++ b/src/SharpCompress/Compressor/Rar/Unpack.cs @@ -1,1228 +1,1228 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.Compressor.PPMd.H; -using SharpCompress.Compressor.Rar.decode; -using SharpCompress.Compressor.Rar.PPM; -using SharpCompress.Compressor.Rar.VM; - -namespace SharpCompress.Compressor.Rar -{ - internal sealed class Unpack : Unpack20 - { - public bool FileExtracted - { - // Duplicate method - // private boolean ReadEndOfBlock() throws IOException, RarException - // { - // int BitField = getbits(); - // boolean NewTable, NewFile = false; - // if ((BitField & 0x8000) != 0) { - // NewTable = true; - // addbits(1); - // } else { - // NewFile = true; - // NewTable = (BitField & 0x4000) != 0; - // addbits(2); - // } - // tablesRead = !NewTable; - // return !(NewFile || NewTable && !readTables()); - // } - get { return fileExtracted; } - } - - public long DestSize - { - get { return destUnpSize; } - set - { - this.destUnpSize = value; - this.fileExtracted = false; - } - } - - public bool Suspended - { - set { this.suspended = value; } - } - - public int Char - { - get - { - if (inAddr > BitInput.MAX_SIZE - 30) - { - unpReadBuf(); - } - return (InBuf[inAddr++] & 0xff); - } - } - - public int PpmEscChar - { - get { return ppmEscChar; } - - set { this.ppmEscChar = value; } - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'ppm '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ModelPPM ppm = new ModelPPM(); - - private int ppmEscChar; - - private RarVM rarVM = new RarVM(); - - /* Filters code, one entry per filter */ - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - private List filters = new List(); - - /* Filters stack, several entrances of same filter are possible */ - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - private List prgStack = new List(); - - /* - * lengths of preceding blocks, one length per filter. Used to reduce size - * required to write block length if lengths are repeating - */ - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - private List oldFilterLengths = new List(); - - private int lastFilter; - - private bool tablesRead; - - //UPGRADE_NOTE: The initialization of 'unpOldTable' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" - - private byte[] unpOldTable = new byte[Compress.HUFF_TABLE_SIZE]; - - private BlockTypes unpBlockType; - - //private bool externalWindow; - - private long writtenFileSize; - - private bool fileExtracted; - - private bool ppmError; - - private int prevLowDist; - - private int lowDistRepCount; - - public static int[] DBitLengthCounts = new int[] {4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, 0, 12}; - - private FileHeader fileHeader; - - public Unpack() - { - window = null; - //externalWindow = false; - suspended = false; - unpAllBuf = false; - unpSomeRead = false; - } - - public void init(byte[] window) - { - if (window == null) - { - this.window = new byte[Compress.MAXWINSIZE]; - } - else - { - this.window = window; - //externalWindow = true; - } - inAddr = 0; - unpInitData(false); - } - - public void doUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) - { - destUnpSize = fileHeader.UncompressedSize; - this.fileHeader = fileHeader; - base.writeStream = writeStream; - base.readStream = readStream; - bool solid = FlagUtility.HasFlag(fileHeader.FileFlags, FileFlags.SOLID); - if (!solid) - { - init(null); - } - suspended = false; - doUnpack(); - } - - public void doUnpack() - { - bool solid = FlagUtility.HasFlag(fileHeader.FileFlags, FileFlags.SOLID); - if (fileHeader.PackingMethod == 0x30) - { - unstoreFile(); - return; - } - switch (fileHeader.RarVersion) - { - case 15: // rar 1.5 compression - unpack15(solid); - break; - - case 20: - // rar 2.x compression - case 26: // files larger than 2GB - unpack20(solid); - break; - - case 29: - // rar 3.x compression - case 36: // alternative hash - unpack29(solid); - break; - } - } - - private void unstoreFile() - { - byte[] buffer = new byte[0x10000]; - while (true) - { - int code = readStream.Read(buffer, 0, (int) System.Math.Min(buffer.Length, destUnpSize)); - if (code == 0 || code == -1) - break; - code = code < destUnpSize ? code : (int) destUnpSize; - writeStream.Write(buffer, 0, code); - if (destUnpSize >= 0) - destUnpSize -= code; - if (suspended) - return; - } - } - - private void unpack29(bool solid) - { - int[] DDecode = new int[Compress.DC]; - byte[] DBits = new byte[Compress.DC]; - - int Bits; - - if (DDecode[1] == 0) - { - int Dist = 0, BitLength = 0, Slot = 0; - for (int I = 0; I < DBitLengthCounts.Length; I++, BitLength++) - { - int count = DBitLengthCounts[I]; - for (int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) - { - DDecode[Slot] = Dist; - DBits[Slot] = (byte) BitLength; - } - } - } - - fileExtracted = true; - - if (!suspended) - { - unpInitData(solid); - if (!unpReadBuf()) - { - return; - } - if ((!solid || !tablesRead) && !readTables()) - { - return; - } - } - - if (ppmError) - { - return; - } - - while (true) - { - unpPtr &= Compress.MAXWINMASK; - - if (inAddr > readBorder) - { - if (!unpReadBuf()) - { - break; - } - } - // System.out.println(((wrPtr - unpPtr) & - // Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr); - if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 260 && wrPtr != unpPtr) - { - UnpWriteBuf(); - if (destUnpSize <= 0) - { - return; - } - if (suspended) - { - fileExtracted = false; - return; - } - } - if (unpBlockType == BlockTypes.BLOCK_PPM) - { - int Ch = ppm.decodeChar(); - if (Ch == -1) - { - ppmError = true; - break; - } - if (Ch == ppmEscChar) - { - int NextCh = ppm.decodeChar(); - if (NextCh == 0) - { - if (!readTables()) - { - break; - } - continue; - } - if (NextCh == 2 || NextCh == -1) - { - break; - } - if (NextCh == 3) - { - if (!readVMCodePPM()) - { - break; - } - continue; - } - if (NextCh == 4) - { - int Distance = 0, Length = 0; - bool failed = false; - for (int I = 0; I < 4 && !failed; I++) - { - int ch = ppm.decodeChar(); - if (ch == -1) - { - failed = true; - } - else - { - if (I == 3) - { - // Bug fixed - Length = ch & 0xff; - } - else - { - // Bug fixed - Distance = (Distance << 8) + (ch & 0xff); - } - } - } - if (failed) - { - break; - } - copyString(Length + 32, Distance + 2); - continue; - } - if (NextCh == 5) - { - int Length = ppm.decodeChar(); - if (Length == -1) - { - break; - } - copyString(Length + 4, 1); - continue; - } - } - window[unpPtr++] = (byte) Ch; - continue; - } - - int Number = this.decodeNumber(LD); - if (Number < 256) - { - window[unpPtr++] = (byte) Number; - continue; - } - if (Number >= 271) - { - int Length = LDecode[Number -= 271] + 3; - if ((Bits = LBits[Number]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - - int DistNumber = this.decodeNumber(DD); - int Distance = DDecode[DistNumber] + 1; - if ((Bits = DBits[DistNumber]) > 0) - { - if (DistNumber > 9) - { - if (Bits > 4) - { - Distance += ((Utility.URShift(GetBits(), (20 - Bits))) << 4); - AddBits(Bits - 4); - } - if (lowDistRepCount > 0) - { - lowDistRepCount--; - Distance += prevLowDist; - } - else - { - int LowDist = this.decodeNumber(LDD); - if (LowDist == 16) - { - lowDistRepCount = Compress.LOW_DIST_REP_COUNT - 1; - Distance += prevLowDist; - } - else - { - Distance += LowDist; - prevLowDist = LowDist; - } - } - } - else - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - } - - if (Distance >= 0x2000) - { - Length++; - if (Distance >= 0x40000L) - { - Length++; - } - } - - insertOldDist(Distance); - insertLastMatch(Length, Distance); - - copyString(Length, Distance); - continue; - } - if (Number == 256) - { - if (!readEndOfBlock()) - { - break; - } - continue; - } - if (Number == 257) - { - if (!readVMCode()) - { - break; - } - continue; - } - if (Number == 258) - { - if (lastLength != 0) - { - copyString(lastLength, lastDist); - } - continue; - } - if (Number < 263) - { - int DistNum = Number - 259; - int Distance = oldDist[DistNum]; - for (int I = DistNum; I > 0; I--) - { - oldDist[I] = oldDist[I - 1]; - } - oldDist[0] = Distance; - - int LengthNumber = this.decodeNumber(RD); - int Length = LDecode[LengthNumber] + 2; - if ((Bits = LBits[LengthNumber]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - insertLastMatch(Length, Distance); - copyString(Length, Distance); - continue; - } - if (Number < 272) - { - int Distance = SDDecode[Number -= 263] + 1; - if ((Bits = SDBits[Number]) > 0) - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - insertOldDist(Distance); - insertLastMatch(2, Distance); - copyString(2, Distance); - continue; - } - } - UnpWriteBuf(); - } - - private void UnpWriteBuf() - { - int WrittenBorder = wrPtr; - int WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; - for (int I = 0; I < prgStack.Count; I++) - { - UnpackFilter flt = prgStack[I]; - if (flt == null) - { - continue; - } - if (flt.NextWindow) - { - flt.NextWindow = false; // ->NextWindow=false; - continue; - } - int BlockStart = flt.BlockStart; // ->BlockStart; - int BlockLength = flt.BlockLength; // ->BlockLength; - if (((BlockStart - WrittenBorder) & Compress.MAXWINMASK) < WriteSize) - { - if (WrittenBorder != BlockStart) - { - UnpWriteArea(WrittenBorder, BlockStart); - WrittenBorder = BlockStart; - WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; - } - if (BlockLength <= WriteSize) - { - int BlockEnd = (BlockStart + BlockLength) & Compress.MAXWINMASK; - if (BlockStart < BlockEnd || BlockEnd == 0) - { - // VM.SetMemory(0,Window+BlockStart,BlockLength); - rarVM.setMemory(0, window, BlockStart, BlockLength); - } - else - { - int FirstPartLength = Compress.MAXWINSIZE - BlockStart; - // VM.SetMemory(0,Window+BlockStart,FirstPartLength); - rarVM.setMemory(0, window, BlockStart, FirstPartLength); - // VM.SetMemory(FirstPartLength,Window,BlockEnd); - rarVM.setMemory(FirstPartLength, window, 0, BlockEnd); - } - - VMPreparedProgram ParentPrg = filters[flt.ParentFilter].Program; - VMPreparedProgram Prg = flt.Program; - - if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // copy global data from previous script execution if - // any - // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); - // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - Prg.GlobalData.Clear(); - for (int i = 0; i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) - { - Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; - } - } - - ExecuteCode(Prg); - - if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // save global data for next script execution - if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count) - { - //ParentPrg.GlobalData.Clear(); // ->GlobalData.Alloc(Prg->GlobalData.Size()); - ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count); - } - // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for (int i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) - { - ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; - } - } - else - { - ParentPrg.GlobalData.Clear(); - } - - int FilteredDataOffset = Prg.FilteredDataOffset; - int FilteredDataSize = Prg.FilteredDataSize; - byte[] FilteredData = new byte[FilteredDataSize]; - - for (int i = 0; i < FilteredDataSize; i++) - { - FilteredData[i] = rarVM.Mem[FilteredDataOffset + i]; - // Prg.GlobalData.get(FilteredDataOffset - // + - // i); - } - - prgStack[I] = null; - while (I + 1 < prgStack.Count) - { - UnpackFilter NextFilter = prgStack[I + 1]; - if (NextFilter == null || NextFilter.BlockStart != BlockStart || - NextFilter.BlockLength != FilteredDataSize || NextFilter.NextWindow) - { - break; - } - // apply several filters to same data block - - rarVM.setMemory(0, FilteredData, 0, FilteredDataSize); - // .SetMemory(0,FilteredData,FilteredDataSize); - - VMPreparedProgram pPrg = filters[NextFilter.ParentFilter].Program; - VMPreparedProgram NextPrg = NextFilter.Program; - - if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // copy global data from previous script execution - // if any - // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); - NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count); - // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for (int i = 0; i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) - { - NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; - } - } - - ExecuteCode(NextPrg); - - if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // save global data for next script execution - if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count) - { - pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count); - } - // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for (int i = 0; i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) - { - pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; - } - } - else - { - pPrg.GlobalData.Clear(); - } - FilteredDataOffset = NextPrg.FilteredDataOffset; - FilteredDataSize = NextPrg.FilteredDataSize; - - FilteredData = new byte[FilteredDataSize]; - for (int i = 0; i < FilteredDataSize; i++) - { - FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i]; - } - - I++; - prgStack[I] = null; - } - writeStream.Write(FilteredData, 0, FilteredDataSize); - unpSomeRead = true; - writtenFileSize += FilteredDataSize; - destUnpSize -= FilteredDataSize; - WrittenBorder = BlockEnd; - WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; - } - else - { - for (int J = I; J < prgStack.Count; J++) - { - UnpackFilter filt = prgStack[J]; - if (filt != null && filt.NextWindow) - { - filt.NextWindow = false; - } - } - wrPtr = WrittenBorder; - return; - } - } - } - - UnpWriteArea(WrittenBorder, unpPtr); - wrPtr = unpPtr; - } - - private void UnpWriteArea(int startPtr, int endPtr) - { - if (endPtr != startPtr) - { - unpSomeRead = true; - } - if (endPtr < startPtr) - { - UnpWriteData(window, startPtr, -startPtr & Compress.MAXWINMASK); - UnpWriteData(window, 0, endPtr); - unpAllBuf = true; - } - else - { - UnpWriteData(window, startPtr, endPtr - startPtr); - } - } - - private void UnpWriteData(byte[] data, int offset, int size) - { - if (destUnpSize <= 0) - { - return; - } - int writeSize = size; - if (writeSize > destUnpSize) - { - writeSize = (int) destUnpSize; - } - writeStream.Write(data, offset, writeSize); - - writtenFileSize += size; - destUnpSize -= size; - } - - private void insertOldDist(int distance) - { - oldDist[3] = oldDist[2]; - oldDist[2] = oldDist[1]; - oldDist[1] = oldDist[0]; - oldDist[0] = distance; - } - - private void insertLastMatch(int length, int distance) - { - lastDist = distance; - lastLength = length; - } - - private void copyString(int length, int distance) - { - // System.out.println("copyString(" + length + ", " + distance + ")"); - - int destPtr = unpPtr - distance; - // System.out.println(unpPtr+":"+distance); - if (destPtr >= 0 && destPtr < Compress.MAXWINSIZE - 260 && unpPtr < Compress.MAXWINSIZE - 260) - { - window[unpPtr++] = window[destPtr++]; - - while (--length > 0) - window[unpPtr++] = window[destPtr++]; - } - else - while (length-- != 0) - { - window[unpPtr] = window[destPtr++ & Compress.MAXWINMASK]; - unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; - } - } - - protected internal override void unpInitData(bool solid) - { - if (!solid) - { - tablesRead = false; - Utility.Fill(oldDist, 0); // memset(oldDist,0,sizeof(OldDist)); - - oldDistPtr = 0; - lastDist = 0; - lastLength = 0; - - Utility.Fill(unpOldTable, (byte) 0); // memset(UnpOldTable,0,sizeof(UnpOldTable)); - - unpPtr = 0; - wrPtr = 0; - ppmEscChar = 2; - - initFilters(); - } - InitBitInput(); - ppmError = false; - writtenFileSize = 0; - readTop = 0; - readBorder = 0; - unpInitData20(solid); - } - - private void initFilters() - { - oldFilterLengths.Clear(); - lastFilter = 0; - - filters.Clear(); - - prgStack.Clear(); - } - - private bool readEndOfBlock() - { - int BitField = GetBits(); - bool NewTable, NewFile = false; - if ((BitField & 0x8000) != 0) - { - NewTable = true; - AddBits(1); - } - else - { - NewFile = true; - NewTable = (BitField & 0x4000) != 0 ? true : false; - AddBits(2); - } - tablesRead = !NewTable; - return !(NewFile || NewTable && !readTables()); - } - - private bool readTables() - { - byte[] bitLength = new byte[Compress.BC]; - - byte[] table = new byte[Compress.HUFF_TABLE_SIZE]; - if (inAddr > readTop - 25) - { - if (!unpReadBuf()) - { - return (false); - } - } - AddBits((8 - inBit) & 7); - long bitField = GetBits() & unchecked((int) 0xffFFffFF); - if ((bitField & 0x8000) != 0) - { - unpBlockType = BlockTypes.BLOCK_PPM; - return (ppm.decodeInit(this, ppmEscChar)); - } - unpBlockType = BlockTypes.BLOCK_LZ; - - prevLowDist = 0; - lowDistRepCount = 0; - - if ((bitField & 0x4000) == 0) - { - Utility.Fill(unpOldTable, (byte) 0); // memset(UnpOldTable,0,sizeof(UnpOldTable)); - } - AddBits(2); - - for (int i = 0; i < Compress.BC; i++) - { - int length = (Utility.URShift(GetBits(), 12)) & 0xFF; - AddBits(4); - if (length == 15) - { - int zeroCount = (Utility.URShift(GetBits(), 12)) & 0xFF; - AddBits(4); - if (zeroCount == 0) - { - bitLength[i] = 15; - } - else - { - zeroCount += 2; - while (zeroCount-- > 0 && i < bitLength.Length) - { - bitLength[i++] = 0; - } - i--; - } - } - else - { - bitLength[i] = (byte) length; - } - } - - UnpackUtility.makeDecodeTables(bitLength, 0, BD, Compress.BC); - - int TableSize = Compress.HUFF_TABLE_SIZE; - - for (int i = 0; i < TableSize;) - { - if (inAddr > readTop - 5) - { - if (!unpReadBuf()) - { - return (false); - } - } - int Number = this.decodeNumber(BD); - if (Number < 16) - { - table[i] = (byte) ((Number + unpOldTable[i]) & 0xf); - i++; - } - else if (Number < 18) - { - int N; - if (Number == 16) - { - N = (Utility.URShift(GetBits(), 13)) + 3; - AddBits(3); - } - else - { - N = (Utility.URShift(GetBits(), 9)) + 11; - AddBits(7); - } - while (N-- > 0 && i < TableSize) - { - table[i] = table[i - 1]; - i++; - } - } - else - { - int N; - if (Number == 18) - { - N = (Utility.URShift(GetBits(), 13)) + 3; - AddBits(3); - } - else - { - N = (Utility.URShift(GetBits(), 9)) + 11; - AddBits(7); - } - while (N-- > 0 && i < TableSize) - { - table[i++] = 0; - } - } - } - tablesRead = true; - if (inAddr > readTop) - { - return (false); - } - UnpackUtility.makeDecodeTables(table, 0, LD, Compress.NC); - UnpackUtility.makeDecodeTables(table, Compress.NC, DD, Compress.DC); - UnpackUtility.makeDecodeTables(table, Compress.NC + Compress.DC, LDD, Compress.LDC); - UnpackUtility.makeDecodeTables(table, Compress.NC + Compress.DC + Compress.LDC, RD, Compress.RC); - - // memcpy(unpOldTable,table,sizeof(unpOldTable)); - - Buffer.BlockCopy(table, 0, unpOldTable, 0, unpOldTable.Length); - return (true); - } - - private bool readVMCode() - { - int FirstByte = GetBits() >> 8; - AddBits(8); - int Length = (FirstByte & 7) + 1; - if (Length == 7) - { - Length = (GetBits() >> 8) + 7; - AddBits(8); - } - else if (Length == 8) - { - Length = GetBits(); - AddBits(16); - } - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - List vmCode = new List(); - for (int I = 0; I < Length; I++) - { - if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) - { - return (false); - } - vmCode.Add((byte) (GetBits() >> 8)); - AddBits(8); - } - return (addVMCode(FirstByte, vmCode, Length)); - } - - private bool readVMCodePPM() - { - int FirstByte = ppm.decodeChar(); - if ((int) FirstByte == -1) - { - return (false); - } - int Length = (FirstByte & 7) + 1; - if (Length == 7) - { - int B1 = ppm.decodeChar(); - if (B1 == -1) - { - return (false); - } - Length = B1 + 7; - } - else if (Length == 8) - { - int B1 = ppm.decodeChar(); - if (B1 == -1) - { - return (false); - } - int B2 = ppm.decodeChar(); - if (B2 == -1) - { - return (false); - } - Length = B1*256 + B2; - } - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - List vmCode = new List(); - for (int I = 0; I < Length; I++) - { - int Ch = ppm.decodeChar(); - if (Ch == -1) - { - return (false); - } - vmCode.Add((byte) Ch); // VMCode[I]=Ch; - } - return (addVMCode(FirstByte, vmCode, Length)); - } - - private bool addVMCode(int firstByte, List vmCode, int length) - { - BitInput Inp = new BitInput(); - Inp.InitBitInput(); - // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); - for (int i = 0; i < Math.Min(BitInput.MAX_SIZE, vmCode.Count); i++) - { - Inp.InBuf[i] = vmCode[i]; - } - rarVM.init(); - - int FiltPos; - if ((firstByte & 0x80) != 0) - { - FiltPos = RarVM.ReadData(Inp); - if (FiltPos == 0) - { - initFilters(); - } - else - { - FiltPos--; - } - } - else - FiltPos = lastFilter; // use the same filter as last time - - if (FiltPos > filters.Count || FiltPos > oldFilterLengths.Count) - { - return (false); - } - lastFilter = FiltPos; - bool NewFilter = (FiltPos == filters.Count); - - UnpackFilter StackFilter = new UnpackFilter(); // new filter for - // PrgStack - - UnpackFilter Filter; - if (NewFilter) - // new filter code, never used before since VM reset - { - // too many different filters, corrupt archive - if (FiltPos > 1024) - { - return (false); - } - - // Filters[Filters.Size()-1]=Filter=new UnpackFilter; - Filter = new UnpackFilter(); - filters.Add(Filter); - StackFilter.ParentFilter = filters.Count - 1; - oldFilterLengths.Add(0); - Filter.ExecCount = 0; - } - // filter was used in the past - else - { - Filter = filters[FiltPos]; - StackFilter.ParentFilter = FiltPos; - Filter.ExecCount = Filter.ExecCount + 1; // ->ExecCount++; - } - - prgStack.Add(StackFilter); - StackFilter.ExecCount = Filter.ExecCount; // ->ExecCount; - - int BlockStart = RarVM.ReadData(Inp); - if ((firstByte & 0x40) != 0) - { - BlockStart += 258; - } - StackFilter.BlockStart = ((BlockStart + unpPtr) & Compress.MAXWINMASK); - if ((firstByte & 0x20) != 0) - { - StackFilter.BlockLength = RarVM.ReadData(Inp); - } - else - { - StackFilter.BlockLength = FiltPos < oldFilterLengths.Count ? oldFilterLengths[FiltPos] : 0; - } - StackFilter.NextWindow = (wrPtr != unpPtr) && ((wrPtr - unpPtr) & Compress.MAXWINMASK) <= BlockStart; - - // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x - // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); - - oldFilterLengths[FiltPos] = StackFilter.BlockLength; - - // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); - Utility.Fill(StackFilter.Program.InitR, 0); - StackFilter.Program.InitR[3] = RarVM.VM_GLOBALMEMADDR; // StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; - StackFilter.Program.InitR[4] = StackFilter.BlockLength; - // StackFilter->Prg.InitR[4]=StackFilter->BlockLength; - StackFilter.Program.InitR[5] = StackFilter.ExecCount; // StackFilter->Prg.InitR[5]=StackFilter->ExecCount; - - if ((firstByte & 0x10) != 0) - // set registers to optional parameters - // if any - { - int InitMask = Utility.URShift(Inp.GetBits(), 9); - Inp.AddBits(7); - for (int I = 0; I < 7; I++) - { - if ((InitMask & (1 << I)) != 0) - { - // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp); - StackFilter.Program.InitR[I] = RarVM.ReadData(Inp); - } - } - } - - if (NewFilter) - { - int VMCodeSize = RarVM.ReadData(Inp); - if (VMCodeSize >= 0x10000 || VMCodeSize == 0) - { - return (false); - } - byte[] VMCode = new byte[VMCodeSize]; - for (int I = 0; I < VMCodeSize; I++) - { - if (Inp.Overflow(3)) - { - return (false); - } - VMCode[I] = (byte) (Inp.GetBits() >> 8); - Inp.AddBits(8); - } - // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); - rarVM.prepare(VMCode, VMCodeSize, Filter.Program); - } - StackFilter.Program.AltCommands = Filter.Program.Commands; // StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; - StackFilter.Program.CommandCount = Filter.Program.CommandCount; - // StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; - - int StaticDataSize = Filter.Program.StaticData.Count; - if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) - { - // read statically defined data contained in DB commands - // StackFilter->Prg.StaticData.Add(StaticDataSize); - StackFilter.Program.StaticData = Filter.Program.StaticData; - // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); - } - - if (StackFilter.Program.GlobalData.Count < RarVM.VM_FIXEDGLOBALSIZE) - { - // StackFilter->Prg.GlobalData.Reset(); - // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); - StackFilter.Program.GlobalData.Clear(); - StackFilter.Program.GlobalData.SetSize(RarVM.VM_FIXEDGLOBALSIZE); - } - - // byte *GlobalData=&StackFilter->Prg.GlobalData[0]; - - List globalData = StackFilter.Program.GlobalData; - for (int I = 0; I < 7; I++) - { - rarVM.SetLowEndianValue(globalData, I*4, StackFilter.Program.InitR[I]); - } - - // VM.SetLowEndianValue((uint - // *)&GlobalData[0x1c],StackFilter->BlockLength); - rarVM.SetLowEndianValue(globalData, 0x1c, StackFilter.BlockLength); - // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); - rarVM.SetLowEndianValue(globalData, 0x20, 0); - rarVM.SetLowEndianValue(globalData, 0x24, 0); - rarVM.SetLowEndianValue(globalData, 0x28, 0); - - // VM.SetLowEndianValue((uint - // *)&GlobalData[0x2c],StackFilter->ExecCount); - rarVM.SetLowEndianValue(globalData, 0x2c, StackFilter.ExecCount); - // memset(&GlobalData[0x30],0,16); - for (int i = 0; i < 16; i++) - { - globalData[0x30 + i] = 0x0; - } - if ((firstByte & 8) != 0) - // put data block passed as parameter if any - { - if (Inp.Overflow(3)) - { - return (false); - } - int DataSize = RarVM.ReadData(Inp); - if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) - { - return (false); - } - int CurSize = StackFilter.Program.GlobalData.Count; - if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) - { - // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); - StackFilter.Program.GlobalData.SetSize(DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize); - } - int offset = RarVM.VM_FIXEDGLOBALSIZE; - globalData = StackFilter.Program.GlobalData; - for (int I = 0; I < DataSize; I++) - { - if (Inp.Overflow(3)) - { - return (false); - } - globalData[offset + I] = (byte) (Utility.URShift(Inp.GetBits(), 8)); - Inp.AddBits(8); - } - } - return (true); - } - - - private void ExecuteCode(VMPreparedProgram Prg) - { - if (Prg.GlobalData.Count > 0) - { - // Prg->InitR[6]=int64to32(WrittenFileSize); - Prg.InitR[6] = (int) (writtenFileSize); - // rarVM.SetLowEndianValue((uint - // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); - rarVM.SetLowEndianValue(Prg.GlobalData, 0x24, (int) writtenFileSize); - // rarVM.SetLowEndianValue((uint - // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); - rarVM.SetLowEndianValue(Prg.GlobalData, 0x28, (int) (Utility.URShift(writtenFileSize, 32))); - rarVM.execute(Prg); - } - } - - public void cleanUp() - { - if (ppm != null) - { - SubAllocator allocator = ppm.SubAlloc; - if (allocator != null) - { - allocator.stopSubAllocator(); - } - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.Compressor.PPMd.H; +using SharpCompress.Compressor.Rar.decode; +using SharpCompress.Compressor.Rar.PPM; +using SharpCompress.Compressor.Rar.VM; + +namespace SharpCompress.Compressor.Rar +{ + internal sealed class Unpack : Unpack20 + { + public bool FileExtracted + { + // Duplicate method + // private boolean ReadEndOfBlock() throws IOException, RarException + // { + // int BitField = getbits(); + // boolean NewTable, NewFile = false; + // if ((BitField & 0x8000) != 0) { + // NewTable = true; + // addbits(1); + // } else { + // NewFile = true; + // NewTable = (BitField & 0x4000) != 0; + // addbits(2); + // } + // tablesRead = !NewTable; + // return !(NewFile || NewTable && !readTables()); + // } + get { return fileExtracted; } + } + + public long DestSize + { + get { return destUnpSize; } + set + { + this.destUnpSize = value; + this.fileExtracted = false; + } + } + + public bool Suspended + { + set { this.suspended = value; } + } + + public int Char + { + get + { + if (inAddr > BitInput.MAX_SIZE - 30) + { + unpReadBuf(); + } + return (InBuf[inAddr++] & 0xff); + } + } + + public int PpmEscChar + { + get { return ppmEscChar; } + + set { this.ppmEscChar = value; } + } + + //UPGRADE_NOTE: Final was removed from the declaration of 'ppm '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private ModelPPM ppm = new ModelPPM(); + + private int ppmEscChar; + + private RarVM rarVM = new RarVM(); + + /* Filters code, one entry per filter */ + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + private List filters = new List(); + + /* Filters stack, several entrances of same filter are possible */ + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + private List prgStack = new List(); + + /* + * lengths of preceding blocks, one length per filter. Used to reduce size + * required to write block length if lengths are repeating + */ + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + private List oldFilterLengths = new List(); + + private int lastFilter; + + private bool tablesRead; + + //UPGRADE_NOTE: The initialization of 'unpOldTable' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" + + private byte[] unpOldTable = new byte[Compress.HUFF_TABLE_SIZE]; + + private BlockTypes unpBlockType; + + //private bool externalWindow; + + private long writtenFileSize; + + private bool fileExtracted; + + private bool ppmError; + + private int prevLowDist; + + private int lowDistRepCount; + + public static int[] DBitLengthCounts = new int[] {4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, 0, 12}; + + private FileHeader fileHeader; + + public Unpack() + { + window = null; + //externalWindow = false; + suspended = false; + unpAllBuf = false; + unpSomeRead = false; + } + + public void init(byte[] window) + { + if (window == null) + { + this.window = new byte[Compress.MAXWINSIZE]; + } + else + { + this.window = window; + //externalWindow = true; + } + inAddr = 0; + unpInitData(false); + } + + public void doUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) + { + destUnpSize = fileHeader.UncompressedSize; + this.fileHeader = fileHeader; + base.writeStream = writeStream; + base.readStream = readStream; + bool solid = FlagUtility.HasFlag(fileHeader.FileFlags, FileFlags.SOLID); + if (!solid) + { + init(null); + } + suspended = false; + doUnpack(); + } + + public void doUnpack() + { + bool solid = FlagUtility.HasFlag(fileHeader.FileFlags, FileFlags.SOLID); + if (fileHeader.PackingMethod == 0x30) + { + unstoreFile(); + return; + } + switch (fileHeader.RarVersion) + { + case 15: // rar 1.5 compression + unpack15(solid); + break; + + case 20: + // rar 2.x compression + case 26: // files larger than 2GB + unpack20(solid); + break; + + case 29: + // rar 3.x compression + case 36: // alternative hash + unpack29(solid); + break; + } + } + + private void unstoreFile() + { + byte[] buffer = new byte[0x10000]; + while (true) + { + int code = readStream.Read(buffer, 0, (int) System.Math.Min(buffer.Length, destUnpSize)); + if (code == 0 || code == -1) + break; + code = code < destUnpSize ? code : (int) destUnpSize; + writeStream.Write(buffer, 0, code); + if (destUnpSize >= 0) + destUnpSize -= code; + if (suspended) + return; + } + } + + private void unpack29(bool solid) + { + int[] DDecode = new int[Compress.DC]; + byte[] DBits = new byte[Compress.DC]; + + int Bits; + + if (DDecode[1] == 0) + { + int Dist = 0, BitLength = 0, Slot = 0; + for (int I = 0; I < DBitLengthCounts.Length; I++, BitLength++) + { + int count = DBitLengthCounts[I]; + for (int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) + { + DDecode[Slot] = Dist; + DBits[Slot] = (byte) BitLength; + } + } + } + + fileExtracted = true; + + if (!suspended) + { + unpInitData(solid); + if (!unpReadBuf()) + { + return; + } + if ((!solid || !tablesRead) && !readTables()) + { + return; + } + } + + if (ppmError) + { + return; + } + + while (true) + { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readBorder) + { + if (!unpReadBuf()) + { + break; + } + } + // System.out.println(((wrPtr - unpPtr) & + // Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr); + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 260 && wrPtr != unpPtr) + { + UnpWriteBuf(); + if (destUnpSize <= 0) + { + return; + } + if (suspended) + { + fileExtracted = false; + return; + } + } + if (unpBlockType == BlockTypes.BLOCK_PPM) + { + int Ch = ppm.decodeChar(); + if (Ch == -1) + { + ppmError = true; + break; + } + if (Ch == ppmEscChar) + { + int NextCh = ppm.decodeChar(); + if (NextCh == 0) + { + if (!readTables()) + { + break; + } + continue; + } + if (NextCh == 2 || NextCh == -1) + { + break; + } + if (NextCh == 3) + { + if (!readVMCodePPM()) + { + break; + } + continue; + } + if (NextCh == 4) + { + int Distance = 0, Length = 0; + bool failed = false; + for (int I = 0; I < 4 && !failed; I++) + { + int ch = ppm.decodeChar(); + if (ch == -1) + { + failed = true; + } + else + { + if (I == 3) + { + // Bug fixed + Length = ch & 0xff; + } + else + { + // Bug fixed + Distance = (Distance << 8) + (ch & 0xff); + } + } + } + if (failed) + { + break; + } + copyString(Length + 32, Distance + 2); + continue; + } + if (NextCh == 5) + { + int Length = ppm.decodeChar(); + if (Length == -1) + { + break; + } + copyString(Length + 4, 1); + continue; + } + } + window[unpPtr++] = (byte) Ch; + continue; + } + + int Number = this.decodeNumber(LD); + if (Number < 256) + { + window[unpPtr++] = (byte) Number; + continue; + } + if (Number >= 271) + { + int Length = LDecode[Number -= 271] + 3; + if ((Bits = LBits[Number]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + + int DistNumber = this.decodeNumber(DD); + int Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) + { + if (DistNumber > 9) + { + if (Bits > 4) + { + Distance += ((Utility.URShift(GetBits(), (20 - Bits))) << 4); + AddBits(Bits - 4); + } + if (lowDistRepCount > 0) + { + lowDistRepCount--; + Distance += prevLowDist; + } + else + { + int LowDist = this.decodeNumber(LDD); + if (LowDist == 16) + { + lowDistRepCount = Compress.LOW_DIST_REP_COUNT - 1; + Distance += prevLowDist; + } + else + { + Distance += LowDist; + prevLowDist = LowDist; + } + } + } + else + { + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + } + + if (Distance >= 0x2000) + { + Length++; + if (Distance >= 0x40000L) + { + Length++; + } + } + + insertOldDist(Distance); + insertLastMatch(Length, Distance); + + copyString(Length, Distance); + continue; + } + if (Number == 256) + { + if (!readEndOfBlock()) + { + break; + } + continue; + } + if (Number == 257) + { + if (!readVMCode()) + { + break; + } + continue; + } + if (Number == 258) + { + if (lastLength != 0) + { + copyString(lastLength, lastDist); + } + continue; + } + if (Number < 263) + { + int DistNum = Number - 259; + int Distance = oldDist[DistNum]; + for (int I = DistNum; I > 0; I--) + { + oldDist[I] = oldDist[I - 1]; + } + oldDist[0] = Distance; + + int LengthNumber = this.decodeNumber(RD); + int Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + insertLastMatch(Length, Distance); + copyString(Length, Distance); + continue; + } + if (Number < 272) + { + int Distance = SDDecode[Number -= 263] + 1; + if ((Bits = SDBits[Number]) > 0) + { + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + insertOldDist(Distance); + insertLastMatch(2, Distance); + copyString(2, Distance); + continue; + } + } + UnpWriteBuf(); + } + + private void UnpWriteBuf() + { + int WrittenBorder = wrPtr; + int WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + for (int I = 0; I < prgStack.Count; I++) + { + UnpackFilter flt = prgStack[I]; + if (flt == null) + { + continue; + } + if (flt.NextWindow) + { + flt.NextWindow = false; // ->NextWindow=false; + continue; + } + int BlockStart = flt.BlockStart; // ->BlockStart; + int BlockLength = flt.BlockLength; // ->BlockLength; + if (((BlockStart - WrittenBorder) & Compress.MAXWINMASK) < WriteSize) + { + if (WrittenBorder != BlockStart) + { + UnpWriteArea(WrittenBorder, BlockStart); + WrittenBorder = BlockStart; + WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + } + if (BlockLength <= WriteSize) + { + int BlockEnd = (BlockStart + BlockLength) & Compress.MAXWINMASK; + if (BlockStart < BlockEnd || BlockEnd == 0) + { + // VM.SetMemory(0,Window+BlockStart,BlockLength); + rarVM.setMemory(0, window, BlockStart, BlockLength); + } + else + { + int FirstPartLength = Compress.MAXWINSIZE - BlockStart; + // VM.SetMemory(0,Window+BlockStart,FirstPartLength); + rarVM.setMemory(0, window, BlockStart, FirstPartLength); + // VM.SetMemory(FirstPartLength,Window,BlockEnd); + rarVM.setMemory(FirstPartLength, window, 0, BlockEnd); + } + + VMPreparedProgram ParentPrg = filters[flt.ParentFilter].Program; + VMPreparedProgram Prg = flt.Program; + + if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution if + // any + // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + Prg.GlobalData.Clear(); + for (int i = 0; i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = + ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + } + } + + ExecuteCode(Prg); + + if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count) + { + //ParentPrg.GlobalData.Clear(); // ->GlobalData.Alloc(Prg->GlobalData.Size()); + ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count); + } + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for (int i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = + Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + } + } + else + { + ParentPrg.GlobalData.Clear(); + } + + int FilteredDataOffset = Prg.FilteredDataOffset; + int FilteredDataSize = Prg.FilteredDataSize; + byte[] FilteredData = new byte[FilteredDataSize]; + + for (int i = 0; i < FilteredDataSize; i++) + { + FilteredData[i] = rarVM.Mem[FilteredDataOffset + i]; + // Prg.GlobalData.get(FilteredDataOffset + // + + // i); + } + + prgStack[I] = null; + while (I + 1 < prgStack.Count) + { + UnpackFilter NextFilter = prgStack[I + 1]; + if (NextFilter == null || NextFilter.BlockStart != BlockStart || + NextFilter.BlockLength != FilteredDataSize || NextFilter.NextWindow) + { + break; + } + // apply several filters to same data block + + rarVM.setMemory(0, FilteredData, 0, FilteredDataSize); + // .SetMemory(0,FilteredData,FilteredDataSize); + + VMPreparedProgram pPrg = filters[NextFilter.ParentFilter].Program; + VMPreparedProgram NextPrg = NextFilter.Program; + + if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution + // if any + // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count); + // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for (int i = 0; i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = + pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + } + } + + ExecuteCode(NextPrg); + + if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count) + { + pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count); + } + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for (int i = 0; i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + { + pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = + NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + } + } + else + { + pPrg.GlobalData.Clear(); + } + FilteredDataOffset = NextPrg.FilteredDataOffset; + FilteredDataSize = NextPrg.FilteredDataSize; + + FilteredData = new byte[FilteredDataSize]; + for (int i = 0; i < FilteredDataSize; i++) + { + FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i]; + } + + I++; + prgStack[I] = null; + } + writeStream.Write(FilteredData, 0, FilteredDataSize); + unpSomeRead = true; + writtenFileSize += FilteredDataSize; + destUnpSize -= FilteredDataSize; + WrittenBorder = BlockEnd; + WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK; + } + else + { + for (int J = I; J < prgStack.Count; J++) + { + UnpackFilter filt = prgStack[J]; + if (filt != null && filt.NextWindow) + { + filt.NextWindow = false; + } + } + wrPtr = WrittenBorder; + return; + } + } + } + + UnpWriteArea(WrittenBorder, unpPtr); + wrPtr = unpPtr; + } + + private void UnpWriteArea(int startPtr, int endPtr) + { + if (endPtr != startPtr) + { + unpSomeRead = true; + } + if (endPtr < startPtr) + { + UnpWriteData(window, startPtr, -startPtr & Compress.MAXWINMASK); + UnpWriteData(window, 0, endPtr); + unpAllBuf = true; + } + else + { + UnpWriteData(window, startPtr, endPtr - startPtr); + } + } + + private void UnpWriteData(byte[] data, int offset, int size) + { + if (destUnpSize <= 0) + { + return; + } + int writeSize = size; + if (writeSize > destUnpSize) + { + writeSize = (int) destUnpSize; + } + writeStream.Write(data, offset, writeSize); + + writtenFileSize += size; + destUnpSize -= size; + } + + private void insertOldDist(int distance) + { + oldDist[3] = oldDist[2]; + oldDist[2] = oldDist[1]; + oldDist[1] = oldDist[0]; + oldDist[0] = distance; + } + + private void insertLastMatch(int length, int distance) + { + lastDist = distance; + lastLength = length; + } + + private void copyString(int length, int distance) + { + // System.out.println("copyString(" + length + ", " + distance + ")"); + + int destPtr = unpPtr - distance; + // System.out.println(unpPtr+":"+distance); + if (destPtr >= 0 && destPtr < Compress.MAXWINSIZE - 260 && unpPtr < Compress.MAXWINSIZE - 260) + { + window[unpPtr++] = window[destPtr++]; + + while (--length > 0) + window[unpPtr++] = window[destPtr++]; + } + else + while (length-- != 0) + { + window[unpPtr] = window[destPtr++ & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + + protected internal override void unpInitData(bool solid) + { + if (!solid) + { + tablesRead = false; + Utility.Fill(oldDist, 0); // memset(oldDist,0,sizeof(OldDist)); + + oldDistPtr = 0; + lastDist = 0; + lastLength = 0; + + Utility.Fill(unpOldTable, (byte) 0); // memset(UnpOldTable,0,sizeof(UnpOldTable)); + + unpPtr = 0; + wrPtr = 0; + ppmEscChar = 2; + + initFilters(); + } + InitBitInput(); + ppmError = false; + writtenFileSize = 0; + readTop = 0; + readBorder = 0; + unpInitData20(solid); + } + + private void initFilters() + { + oldFilterLengths.Clear(); + lastFilter = 0; + + filters.Clear(); + + prgStack.Clear(); + } + + private bool readEndOfBlock() + { + int BitField = GetBits(); + bool NewTable, NewFile = false; + if ((BitField & 0x8000) != 0) + { + NewTable = true; + AddBits(1); + } + else + { + NewFile = true; + NewTable = (BitField & 0x4000) != 0 ? true : false; + AddBits(2); + } + tablesRead = !NewTable; + return !(NewFile || NewTable && !readTables()); + } + + private bool readTables() + { + byte[] bitLength = new byte[Compress.BC]; + + byte[] table = new byte[Compress.HUFF_TABLE_SIZE]; + if (inAddr > readTop - 25) + { + if (!unpReadBuf()) + { + return (false); + } + } + AddBits((8 - inBit) & 7); + long bitField = GetBits() & unchecked((int) 0xffFFffFF); + if ((bitField & 0x8000) != 0) + { + unpBlockType = BlockTypes.BLOCK_PPM; + return (ppm.decodeInit(this, ppmEscChar)); + } + unpBlockType = BlockTypes.BLOCK_LZ; + + prevLowDist = 0; + lowDistRepCount = 0; + + if ((bitField & 0x4000) == 0) + { + Utility.Fill(unpOldTable, (byte) 0); // memset(UnpOldTable,0,sizeof(UnpOldTable)); + } + AddBits(2); + + for (int i = 0; i < Compress.BC; i++) + { + int length = (Utility.URShift(GetBits(), 12)) & 0xFF; + AddBits(4); + if (length == 15) + { + int zeroCount = (Utility.URShift(GetBits(), 12)) & 0xFF; + AddBits(4); + if (zeroCount == 0) + { + bitLength[i] = 15; + } + else + { + zeroCount += 2; + while (zeroCount-- > 0 && i < bitLength.Length) + { + bitLength[i++] = 0; + } + i--; + } + } + else + { + bitLength[i] = (byte) length; + } + } + + UnpackUtility.makeDecodeTables(bitLength, 0, BD, Compress.BC); + + int TableSize = Compress.HUFF_TABLE_SIZE; + + for (int i = 0; i < TableSize;) + { + if (inAddr > readTop - 5) + { + if (!unpReadBuf()) + { + return (false); + } + } + int Number = this.decodeNumber(BD); + if (Number < 16) + { + table[i] = (byte) ((Number + unpOldTable[i]) & 0xf); + i++; + } + else if (Number < 18) + { + int N; + if (Number == 16) + { + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); + } + else + { + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && i < TableSize) + { + table[i] = table[i - 1]; + i++; + } + } + else + { + int N; + if (Number == 18) + { + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); + } + else + { + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && i < TableSize) + { + table[i++] = 0; + } + } + } + tablesRead = true; + if (inAddr > readTop) + { + return (false); + } + UnpackUtility.makeDecodeTables(table, 0, LD, Compress.NC); + UnpackUtility.makeDecodeTables(table, Compress.NC, DD, Compress.DC); + UnpackUtility.makeDecodeTables(table, Compress.NC + Compress.DC, LDD, Compress.LDC); + UnpackUtility.makeDecodeTables(table, Compress.NC + Compress.DC + Compress.LDC, RD, Compress.RC); + + // memcpy(unpOldTable,table,sizeof(unpOldTable)); + + Buffer.BlockCopy(table, 0, unpOldTable, 0, unpOldTable.Length); + return (true); + } + + private bool readVMCode() + { + int FirstByte = GetBits() >> 8; + AddBits(8); + int Length = (FirstByte & 7) + 1; + if (Length == 7) + { + Length = (GetBits() >> 8) + 7; + AddBits(8); + } + else if (Length == 8) + { + Length = GetBits(); + AddBits(16); + } + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + List vmCode = new List(); + for (int I = 0; I < Length; I++) + { + if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) + { + return (false); + } + vmCode.Add((byte) (GetBits() >> 8)); + AddBits(8); + } + return (addVMCode(FirstByte, vmCode, Length)); + } + + private bool readVMCodePPM() + { + int FirstByte = ppm.decodeChar(); + if ((int) FirstByte == -1) + { + return (false); + } + int Length = (FirstByte & 7) + 1; + if (Length == 7) + { + int B1 = ppm.decodeChar(); + if (B1 == -1) + { + return (false); + } + Length = B1 + 7; + } + else if (Length == 8) + { + int B1 = ppm.decodeChar(); + if (B1 == -1) + { + return (false); + } + int B2 = ppm.decodeChar(); + if (B2 == -1) + { + return (false); + } + Length = B1*256 + B2; + } + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + List vmCode = new List(); + for (int I = 0; I < Length; I++) + { + int Ch = ppm.decodeChar(); + if (Ch == -1) + { + return (false); + } + vmCode.Add((byte) Ch); // VMCode[I]=Ch; + } + return (addVMCode(FirstByte, vmCode, Length)); + } + + private bool addVMCode(int firstByte, List vmCode, int length) + { + BitInput Inp = new BitInput(); + Inp.InitBitInput(); + // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); + for (int i = 0; i < Math.Min(BitInput.MAX_SIZE, vmCode.Count); i++) + { + Inp.InBuf[i] = vmCode[i]; + } + rarVM.init(); + + int FiltPos; + if ((firstByte & 0x80) != 0) + { + FiltPos = RarVM.ReadData(Inp); + if (FiltPos == 0) + { + initFilters(); + } + else + { + FiltPos--; + } + } + else + FiltPos = lastFilter; // use the same filter as last time + + if (FiltPos > filters.Count || FiltPos > oldFilterLengths.Count) + { + return (false); + } + lastFilter = FiltPos; + bool NewFilter = (FiltPos == filters.Count); + + UnpackFilter StackFilter = new UnpackFilter(); // new filter for + // PrgStack + + UnpackFilter Filter; + if (NewFilter) + // new filter code, never used before since VM reset + { + // too many different filters, corrupt archive + if (FiltPos > 1024) + { + return (false); + } + + // Filters[Filters.Size()-1]=Filter=new UnpackFilter; + Filter = new UnpackFilter(); + filters.Add(Filter); + StackFilter.ParentFilter = filters.Count - 1; + oldFilterLengths.Add(0); + Filter.ExecCount = 0; + } + // filter was used in the past + else + { + Filter = filters[FiltPos]; + StackFilter.ParentFilter = FiltPos; + Filter.ExecCount = Filter.ExecCount + 1; // ->ExecCount++; + } + + prgStack.Add(StackFilter); + StackFilter.ExecCount = Filter.ExecCount; // ->ExecCount; + + int BlockStart = RarVM.ReadData(Inp); + if ((firstByte & 0x40) != 0) + { + BlockStart += 258; + } + StackFilter.BlockStart = ((BlockStart + unpPtr) & Compress.MAXWINMASK); + if ((firstByte & 0x20) != 0) + { + StackFilter.BlockLength = RarVM.ReadData(Inp); + } + else + { + StackFilter.BlockLength = FiltPos < oldFilterLengths.Count ? oldFilterLengths[FiltPos] : 0; + } + StackFilter.NextWindow = (wrPtr != unpPtr) && ((wrPtr - unpPtr) & Compress.MAXWINMASK) <= BlockStart; + + // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x + // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); + + oldFilterLengths[FiltPos] = StackFilter.BlockLength; + + // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); + Utility.Fill(StackFilter.Program.InitR, 0); + StackFilter.Program.InitR[3] = RarVM.VM_GLOBALMEMADDR; // StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; + StackFilter.Program.InitR[4] = StackFilter.BlockLength; + // StackFilter->Prg.InitR[4]=StackFilter->BlockLength; + StackFilter.Program.InitR[5] = StackFilter.ExecCount; // StackFilter->Prg.InitR[5]=StackFilter->ExecCount; + + if ((firstByte & 0x10) != 0) + // set registers to optional parameters + // if any + { + int InitMask = Utility.URShift(Inp.GetBits(), 9); + Inp.AddBits(7); + for (int I = 0; I < 7; I++) + { + if ((InitMask & (1 << I)) != 0) + { + // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp); + StackFilter.Program.InitR[I] = RarVM.ReadData(Inp); + } + } + } + + if (NewFilter) + { + int VMCodeSize = RarVM.ReadData(Inp); + if (VMCodeSize >= 0x10000 || VMCodeSize == 0) + { + return (false); + } + byte[] VMCode = new byte[VMCodeSize]; + for (int I = 0; I < VMCodeSize; I++) + { + if (Inp.Overflow(3)) + { + return (false); + } + VMCode[I] = (byte) (Inp.GetBits() >> 8); + Inp.AddBits(8); + } + // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); + rarVM.prepare(VMCode, VMCodeSize, Filter.Program); + } + StackFilter.Program.AltCommands = Filter.Program.Commands; // StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; + StackFilter.Program.CommandCount = Filter.Program.CommandCount; + // StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; + + int StaticDataSize = Filter.Program.StaticData.Count; + if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) + { + // read statically defined data contained in DB commands + // StackFilter->Prg.StaticData.Add(StaticDataSize); + StackFilter.Program.StaticData = Filter.Program.StaticData; + // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); + } + + if (StackFilter.Program.GlobalData.Count < RarVM.VM_FIXEDGLOBALSIZE) + { + // StackFilter->Prg.GlobalData.Reset(); + // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); + StackFilter.Program.GlobalData.Clear(); + StackFilter.Program.GlobalData.SetSize(RarVM.VM_FIXEDGLOBALSIZE); + } + + // byte *GlobalData=&StackFilter->Prg.GlobalData[0]; + + List globalData = StackFilter.Program.GlobalData; + for (int I = 0; I < 7; I++) + { + rarVM.SetLowEndianValue(globalData, I*4, StackFilter.Program.InitR[I]); + } + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x1c],StackFilter->BlockLength); + rarVM.SetLowEndianValue(globalData, 0x1c, StackFilter.BlockLength); + // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); + rarVM.SetLowEndianValue(globalData, 0x20, 0); + rarVM.SetLowEndianValue(globalData, 0x24, 0); + rarVM.SetLowEndianValue(globalData, 0x28, 0); + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x2c],StackFilter->ExecCount); + rarVM.SetLowEndianValue(globalData, 0x2c, StackFilter.ExecCount); + // memset(&GlobalData[0x30],0,16); + for (int i = 0; i < 16; i++) + { + globalData[0x30 + i] = 0x0; + } + if ((firstByte & 8) != 0) + // put data block passed as parameter if any + { + if (Inp.Overflow(3)) + { + return (false); + } + int DataSize = RarVM.ReadData(Inp); + if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) + { + return (false); + } + int CurSize = StackFilter.Program.GlobalData.Count; + if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) + { + // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); + StackFilter.Program.GlobalData.SetSize(DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize); + } + int offset = RarVM.VM_FIXEDGLOBALSIZE; + globalData = StackFilter.Program.GlobalData; + for (int I = 0; I < DataSize; I++) + { + if (Inp.Overflow(3)) + { + return (false); + } + globalData[offset + I] = (byte) (Utility.URShift(Inp.GetBits(), 8)); + Inp.AddBits(8); + } + } + return (true); + } + + + private void ExecuteCode(VMPreparedProgram Prg) + { + if (Prg.GlobalData.Count > 0) + { + // Prg->InitR[6]=int64to32(WrittenFileSize); + Prg.InitR[6] = (int) (writtenFileSize); + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); + rarVM.SetLowEndianValue(Prg.GlobalData, 0x24, (int) writtenFileSize); + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); + rarVM.SetLowEndianValue(Prg.GlobalData, 0x28, (int) (Utility.URShift(writtenFileSize, 32))); + rarVM.execute(Prg); + } + } + + public void cleanUp() + { + if (ppm != null) + { + SubAllocator allocator = ppm.SubAlloc; + if (allocator != null) + { + allocator.stopSubAllocator(); + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Unpack15.cs b/src/SharpCompress/Compressor/Rar/Unpack15.cs similarity index 96% rename from SharpCompress/Compressor/Rar/Unpack15.cs rename to src/SharpCompress/Compressor/Rar/Unpack15.cs index 1c52980e..e25e4ed3 100644 --- a/SharpCompress/Compressor/Rar/Unpack15.cs +++ b/src/SharpCompress/Compressor/Rar/Unpack15.cs @@ -1,738 +1,738 @@ -/* -* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. -* Original author: Edmund Wagner -* Creation date: 21.06.2007 -* -* Source: $HeadURL$ -* Last changed: $LastChangedDate$ -* -* the unrar licence applies to all junrar source and binary distributions -* you are not allowed to use this source to re-create the RAR compression algorithm -* -* Here some html entities which can be used for escaping javadoc tags: -* "&": "&" or "&" -* "<": "<" or "<" -* ">": ">" or ">" -* "@": "@" -*/ - -using System; -using System.IO; -using SharpCompress.Compressor.Rar.decode; -using SharpCompress.Compressor.Rar.VM; - -namespace SharpCompress.Compressor.Rar -{ - /// DOCUMENT ME - /// - /// - /// $LastChangedBy$ - /// - /// $LastChangedRevision$ - /// - internal abstract class Unpack15 : BitInput - { - protected internal int readBorder; - - protected internal bool suspended; - - protected internal bool unpAllBuf; - - //protected internal ComprDataIO unpIO; - - protected Stream readStream; - protected Stream writeStream; - - protected internal bool unpSomeRead; - - protected internal int readTop; - - protected internal long destUnpSize; - - protected internal byte[] window; - - protected internal int[] oldDist = new int[4]; - - protected internal int unpPtr, wrPtr; - - protected internal int oldDistPtr; - - protected internal int[] ChSet = new int[256], - ChSetA = new int[256], - ChSetB = new int[256], - ChSetC = new int[256]; - - protected internal int[] Place = new int[256], - PlaceA = new int[256], - PlaceB = new int[256], - PlaceC = new int[256]; - - protected internal int[] NToPl = new int[256], NToPlB = new int[256], NToPlC = new int[256]; - - protected internal int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; - - protected internal int Buf60, NumHuf, StMode, LCount, FlagsCnt; - - protected internal int Nhfb, Nlzb, MaxDist3; - - protected internal int lastDist, lastLength; - - private const int STARTL1 = 2; - - private static int[] DecL1 = new int[] - { - 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf200 - , 0xffff - }; - - private static int[] PosL1 = new int[] {0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32}; - - private const int STARTL2 = 3; - - private static int[] DecL2 = new int[] - { - 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf240, 0xffff - }; - - private static int[] PosL2 = new int[] {0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36}; - - private const int STARTHF0 = 4; - - private static int[] DecHf0 = new int[] {0x8000, 0xc000, 0xe000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xffff}; - - private static int[] PosHf0 = new int[] {0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33}; - - private const int STARTHF1 = 5; - - private static int[] DecHf1 = new int[] {0x2000, 0xc000, 0xe000, 0xf000, 0xf200, 0xf200, 0xf7e0, 0xffff}; - - private static int[] PosHf1 = new int[] {0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127}; - - private const int STARTHF2 = 5; - - private static int[] DecHf2 = new int[] {0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, 0xffff, 0xffff, 0xffff}; - - private static int[] PosHf2 = new int[] {0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0}; - - private const int STARTHF3 = 6; - - private static int[] DecHf3 = new int[] {0x800, 0x2400, 0xee00, 0xfe80, 0xffff, 0xffff, 0xffff}; - - private static int[] PosHf3 = new int[] {0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0}; - - private const int STARTHF4 = 8; - - private static int[] DecHf4 = new int[] {0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; - - private static int[] PosHf4 = new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0}; - - internal static int[] ShortLen1 = new int[] {1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0}; - - internal static int[] ShortXor1 = new int[] - { - 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xc0, 0x80, 0x90, 0x98 - , 0x9c, 0xb0 - }; - - internal static int[] ShortLen2 = new int[] {2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0}; - - internal static int[] ShortXor2 = new int[] - { - 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xc0, 0x80, 0x90, 0x98 - , 0x9c, 0xb0 - }; - - protected internal abstract void unpInitData(bool solid); - - protected void unpack15(bool solid) - { - if (suspended) - { - unpPtr = wrPtr; - } - else - { - unpInitData(solid); - oldUnpInitData(solid); - unpReadBuf(); - if (!solid) - { - initHuff(); - unpPtr = 0; - } - else - { - unpPtr = wrPtr; - } - --destUnpSize; - } - if (destUnpSize >= 0) - { - getFlagsBuf(); - FlagsCnt = 8; - } - - while (destUnpSize >= 0) - { - unpPtr &= Compress.MAXWINMASK; - - if (inAddr > readTop - 30 && !unpReadBuf()) - { - break; - } - if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr) - { - oldUnpWriteBuf(); - if (suspended) - { - return; - } - } - if (StMode != 0) - { - huffDecode(); - continue; - } - - if (--FlagsCnt < 0) - { - getFlagsBuf(); - FlagsCnt = 7; - } - - if ((FlagBuf & 0x80) != 0) - { - FlagBuf <<= 1; - if (Nlzb > Nhfb) - { - longLZ(); - } - else - { - huffDecode(); - } - } - else - { - FlagBuf <<= 1; - if (--FlagsCnt < 0) - { - getFlagsBuf(); - FlagsCnt = 7; - } - if ((FlagBuf & 0x80) != 0) - { - FlagBuf <<= 1; - if (Nlzb > Nhfb) - { - huffDecode(); - } - else - { - longLZ(); - } - } - else - { - FlagBuf <<= 1; - shortLZ(); - } - } - } - oldUnpWriteBuf(); - } - - - protected bool unpReadBuf() - { - int dataSize = readTop - inAddr; - if (dataSize < 0) - { - return (false); - } - if (inAddr > BitInput.MAX_SIZE/2) - { - if (dataSize > 0) - { - //memmove(InBuf,InBuf+InAddr,DataSize); - // for (int i = 0; i < dataSize; i++) { - // inBuf[i] = inBuf[inAddr + i]; - // } - Array.Copy(InBuf, inAddr, InBuf, 0, dataSize); - } - inAddr = 0; - readTop = dataSize; - } - else - { - dataSize = readTop; - } - //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); - int readCode = readStream.Read(InBuf, dataSize, (BitInput.MAX_SIZE - dataSize) & ~0xf); - if (readCode > 0) - { - readTop += readCode; - } - readBorder = readTop - 30; - return (readCode != -1); - } - - private int getShortLen1(int pos) - { - return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; - } - - private int getShortLen2(int pos) - { - return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; - } - - private void shortLZ() - { - int Length, SaveLength; - int LastDistance; - int Distance; - int DistancePlace; - NumHuf = 0; - - int BitField = GetBits(); - if (LCount == 2) - { - AddBits(1); - if (BitField >= 0x8000) - { - oldCopyString(lastDist, lastLength); - return; - } - BitField <<= 1; - LCount = 0; - } - BitField = Utility.URShift(BitField, 8); - if (AvrLn1 < 37) - { - for (Length = 0;; Length++) - { - if (((BitField ^ ShortXor1[Length]) & (~(Utility.URShift(0xff, getShortLen1(Length))))) == 0) - { - break; - } - } - AddBits(getShortLen1(Length)); - } - else - { - for (Length = 0;; Length++) - { - if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) - { - break; - } - } - AddBits(getShortLen2(Length)); - } - - if (Length >= 9) - { - if (Length == 9) - { - LCount++; - oldCopyString(lastDist, lastLength); - return; - } - if (Length == 14) - { - LCount = 0; - Length = decodeNum(GetBits(), STARTL2, DecL2, PosL2) + 5; - Distance = (GetBits() >> 1) | 0x8000; - AddBits(15); - lastLength = Length; - lastDist = Distance; - oldCopyString(Distance, Length); - return; - } - - LCount = 0; - SaveLength = Length; - Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; - Length = decodeNum(GetBits(), STARTL1, DecL1, PosL1) + 2; - if (Length == 0x101 && SaveLength == 10) - { - Buf60 ^= 1; - return; - } - if (Distance > 256) - Length++; - if (Distance >= MaxDist3) - Length++; - - oldDist[oldDistPtr++] = Distance; - oldDistPtr = oldDistPtr & 3; - lastLength = Length; - lastDist = Distance; - oldCopyString(Distance, Length); - return; - } - - LCount = 0; - AvrLn1 += Length; - AvrLn1 -= (AvrLn1 >> 4); - - DistancePlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2) & 0xff; - Distance = ChSetA[DistancePlace]; - if (--DistancePlace != -1) - { - PlaceA[Distance]--; - LastDistance = ChSetA[DistancePlace]; - PlaceA[LastDistance]++; - ChSetA[DistancePlace + 1] = LastDistance; - ChSetA[DistancePlace] = Distance; - } - Length += 2; - oldDist[oldDistPtr++] = ++Distance; - oldDistPtr = oldDistPtr & 3; - lastLength = Length; - lastDist = Distance; - oldCopyString(Distance, Length); - } - - private void longLZ() - { - int Length; - int Distance; - int DistancePlace, NewDistancePlace; - int OldAvr2, OldAvr3; - - NumHuf = 0; - Nlzb += 16; - if (Nlzb > 0xff) - { - Nlzb = 0x90; - Nhfb = Utility.URShift(Nhfb, 1); - } - OldAvr2 = AvrLn2; - - int BitField = GetBits(); - if (AvrLn2 >= 122) - { - Length = decodeNum(BitField, STARTL2, DecL2, PosL2); - } - else - { - if (AvrLn2 >= 64) - { - Length = decodeNum(BitField, STARTL1, DecL1, PosL1); - } - else - { - if (BitField < 0x100) - { - Length = BitField; - AddBits(16); - } - else - { - for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) - { - ; - } - AddBits(Length + 1); - } - } - } - AvrLn2 += Length; - AvrLn2 -= Utility.URShift(AvrLn2, 5); - - BitField = GetBits(); - if (AvrPlcB > 0x28ff) - { - DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); - } - else - { - if (AvrPlcB > 0x6ff) - { - DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); - } - else - { - DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); - } - } - AvrPlcB += DistancePlace; - AvrPlcB -= (AvrPlcB >> 8); - while (true) - { - Distance = ChSetB[DistancePlace & 0xff]; - NewDistancePlace = NToPlB[Distance++ & 0xff]++; - if ((Distance & 0xff) == 0) - { - corrHuff(ChSetB, NToPlB); - } - else - { - break; - } - } - - ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; - ChSetB[NewDistancePlace] = Distance; - - Distance = Utility.URShift(((Distance & 0xff00) | (Utility.URShift(GetBits(), 8))), 1); - AddBits(7); - - OldAvr3 = AvrLn3; - if (Length != 1 && Length != 4) - { - if (Length == 0 && Distance <= MaxDist3) - { - AvrLn3++; - AvrLn3 -= (AvrLn3 >> 8); - } - else - { - if (AvrLn3 > 0) - { - AvrLn3--; - } - } - } - Length += 3; - if (Distance >= MaxDist3) - { - Length++; - } - if (Distance <= 256) - { - Length += 8; - } - if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) - { - MaxDist3 = 0x7f00; - } - else - { - MaxDist3 = 0x2001; - } - oldDist[oldDistPtr++] = Distance; - oldDistPtr = oldDistPtr & 3; - lastLength = Length; - lastDist = Distance; - oldCopyString(Distance, Length); - } - - private void huffDecode() - { - int CurByte, NewBytePlace; - int Length; - int Distance; - int BytePlace; - - int BitField = GetBits(); - - if (AvrPlc > 0x75ff) - { - BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); - } - else - { - if (AvrPlc > 0x5dff) - { - BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); - } - else - { - if (AvrPlc > 0x35ff) - { - BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); - } - else - { - if (AvrPlc > 0x0dff) - { - BytePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); - } - else - { - BytePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); - } - } - } - } - BytePlace &= 0xff; - if (StMode != 0) - { - if (BytePlace == 0 && BitField > 0xfff) - { - BytePlace = 0x100; - } - if (--BytePlace == -1) - { - BitField = GetBits(); - AddBits(1); - if ((BitField & 0x8000) != 0) - { - NumHuf = StMode = 0; - return; - } - else - { - Length = (BitField & 0x4000) != 0 ? 4 : 3; - AddBits(1); - Distance = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); - Distance = (Distance << 5) | (Utility.URShift(GetBits(), 11)); - AddBits(5); - oldCopyString(Distance, Length); - return; - } - } - } - else - { - if (NumHuf++ >= 16 && FlagsCnt == 0) - { - StMode = 1; - } - } - AvrPlc += BytePlace; - AvrPlc -= Utility.URShift(AvrPlc, 8); - Nhfb += 16; - if (Nhfb > 0xff) - { - Nhfb = 0x90; - Nlzb = Utility.URShift(Nlzb, 1); - } - - window[unpPtr++] = (byte) (Utility.URShift(ChSet[BytePlace], 8)); - --destUnpSize; - - while (true) - { - CurByte = ChSet[BytePlace]; - NewBytePlace = NToPl[CurByte++ & 0xff]++; - if ((CurByte & 0xff) > 0xa1) - { - corrHuff(ChSet, NToPl); - } - else - { - break; - } - } - - ChSet[BytePlace] = ChSet[NewBytePlace]; - ChSet[NewBytePlace] = CurByte; - } - - private void getFlagsBuf() - { - int Flags, NewFlagsPlace; - int FlagsPlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); - - while (true) - { - Flags = ChSetC[FlagsPlace]; - FlagBuf = Utility.URShift(Flags, 8); - NewFlagsPlace = NToPlC[Flags++ & 0xff]++; - if ((Flags & 0xff) != 0) - { - break; - } - corrHuff(ChSetC, NToPlC); - } - - ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; - ChSetC[NewFlagsPlace] = Flags; - } - - private void oldUnpInitData(bool Solid) - { - if (!Solid) - { - AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; - AvrPlc = 0x3500; - MaxDist3 = 0x2001; - Nhfb = Nlzb = 0x80; - } - FlagsCnt = 0; - FlagBuf = 0; - StMode = 0; - LCount = 0; - readTop = 0; - } - - private void initHuff() - { - for (int I = 0; I < 256; I++) - { - Place[I] = PlaceA[I] = PlaceB[I] = I; - PlaceC[I] = (~I + 1) & 0xff; - ChSet[I] = ChSetB[I] = I << 8; - ChSetA[I] = I; - ChSetC[I] = ((~I + 1) & 0xff) << 8; - } - - Utility.Fill(NToPl, 0); // memset(NToPl,0,sizeof(NToPl)); - Utility.Fill(NToPlB, 0); // memset(NToPlB,0,sizeof(NToPlB)); - Utility.Fill(NToPlC, 0); // memset(NToPlC,0,sizeof(NToPlC)); - corrHuff(ChSetB, NToPlB); - } - - private void corrHuff(int[] CharSet, int[] NumToPlace) - { - int I, J, pos = 0; - for (I = 7; I >= 0; I--) - { - for (J = 0; J < 32; J++, pos++) - { - CharSet[pos] = ((CharSet[pos] & ~0xff) | I); // *CharSet=(*CharSet - // & ~0xff) | I; - } - } - Utility.Fill(NumToPlace, 0); // memset(NumToPlace,0,sizeof(NToPl)); - for (I = 6; I >= 0; I--) - { - NumToPlace[I] = (7 - I)*32; - } - } - - private void oldCopyString(int Distance, int Length) - { - destUnpSize -= Length; - while ((Length--) != 0) - { - window[unpPtr] = window[(unpPtr - Distance) & Compress.MAXWINMASK]; - unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; - } - } - - private int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) - { - int I; - for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) - { - StartPos++; - } - AddBits(StartPos); - return ((Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) + PosTab[StartPos]); - } - - protected void oldUnpWriteBuf() - { - if (unpPtr != wrPtr) - { - unpSomeRead = true; - } - if (unpPtr < wrPtr) - { - writeStream.Write(window, wrPtr, -wrPtr & Compress.MAXWINMASK); - writeStream.Write(window, 0, unpPtr); - unpAllBuf = true; - } - else - { - writeStream.Write(window, wrPtr, unpPtr - wrPtr); - } - wrPtr = unpPtr; - } - } +/* +* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. +* Original author: Edmund Wagner +* Creation date: 21.06.2007 +* +* Source: $HeadURL$ +* Last changed: $LastChangedDate$ +* +* the unrar licence applies to all junrar source and binary distributions +* you are not allowed to use this source to re-create the RAR compression algorithm +* +* Here some html entities which can be used for escaping javadoc tags: +* "&": "&" or "&" +* "<": "<" or "<" +* ">": ">" or ">" +* "@": "@" +*/ + +using System; +using System.IO; +using SharpCompress.Compressor.Rar.decode; +using SharpCompress.Compressor.Rar.VM; + +namespace SharpCompress.Compressor.Rar +{ + /// DOCUMENT ME + /// + /// + /// $LastChangedBy$ + /// + /// $LastChangedRevision$ + /// + internal abstract class Unpack15 : BitInput + { + protected internal int readBorder; + + protected internal bool suspended; + + protected internal bool unpAllBuf; + + //protected internal ComprDataIO unpIO; + + protected Stream readStream; + protected Stream writeStream; + + protected internal bool unpSomeRead; + + protected internal int readTop; + + protected internal long destUnpSize; + + protected internal byte[] window; + + protected internal int[] oldDist = new int[4]; + + protected internal int unpPtr, wrPtr; + + protected internal int oldDistPtr; + + protected internal int[] ChSet = new int[256], + ChSetA = new int[256], + ChSetB = new int[256], + ChSetC = new int[256]; + + protected internal int[] Place = new int[256], + PlaceA = new int[256], + PlaceB = new int[256], + PlaceC = new int[256]; + + protected internal int[] NToPl = new int[256], NToPlB = new int[256], NToPlC = new int[256]; + + protected internal int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + + protected internal int Buf60, NumHuf, StMode, LCount, FlagsCnt; + + protected internal int Nhfb, Nlzb, MaxDist3; + + protected internal int lastDist, lastLength; + + private const int STARTL1 = 2; + + private static int[] DecL1 = new int[] + { + 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf200 + , 0xffff + }; + + private static int[] PosL1 = new int[] {0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32}; + + private const int STARTL2 = 3; + + private static int[] DecL2 = new int[] + { + 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf240, 0xffff + }; + + private static int[] PosL2 = new int[] {0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36}; + + private const int STARTHF0 = 4; + + private static int[] DecHf0 = new int[] {0x8000, 0xc000, 0xe000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xffff}; + + private static int[] PosHf0 = new int[] {0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33}; + + private const int STARTHF1 = 5; + + private static int[] DecHf1 = new int[] {0x2000, 0xc000, 0xe000, 0xf000, 0xf200, 0xf200, 0xf7e0, 0xffff}; + + private static int[] PosHf1 = new int[] {0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127}; + + private const int STARTHF2 = 5; + + private static int[] DecHf2 = new int[] {0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, 0xffff, 0xffff, 0xffff}; + + private static int[] PosHf2 = new int[] {0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0}; + + private const int STARTHF3 = 6; + + private static int[] DecHf3 = new int[] {0x800, 0x2400, 0xee00, 0xfe80, 0xffff, 0xffff, 0xffff}; + + private static int[] PosHf3 = new int[] {0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0}; + + private const int STARTHF4 = 8; + + private static int[] DecHf4 = new int[] {0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; + + private static int[] PosHf4 = new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0}; + + internal static int[] ShortLen1 = new int[] {1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0}; + + internal static int[] ShortXor1 = new int[] + { + 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xc0, 0x80, 0x90, 0x98 + , 0x9c, 0xb0 + }; + + internal static int[] ShortLen2 = new int[] {2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0}; + + internal static int[] ShortXor2 = new int[] + { + 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xc0, 0x80, 0x90, 0x98 + , 0x9c, 0xb0 + }; + + protected internal abstract void unpInitData(bool solid); + + protected void unpack15(bool solid) + { + if (suspended) + { + unpPtr = wrPtr; + } + else + { + unpInitData(solid); + oldUnpInitData(solid); + unpReadBuf(); + if (!solid) + { + initHuff(); + unpPtr = 0; + } + else + { + unpPtr = wrPtr; + } + --destUnpSize; + } + if (destUnpSize >= 0) + { + getFlagsBuf(); + FlagsCnt = 8; + } + + while (destUnpSize >= 0) + { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readTop - 30 && !unpReadBuf()) + { + break; + } + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr) + { + oldUnpWriteBuf(); + if (suspended) + { + return; + } + } + if (StMode != 0) + { + huffDecode(); + continue; + } + + if (--FlagsCnt < 0) + { + getFlagsBuf(); + FlagsCnt = 7; + } + + if ((FlagBuf & 0x80) != 0) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + longLZ(); + } + else + { + huffDecode(); + } + } + else + { + FlagBuf <<= 1; + if (--FlagsCnt < 0) + { + getFlagsBuf(); + FlagsCnt = 7; + } + if ((FlagBuf & 0x80) != 0) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + huffDecode(); + } + else + { + longLZ(); + } + } + else + { + FlagBuf <<= 1; + shortLZ(); + } + } + } + oldUnpWriteBuf(); + } + + + protected bool unpReadBuf() + { + int dataSize = readTop - inAddr; + if (dataSize < 0) + { + return (false); + } + if (inAddr > BitInput.MAX_SIZE/2) + { + if (dataSize > 0) + { + //memmove(InBuf,InBuf+InAddr,DataSize); + // for (int i = 0; i < dataSize; i++) { + // inBuf[i] = inBuf[inAddr + i]; + // } + Array.Copy(InBuf, inAddr, InBuf, 0, dataSize); + } + inAddr = 0; + readTop = dataSize; + } + else + { + dataSize = readTop; + } + //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); + int readCode = readStream.Read(InBuf, dataSize, (BitInput.MAX_SIZE - dataSize) & ~0xf); + if (readCode > 0) + { + readTop += readCode; + } + readBorder = readTop - 30; + return (readCode != -1); + } + + private int getShortLen1(int pos) + { + return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; + } + + private int getShortLen2(int pos) + { + return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; + } + + private void shortLZ() + { + int Length, SaveLength; + int LastDistance; + int Distance; + int DistancePlace; + NumHuf = 0; + + int BitField = GetBits(); + if (LCount == 2) + { + AddBits(1); + if (BitField >= 0x8000) + { + oldCopyString(lastDist, lastLength); + return; + } + BitField <<= 1; + LCount = 0; + } + BitField = Utility.URShift(BitField, 8); + if (AvrLn1 < 37) + { + for (Length = 0;; Length++) + { + if (((BitField ^ ShortXor1[Length]) & (~(Utility.URShift(0xff, getShortLen1(Length))))) == 0) + { + break; + } + } + AddBits(getShortLen1(Length)); + } + else + { + for (Length = 0;; Length++) + { + if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) + { + break; + } + } + AddBits(getShortLen2(Length)); + } + + if (Length >= 9) + { + if (Length == 9) + { + LCount++; + oldCopyString(lastDist, lastLength); + return; + } + if (Length == 14) + { + LCount = 0; + Length = decodeNum(GetBits(), STARTL2, DecL2, PosL2) + 5; + Distance = (GetBits() >> 1) | 0x8000; + AddBits(15); + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + return; + } + + LCount = 0; + SaveLength = Length; + Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; + Length = decodeNum(GetBits(), STARTL1, DecL1, PosL1) + 2; + if (Length == 0x101 && SaveLength == 10) + { + Buf60 ^= 1; + return; + } + if (Distance > 256) + Length++; + if (Distance >= MaxDist3) + Length++; + + oldDist[oldDistPtr++] = Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + return; + } + + LCount = 0; + AvrLn1 += Length; + AvrLn1 -= (AvrLn1 >> 4); + + DistancePlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2) & 0xff; + Distance = ChSetA[DistancePlace]; + if (--DistancePlace != -1) + { + PlaceA[Distance]--; + LastDistance = ChSetA[DistancePlace]; + PlaceA[LastDistance]++; + ChSetA[DistancePlace + 1] = LastDistance; + ChSetA[DistancePlace] = Distance; + } + Length += 2; + oldDist[oldDistPtr++] = ++Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + private void longLZ() + { + int Length; + int Distance; + int DistancePlace, NewDistancePlace; + int OldAvr2, OldAvr3; + + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb = Utility.URShift(Nhfb, 1); + } + OldAvr2 = AvrLn2; + + int BitField = GetBits(); + if (AvrLn2 >= 122) + { + Length = decodeNum(BitField, STARTL2, DecL2, PosL2); + } + else + { + if (AvrLn2 >= 64) + { + Length = decodeNum(BitField, STARTL1, DecL1, PosL1); + } + else + { + if (BitField < 0x100) + { + Length = BitField; + AddBits(16); + } + else + { + for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) + { + ; + } + AddBits(Length + 1); + } + } + } + AvrLn2 += Length; + AvrLn2 -= Utility.URShift(AvrLn2, 5); + + BitField = GetBits(); + if (AvrPlcB > 0x28ff) + { + DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else + { + if (AvrPlcB > 0x6ff) + { + DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } + else + { + DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + } + AvrPlcB += DistancePlace; + AvrPlcB -= (AvrPlcB >> 8); + while (true) + { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if ((Distance & 0xff) == 0) + { + corrHuff(ChSetB, NToPlB); + } + else + { + break; + } + } + + ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace] = Distance; + + Distance = Utility.URShift(((Distance & 0xff00) | (Utility.URShift(GetBits(), 8))), 1); + AddBits(7); + + OldAvr3 = AvrLn3; + if (Length != 1 && Length != 4) + { + if (Length == 0 && Distance <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= (AvrLn3 >> 8); + } + else + { + if (AvrLn3 > 0) + { + AvrLn3--; + } + } + } + Length += 3; + if (Distance >= MaxDist3) + { + Length++; + } + if (Distance <= 256) + { + Length += 8; + } + if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) + { + MaxDist3 = 0x7f00; + } + else + { + MaxDist3 = 0x2001; + } + oldDist[oldDistPtr++] = Distance; + oldDistPtr = oldDistPtr & 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + private void huffDecode() + { + int CurByte, NewBytePlace; + int Length; + int Distance; + int BytePlace; + + int BitField = GetBits(); + + if (AvrPlc > 0x75ff) + { + BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); + } + else + { + if (AvrPlc > 0x5dff) + { + BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); + } + else + { + if (AvrPlc > 0x35ff) + { + BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else + { + if (AvrPlc > 0x0dff) + { + BytePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } + else + { + BytePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + } + } + } + BytePlace &= 0xff; + if (StMode != 0) + { + if (BytePlace == 0 && BitField > 0xfff) + { + BytePlace = 0x100; + } + if (--BytePlace == -1) + { + BitField = GetBits(); + AddBits(1); + if ((BitField & 0x8000) != 0) + { + NumHuf = StMode = 0; + return; + } + else + { + Length = (BitField & 0x4000) != 0 ? 4 : 3; + AddBits(1); + Distance = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); + Distance = (Distance << 5) | (Utility.URShift(GetBits(), 11)); + AddBits(5); + oldCopyString(Distance, Length); + return; + } + } + } + else + { + if (NumHuf++ >= 16 && FlagsCnt == 0) + { + StMode = 1; + } + } + AvrPlc += BytePlace; + AvrPlc -= Utility.URShift(AvrPlc, 8); + Nhfb += 16; + if (Nhfb > 0xff) + { + Nhfb = 0x90; + Nlzb = Utility.URShift(Nlzb, 1); + } + + window[unpPtr++] = (byte) (Utility.URShift(ChSet[BytePlace], 8)); + --destUnpSize; + + while (true) + { + CurByte = ChSet[BytePlace]; + NewBytePlace = NToPl[CurByte++ & 0xff]++; + if ((CurByte & 0xff) > 0xa1) + { + corrHuff(ChSet, NToPl); + } + else + { + break; + } + } + + ChSet[BytePlace] = ChSet[NewBytePlace]; + ChSet[NewBytePlace] = CurByte; + } + + private void getFlagsBuf() + { + int Flags, NewFlagsPlace; + int FlagsPlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); + + while (true) + { + Flags = ChSetC[FlagsPlace]; + FlagBuf = Utility.URShift(Flags, 8); + NewFlagsPlace = NToPlC[Flags++ & 0xff]++; + if ((Flags & 0xff) != 0) + { + break; + } + corrHuff(ChSetC, NToPlC); + } + + ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; + ChSetC[NewFlagsPlace] = Flags; + } + + private void oldUnpInitData(bool Solid) + { + if (!Solid) + { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + } + FlagsCnt = 0; + FlagBuf = 0; + StMode = 0; + LCount = 0; + readTop = 0; + } + + private void initHuff() + { + for (int I = 0; I < 256; I++) + { + Place[I] = PlaceA[I] = PlaceB[I] = I; + PlaceC[I] = (~I + 1) & 0xff; + ChSet[I] = ChSetB[I] = I << 8; + ChSetA[I] = I; + ChSetC[I] = ((~I + 1) & 0xff) << 8; + } + + Utility.Fill(NToPl, 0); // memset(NToPl,0,sizeof(NToPl)); + Utility.Fill(NToPlB, 0); // memset(NToPlB,0,sizeof(NToPlB)); + Utility.Fill(NToPlC, 0); // memset(NToPlC,0,sizeof(NToPlC)); + corrHuff(ChSetB, NToPlB); + } + + private void corrHuff(int[] CharSet, int[] NumToPlace) + { + int I, J, pos = 0; + for (I = 7; I >= 0; I--) + { + for (J = 0; J < 32; J++, pos++) + { + CharSet[pos] = ((CharSet[pos] & ~0xff) | I); // *CharSet=(*CharSet + // & ~0xff) | I; + } + } + Utility.Fill(NumToPlace, 0); // memset(NumToPlace,0,sizeof(NToPl)); + for (I = 6; I >= 0; I--) + { + NumToPlace[I] = (7 - I)*32; + } + } + + private void oldCopyString(int Distance, int Length) + { + destUnpSize -= Length; + while ((Length--) != 0) + { + window[unpPtr] = window[(unpPtr - Distance) & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + + private int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) + { + int I; + for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) + { + StartPos++; + } + AddBits(StartPos); + return ((Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) + PosTab[StartPos]); + } + + protected void oldUnpWriteBuf() + { + if (unpPtr != wrPtr) + { + unpSomeRead = true; + } + if (unpPtr < wrPtr) + { + writeStream.Write(window, wrPtr, -wrPtr & Compress.MAXWINMASK); + writeStream.Write(window, 0, unpPtr); + unpAllBuf = true; + } + else + { + writeStream.Write(window, wrPtr, unpPtr - wrPtr); + } + wrPtr = unpPtr; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/Unpack20.cs b/src/SharpCompress/Compressor/Rar/Unpack20.cs similarity index 97% rename from SharpCompress/Compressor/Rar/Unpack20.cs rename to src/SharpCompress/Compressor/Rar/Unpack20.cs index fcd0ccca..b264ceaa 100644 --- a/SharpCompress/Compressor/Rar/Unpack20.cs +++ b/src/SharpCompress/Compressor/Rar/Unpack20.cs @@ -1,532 +1,532 @@ -/* -* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. -* Original author: Edmund Wagner -* Creation date: 21.06.2007 -* -* Source: $HeadURL$ -* Last changed: $LastChangedDate$ -* -* the unrar licence applies to all junrar source and binary distributions -* you are not allowed to use this source to re-create the RAR compression algorithm -* -* Here some html entities which can be used for escaping javadoc tags: -* "&": "&" or "&" -* "<": "<" or "<" -* ">": ">" or ">" -* "@": "@" -*/ - -using SharpCompress.Compressor.Rar.decode; - -namespace SharpCompress.Compressor.Rar -{ - /// DOCUMENT ME - /// - /// - /// $LastChangedBy$ - /// - /// $LastChangedRevision$ - /// - internal abstract class Unpack20 : Unpack15 - { - public Unpack20() - { - InitBlock(); - } - - private void InitBlock() - { - UnpOldTable20 = new byte[Compress.MC20*4]; - } - - protected internal MultDecode[] MD = new MultDecode[4]; - - //UPGRADE_NOTE: The initialization of 'UnpOldTable20' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" - protected internal byte[] UnpOldTable20; - - protected internal int UnpAudioBlock, UnpChannels, UnpCurChannel, UnpChannelDelta; - - private readonly AudioVariables[] AudV = new AudioVariables[4]; - - protected internal LitDecode LD = new LitDecode(); - - protected internal DistDecode DD = new DistDecode(); - - protected internal LowDistDecode LDD = new LowDistDecode(); - - protected internal RepDecode RD = new RepDecode(); - - protected internal BitDecode BD = new BitDecode(); - - //UPGRADE_NOTE: Final was removed from the declaration of 'LDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] LDecode = new int[] - { - 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 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'LBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly byte[] LBits = new byte[] - { - 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 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'DDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] DDecode = new int[] - { - 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, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 327680, - 393216, 458752, 524288, 589824, 655360, 720896, 786432, 851968, - 917504, 983040 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'DBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] DBits = new int[] - { - 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, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16 - , 16, 16, 16, 16, 16, 16, 16 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'SDDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] SDDecode = new int[] {0, 4, 8, 16, 32, 64, 128, 192}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'SDBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] SDBits = new int[] {2, 2, 3, 4, 5, 6, 6, 6}; - - internal void unpack20(bool solid) - { - int Bits; - - if (suspended) - { - unpPtr = wrPtr; - } - else - { - unpInitData(solid); - if (!unpReadBuf()) - { - return; - } - if (!solid) - { - if (!ReadTables20()) - { - return; - } - } - --destUnpSize; - } - - while (destUnpSize >= 0) - { - unpPtr &= Compress.MAXWINMASK; - - if (inAddr > readTop - 30) - if (!unpReadBuf()) - break; - if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr) - { - oldUnpWriteBuf(); - if (suspended) - return; - } - if (UnpAudioBlock != 0) - { - int AudioNumber = this.decodeNumber(MD[UnpCurChannel]); - - if (AudioNumber == 256) - { - if (!ReadTables20()) - break; - continue; - } - window[unpPtr++] = DecodeAudio(AudioNumber); - if (++UnpCurChannel == UnpChannels) - UnpCurChannel = 0; - --destUnpSize; - continue; - } - - int Number = this.decodeNumber(LD); - if (Number < 256) - { - window[unpPtr++] = (byte) Number; - --destUnpSize; - continue; - } - if (Number > 269) - { - int Length = LDecode[Number -= 270] + 3; - if ((Bits = LBits[Number]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - - int DistNumber = this.decodeNumber(DD); - int Distance = DDecode[DistNumber] + 1; - if ((Bits = DBits[DistNumber]) > 0) - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - - if (Distance >= 0x2000) - { - Length++; - if (Distance >= 0x40000L) - Length++; - } - - CopyString20(Length, Distance); - continue; - } - if (Number == 269) - { - if (!ReadTables20()) - break; - continue; - } - if (Number == 256) - { - CopyString20(lastLength, lastDist); - continue; - } - if (Number < 261) - { - int Distance = oldDist[(oldDistPtr - (Number - 256)) & 3]; - int LengthNumber = this.decodeNumber(RD); - int Length = LDecode[LengthNumber] + 2; - if ((Bits = LBits[LengthNumber]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - if (Distance >= 0x101) - { - Length++; - if (Distance >= 0x2000) - { - Length++; - if (Distance >= 0x40000) - Length++; - } - } - CopyString20(Length, Distance); - continue; - } - if (Number < 270) - { - int Distance = SDDecode[Number -= 261] + 1; - if ((Bits = SDBits[Number]) > 0) - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - CopyString20(2, Distance); - continue; - } - } - ReadLastTables(); - oldUnpWriteBuf(); - } - - private void CopyString20(int Length, int Distance) - { - lastDist = oldDist[oldDistPtr++ & 3] = Distance; - lastLength = Length; - destUnpSize -= Length; - - int DestPtr = unpPtr - Distance; - if (DestPtr < Compress.MAXWINSIZE - 300 && unpPtr < Compress.MAXWINSIZE - 300) - { - window[unpPtr++] = window[DestPtr++]; - window[unpPtr++] = window[DestPtr++]; - while (Length > 2) - { - Length--; - window[unpPtr++] = window[DestPtr++]; - } - } - else - { - while ((Length--) != 0) - { - window[unpPtr] = window[DestPtr++ & Compress.MAXWINMASK]; - unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; - } - } - } - - - private bool ReadTables20() - { - byte[] BitLength = new byte[Compress.BC20]; - byte[] Table = new byte[Compress.MC20*4]; - int TableSize, N, I; - if (inAddr > readTop - 25) - { - if (!unpReadBuf()) - { - return (false); - } - } - int BitField = GetBits(); - UnpAudioBlock = (BitField & 0x8000); - - if (0 == (BitField & 0x4000)) - { - // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); - Utility.Fill(UnpOldTable20, (byte) 0); - } - AddBits(2); - - if (UnpAudioBlock != 0) - { - UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1; - if (UnpCurChannel >= UnpChannels) - { - UnpCurChannel = 0; - } - AddBits(2); - TableSize = Compress.MC20*UnpChannels; - } - else - { - TableSize = Compress.NC20 + Compress.DC20 + Compress.RC20; - } - for (I = 0; I < Compress.BC20; I++) - { - BitLength[I] = (byte) (Utility.URShift(GetBits(), 12)); - AddBits(4); - } - UnpackUtility.makeDecodeTables(BitLength, 0, BD, Compress.BC20); - I = 0; - while (I < TableSize) - { - if (inAddr > readTop - 5) - { - if (!unpReadBuf()) - { - return (false); - } - } - int Number = this.decodeNumber(BD); - if (Number < 16) - { - Table[I] = (byte) ((Number + UnpOldTable20[I]) & 0xf); - I++; - } - else if (Number == 16) - { - N = (Utility.URShift(GetBits(), 14)) + 3; - AddBits(2); - while (N-- > 0 && I < TableSize) - { - Table[I] = Table[I - 1]; - I++; - } - } - else - { - if (Number == 17) - { - N = (Utility.URShift(GetBits(), 13)) + 3; - AddBits(3); - } - else - { - N = (Utility.URShift(GetBits(), 9)) + 11; - AddBits(7); - } - while (N-- > 0 && I < TableSize) - Table[I++] = 0; - } - } - if (inAddr > readTop) - { - return (true); - } - if (UnpAudioBlock != 0) - for (I = 0; I < UnpChannels; I++) - UnpackUtility.makeDecodeTables(Table, I*Compress.MC20, MD[I], Compress.MC20); - else - { - UnpackUtility.makeDecodeTables(Table, 0, LD, Compress.NC20); - UnpackUtility.makeDecodeTables(Table, Compress.NC20, DD, Compress.DC20); - UnpackUtility.makeDecodeTables(Table, Compress.NC20 + Compress.DC20, RD, Compress.RC20); - } - // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); - for (int i = 0; i < UnpOldTable20.Length; i++) - { - UnpOldTable20[i] = Table[i]; - } - return (true); - } - - protected void unpInitData20(bool Solid) - { - if (!Solid) - { - UnpChannelDelta = UnpCurChannel = 0; - UnpChannels = 1; - // memset(AudV,0,sizeof(AudV)); - AudV[0] = new AudioVariables(); - AudV[1] = new AudioVariables(); - AudV[2] = new AudioVariables(); - AudV[3] = new AudioVariables(); - // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); - Utility.Fill(UnpOldTable20, (byte) 0); - } - } - - private void ReadLastTables() - { - if (readTop >= inAddr + 5) - { - if (UnpAudioBlock != 0) - { - if (this.decodeNumber(MD[UnpCurChannel]) == 256) - { - ReadTables20(); - } - } - else - { - if (this.decodeNumber(LD) == 269) - { - ReadTables20(); - } - } - } - } - - private byte DecodeAudio(int Delta) - { - AudioVariables v = AudV[UnpCurChannel]; - v.ByteCount = v.ByteCount + 1; - v.D4 = v.D3; - v.D3 = v.D2; // ->D3=V->D2; - v.D2 = v.LastDelta - v.D1; // ->D2=V->LastDelta-V->D1; - v.D1 = v.LastDelta; // V->D1=V->LastDelta; - // int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3 - // +V->K4*V->D4+ V->K5*UnpChannelDelta; - int PCh = 8*v.LastChar + v.K1*v.D1; - PCh += v.K2*v.D2 + v.K3*v.D3; - PCh += v.K4*v.D4 + v.K5*UnpChannelDelta; - PCh = (Utility.URShift(PCh, 3)) & 0xFF; - - int Ch = PCh - Delta; - - int D = ((byte) Delta) << 3; - - v.Dif[0] += System.Math.Abs(D); // V->Dif[0]+=abs(D); - v.Dif[1] += System.Math.Abs(D - v.D1); // V->Dif[1]+=abs(D-V->D1); - v.Dif[2] += System.Math.Abs(D + v.D1); // V->Dif[2]+=abs(D+V->D1); - v.Dif[3] += System.Math.Abs(D - v.D2); // V->Dif[3]+=abs(D-V->D2); - v.Dif[4] += System.Math.Abs(D + v.D2); // V->Dif[4]+=abs(D+V->D2); - v.Dif[5] += System.Math.Abs(D - v.D3); // V->Dif[5]+=abs(D-V->D3); - v.Dif[6] += System.Math.Abs(D + v.D3); // V->Dif[6]+=abs(D+V->D3); - v.Dif[7] += System.Math.Abs(D - v.D4); // V->Dif[7]+=abs(D-V->D4); - v.Dif[8] += System.Math.Abs(D + v.D4); // V->Dif[8]+=abs(D+V->D4); - v.Dif[9] += System.Math.Abs(D - UnpChannelDelta); // V->Dif[9]+=abs(D-UnpChannelDelta); - v.Dif[10] += System.Math.Abs(D + UnpChannelDelta); // V->Dif[10]+=abs(D+UnpChannelDelta); - - v.LastDelta = (byte) (Ch - v.LastChar); - UnpChannelDelta = v.LastDelta; - v.LastChar = Ch; // V->LastChar=Ch; - - if ((v.ByteCount & 0x1F) == 0) - { - int MinDif = v.Dif[0], NumMinDif = 0; - v.Dif[0] = 0; // ->Dif[0]=0; - for (int I = 1; I < v.Dif.Length; I++) - { - if (v.Dif[I] < MinDif) - { - MinDif = v.Dif[I]; - NumMinDif = I; - } - v.Dif[I] = 0; - } - switch (NumMinDif) - { - case 1: - if (v.K1 >= -16) - { - v.K1 = v.K1 - 1; // V->K1--; - } - break; - - case 2: - if (v.K1 < 16) - { - v.K1 = v.K1 + 1; // V->K1++; - } - break; - - case 3: - if (v.K2 >= -16) - { - v.K2 = v.K2 - 1; // V->K2--; - } - break; - - case 4: - if (v.K2 < 16) - { - v.K2 = v.K2 + 1; // V->K2++; - } - break; - - case 5: - if (v.K3 >= -16) - { - v.K3 = v.K3 - 1; - } - break; - - case 6: - if (v.K3 < 16) - { - v.K3 = v.K3 + 1; - } - break; - - case 7: - if (v.K4 >= -16) - { - v.K4 = v.K4 - 1; - } - break; - - case 8: - if (v.K4 < 16) - { - v.K4 = v.K4 + 1; - } - break; - - case 9: - if (v.K5 >= -16) - { - v.K5 = v.K5 - 1; - } - break; - - case 10: - if (v.K5 < 16) - { - v.K5 = v.K5 + 1; - } - break; - } - } - return ((byte) Ch); - } - } +/* +* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. +* Original author: Edmund Wagner +* Creation date: 21.06.2007 +* +* Source: $HeadURL$ +* Last changed: $LastChangedDate$ +* +* the unrar licence applies to all junrar source and binary distributions +* you are not allowed to use this source to re-create the RAR compression algorithm +* +* Here some html entities which can be used for escaping javadoc tags: +* "&": "&" or "&" +* "<": "<" or "<" +* ">": ">" or ">" +* "@": "@" +*/ + +using SharpCompress.Compressor.Rar.decode; + +namespace SharpCompress.Compressor.Rar +{ + /// DOCUMENT ME + /// + /// + /// $LastChangedBy$ + /// + /// $LastChangedRevision$ + /// + internal abstract class Unpack20 : Unpack15 + { + public Unpack20() + { + InitBlock(); + } + + private void InitBlock() + { + UnpOldTable20 = new byte[Compress.MC20*4]; + } + + protected internal MultDecode[] MD = new MultDecode[4]; + + //UPGRADE_NOTE: The initialization of 'UnpOldTable20' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" + protected internal byte[] UnpOldTable20; + + protected internal int UnpAudioBlock, UnpChannels, UnpCurChannel, UnpChannelDelta; + + private readonly AudioVariables[] AudV = new AudioVariables[4]; + + protected internal LitDecode LD = new LitDecode(); + + protected internal DistDecode DD = new DistDecode(); + + protected internal LowDistDecode LDD = new LowDistDecode(); + + protected internal RepDecode RD = new RepDecode(); + + protected internal BitDecode BD = new BitDecode(); + + //UPGRADE_NOTE: Final was removed from the declaration of 'LDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] LDecode = new int[] + { + 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 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'LBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly byte[] LBits = new byte[] + { + 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 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'DDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] DDecode = new int[] + { + 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, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 327680, + 393216, 458752, 524288, 589824, 655360, 720896, 786432, 851968, + 917504, 983040 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'DBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] DBits = new int[] + { + 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, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16 + , 16, 16, 16, 16, 16, 16, 16 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'SDDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] SDDecode = new int[] {0, 4, 8, 16, 32, 64, 128, 192}; + + //UPGRADE_NOTE: Final was removed from the declaration of 'SDBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] SDBits = new int[] {2, 2, 3, 4, 5, 6, 6, 6}; + + internal void unpack20(bool solid) + { + int Bits; + + if (suspended) + { + unpPtr = wrPtr; + } + else + { + unpInitData(solid); + if (!unpReadBuf()) + { + return; + } + if (!solid) + { + if (!ReadTables20()) + { + return; + } + } + --destUnpSize; + } + + while (destUnpSize >= 0) + { + unpPtr &= Compress.MAXWINMASK; + + if (inAddr > readTop - 30) + if (!unpReadBuf()) + break; + if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr) + { + oldUnpWriteBuf(); + if (suspended) + return; + } + if (UnpAudioBlock != 0) + { + int AudioNumber = this.decodeNumber(MD[UnpCurChannel]); + + if (AudioNumber == 256) + { + if (!ReadTables20()) + break; + continue; + } + window[unpPtr++] = DecodeAudio(AudioNumber); + if (++UnpCurChannel == UnpChannels) + UnpCurChannel = 0; + --destUnpSize; + continue; + } + + int Number = this.decodeNumber(LD); + if (Number < 256) + { + window[unpPtr++] = (byte) Number; + --destUnpSize; + continue; + } + if (Number > 269) + { + int Length = LDecode[Number -= 270] + 3; + if ((Bits = LBits[Number]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + + int DistNumber = this.decodeNumber(DD); + int Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) + { + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + + if (Distance >= 0x2000) + { + Length++; + if (Distance >= 0x40000L) + Length++; + } + + CopyString20(Length, Distance); + continue; + } + if (Number == 269) + { + if (!ReadTables20()) + break; + continue; + } + if (Number == 256) + { + CopyString20(lastLength, lastDist); + continue; + } + if (Number < 261) + { + int Distance = oldDist[(oldDistPtr - (Number - 256)) & 3]; + int LengthNumber = this.decodeNumber(RD); + int Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + if (Distance >= 0x101) + { + Length++; + if (Distance >= 0x2000) + { + Length++; + if (Distance >= 0x40000) + Length++; + } + } + CopyString20(Length, Distance); + continue; + } + if (Number < 270) + { + int Distance = SDDecode[Number -= 261] + 1; + if ((Bits = SDBits[Number]) > 0) + { + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + CopyString20(2, Distance); + continue; + } + } + ReadLastTables(); + oldUnpWriteBuf(); + } + + private void CopyString20(int Length, int Distance) + { + lastDist = oldDist[oldDistPtr++ & 3] = Distance; + lastLength = Length; + destUnpSize -= Length; + + int DestPtr = unpPtr - Distance; + if (DestPtr < Compress.MAXWINSIZE - 300 && unpPtr < Compress.MAXWINSIZE - 300) + { + window[unpPtr++] = window[DestPtr++]; + window[unpPtr++] = window[DestPtr++]; + while (Length > 2) + { + Length--; + window[unpPtr++] = window[DestPtr++]; + } + } + else + { + while ((Length--) != 0) + { + window[unpPtr] = window[DestPtr++ & Compress.MAXWINMASK]; + unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; + } + } + } + + + private bool ReadTables20() + { + byte[] BitLength = new byte[Compress.BC20]; + byte[] Table = new byte[Compress.MC20*4]; + int TableSize, N, I; + if (inAddr > readTop - 25) + { + if (!unpReadBuf()) + { + return (false); + } + } + int BitField = GetBits(); + UnpAudioBlock = (BitField & 0x8000); + + if (0 == (BitField & 0x4000)) + { + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Utility.Fill(UnpOldTable20, (byte) 0); + } + AddBits(2); + + if (UnpAudioBlock != 0) + { + UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1; + if (UnpCurChannel >= UnpChannels) + { + UnpCurChannel = 0; + } + AddBits(2); + TableSize = Compress.MC20*UnpChannels; + } + else + { + TableSize = Compress.NC20 + Compress.DC20 + Compress.RC20; + } + for (I = 0; I < Compress.BC20; I++) + { + BitLength[I] = (byte) (Utility.URShift(GetBits(), 12)); + AddBits(4); + } + UnpackUtility.makeDecodeTables(BitLength, 0, BD, Compress.BC20); + I = 0; + while (I < TableSize) + { + if (inAddr > readTop - 5) + { + if (!unpReadBuf()) + { + return (false); + } + } + int Number = this.decodeNumber(BD); + if (Number < 16) + { + Table[I] = (byte) ((Number + UnpOldTable20[I]) & 0xf); + I++; + } + else if (Number == 16) + { + N = (Utility.URShift(GetBits(), 14)) + 3; + AddBits(2); + while (N-- > 0 && I < TableSize) + { + Table[I] = Table[I - 1]; + I++; + } + } + else + { + if (Number == 17) + { + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); + } + else + { + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && I < TableSize) + Table[I++] = 0; + } + } + if (inAddr > readTop) + { + return (true); + } + if (UnpAudioBlock != 0) + for (I = 0; I < UnpChannels; I++) + UnpackUtility.makeDecodeTables(Table, I*Compress.MC20, MD[I], Compress.MC20); + else + { + UnpackUtility.makeDecodeTables(Table, 0, LD, Compress.NC20); + UnpackUtility.makeDecodeTables(Table, Compress.NC20, DD, Compress.DC20); + UnpackUtility.makeDecodeTables(Table, Compress.NC20 + Compress.DC20, RD, Compress.RC20); + } + // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); + for (int i = 0; i < UnpOldTable20.Length; i++) + { + UnpOldTable20[i] = Table[i]; + } + return (true); + } + + protected void unpInitData20(bool Solid) + { + if (!Solid) + { + UnpChannelDelta = UnpCurChannel = 0; + UnpChannels = 1; + // memset(AudV,0,sizeof(AudV)); + AudV[0] = new AudioVariables(); + AudV[1] = new AudioVariables(); + AudV[2] = new AudioVariables(); + AudV[3] = new AudioVariables(); + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Utility.Fill(UnpOldTable20, (byte) 0); + } + } + + private void ReadLastTables() + { + if (readTop >= inAddr + 5) + { + if (UnpAudioBlock != 0) + { + if (this.decodeNumber(MD[UnpCurChannel]) == 256) + { + ReadTables20(); + } + } + else + { + if (this.decodeNumber(LD) == 269) + { + ReadTables20(); + } + } + } + } + + private byte DecodeAudio(int Delta) + { + AudioVariables v = AudV[UnpCurChannel]; + v.ByteCount = v.ByteCount + 1; + v.D4 = v.D3; + v.D3 = v.D2; // ->D3=V->D2; + v.D2 = v.LastDelta - v.D1; // ->D2=V->LastDelta-V->D1; + v.D1 = v.LastDelta; // V->D1=V->LastDelta; + // int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3 + // +V->K4*V->D4+ V->K5*UnpChannelDelta; + int PCh = 8*v.LastChar + v.K1*v.D1; + PCh += v.K2*v.D2 + v.K3*v.D3; + PCh += v.K4*v.D4 + v.K5*UnpChannelDelta; + PCh = (Utility.URShift(PCh, 3)) & 0xFF; + + int Ch = PCh - Delta; + + int D = ((byte) Delta) << 3; + + v.Dif[0] += System.Math.Abs(D); // V->Dif[0]+=abs(D); + v.Dif[1] += System.Math.Abs(D - v.D1); // V->Dif[1]+=abs(D-V->D1); + v.Dif[2] += System.Math.Abs(D + v.D1); // V->Dif[2]+=abs(D+V->D1); + v.Dif[3] += System.Math.Abs(D - v.D2); // V->Dif[3]+=abs(D-V->D2); + v.Dif[4] += System.Math.Abs(D + v.D2); // V->Dif[4]+=abs(D+V->D2); + v.Dif[5] += System.Math.Abs(D - v.D3); // V->Dif[5]+=abs(D-V->D3); + v.Dif[6] += System.Math.Abs(D + v.D3); // V->Dif[6]+=abs(D+V->D3); + v.Dif[7] += System.Math.Abs(D - v.D4); // V->Dif[7]+=abs(D-V->D4); + v.Dif[8] += System.Math.Abs(D + v.D4); // V->Dif[8]+=abs(D+V->D4); + v.Dif[9] += System.Math.Abs(D - UnpChannelDelta); // V->Dif[9]+=abs(D-UnpChannelDelta); + v.Dif[10] += System.Math.Abs(D + UnpChannelDelta); // V->Dif[10]+=abs(D+UnpChannelDelta); + + v.LastDelta = (byte) (Ch - v.LastChar); + UnpChannelDelta = v.LastDelta; + v.LastChar = Ch; // V->LastChar=Ch; + + if ((v.ByteCount & 0x1F) == 0) + { + int MinDif = v.Dif[0], NumMinDif = 0; + v.Dif[0] = 0; // ->Dif[0]=0; + for (int I = 1; I < v.Dif.Length; I++) + { + if (v.Dif[I] < MinDif) + { + MinDif = v.Dif[I]; + NumMinDif = I; + } + v.Dif[I] = 0; + } + switch (NumMinDif) + { + case 1: + if (v.K1 >= -16) + { + v.K1 = v.K1 - 1; // V->K1--; + } + break; + + case 2: + if (v.K1 < 16) + { + v.K1 = v.K1 + 1; // V->K1++; + } + break; + + case 3: + if (v.K2 >= -16) + { + v.K2 = v.K2 - 1; // V->K2--; + } + break; + + case 4: + if (v.K2 < 16) + { + v.K2 = v.K2 + 1; // V->K2++; + } + break; + + case 5: + if (v.K3 >= -16) + { + v.K3 = v.K3 - 1; + } + break; + + case 6: + if (v.K3 < 16) + { + v.K3 = v.K3 + 1; + } + break; + + case 7: + if (v.K4 >= -16) + { + v.K4 = v.K4 - 1; + } + break; + + case 8: + if (v.K4 < 16) + { + v.K4 = v.K4 + 1; + } + break; + + case 9: + if (v.K5 >= -16) + { + v.K5 = v.K5 - 1; + } + break; + + case 10: + if (v.K5 < 16) + { + v.K5 = v.K5 + 1; + } + break; + } + } + return ((byte) Ch); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/UnpackFilter.cs b/src/SharpCompress/Compressor/Rar/UnpackFilter.cs similarity index 96% rename from SharpCompress/Compressor/Rar/UnpackFilter.cs rename to src/SharpCompress/Compressor/Rar/UnpackFilter.cs index dd878512..bbf7fa96 100644 --- a/SharpCompress/Compressor/Rar/UnpackFilter.cs +++ b/src/SharpCompress/Compressor/Rar/UnpackFilter.cs @@ -1,26 +1,26 @@ -using SharpCompress.Compressor.Rar.VM; - -namespace SharpCompress.Compressor.Rar -{ - internal class UnpackFilter - { - internal UnpackFilter() - { - Program = new VMPreparedProgram(); - } - - internal int BlockStart { get; set; } - - internal int BlockLength { get; set; } - - internal int ExecCount { get; set; } - - internal bool NextWindow { get; set; } - - // position of parent filter in Filters array used as prototype for filter - // in PrgStack array. Not defined for filters in Filters array. - internal int ParentFilter { get; set; } - - internal VMPreparedProgram Program { get; set; } - } +using SharpCompress.Compressor.Rar.VM; + +namespace SharpCompress.Compressor.Rar +{ + internal class UnpackFilter + { + internal UnpackFilter() + { + Program = new VMPreparedProgram(); + } + + internal int BlockStart { get; set; } + + internal int BlockLength { get; set; } + + internal int ExecCount { get; set; } + + internal bool NextWindow { get; set; } + + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + internal int ParentFilter { get; set; } + + internal VMPreparedProgram Program { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/UnpackUtility.cs b/src/SharpCompress/Compressor/Rar/UnpackUtility.cs similarity index 97% rename from SharpCompress/Compressor/Rar/UnpackUtility.cs rename to src/SharpCompress/Compressor/Rar/UnpackUtility.cs index 53b83326..9e8c81d9 100644 --- a/SharpCompress/Compressor/Rar/UnpackUtility.cs +++ b/src/SharpCompress/Compressor/Rar/UnpackUtility.cs @@ -1,201 +1,201 @@ -using SharpCompress.Compressor.Rar.decode; -using SharpCompress.Compressor.Rar.VM; - -namespace SharpCompress.Compressor.Rar -{ - internal static class UnpackUtility - { - internal static int decodeNumber(this BitInput input, Decode dec) - { - int bits; - long bitField = input.GetBits() & 0xfffe; - // if (bitField < dec.getDecodeLen()[8]) { - // if (bitField < dec.getDecodeLen()[4]) { - // if (bitField < dec.getDecodeLen()[2]) { - // if (bitField < dec.getDecodeLen()[1]) { - // bits = 1; - // } else { - // bits = 2; - // } - // } else { - // if (bitField < dec.getDecodeLen()[3]) { - // bits = 3; - // } else { - // bits = 4; - // } - // } - // } else { - // if (bitField < dec.getDecodeLen()[6]) { - // if (bitField < dec.getDecodeLen()[5]) - // bits = 5; - // else - // bits = 6; - // } else { - // if (bitField < dec.getDecodeLen()[7]) { - // bits = 7; - // } else { - // bits = 8; - // } - // } - // } - // } else { - // if (bitField < dec.getDecodeLen()[12]) { - // if (bitField < dec.getDecodeLen()[10]) - // if (bitField < dec.getDecodeLen()[9]) - // bits = 9; - // else - // bits = 10; - // else if (bitField < dec.getDecodeLen()[11]) - // bits = 11; - // else - // bits = 12; - // } else { - // if (bitField < dec.getDecodeLen()[14]) { - // if (bitField < dec.getDecodeLen()[13]) { - // bits = 13; - // } else { - // bits = 14; - // } - // } else { - // bits = 15; - // } - // } - // } - // addbits(bits); - // int N = dec.getDecodePos()[bits] - // + (((int) bitField - dec.getDecodeLen()[bits - 1]) >>> (16 - bits)); - // if (N >= dec.getMaxNum()) { - // N = 0; - // } - // return (dec.getDecodeNum()[N]); - int[] decodeLen = dec.DecodeLen; - if (bitField < decodeLen[8]) - { - if (bitField < decodeLen[4]) - { - if (bitField < decodeLen[2]) - { - if (bitField < decodeLen[1]) - { - bits = 1; - } - else - { - bits = 2; - } - } - else - { - if (bitField < decodeLen[3]) - { - bits = 3; - } - else - { - bits = 4; - } - } - } - else - { - if (bitField < decodeLen[6]) - { - if (bitField < decodeLen[5]) - bits = 5; - else - bits = 6; - } - else - { - if (bitField < decodeLen[7]) - { - bits = 7; - } - else - { - bits = 8; - } - } - } - } - else - { - if (bitField < decodeLen[12]) - { - if (bitField < decodeLen[10]) - if (bitField < decodeLen[9]) - bits = 9; - else - bits = 10; - else if (bitField < decodeLen[11]) - bits = 11; - else - bits = 12; - } - else - { - if (bitField < decodeLen[14]) - { - if (bitField < decodeLen[13]) - { - bits = 13; - } - else - { - bits = 14; - } - } - else - { - bits = 15; - } - } - } - input.AddBits(bits); - int N = dec.DecodePos[bits] + (Utility.URShift(((int) bitField - decodeLen[bits - 1]), (16 - bits))); - if (N >= dec.MaxNum) - { - N = 0; - } - return (dec.DecodeNum[N]); - } - - internal static void makeDecodeTables(byte[] lenTab, int offset, Decode dec, int size) - { - int[] lenCount = new int[16]; - int[] tmpPos = new int[16]; - int i; - long M, N; - - Utility.Fill(lenCount, 0); // memset(LenCount,0,sizeof(LenCount)); - - Utility.Fill(dec.DecodeNum, 0); // memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); - - for (i = 0; i < size; i++) - { - lenCount[(int) (lenTab[offset + i] & 0xF)]++; - } - lenCount[0] = 0; - for (tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; i < 16; i++) - { - N = 2*(N + lenCount[i]); - M = N << (15 - i); - if (M > 0xFFFF) - { - M = 0xFFFF; - } - dec.DecodeLen[i] = (int) M; - tmpPos[i] = dec.DecodePos[i] = dec.DecodePos[i - 1] + lenCount[i - 1]; - } - - for (i = 0; i < size; i++) - { - if (lenTab[offset + i] != 0) - { - dec.DecodeNum[tmpPos[lenTab[offset + i] & 0xF]++] = i; - } - } - dec.MaxNum = size; - } - } +using SharpCompress.Compressor.Rar.decode; +using SharpCompress.Compressor.Rar.VM; + +namespace SharpCompress.Compressor.Rar +{ + internal static class UnpackUtility + { + internal static int decodeNumber(this BitInput input, Decode dec) + { + int bits; + long bitField = input.GetBits() & 0xfffe; + // if (bitField < dec.getDecodeLen()[8]) { + // if (bitField < dec.getDecodeLen()[4]) { + // if (bitField < dec.getDecodeLen()[2]) { + // if (bitField < dec.getDecodeLen()[1]) { + // bits = 1; + // } else { + // bits = 2; + // } + // } else { + // if (bitField < dec.getDecodeLen()[3]) { + // bits = 3; + // } else { + // bits = 4; + // } + // } + // } else { + // if (bitField < dec.getDecodeLen()[6]) { + // if (bitField < dec.getDecodeLen()[5]) + // bits = 5; + // else + // bits = 6; + // } else { + // if (bitField < dec.getDecodeLen()[7]) { + // bits = 7; + // } else { + // bits = 8; + // } + // } + // } + // } else { + // if (bitField < dec.getDecodeLen()[12]) { + // if (bitField < dec.getDecodeLen()[10]) + // if (bitField < dec.getDecodeLen()[9]) + // bits = 9; + // else + // bits = 10; + // else if (bitField < dec.getDecodeLen()[11]) + // bits = 11; + // else + // bits = 12; + // } else { + // if (bitField < dec.getDecodeLen()[14]) { + // if (bitField < dec.getDecodeLen()[13]) { + // bits = 13; + // } else { + // bits = 14; + // } + // } else { + // bits = 15; + // } + // } + // } + // addbits(bits); + // int N = dec.getDecodePos()[bits] + // + (((int) bitField - dec.getDecodeLen()[bits - 1]) >>> (16 - bits)); + // if (N >= dec.getMaxNum()) { + // N = 0; + // } + // return (dec.getDecodeNum()[N]); + int[] decodeLen = dec.DecodeLen; + if (bitField < decodeLen[8]) + { + if (bitField < decodeLen[4]) + { + if (bitField < decodeLen[2]) + { + if (bitField < decodeLen[1]) + { + bits = 1; + } + else + { + bits = 2; + } + } + else + { + if (bitField < decodeLen[3]) + { + bits = 3; + } + else + { + bits = 4; + } + } + } + else + { + if (bitField < decodeLen[6]) + { + if (bitField < decodeLen[5]) + bits = 5; + else + bits = 6; + } + else + { + if (bitField < decodeLen[7]) + { + bits = 7; + } + else + { + bits = 8; + } + } + } + } + else + { + if (bitField < decodeLen[12]) + { + if (bitField < decodeLen[10]) + if (bitField < decodeLen[9]) + bits = 9; + else + bits = 10; + else if (bitField < decodeLen[11]) + bits = 11; + else + bits = 12; + } + else + { + if (bitField < decodeLen[14]) + { + if (bitField < decodeLen[13]) + { + bits = 13; + } + else + { + bits = 14; + } + } + else + { + bits = 15; + } + } + } + input.AddBits(bits); + int N = dec.DecodePos[bits] + (Utility.URShift(((int) bitField - decodeLen[bits - 1]), (16 - bits))); + if (N >= dec.MaxNum) + { + N = 0; + } + return (dec.DecodeNum[N]); + } + + internal static void makeDecodeTables(byte[] lenTab, int offset, Decode dec, int size) + { + int[] lenCount = new int[16]; + int[] tmpPos = new int[16]; + int i; + long M, N; + + Utility.Fill(lenCount, 0); // memset(LenCount,0,sizeof(LenCount)); + + Utility.Fill(dec.DecodeNum, 0); // memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + + for (i = 0; i < size; i++) + { + lenCount[(int) (lenTab[offset + i] & 0xF)]++; + } + lenCount[0] = 0; + for (tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; i < 16; i++) + { + N = 2*(N + lenCount[i]); + M = N << (15 - i); + if (M > 0xFFFF) + { + M = 0xFFFF; + } + dec.DecodeLen[i] = (int) M; + tmpPos[i] = dec.DecodePos[i] = dec.DecodePos[i - 1] + lenCount[i - 1]; + } + + for (i = 0; i < size; i++) + { + if (lenTab[offset + i] != 0) + { + dec.DecodeNum[tmpPos[lenTab[offset + i] & 0xF]++] = i; + } + } + dec.MaxNum = size; + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/BitInput.cs b/src/SharpCompress/Compressor/Rar/VM/BitInput.cs similarity index 96% rename from SharpCompress/Compressor/Rar/VM/BitInput.cs rename to src/SharpCompress/Compressor/Rar/VM/BitInput.cs index b9d6b8c0..915a0841 100644 --- a/SharpCompress/Compressor/Rar/VM/BitInput.cs +++ b/src/SharpCompress/Compressor/Rar/VM/BitInput.cs @@ -1,65 +1,65 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal class BitInput - { - /// the max size of the input - internal const int MAX_SIZE = 0x8000; - - protected int inAddr; - protected int inBit; - - /// - internal BitInput() - { - InBuf = new byte[MAX_SIZE]; - } - - internal byte[] InBuf { get; private set; } - - internal void InitBitInput() - { - inAddr = 0; - inBit = 0; - } - - /// - /// also named faddbits - /// - /// - internal void AddBits(int bits) - { - bits += inBit; - inAddr += (bits >> 3); - inBit = bits & 7; - } - - /// - /// (also named fgetbits) - /// - /// - /// the bits (unsigned short) - /// - internal int GetBits() - { - // int BitField=0; - // BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; - // BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; - // BitField|=(int)(inBuf[inAddr+2])&0xFF; - // BitField >>>= (8-inBit); - // return (BitField & 0xffff); - return ((Utility.URShift((((InBuf[inAddr] & 0xff) << 16) - + ((InBuf[inAddr + 1] & 0xff) << 8) - + ((InBuf[inAddr + 2] & 0xff))), (8 - inBit))) & 0xffff); - } - - /// Indicates an Overfow - /// how many bytes to inc - /// - /// true if an Oververflow would occur - /// - internal bool Overflow(int IncPtr) - { - return (inAddr + IncPtr >= MAX_SIZE); - } - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal class BitInput + { + /// the max size of the input + internal const int MAX_SIZE = 0x8000; + + protected int inAddr; + protected int inBit; + + /// + internal BitInput() + { + InBuf = new byte[MAX_SIZE]; + } + + internal byte[] InBuf { get; private set; } + + internal void InitBitInput() + { + inAddr = 0; + inBit = 0; + } + + /// + /// also named faddbits + /// + /// + internal void AddBits(int bits) + { + bits += inBit; + inAddr += (bits >> 3); + inBit = bits & 7; + } + + /// + /// (also named fgetbits) + /// + /// + /// the bits (unsigned short) + /// + internal int GetBits() + { + // int BitField=0; + // BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; + // BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; + // BitField|=(int)(inBuf[inAddr+2])&0xFF; + // BitField >>>= (8-inBit); + // return (BitField & 0xffff); + return ((Utility.URShift((((InBuf[inAddr] & 0xff) << 16) + + ((InBuf[inAddr + 1] & 0xff) << 8) + + ((InBuf[inAddr + 2] & 0xff))), (8 - inBit))) & 0xffff); + } + + /// Indicates an Overfow + /// how many bytes to inc + /// + /// true if an Oververflow would occur + /// + internal bool Overflow(int IncPtr) + { + return (inAddr + IncPtr >= MAX_SIZE); + } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/RarVM.cs b/src/SharpCompress/Compressor/Rar/VM/RarVM.cs similarity index 97% rename from SharpCompress/Compressor/Rar/VM/RarVM.cs rename to src/SharpCompress/Compressor/Rar/VM/RarVM.cs index 344426cc..85763671 100644 --- a/SharpCompress/Compressor/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressor/Rar/VM/RarVM.cs @@ -1,1439 +1,1439 @@ -using System; -using System.Collections.Generic; - -namespace SharpCompress.Compressor.Rar.VM -{ - internal class RarVM : BitInput - { - //private void InitBlock() - //{ - // Mem.set_Renamed(offset + 0, Byte.valueOf((sbyte) (value_Renamed & 0xff))); - // Mem.set_Renamed(offset + 1, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 8)) & 0xff))); - // Mem.set_Renamed(offset + 2, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 16)) & 0xff))); - // Mem.set_Renamed(offset + 3, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 24)) & 0xff))); - - - //} - internal byte[] Mem { get; private set; } - - public const int VM_MEMSIZE = 0x40000; - - //UPGRADE_NOTE: Final was removed from the declaration of 'VM_MEMMASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int VM_MEMMASK = (VM_MEMSIZE - 1); - - public const int VM_GLOBALMEMADDR = 0x3C000; - - public const int VM_GLOBALMEMSIZE = 0x2000; - - public const int VM_FIXEDGLOBALSIZE = 64; - - private const int regCount = 8; - - private const long UINT_MASK = 0xffffFFFF; //((long)2*(long)Integer.MAX_VALUE); - - private int[] R = new int[regCount]; - - private VMFlags flags; - - private int maxOpCount = 25000000; - - private int codeSize; - - private int IP; - - internal RarVM() - { - //InitBlock(); - Mem = null; - } - - internal void init() - { - if (Mem == null) - { - Mem = new byte[VM_MEMSIZE + 4]; - } - } - - private bool IsVMMem(byte[] mem) - { - return this.Mem == mem; - } - - private int GetValue(bool byteMode, byte[] mem, int offset) - { - if (byteMode) - { - if (IsVMMem(mem)) - { - return (mem[offset]); - } - else - { - return (mem[offset] & 0xff); - } - } - else - { - if (IsVMMem(mem)) - { - return Utility.readIntLittleEndian(mem, offset); - } - else - { - return Utility.readIntBigEndian(mem, offset); - } - } - } - - private void SetValue(bool byteMode, byte[] mem, int offset, int value) - { - if (byteMode) - { - if (IsVMMem(mem)) - { - mem[offset] = (byte) value; - } - else - { - mem[offset] = (byte) ((mem[offset] & 0x00) | (byte) (value & 0xff)); - } - } - else - { - if (IsVMMem(mem)) - { - Utility.WriteLittleEndian(mem, offset, value); - // Mem[offset + 0] = (byte) value; - // Mem[offset + 1] = (byte) (value >>> 8); - // Mem[offset + 2] = (byte) (value >>> 16); - // Mem[offset + 3] = (byte) (value >>> 24); - } - else - { - Utility.writeIntBigEndian(mem, offset, value); - // Mem[offset + 3] = (byte) value; - // Mem[offset + 2] = (byte) (value >>> 8); - // Mem[offset + 1] = (byte) (value >>> 16); - // Mem[offset + 0] = (byte) (value >>> 24); - } - } - // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint - // *)Addr,Value) - } - - internal void SetLowEndianValue(List mem, int offset, int value) - { - mem[offset + 0] = (byte) (value & 0xff); - mem[offset + 1] = (byte) (Utility.URShift(value, 8) & 0xff); - mem[offset + 2] = (byte) (Utility.URShift(value, 16) & 0xff); - mem[offset + 3] = (byte) (Utility.URShift(value, 24) & 0xff); - } - - private int GetOperand(VMPreparedOperand cmdOp) - { - int ret = 0; - if (cmdOp.Type == VMOpType.VM_OPREGMEM) - { - int pos = (cmdOp.Offset + cmdOp.Base) & VM_MEMMASK; - ret = Utility.readIntLittleEndian(Mem, pos); - } - else - { - int pos = cmdOp.Offset; - ret = Utility.readIntLittleEndian(Mem, pos); - } - return ret; - } - - public void execute(VMPreparedProgram prg) - { - for (int i = 0; i < prg.InitR.Length; i++) - // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); - { - R[i] = prg.InitR[i]; - } - - long globalSize = (long) (Math.Min(prg.GlobalData.Count, VM_GLOBALMEMSIZE)) & 0xffFFffFF; - if (globalSize != 0) - { - for (int i = 0; i < globalSize; i++) - // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); - { - Mem[VM_GLOBALMEMADDR + i] = prg.GlobalData[i]; - } - } - long staticSize = (long) (Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize)) & 0xffFFffFF; - if (staticSize != 0) - { - for (int i = 0; i < staticSize; i++) - // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); - { - Mem[VM_GLOBALMEMADDR + (int) globalSize + i] = prg.StaticData[i]; - } - } - R[7] = VM_MEMSIZE; - flags = 0; - - //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" - List preparedCode = prg.AltCommands.Count != 0 - ? prg - .AltCommands - : prg.Commands; - - if (!ExecuteCode(preparedCode, prg.CommandCount)) - { - preparedCode[0].OpCode = VMCommands.VM_RET; - } - int newBlockPos = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x20) & VM_MEMMASK; - int newBlockSize = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c) & VM_MEMMASK; - if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) - { - newBlockPos = 0; - newBlockSize = 0; - } - - prg.FilteredDataOffset = newBlockPos; - prg.FilteredDataSize = newBlockSize; - - prg.GlobalData.Clear(); - - int dataSize = Math.Min(GetValue(false, Mem, VM_GLOBALMEMADDR + 0x30), VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); - if (dataSize != 0) - { - //prg.GlobalData.Clear(); - // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); - prg.GlobalData.SetSize(dataSize + VM_FIXEDGLOBALSIZE); - for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) - // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); - { - prg.GlobalData[i] = Mem[VM_GLOBALMEMADDR + i]; - } - } - } - - private bool setIP(int ip) - { - if ((ip) >= codeSize) - { - return (true); - } - - if (--maxOpCount <= 0) - { - return (false); - } - - IP = ip; - return true; - } - - private bool ExecuteCode(List preparedCode, - int cmdCount) - { - maxOpCount = 25000000; - this.codeSize = cmdCount; - this.IP = 0; - - while (true) - { - VMPreparedCommand cmd = preparedCode[IP]; - int op1 = GetOperand(cmd.Op1); - int op2 = GetOperand(cmd.Op2); - switch (cmd.OpCode) - { - case VMCommands.VM_MOV: - SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); - // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); - break; - - case VMCommands.VM_MOVB: - SetValue(true, Mem, op1, GetValue(true, Mem, op2)); - break; - - case VMCommands.VM_MOVD: - SetValue(false, Mem, op1, GetValue(false, Mem, op2)); - break; - - - case VMCommands.VM_CMP: - { - VMFlags value1 = (VMFlags) GetValue(cmd.IsByteMode, Mem, op1); - VMFlags result = value1 - GetValue(cmd.IsByteMode, Mem, op2); - - if (result == 0) - { - flags = VMFlags.VM_FZ; - } - else - { - flags = (VMFlags) ((result > value1) ? 1 : 0 | (int) (result & VMFlags.VM_FS)); - } - } - break; - - - case VMCommands.VM_CMPB: - { - VMFlags value1 = (VMFlags) GetValue(true, Mem, op1); - VMFlags result = value1 - GetValue(true, Mem, op2); - if (result == 0) - { - flags = VMFlags.VM_FZ; - } - else - { - flags = (VMFlags) ((result > value1) ? 1 : 0 | (int) (result & VMFlags.VM_FS)); - } - } - break; - - case VMCommands.VM_CMPD: - { - VMFlags value1 = (VMFlags) GetValue(false, Mem, op1); - VMFlags result = value1 - GetValue(false, Mem, op2); - if (result == 0) - { - flags = VMFlags.VM_FZ; - } - else - { - flags = (VMFlags) ((result > value1) ? 1 : 0 | (int) (result & VMFlags.VM_FS)); - } - } - break; - - - case VMCommands.VM_ADD: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int result = - (int) - ((((long) value1 + (long) GetValue(cmd.IsByteMode, Mem, op2))) & - unchecked((int) 0xffffffff)); - if (cmd.IsByteMode) - { - result &= 0xff; - flags = - (VMFlags) - ((result < value1) - ? 1 - : 0 | - (result == 0 - ? (int) VMFlags.VM_FZ - : (((result & 0x80) != 0) ? (int) VMFlags.VM_FS : 0))); - // Flags=(Result value1) ? 1 : 0 | (result & (int) VMFlags.VM_FS))); - SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); - } - break; - - - case VMCommands.VM_SUBB: - SetValue(true, Mem, op1, - (int) - ((long) GetValue(true, Mem, op1) & 0xFFffFFff - (long) GetValue(true, Mem, op2) & - unchecked((int) 0xFFffFFff))); - break; - - case VMCommands.VM_SUBD: - SetValue(false, Mem, op1, - (int) - ((long) GetValue(false, Mem, op1) & 0xFFffFFff - (long) GetValue(false, Mem, op2) & - unchecked((int) 0xFFffFFff))); - break; - - - case VMCommands.VM_JZ: - if ((flags & VMFlags.VM_FZ) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JNZ: - if ((flags & VMFlags.VM_FZ) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_INC: - { - int result = (int) ((long) GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFffL + 1L); - if (cmd.IsByteMode) - { - result &= 0xff; - } - - SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); - } - break; - - - case VMCommands.VM_INCB: - SetValue(true, Mem, op1, (int) ((long) GetValue(true, Mem, op1) & 0xFFffFFffL + 1L)); - break; - - case VMCommands.VM_INCD: - SetValue(false, Mem, op1, (int) ((long) GetValue(false, Mem, op1) & 0xFFffFFffL + 1L)); - break; - - - case VMCommands.VM_DEC: - { - int result = (int) ((long) GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFff - 1); - SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); - } - break; - - - case VMCommands.VM_DECB: - SetValue(true, Mem, op1, (int) ((long) GetValue(true, Mem, op1) & 0xFFffFFff - 1)); - break; - - case VMCommands.VM_DECD: - SetValue(false, Mem, op1, (int) ((long) GetValue(false, Mem, op1) & 0xFFffFFff - 1)); - break; - - - case VMCommands.VM_JMP: - setIP(GetValue(false, Mem, op1)); - continue; - - case VMCommands.VM_XOR: - { - int result = GetValue(cmd.IsByteMode, Mem, op1) ^ GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_AND: - { - int result = GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_OR: - { - int result = GetValue(cmd.IsByteMode, Mem, op1) | GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_TEST: - { - int result = GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); - } - break; - - case VMCommands.VM_JS: - if ((flags & VMFlags.VM_FS) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JNS: - if ((flags & VMFlags.VM_FS) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JB: - if ((flags & VMFlags.VM_FC) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JBE: - if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JA: - if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JAE: - if ((flags & VMFlags.VM_FC) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_PUSH: - R[7] -= 4; - SetValue(false, Mem, R[7] & VM_MEMMASK, GetValue(false, Mem, op1)); - break; - - case VMCommands.VM_POP: - SetValue(false, Mem, op1, GetValue(false, Mem, R[7] & VM_MEMMASK)); - R[7] += 4; - break; - - case VMCommands.VM_CALL: - R[7] -= 4; - SetValue(false, Mem, R[7] & VM_MEMMASK, IP + 1); - setIP(GetValue(false, Mem, op1)); - continue; - - case VMCommands.VM_NOT: - SetValue(cmd.IsByteMode, Mem, op1, ~GetValue(cmd.IsByteMode, Mem, op1)); - break; - - case VMCommands.VM_SHL: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int value2 = GetValue(cmd.IsByteMode, Mem, op2); - int result = value1 << value2; - flags = - (VMFlags) - ((result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS)) | - (((value1 << (value2 - 1)) & unchecked((int) 0x80000000)) != 0 - ? (int) VMFlags.VM_FC - : 0)); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_SHR: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int value2 = GetValue(cmd.IsByteMode, Mem, op2); - int result = Utility.URShift(value1, value2); - flags = - (VMFlags) - ((result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS)) | - ((Utility.URShift(value1, (value2 - 1))) & (int) VMFlags.VM_FC)); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_SAR: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int value2 = GetValue(cmd.IsByteMode, Mem, op2); - int result = ((int) value1) >> value2; - flags = - (VMFlags) - ((result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS)) | - ((value1 >> (value2 - 1)) & (int) VMFlags.VM_FC)); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_NEG: - { - int result = -GetValue(cmd.IsByteMode, Mem, op1); - flags = - (VMFlags) - (result == 0 - ? (int) VMFlags.VM_FZ - : (int) VMFlags.VM_FC | (result & (int) VMFlags.VM_FS)); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - - case VMCommands.VM_NEGB: - SetValue(true, Mem, op1, -GetValue(true, Mem, op1)); - break; - - case VMCommands.VM_NEGD: - SetValue(false, Mem, op1, -GetValue(false, Mem, op1)); - break; - - case VMCommands.VM_PUSHA: - { - for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) - { - SetValue(false, Mem, SP & VM_MEMMASK, R[i]); - } - R[7] -= regCount*4; - } - break; - - case VMCommands.VM_POPA: - { - for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) - R[7 - i] = GetValue(false, Mem, SP & VM_MEMMASK); - } - break; - - case VMCommands.VM_PUSHF: - R[7] -= 4; - SetValue(false, Mem, R[7] & VM_MEMMASK, (int) flags); - break; - - case VMCommands.VM_POPF: - flags = (VMFlags) GetValue(false, Mem, R[7] & VM_MEMMASK); - R[7] += 4; - break; - - case VMCommands.VM_MOVZX: - SetValue(false, Mem, op1, GetValue(true, Mem, op2)); - break; - - case VMCommands.VM_MOVSX: - SetValue(false, Mem, op1, (byte) GetValue(true, Mem, op2)); - break; - - case VMCommands.VM_XCHG: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); - SetValue(cmd.IsByteMode, Mem, op2, value1); - } - break; - - case VMCommands.VM_MUL: - { - int result = - (int) - (((long) GetValue(cmd.IsByteMode, Mem, op1) & - 0xFFffFFff*(long) GetValue(cmd.IsByteMode, Mem, op2) & unchecked((int) 0xFFffFFff)) & - unchecked((int) 0xFFffFFff)); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_DIV: - { - int divider = GetValue(cmd.IsByteMode, Mem, op2); - if (divider != 0) - { - int result = GetValue(cmd.IsByteMode, Mem, op1)/divider; - SetValue(cmd.IsByteMode, Mem, op1, result); - } - } - break; - - case VMCommands.VM_ADC: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int FC = (int) (flags & VMFlags.VM_FC); - int result = - (int) - ((long) value1 & 0xFFffFFff + (long) GetValue(cmd.IsByteMode, Mem, op2) & - 0xFFffFFff + (long) FC & unchecked((int) 0xFFffFFff)); - if (cmd.IsByteMode) - { - result &= 0xff; - } - - flags = - (VMFlags) - ((result < value1 || result == value1 && FC != 0) - ? 1 - : 0 | (result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS))); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_SBB: - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int FC = (int) (flags & VMFlags.VM_FC); - int result = - (int) - ((long) value1 & 0xFFffFFff - (long) GetValue(cmd.IsByteMode, Mem, op2) & - 0xFFffFFff - (long) FC & unchecked((int) 0xFFffFFff)); - if (cmd.IsByteMode) - { - result &= 0xff; - } - flags = - (VMFlags) - ((result > value1 || result == value1 && FC != 0) - ? 1 - : 0 | (result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS))); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - - case VMCommands.VM_RET: - if (R[7] >= VM_MEMSIZE) - { - return (true); - } - setIP(GetValue(false, Mem, R[7] & VM_MEMMASK)); - R[7] += 4; - continue; - - - case VMCommands.VM_STANDARD: - ExecuteStandardFilter((VMStandardFilters) (cmd.Op1.Data)); - break; - - case VMCommands.VM_PRINT: - break; - } - IP++; - --maxOpCount; - } - } - - public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) - { - InitBitInput(); - int cpLength = System.Math.Min(MAX_SIZE, codeSize); - // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); - - Buffer.BlockCopy(code, 0, InBuf, 0, cpLength); - byte xorSum = 0; - for (int i = 1; i < codeSize; i++) - { - xorSum ^= code[i]; - } - - AddBits(8); - - prg.CommandCount = 0; - if (xorSum == code[0]) - { - VMStandardFilters filterType = IsStandardFilter(code, codeSize); - if (filterType != VMStandardFilters.VMSF_NONE) - { - VMPreparedCommand curCmd = new VMPreparedCommand(); - curCmd.OpCode = VMCommands.VM_STANDARD; - curCmd.Op1.Data = (int) filterType; - curCmd.Op1.Type = VMOpType.VM_OPNONE; - curCmd.Op2.Type = VMOpType.VM_OPNONE; - codeSize = 0; - prg.Commands.Add(curCmd); - prg.CommandCount = prg.CommandCount + 1; - // TODO - // curCmd->Op1.Data=FilterType; - // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set - // do i need to ? - // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " - // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; - // CodeSize=0; - } - int dataFlag = GetBits(); - AddBits(1); - - // Read static data contained in DB operators. This data cannot be - // changed, - // it is a part of VM code, not a filter parameter. - - if ((dataFlag & 0x8000) != 0) - { - long dataSize = (long) ((long) ReadData(this) & 0xffFFffFFL + 1L); - for (int i = 0; inAddr < codeSize && i < dataSize; i++) - { - prg.StaticData.Add((byte) (GetBits() >> 8)); - AddBits(8); - } - } - - while (inAddr < codeSize) - { - VMPreparedCommand curCmd = new VMPreparedCommand(); - int data = GetBits(); - if ((data & 0x8000) == 0) - { - curCmd.OpCode = (VMCommands) ((data >> 12)); - AddBits(4); - } - else - { - curCmd.OpCode = (VMCommands) ((data >> 10) - 24); - AddBits(6); - } - if ((VMCmdFlags.VM_CmdFlags[(int) curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0) - { - curCmd.IsByteMode = (GetBits() >> 15) == 1 ? true : false; - AddBits(1); - } - else - { - curCmd.IsByteMode = false; - } - curCmd.Op1.Type = VMOpType.VM_OPNONE; - curCmd.Op2.Type = VMOpType.VM_OPNONE; - - int opNum = (VMCmdFlags.VM_CmdFlags[(int) curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK); - // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) - { - decodeArg(curCmd.Op1, curCmd.IsByteMode); - if (opNum == 2) - decodeArg(curCmd.Op2, curCmd.IsByteMode); - else - { - if (curCmd.Op1.Type == VMOpType.VM_OPINT && - (VMCmdFlags.VM_CmdFlags[(int) curCmd.OpCode] & - (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) - { - int distance = curCmd.Op1.Data; - if (distance >= 256) - distance -= 256; - else - { - if (distance >= 136) - { - distance -= 264; - } - else - { - if (distance >= 16) - { - distance -= 8; - } - else - { - if (distance >= 8) - { - distance -= 16; - } - } - } - distance += prg.CommandCount; - } - curCmd.Op1.Data = distance; - } - } - } - prg.CommandCount = (prg.CommandCount + 1); - prg.Commands.Add(curCmd); - } - } - VMPreparedCommand curCmd2 = new VMPreparedCommand(); - curCmd2.OpCode = VMCommands.VM_RET; - // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; - // CurCmd->Op2.Addr=&CurCmd->Op2.Data; - curCmd2.Op1.Type = VMOpType.VM_OPNONE; - curCmd2.Op2.Type = VMOpType.VM_OPNONE; - - // for (int i=0;iCmd[I]; - // if (Cmd->Op1.Addr==NULL) - // Cmd->Op1.Addr=&Cmd->Op1.Data; - // if (Cmd->Op2.Addr==NULL) - // Cmd->Op2.Addr=&Cmd->Op2.Data; - // } - - prg.Commands.Add(curCmd2); - prg.CommandCount = prg.CommandCount + 1; - // #ifdef VM_OPTIMIZE - if (codeSize != 0) - { - optimize(prg); - } - } - - private void decodeArg(VMPreparedOperand op, bool byteMode) - { - int data = GetBits(); - if ((data & 0x8000) != 0) - { - op.Type = VMOpType.VM_OPREG; - op.Data = (data >> 12) & 7; - op.Offset = op.Data; - AddBits(4); - } - else - { - if ((data & 0xc000) == 0) - { - op.Type = VMOpType.VM_OPINT; - if (byteMode) - { - op.Data = (data >> 6) & 0xff; - AddBits(10); - } - else - { - AddBits(2); - op.Data = ReadData(this); - } - } - else - { - op.Type = VMOpType.VM_OPREGMEM; - if ((data & 0x2000) == 0) - { - op.Data = (data >> 10) & 7; - op.Offset = op.Data; - op.Base = 0; - AddBits(6); - } - else - { - if ((data & 0x1000) == 0) - { - op.Data = (data >> 9) & 7; - op.Offset = op.Data; - AddBits(7); - } - else - { - op.Data = 0; - AddBits(4); - } - op.Base = ReadData(this); - } - } - } - } - - private void optimize(VMPreparedProgram prg) - { - //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" - - List commands = prg.Commands; - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - foreach (VMPreparedCommand cmd in commands) - { - switch (cmd.OpCode) - { - case VMCommands.VM_MOV: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_MOVB : VMCommands.VM_MOVD; - continue; - - case VMCommands.VM_CMP: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_CMPB : VMCommands.VM_CMPD; - continue; - } - if ((VMCmdFlags.VM_CmdFlags[(int) cmd.OpCode] & VMCmdFlags.VMCF_CHFLAGS) == 0) - { - continue; - } - bool flagsRequired = false; - - for (int i = commands.IndexOf(cmd) + 1; i < commands.Count; i++) - { - int flags = VMCmdFlags.VM_CmdFlags[(int) commands[i].OpCode]; - if ((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) - { - flagsRequired = true; - break; - } - if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) - { - break; - } - } - if (flagsRequired) - { - continue; - } - switch (cmd.OpCode) - { - case VMCommands.VM_ADD: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_ADDB : VMCommands.VM_ADDD; - continue; - - case VMCommands.VM_SUB: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_SUBB : VMCommands.VM_SUBD; - continue; - - case VMCommands.VM_INC: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_INCB : VMCommands.VM_INCD; - continue; - - case VMCommands.VM_DEC: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_DECB : VMCommands.VM_DECD; - continue; - - case VMCommands.VM_NEG: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_NEGB : VMCommands.VM_NEGD; - continue; - } - } - } - - internal static int ReadData(BitInput rarVM) - { - int data = rarVM.GetBits(); - switch (data & 0xc000) - { - case 0: - rarVM.AddBits(6); - return ((data >> 10) & 0xf); - - case 0x4000: - if ((data & 0x3c00) == 0) - { - data = unchecked((int) 0xffffff00) | ((data >> 2) & 0xff); - rarVM.AddBits(14); - } - else - { - data = (data >> 6) & 0xff; - rarVM.AddBits(10); - } - return (data); - - case 0x8000: - rarVM.AddBits(2); - data = rarVM.GetBits(); - rarVM.AddBits(16); - return (data); - - default: - rarVM.AddBits(2); - data = (rarVM.GetBits() << 16); - rarVM.AddBits(16); - data |= rarVM.GetBits(); - rarVM.AddBits(16); - return (data); - } - } - - private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) - { - VMStandardFilterSignature[] stdList = new VMStandardFilterSignature[] - { - new VMStandardFilterSignature(53, 0xad576887, - VMStandardFilters.VMSF_E8), - new VMStandardFilterSignature(57, 0x3cd7e57e, - VMStandardFilters.VMSF_E8E9), - new VMStandardFilterSignature(120, 0x3769893f, - VMStandardFilters.VMSF_ITANIUM), - new VMStandardFilterSignature(29, 0x0e06077d, - VMStandardFilters.VMSF_DELTA), - new VMStandardFilterSignature(149, 0x1c2c5dc8, - VMStandardFilters.VMSF_RGB), - new VMStandardFilterSignature(216, 0xbc85e701, - VMStandardFilters.VMSF_AUDIO), - new VMStandardFilterSignature(40, 0x46b9c560, - VMStandardFilters.VMSF_UPCASE) - }; - uint CodeCRC = RarCRC.CheckCrc(0xffffffff, code, 0, code.Length) ^ 0xffffffff; - for (int i = 0; i < stdList.Length; i++) - { - if (stdList[i].CRC == CodeCRC && stdList[i].Length == code.Length) - { - return (stdList[i].Type); - } - } - return (VMStandardFilters.VMSF_NONE); - } - - private void ExecuteStandardFilter(VMStandardFilters filterType) - { - switch (filterType) - { - case VMStandardFilters.VMSF_E8: - case VMStandardFilters.VMSF_E8E9: - { - int dataSize = R[4]; - long fileOffset = R[6] & unchecked((int) 0xFFffFFff); - - if (dataSize >= VM_GLOBALMEMADDR) - { - break; - } - int fileSize = 0x1000000; - byte cmpByte2 = (byte) ((filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8); - for (int curPos = 0; curPos < dataSize - 4;) - { - byte curByte = Mem[curPos++]; - if (curByte == 0xe8 || curByte == cmpByte2) - { - // #ifdef PRESENT_INT32 - // sint32 Offset=CurPos+FileOffset; - // sint32 Addr=GET_VALUE(false,Data); - // if (Addr<0) - // { - // if (Addr+Offset>=0) - // SET_VALUE(false,Data,Addr+FileSize); - // } - // else - // if (Addr= VM_GLOBALMEMADDR) - { - break; - } - int curPos = 0; - //UPGRADE_NOTE: Final was removed from the declaration of 'Masks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - byte[] Masks = new byte[] {4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0}; - fileOffset = Utility.URShift(fileOffset, 4); - - while (curPos < dataSize - 21) - { - int Byte = (Mem[curPos] & 0x1f) - 0x10; - if (Byte >= 0) - { - byte cmdMask = Masks[Byte]; - if (cmdMask != 0) - for (int i = 0; i <= 2; i++) - if ((cmdMask & (1 << i)) != 0) - { - int startPos = i*41 + 5; - int opType = filterItanium_GetBits(curPos, startPos + 37, 4); - if (opType == 5) - { - int offset = filterItanium_GetBits(curPos, startPos + 13, 20); - filterItanium_SetBits(curPos, (int) (offset - fileOffset) & 0xfffff, - startPos + 13, 20); - } - } - } - curPos += 16; - fileOffset++; - } - } - break; - - case VMStandardFilters.VMSF_DELTA: - { - int dataSize = R[4] & unchecked((int) 0xFFffFFff); - int channels = R[0] & unchecked((int) 0xFFffFFff); - int srcPos = 0; - int border = (dataSize*2) & unchecked((int) 0xFFffFFff); - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, (int) dataSize); - if (dataSize >= VM_GLOBALMEMADDR/2) - { - break; - } - // bytes from same channels are grouped to continual data blocks, - // so we need to place them back to their interleaving positions - - for (int curChannel = 0; curChannel < channels; curChannel++) - { - byte PrevByte = 0; - for (int destPos = dataSize + curChannel; destPos < border; destPos += channels) - { - Mem[destPos] = (PrevByte = (byte) (PrevByte - Mem[srcPos++])); - } - } - } - break; - - case VMStandardFilters.VMSF_RGB: - { - // byte *SrcData=Mem,*DestData=SrcData+DataSize; - int dataSize = R[4], width = R[0] - 3, posR = R[1]; - int channels = 3; - int srcPos = 0; - int destDataPos = dataSize; - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR/2 || posR < 0) - { - break; - } - for (int curChannel = 0; curChannel < channels; curChannel++) - { - long prevByte = 0; - - for (int i = curChannel; i < dataSize; i += channels) - { - long predicted; - int upperPos = i - width; - if (upperPos >= 3) - { - int upperDataPos = destDataPos + upperPos; - int upperByte = Mem[(int) upperDataPos] & 0xff; - int upperLeftByte = Mem[upperDataPos - 3] & 0xff; - predicted = prevByte + upperByte - upperLeftByte; - int pa = System.Math.Abs((int) (predicted - prevByte)); - int pb = System.Math.Abs((int) (predicted - upperByte)); - int pc = System.Math.Abs((int) (predicted - upperLeftByte)); - if (pa <= pb && pa <= pc) - { - predicted = prevByte; - } - else - { - if (pb <= pc) - { - predicted = upperByte; - } - else - { - predicted = upperLeftByte; - } - } - } - else - { - predicted = prevByte; - } - - prevByte = (predicted - Mem[srcPos++] & 0xff) & 0xff; - Mem[destDataPos + i] = (byte) (prevByte & 0xff); - } - } - for (int i = posR, border = dataSize - 2; i < border; i += 3) - { - byte G = Mem[destDataPos + i + 1]; - Mem[destDataPos + i] = (byte) (Mem[destDataPos + i] + G); - Mem[destDataPos + i + 2] = (byte) (Mem[destDataPos + i + 2] + G); - } - } - break; - - case VMStandardFilters.VMSF_AUDIO: - { - int dataSize = R[4], channels = R[0]; - int srcPos = 0; - int destDataPos = dataSize; - //byte *SrcData=Mem,*DestData=SrcData+DataSize; - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR/2) - { - break; - } - for (int curChannel = 0; curChannel < channels; curChannel++) - { - long prevByte = 0; - long prevDelta = 0; - long[] Dif = new long[7]; - int D1 = 0, D2 = 0, D3; - int K1 = 0, K2 = 0, K3 = 0; - - for (int i = curChannel, byteCount = 0; i < dataSize; i += channels, byteCount++) - { - D3 = D2; - D2 = (int) (prevDelta - D1); - D1 = (int) prevDelta; - - long predicted = 8*prevByte + K1*D1 + K2*D2 + K3*D3; - predicted = Utility.URShift(predicted, 3) & 0xff; - - long curByte = (long) (Mem[srcPos++]); - - predicted -= curByte; - Mem[destDataPos + i] = (byte) predicted; - prevDelta = (byte) (predicted - prevByte); - //fix java byte - if (prevDelta >= 128) - { - prevDelta = 0 - (256 - prevDelta); - } - prevByte = predicted; - //fix java byte - if (curByte >= 128) - { - curByte = 0 - (256 - curByte); - } - int D = ((int) curByte) << 3; - - Dif[0] += System.Math.Abs(D); - Dif[1] += System.Math.Abs(D - D1); - Dif[2] += System.Math.Abs(D + D1); - Dif[3] += System.Math.Abs(D - D2); - Dif[4] += System.Math.Abs(D + D2); - Dif[5] += System.Math.Abs(D - D3); - Dif[6] += System.Math.Abs(D + D3); - - if ((byteCount & 0x1f) == 0) - { - long minDif = Dif[0], numMinDif = 0; - Dif[0] = 0; - for (int j = 1; j < Dif.Length; j++) - { - if (Dif[j] < minDif) - { - minDif = Dif[j]; - numMinDif = j; - } - Dif[j] = 0; - } - switch ((int) numMinDif) - { - case 1: - if (K1 >= -16) - K1--; - break; - - case 2: - if (K1 < 16) - K1++; - break; - - case 3: - if (K2 >= -16) - K2--; - break; - - case 4: - if (K2 < 16) - K2++; - break; - - case 5: - if (K3 >= -16) - K3--; - break; - - case 6: - if (K3 < 16) - K3++; - break; - } - } - } - } - } - break; - - case VMStandardFilters.VMSF_UPCASE: - { - int dataSize = R[4], srcPos = 0, destPos = dataSize; - if (dataSize >= VM_GLOBALMEMADDR/2) - { - break; - } - while (srcPos < dataSize) - { - byte curByte = Mem[srcPos++]; - if (curByte == 2 && (curByte = Mem[srcPos++]) != 2) - { - curByte = (byte) (curByte - 32); - } - Mem[destPos++] = curByte; - } - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - } - break; - } - } - - private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) - { - int inAddr = bitPos/8; - int inBit = bitPos & 7; - int andMask = Utility.URShift(unchecked((int) 0xffffffff), (32 - bitCount)); - andMask = ~(andMask << inBit); - - bitField <<= inBit; - - for (int i = 0; i < 4; i++) - { - Mem[curPos + inAddr + i] &= (byte) (andMask); - Mem[curPos + inAddr + i] |= (byte) (bitField); - andMask = (Utility.URShift(andMask, 8)) | unchecked((int) 0xff000000); - bitField = Utility.URShift(bitField, 8); - } - } - - private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) - { - int inAddr = bitPos/8; - int inBit = bitPos & 7; - int bitField = (int) (Mem[curPos + inAddr++] & 0xff); - bitField |= (int) ((Mem[curPos + inAddr++] & 0xff) << 8); - bitField |= (int) ((Mem[curPos + inAddr++] & 0xff) << 16); - bitField |= (int) ((Mem[curPos + inAddr] & 0xff) << 24); - bitField = Utility.URShift(bitField, inBit); - return (bitField & (Utility.URShift(unchecked((int) 0xffffffff), (32 - bitCount)))); - } - - - public virtual void setMemory(int pos, byte[] data, int offset, int dataSize) - { - if (pos < VM_MEMSIZE) - { - //&& data!=Mem+Pos) - //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); - for (int i = 0; i < System.Math.Min(data.Length - offset, dataSize); i++) - { - if ((VM_MEMSIZE - pos) < i) - { - break; - } - Mem[pos + i] = data[offset + i]; - } - } - } - } - - // +using System; +using System.Collections.Generic; + +namespace SharpCompress.Compressor.Rar.VM +{ + internal class RarVM : BitInput + { + //private void InitBlock() + //{ + // Mem.set_Renamed(offset + 0, Byte.valueOf((sbyte) (value_Renamed & 0xff))); + // Mem.set_Renamed(offset + 1, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 8)) & 0xff))); + // Mem.set_Renamed(offset + 2, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 16)) & 0xff))); + // Mem.set_Renamed(offset + 3, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 24)) & 0xff))); + + + //} + internal byte[] Mem { get; private set; } + + public const int VM_MEMSIZE = 0x40000; + + //UPGRADE_NOTE: Final was removed from the declaration of 'VM_MEMMASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int VM_MEMMASK = (VM_MEMSIZE - 1); + + public const int VM_GLOBALMEMADDR = 0x3C000; + + public const int VM_GLOBALMEMSIZE = 0x2000; + + public const int VM_FIXEDGLOBALSIZE = 64; + + private const int regCount = 8; + + private const long UINT_MASK = 0xffffFFFF; //((long)2*(long)Integer.MAX_VALUE); + + private int[] R = new int[regCount]; + + private VMFlags flags; + + private int maxOpCount = 25000000; + + private int codeSize; + + private int IP; + + internal RarVM() + { + //InitBlock(); + Mem = null; + } + + internal void init() + { + if (Mem == null) + { + Mem = new byte[VM_MEMSIZE + 4]; + } + } + + private bool IsVMMem(byte[] mem) + { + return this.Mem == mem; + } + + private int GetValue(bool byteMode, byte[] mem, int offset) + { + if (byteMode) + { + if (IsVMMem(mem)) + { + return (mem[offset]); + } + else + { + return (mem[offset] & 0xff); + } + } + else + { + if (IsVMMem(mem)) + { + return Utility.readIntLittleEndian(mem, offset); + } + else + { + return Utility.readIntBigEndian(mem, offset); + } + } + } + + private void SetValue(bool byteMode, byte[] mem, int offset, int value) + { + if (byteMode) + { + if (IsVMMem(mem)) + { + mem[offset] = (byte) value; + } + else + { + mem[offset] = (byte) ((mem[offset] & 0x00) | (byte) (value & 0xff)); + } + } + else + { + if (IsVMMem(mem)) + { + Utility.WriteLittleEndian(mem, offset, value); + // Mem[offset + 0] = (byte) value; + // Mem[offset + 1] = (byte) (value >>> 8); + // Mem[offset + 2] = (byte) (value >>> 16); + // Mem[offset + 3] = (byte) (value >>> 24); + } + else + { + Utility.writeIntBigEndian(mem, offset, value); + // Mem[offset + 3] = (byte) value; + // Mem[offset + 2] = (byte) (value >>> 8); + // Mem[offset + 1] = (byte) (value >>> 16); + // Mem[offset + 0] = (byte) (value >>> 24); + } + } + // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint + // *)Addr,Value) + } + + internal void SetLowEndianValue(List mem, int offset, int value) + { + mem[offset + 0] = (byte) (value & 0xff); + mem[offset + 1] = (byte) (Utility.URShift(value, 8) & 0xff); + mem[offset + 2] = (byte) (Utility.URShift(value, 16) & 0xff); + mem[offset + 3] = (byte) (Utility.URShift(value, 24) & 0xff); + } + + private int GetOperand(VMPreparedOperand cmdOp) + { + int ret = 0; + if (cmdOp.Type == VMOpType.VM_OPREGMEM) + { + int pos = (cmdOp.Offset + cmdOp.Base) & VM_MEMMASK; + ret = Utility.readIntLittleEndian(Mem, pos); + } + else + { + int pos = cmdOp.Offset; + ret = Utility.readIntLittleEndian(Mem, pos); + } + return ret; + } + + public void execute(VMPreparedProgram prg) + { + for (int i = 0; i < prg.InitR.Length; i++) + // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); + { + R[i] = prg.InitR[i]; + } + + long globalSize = (long) (Math.Min(prg.GlobalData.Count, VM_GLOBALMEMSIZE)) & 0xffFFffFF; + if (globalSize != 0) + { + for (int i = 0; i < globalSize; i++) + // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); + { + Mem[VM_GLOBALMEMADDR + i] = prg.GlobalData[i]; + } + } + long staticSize = (long) (Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize)) & 0xffFFffFF; + if (staticSize != 0) + { + for (int i = 0; i < staticSize; i++) + // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); + { + Mem[VM_GLOBALMEMADDR + (int) globalSize + i] = prg.StaticData[i]; + } + } + R[7] = VM_MEMSIZE; + flags = 0; + + //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" + List preparedCode = prg.AltCommands.Count != 0 + ? prg + .AltCommands + : prg.Commands; + + if (!ExecuteCode(preparedCode, prg.CommandCount)) + { + preparedCode[0].OpCode = VMCommands.VM_RET; + } + int newBlockPos = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x20) & VM_MEMMASK; + int newBlockSize = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c) & VM_MEMMASK; + if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) + { + newBlockPos = 0; + newBlockSize = 0; + } + + prg.FilteredDataOffset = newBlockPos; + prg.FilteredDataSize = newBlockSize; + + prg.GlobalData.Clear(); + + int dataSize = Math.Min(GetValue(false, Mem, VM_GLOBALMEMADDR + 0x30), VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); + if (dataSize != 0) + { + //prg.GlobalData.Clear(); + // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); + prg.GlobalData.SetSize(dataSize + VM_FIXEDGLOBALSIZE); + for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) + // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); + { + prg.GlobalData[i] = Mem[VM_GLOBALMEMADDR + i]; + } + } + } + + private bool setIP(int ip) + { + if ((ip) >= codeSize) + { + return (true); + } + + if (--maxOpCount <= 0) + { + return (false); + } + + IP = ip; + return true; + } + + private bool ExecuteCode(List preparedCode, + int cmdCount) + { + maxOpCount = 25000000; + this.codeSize = cmdCount; + this.IP = 0; + + while (true) + { + VMPreparedCommand cmd = preparedCode[IP]; + int op1 = GetOperand(cmd.Op1); + int op2 = GetOperand(cmd.Op2); + switch (cmd.OpCode) + { + case VMCommands.VM_MOV: + SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); + // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + break; + + case VMCommands.VM_MOVB: + SetValue(true, Mem, op1, GetValue(true, Mem, op2)); + break; + + case VMCommands.VM_MOVD: + SetValue(false, Mem, op1, GetValue(false, Mem, op2)); + break; + + + case VMCommands.VM_CMP: + { + VMFlags value1 = (VMFlags) GetValue(cmd.IsByteMode, Mem, op1); + VMFlags result = value1 - GetValue(cmd.IsByteMode, Mem, op2); + + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags) ((result > value1) ? 1 : 0 | (int) (result & VMFlags.VM_FS)); + } + } + break; + + + case VMCommands.VM_CMPB: + { + VMFlags value1 = (VMFlags) GetValue(true, Mem, op1); + VMFlags result = value1 - GetValue(true, Mem, op2); + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags) ((result > value1) ? 1 : 0 | (int) (result & VMFlags.VM_FS)); + } + } + break; + + case VMCommands.VM_CMPD: + { + VMFlags value1 = (VMFlags) GetValue(false, Mem, op1); + VMFlags result = value1 - GetValue(false, Mem, op2); + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags) ((result > value1) ? 1 : 0 | (int) (result & VMFlags.VM_FS)); + } + } + break; + + + case VMCommands.VM_ADD: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + int result = + (int) + ((((long) value1 + (long) GetValue(cmd.IsByteMode, Mem, op2))) & + unchecked((int) 0xffffffff)); + if (cmd.IsByteMode) + { + result &= 0xff; + flags = + (VMFlags) + ((result < value1) + ? 1 + : 0 | + (result == 0 + ? (int) VMFlags.VM_FZ + : (((result & 0x80) != 0) ? (int) VMFlags.VM_FS : 0))); + // Flags=(Result value1) ? 1 : 0 | (result & (int) VMFlags.VM_FS))); + SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); + } + break; + + + case VMCommands.VM_SUBB: + SetValue(true, Mem, op1, + (int) + ((long) GetValue(true, Mem, op1) & 0xFFffFFff - (long) GetValue(true, Mem, op2) & + unchecked((int) 0xFFffFFff))); + break; + + case VMCommands.VM_SUBD: + SetValue(false, Mem, op1, + (int) + ((long) GetValue(false, Mem, op1) & 0xFFffFFff - (long) GetValue(false, Mem, op2) & + unchecked((int) 0xFFffFFff))); + break; + + + case VMCommands.VM_JZ: + if ((flags & VMFlags.VM_FZ) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JNZ: + if ((flags & VMFlags.VM_FZ) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_INC: + { + int result = (int) ((long) GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFffL + 1L); + if (cmd.IsByteMode) + { + result &= 0xff; + } + + SetValue(cmd.IsByteMode, Mem, op1, result); + flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); + } + break; + + + case VMCommands.VM_INCB: + SetValue(true, Mem, op1, (int) ((long) GetValue(true, Mem, op1) & 0xFFffFFffL + 1L)); + break; + + case VMCommands.VM_INCD: + SetValue(false, Mem, op1, (int) ((long) GetValue(false, Mem, op1) & 0xFFffFFffL + 1L)); + break; + + + case VMCommands.VM_DEC: + { + int result = (int) ((long) GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFff - 1); + SetValue(cmd.IsByteMode, Mem, op1, result); + flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); + } + break; + + + case VMCommands.VM_DECB: + SetValue(true, Mem, op1, (int) ((long) GetValue(true, Mem, op1) & 0xFFffFFff - 1)); + break; + + case VMCommands.VM_DECD: + SetValue(false, Mem, op1, (int) ((long) GetValue(false, Mem, op1) & 0xFFffFFff - 1)); + break; + + + case VMCommands.VM_JMP: + setIP(GetValue(false, Mem, op1)); + continue; + + case VMCommands.VM_XOR: + { + int result = GetValue(cmd.IsByteMode, Mem, op1) ^ GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_AND: + { + int result = GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_OR: + { + int result = GetValue(cmd.IsByteMode, Mem, op1) | GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_TEST: + { + int result = GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags) (result == 0 ? (int) VMFlags.VM_FZ : result & (int) VMFlags.VM_FS); + } + break; + + case VMCommands.VM_JS: + if ((flags & VMFlags.VM_FS) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JNS: + if ((flags & VMFlags.VM_FS) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JB: + if ((flags & VMFlags.VM_FC) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JBE: + if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JA: + if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JAE: + if ((flags & VMFlags.VM_FC) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_PUSH: + R[7] -= 4; + SetValue(false, Mem, R[7] & VM_MEMMASK, GetValue(false, Mem, op1)); + break; + + case VMCommands.VM_POP: + SetValue(false, Mem, op1, GetValue(false, Mem, R[7] & VM_MEMMASK)); + R[7] += 4; + break; + + case VMCommands.VM_CALL: + R[7] -= 4; + SetValue(false, Mem, R[7] & VM_MEMMASK, IP + 1); + setIP(GetValue(false, Mem, op1)); + continue; + + case VMCommands.VM_NOT: + SetValue(cmd.IsByteMode, Mem, op1, ~GetValue(cmd.IsByteMode, Mem, op1)); + break; + + case VMCommands.VM_SHL: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + int value2 = GetValue(cmd.IsByteMode, Mem, op2); + int result = value1 << value2; + flags = + (VMFlags) + ((result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS)) | + (((value1 << (value2 - 1)) & unchecked((int) 0x80000000)) != 0 + ? (int) VMFlags.VM_FC + : 0)); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_SHR: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + int value2 = GetValue(cmd.IsByteMode, Mem, op2); + int result = Utility.URShift(value1, value2); + flags = + (VMFlags) + ((result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS)) | + ((Utility.URShift(value1, (value2 - 1))) & (int) VMFlags.VM_FC)); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_SAR: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + int value2 = GetValue(cmd.IsByteMode, Mem, op2); + int result = ((int) value1) >> value2; + flags = + (VMFlags) + ((result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS)) | + ((value1 >> (value2 - 1)) & (int) VMFlags.VM_FC)); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_NEG: + { + int result = -GetValue(cmd.IsByteMode, Mem, op1); + flags = + (VMFlags) + (result == 0 + ? (int) VMFlags.VM_FZ + : (int) VMFlags.VM_FC | (result & (int) VMFlags.VM_FS)); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + + case VMCommands.VM_NEGB: + SetValue(true, Mem, op1, -GetValue(true, Mem, op1)); + break; + + case VMCommands.VM_NEGD: + SetValue(false, Mem, op1, -GetValue(false, Mem, op1)); + break; + + case VMCommands.VM_PUSHA: + { + for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) + { + SetValue(false, Mem, SP & VM_MEMMASK, R[i]); + } + R[7] -= regCount*4; + } + break; + + case VMCommands.VM_POPA: + { + for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) + R[7 - i] = GetValue(false, Mem, SP & VM_MEMMASK); + } + break; + + case VMCommands.VM_PUSHF: + R[7] -= 4; + SetValue(false, Mem, R[7] & VM_MEMMASK, (int) flags); + break; + + case VMCommands.VM_POPF: + flags = (VMFlags) GetValue(false, Mem, R[7] & VM_MEMMASK); + R[7] += 4; + break; + + case VMCommands.VM_MOVZX: + SetValue(false, Mem, op1, GetValue(true, Mem, op2)); + break; + + case VMCommands.VM_MOVSX: + SetValue(false, Mem, op1, (byte) GetValue(true, Mem, op2)); + break; + + case VMCommands.VM_XCHG: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); + SetValue(cmd.IsByteMode, Mem, op2, value1); + } + break; + + case VMCommands.VM_MUL: + { + int result = + (int) + (((long) GetValue(cmd.IsByteMode, Mem, op1) & + 0xFFffFFff*(long) GetValue(cmd.IsByteMode, Mem, op2) & unchecked((int) 0xFFffFFff)) & + unchecked((int) 0xFFffFFff)); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_DIV: + { + int divider = GetValue(cmd.IsByteMode, Mem, op2); + if (divider != 0) + { + int result = GetValue(cmd.IsByteMode, Mem, op1)/divider; + SetValue(cmd.IsByteMode, Mem, op1, result); + } + } + break; + + case VMCommands.VM_ADC: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + int FC = (int) (flags & VMFlags.VM_FC); + int result = + (int) + ((long) value1 & 0xFFffFFff + (long) GetValue(cmd.IsByteMode, Mem, op2) & + 0xFFffFFff + (long) FC & unchecked((int) 0xFFffFFff)); + if (cmd.IsByteMode) + { + result &= 0xff; + } + + flags = + (VMFlags) + ((result < value1 || result == value1 && FC != 0) + ? 1 + : 0 | (result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS))); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_SBB: + { + int value1 = GetValue(cmd.IsByteMode, Mem, op1); + int FC = (int) (flags & VMFlags.VM_FC); + int result = + (int) + ((long) value1 & 0xFFffFFff - (long) GetValue(cmd.IsByteMode, Mem, op2) & + 0xFFffFFff - (long) FC & unchecked((int) 0xFFffFFff)); + if (cmd.IsByteMode) + { + result &= 0xff; + } + flags = + (VMFlags) + ((result > value1 || result == value1 && FC != 0) + ? 1 + : 0 | (result == 0 ? (int) VMFlags.VM_FZ : (result & (int) VMFlags.VM_FS))); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + + case VMCommands.VM_RET: + if (R[7] >= VM_MEMSIZE) + { + return (true); + } + setIP(GetValue(false, Mem, R[7] & VM_MEMMASK)); + R[7] += 4; + continue; + + + case VMCommands.VM_STANDARD: + ExecuteStandardFilter((VMStandardFilters) (cmd.Op1.Data)); + break; + + case VMCommands.VM_PRINT: + break; + } + IP++; + --maxOpCount; + } + } + + public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) + { + InitBitInput(); + int cpLength = System.Math.Min(MAX_SIZE, codeSize); + // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + + Buffer.BlockCopy(code, 0, InBuf, 0, cpLength); + byte xorSum = 0; + for (int i = 1; i < codeSize; i++) + { + xorSum ^= code[i]; + } + + AddBits(8); + + prg.CommandCount = 0; + if (xorSum == code[0]) + { + VMStandardFilters filterType = IsStandardFilter(code, codeSize); + if (filterType != VMStandardFilters.VMSF_NONE) + { + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.OpCode = VMCommands.VM_STANDARD; + curCmd.Op1.Data = (int) filterType; + curCmd.Op1.Type = VMOpType.VM_OPNONE; + curCmd.Op2.Type = VMOpType.VM_OPNONE; + codeSize = 0; + prg.Commands.Add(curCmd); + prg.CommandCount = prg.CommandCount + 1; + // TODO + // curCmd->Op1.Data=FilterType; + // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set + // do i need to ? + // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " + // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + // CodeSize=0; + } + int dataFlag = GetBits(); + AddBits(1); + + // Read static data contained in DB operators. This data cannot be + // changed, + // it is a part of VM code, not a filter parameter. + + if ((dataFlag & 0x8000) != 0) + { + long dataSize = (long) ((long) ReadData(this) & 0xffFFffFFL + 1L); + for (int i = 0; inAddr < codeSize && i < dataSize; i++) + { + prg.StaticData.Add((byte) (GetBits() >> 8)); + AddBits(8); + } + } + + while (inAddr < codeSize) + { + VMPreparedCommand curCmd = new VMPreparedCommand(); + int data = GetBits(); + if ((data & 0x8000) == 0) + { + curCmd.OpCode = (VMCommands) ((data >> 12)); + AddBits(4); + } + else + { + curCmd.OpCode = (VMCommands) ((data >> 10) - 24); + AddBits(6); + } + if ((VMCmdFlags.VM_CmdFlags[(int) curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0) + { + curCmd.IsByteMode = (GetBits() >> 15) == 1 ? true : false; + AddBits(1); + } + else + { + curCmd.IsByteMode = false; + } + curCmd.Op1.Type = VMOpType.VM_OPNONE; + curCmd.Op2.Type = VMOpType.VM_OPNONE; + + int opNum = (VMCmdFlags.VM_CmdFlags[(int) curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK); + // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) + { + decodeArg(curCmd.Op1, curCmd.IsByteMode); + if (opNum == 2) + decodeArg(curCmd.Op2, curCmd.IsByteMode); + else + { + if (curCmd.Op1.Type == VMOpType.VM_OPINT && + (VMCmdFlags.VM_CmdFlags[(int) curCmd.OpCode] & + (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) + { + int distance = curCmd.Op1.Data; + if (distance >= 256) + distance -= 256; + else + { + if (distance >= 136) + { + distance -= 264; + } + else + { + if (distance >= 16) + { + distance -= 8; + } + else + { + if (distance >= 8) + { + distance -= 16; + } + } + } + distance += prg.CommandCount; + } + curCmd.Op1.Data = distance; + } + } + } + prg.CommandCount = (prg.CommandCount + 1); + prg.Commands.Add(curCmd); + } + } + VMPreparedCommand curCmd2 = new VMPreparedCommand(); + curCmd2.OpCode = VMCommands.VM_RET; + // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; + // CurCmd->Op2.Addr=&CurCmd->Op2.Data; + curCmd2.Op1.Type = VMOpType.VM_OPNONE; + curCmd2.Op2.Type = VMOpType.VM_OPNONE; + + // for (int i=0;iCmd[I]; + // if (Cmd->Op1.Addr==NULL) + // Cmd->Op1.Addr=&Cmd->Op1.Data; + // if (Cmd->Op2.Addr==NULL) + // Cmd->Op2.Addr=&Cmd->Op2.Data; + // } + + prg.Commands.Add(curCmd2); + prg.CommandCount = prg.CommandCount + 1; + // #ifdef VM_OPTIMIZE + if (codeSize != 0) + { + optimize(prg); + } + } + + private void decodeArg(VMPreparedOperand op, bool byteMode) + { + int data = GetBits(); + if ((data & 0x8000) != 0) + { + op.Type = VMOpType.VM_OPREG; + op.Data = (data >> 12) & 7; + op.Offset = op.Data; + AddBits(4); + } + else + { + if ((data & 0xc000) == 0) + { + op.Type = VMOpType.VM_OPINT; + if (byteMode) + { + op.Data = (data >> 6) & 0xff; + AddBits(10); + } + else + { + AddBits(2); + op.Data = ReadData(this); + } + } + else + { + op.Type = VMOpType.VM_OPREGMEM; + if ((data & 0x2000) == 0) + { + op.Data = (data >> 10) & 7; + op.Offset = op.Data; + op.Base = 0; + AddBits(6); + } + else + { + if ((data & 0x1000) == 0) + { + op.Data = (data >> 9) & 7; + op.Offset = op.Data; + AddBits(7); + } + else + { + op.Data = 0; + AddBits(4); + } + op.Base = ReadData(this); + } + } + } + } + + private void optimize(VMPreparedProgram prg) + { + //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" + + List commands = prg.Commands; + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + foreach (VMPreparedCommand cmd in commands) + { + switch (cmd.OpCode) + { + case VMCommands.VM_MOV: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_MOVB : VMCommands.VM_MOVD; + continue; + + case VMCommands.VM_CMP: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_CMPB : VMCommands.VM_CMPD; + continue; + } + if ((VMCmdFlags.VM_CmdFlags[(int) cmd.OpCode] & VMCmdFlags.VMCF_CHFLAGS) == 0) + { + continue; + } + bool flagsRequired = false; + + for (int i = commands.IndexOf(cmd) + 1; i < commands.Count; i++) + { + int flags = VMCmdFlags.VM_CmdFlags[(int) commands[i].OpCode]; + if ((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) + { + flagsRequired = true; + break; + } + if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) + { + break; + } + } + if (flagsRequired) + { + continue; + } + switch (cmd.OpCode) + { + case VMCommands.VM_ADD: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_ADDB : VMCommands.VM_ADDD; + continue; + + case VMCommands.VM_SUB: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_SUBB : VMCommands.VM_SUBD; + continue; + + case VMCommands.VM_INC: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_INCB : VMCommands.VM_INCD; + continue; + + case VMCommands.VM_DEC: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_DECB : VMCommands.VM_DECD; + continue; + + case VMCommands.VM_NEG: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_NEGB : VMCommands.VM_NEGD; + continue; + } + } + } + + internal static int ReadData(BitInput rarVM) + { + int data = rarVM.GetBits(); + switch (data & 0xc000) + { + case 0: + rarVM.AddBits(6); + return ((data >> 10) & 0xf); + + case 0x4000: + if ((data & 0x3c00) == 0) + { + data = unchecked((int) 0xffffff00) | ((data >> 2) & 0xff); + rarVM.AddBits(14); + } + else + { + data = (data >> 6) & 0xff; + rarVM.AddBits(10); + } + return (data); + + case 0x8000: + rarVM.AddBits(2); + data = rarVM.GetBits(); + rarVM.AddBits(16); + return (data); + + default: + rarVM.AddBits(2); + data = (rarVM.GetBits() << 16); + rarVM.AddBits(16); + data |= rarVM.GetBits(); + rarVM.AddBits(16); + return (data); + } + } + + private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) + { + VMStandardFilterSignature[] stdList = new VMStandardFilterSignature[] + { + new VMStandardFilterSignature(53, 0xad576887, + VMStandardFilters.VMSF_E8), + new VMStandardFilterSignature(57, 0x3cd7e57e, + VMStandardFilters.VMSF_E8E9), + new VMStandardFilterSignature(120, 0x3769893f, + VMStandardFilters.VMSF_ITANIUM), + new VMStandardFilterSignature(29, 0x0e06077d, + VMStandardFilters.VMSF_DELTA), + new VMStandardFilterSignature(149, 0x1c2c5dc8, + VMStandardFilters.VMSF_RGB), + new VMStandardFilterSignature(216, 0xbc85e701, + VMStandardFilters.VMSF_AUDIO), + new VMStandardFilterSignature(40, 0x46b9c560, + VMStandardFilters.VMSF_UPCASE) + }; + uint CodeCRC = RarCRC.CheckCrc(0xffffffff, code, 0, code.Length) ^ 0xffffffff; + for (int i = 0; i < stdList.Length; i++) + { + if (stdList[i].CRC == CodeCRC && stdList[i].Length == code.Length) + { + return (stdList[i].Type); + } + } + return (VMStandardFilters.VMSF_NONE); + } + + private void ExecuteStandardFilter(VMStandardFilters filterType) + { + switch (filterType) + { + case VMStandardFilters.VMSF_E8: + case VMStandardFilters.VMSF_E8E9: + { + int dataSize = R[4]; + long fileOffset = R[6] & unchecked((int) 0xFFffFFff); + + if (dataSize >= VM_GLOBALMEMADDR) + { + break; + } + int fileSize = 0x1000000; + byte cmpByte2 = (byte) ((filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8); + for (int curPos = 0; curPos < dataSize - 4;) + { + byte curByte = Mem[curPos++]; + if (curByte == 0xe8 || curByte == cmpByte2) + { + // #ifdef PRESENT_INT32 + // sint32 Offset=CurPos+FileOffset; + // sint32 Addr=GET_VALUE(false,Data); + // if (Addr<0) + // { + // if (Addr+Offset>=0) + // SET_VALUE(false,Data,Addr+FileSize); + // } + // else + // if (Addr= VM_GLOBALMEMADDR) + { + break; + } + int curPos = 0; + //UPGRADE_NOTE: Final was removed from the declaration of 'Masks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + byte[] Masks = new byte[] {4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0}; + fileOffset = Utility.URShift(fileOffset, 4); + + while (curPos < dataSize - 21) + { + int Byte = (Mem[curPos] & 0x1f) - 0x10; + if (Byte >= 0) + { + byte cmdMask = Masks[Byte]; + if (cmdMask != 0) + for (int i = 0; i <= 2; i++) + if ((cmdMask & (1 << i)) != 0) + { + int startPos = i*41 + 5; + int opType = filterItanium_GetBits(curPos, startPos + 37, 4); + if (opType == 5) + { + int offset = filterItanium_GetBits(curPos, startPos + 13, 20); + filterItanium_SetBits(curPos, (int) (offset - fileOffset) & 0xfffff, + startPos + 13, 20); + } + } + } + curPos += 16; + fileOffset++; + } + } + break; + + case VMStandardFilters.VMSF_DELTA: + { + int dataSize = R[4] & unchecked((int) 0xFFffFFff); + int channels = R[0] & unchecked((int) 0xFFffFFff); + int srcPos = 0; + int border = (dataSize*2) & unchecked((int) 0xFFffFFff); + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, (int) dataSize); + if (dataSize >= VM_GLOBALMEMADDR/2) + { + break; + } + // bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions + + for (int curChannel = 0; curChannel < channels; curChannel++) + { + byte PrevByte = 0; + for (int destPos = dataSize + curChannel; destPos < border; destPos += channels) + { + Mem[destPos] = (PrevByte = (byte) (PrevByte - Mem[srcPos++])); + } + } + } + break; + + case VMStandardFilters.VMSF_RGB: + { + // byte *SrcData=Mem,*DestData=SrcData+DataSize; + int dataSize = R[4], width = R[0] - 3, posR = R[1]; + int channels = 3; + int srcPos = 0; + int destDataPos = dataSize; + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR/2 || posR < 0) + { + break; + } + for (int curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + + for (int i = curChannel; i < dataSize; i += channels) + { + long predicted; + int upperPos = i - width; + if (upperPos >= 3) + { + int upperDataPos = destDataPos + upperPos; + int upperByte = Mem[(int) upperDataPos] & 0xff; + int upperLeftByte = Mem[upperDataPos - 3] & 0xff; + predicted = prevByte + upperByte - upperLeftByte; + int pa = System.Math.Abs((int) (predicted - prevByte)); + int pb = System.Math.Abs((int) (predicted - upperByte)); + int pc = System.Math.Abs((int) (predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + { + predicted = prevByte; + } + else + { + if (pb <= pc) + { + predicted = upperByte; + } + else + { + predicted = upperLeftByte; + } + } + } + else + { + predicted = prevByte; + } + + prevByte = (predicted - Mem[srcPos++] & 0xff) & 0xff; + Mem[destDataPos + i] = (byte) (prevByte & 0xff); + } + } + for (int i = posR, border = dataSize - 2; i < border; i += 3) + { + byte G = Mem[destDataPos + i + 1]; + Mem[destDataPos + i] = (byte) (Mem[destDataPos + i] + G); + Mem[destDataPos + i + 2] = (byte) (Mem[destDataPos + i + 2] + G); + } + } + break; + + case VMStandardFilters.VMSF_AUDIO: + { + int dataSize = R[4], channels = R[0]; + int srcPos = 0; + int destDataPos = dataSize; + //byte *SrcData=Mem,*DestData=SrcData+DataSize; + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR/2) + { + break; + } + for (int curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + long prevDelta = 0; + long[] Dif = new long[7]; + int D1 = 0, D2 = 0, D3; + int K1 = 0, K2 = 0, K3 = 0; + + for (int i = curChannel, byteCount = 0; i < dataSize; i += channels, byteCount++) + { + D3 = D2; + D2 = (int) (prevDelta - D1); + D1 = (int) prevDelta; + + long predicted = 8*prevByte + K1*D1 + K2*D2 + K3*D3; + predicted = Utility.URShift(predicted, 3) & 0xff; + + long curByte = (long) (Mem[srcPos++]); + + predicted -= curByte; + Mem[destDataPos + i] = (byte) predicted; + prevDelta = (byte) (predicted - prevByte); + //fix java byte + if (prevDelta >= 128) + { + prevDelta = 0 - (256 - prevDelta); + } + prevByte = predicted; + //fix java byte + if (curByte >= 128) + { + curByte = 0 - (256 - curByte); + } + int D = ((int) curByte) << 3; + + Dif[0] += System.Math.Abs(D); + Dif[1] += System.Math.Abs(D - D1); + Dif[2] += System.Math.Abs(D + D1); + Dif[3] += System.Math.Abs(D - D2); + Dif[4] += System.Math.Abs(D + D2); + Dif[5] += System.Math.Abs(D - D3); + Dif[6] += System.Math.Abs(D + D3); + + if ((byteCount & 0x1f) == 0) + { + long minDif = Dif[0], numMinDif = 0; + Dif[0] = 0; + for (int j = 1; j < Dif.Length; j++) + { + if (Dif[j] < minDif) + { + minDif = Dif[j]; + numMinDif = j; + } + Dif[j] = 0; + } + switch ((int) numMinDif) + { + case 1: + if (K1 >= -16) + K1--; + break; + + case 2: + if (K1 < 16) + K1++; + break; + + case 3: + if (K2 >= -16) + K2--; + break; + + case 4: + if (K2 < 16) + K2++; + break; + + case 5: + if (K3 >= -16) + K3--; + break; + + case 6: + if (K3 < 16) + K3++; + break; + } + } + } + } + } + break; + + case VMStandardFilters.VMSF_UPCASE: + { + int dataSize = R[4], srcPos = 0, destPos = dataSize; + if (dataSize >= VM_GLOBALMEMADDR/2) + { + break; + } + while (srcPos < dataSize) + { + byte curByte = Mem[srcPos++]; + if (curByte == 2 && (curByte = Mem[srcPos++]) != 2) + { + curByte = (byte) (curByte - 32); + } + Mem[destPos++] = curByte; + } + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + } + break; + } + } + + private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) + { + int inAddr = bitPos/8; + int inBit = bitPos & 7; + int andMask = Utility.URShift(unchecked((int) 0xffffffff), (32 - bitCount)); + andMask = ~(andMask << inBit); + + bitField <<= inBit; + + for (int i = 0; i < 4; i++) + { + Mem[curPos + inAddr + i] &= (byte) (andMask); + Mem[curPos + inAddr + i] |= (byte) (bitField); + andMask = (Utility.URShift(andMask, 8)) | unchecked((int) 0xff000000); + bitField = Utility.URShift(bitField, 8); + } + } + + private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) + { + int inAddr = bitPos/8; + int inBit = bitPos & 7; + int bitField = (int) (Mem[curPos + inAddr++] & 0xff); + bitField |= (int) ((Mem[curPos + inAddr++] & 0xff) << 8); + bitField |= (int) ((Mem[curPos + inAddr++] & 0xff) << 16); + bitField |= (int) ((Mem[curPos + inAddr] & 0xff) << 24); + bitField = Utility.URShift(bitField, inBit); + return (bitField & (Utility.URShift(unchecked((int) 0xffffffff), (32 - bitCount)))); + } + + + public virtual void setMemory(int pos, byte[] data, int offset, int dataSize) + { + if (pos < VM_MEMSIZE) + { + //&& data!=Mem+Pos) + //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); + for (int i = 0; i < System.Math.Min(data.Length - offset, dataSize); i++) + { + if ((VM_MEMSIZE - pos) < i) + { + break; + } + Mem[pos + i] = data[offset + i]; + } + } + } + } + + // } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMCmdFlags.cs b/src/SharpCompress/Compressor/Rar/VM/VMCmdFlags.cs similarity index 98% rename from SharpCompress/Compressor/Rar/VM/VMCmdFlags.cs rename to src/SharpCompress/Compressor/Rar/VM/VMCmdFlags.cs index d22785a2..ebe947bb 100644 --- a/SharpCompress/Compressor/Rar/VM/VMCmdFlags.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMCmdFlags.cs @@ -1,46 +1,46 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal class VMCmdFlags - { - public const byte VMCF_OP0 = 0; - public const byte VMCF_OP1 = 1; - public const byte VMCF_OP2 = 2; - public const byte VMCF_OPMASK = 3; - public const byte VMCF_BYTEMODE = 4; - public const byte VMCF_JUMP = 8; - public const byte VMCF_PROC = 16; - public const byte VMCF_USEFLAGS = 32; - public const byte VMCF_CHFLAGS = 64; - - public static byte[] VM_CmdFlags = new byte[] - { - VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP1 | VMCF_JUMP, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1, VMCF_OP1, - VMCF_OP1 | VMCF_PROC, VMCF_OP0 | VMCF_PROC, VMCF_OP1 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP0, VMCF_OP0, - VMCF_OP0 | VMCF_USEFLAGS, VMCF_OP0 | VMCF_CHFLAGS, VMCF_OP2, VMCF_OP2, - VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, VMCF_OP0 - }; - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal class VMCmdFlags + { + public const byte VMCF_OP0 = 0; + public const byte VMCF_OP1 = 1; + public const byte VMCF_OP2 = 2; + public const byte VMCF_OPMASK = 3; + public const byte VMCF_BYTEMODE = 4; + public const byte VMCF_JUMP = 8; + public const byte VMCF_PROC = 16; + public const byte VMCF_USEFLAGS = 32; + public const byte VMCF_CHFLAGS = 64; + + public static byte[] VM_CmdFlags = new byte[] + { + VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP1 | VMCF_JUMP, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1, VMCF_OP1, + VMCF_OP1 | VMCF_PROC, VMCF_OP0 | VMCF_PROC, VMCF_OP1 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP0, VMCF_OP0, + VMCF_OP0 | VMCF_USEFLAGS, VMCF_OP0 | VMCF_CHFLAGS, VMCF_OP2, VMCF_OP2, + VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, VMCF_OP0 + }; + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMCommands.cs b/src/SharpCompress/Compressor/Rar/VM/VMCommands.cs similarity index 94% rename from SharpCompress/Compressor/Rar/VM/VMCommands.cs rename to src/SharpCompress/Compressor/Rar/VM/VMCommands.cs index 7daeba86..6af86b24 100644 --- a/SharpCompress/Compressor/Rar/VM/VMCommands.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMCommands.cs @@ -1,78 +1,78 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal enum VMCommands - { - VM_MOV = 0, - VM_CMP = 1, - VM_ADD = 2, - VM_SUB = 3, - VM_JZ = 4, - VM_JNZ = 5, - VM_INC = 6, - - VM_DEC = - 7, - VM_JMP = 8, - VM_XOR = 9, - VM_AND = 10, - VM_OR = 11, - VM_TEST = 12, - - VM_JS = - 13, - VM_JNS = 14, - VM_JB = 15, - VM_JBE = 16, - VM_JA = 17, - VM_JAE = 18, - - VM_PUSH = - 19, - VM_POP = 20, - VM_CALL = 21, - VM_RET = 22, - VM_NOT = 23, - VM_SHL = 24, - - VM_SHR = - 25, - VM_SAR = 26, - VM_NEG = 27, - VM_PUSHA = 28, - VM_POPA = 29, - VM_PUSHF = 30, - - VM_POPF = - 31, - VM_MOVZX = 32, - VM_MOVSX = 33, - VM_XCHG = 34, - VM_MUL = 35, - VM_DIV = 36, - - VM_ADC = - 37, - VM_SBB = 38, - VM_PRINT = 39, - - VM_MOVB = 40, - VM_MOVD = 41, - VM_CMPB = 42, - VM_CMPD = 43, - - VM_ADDB = 44, - VM_ADDD = 45, - VM_SUBB = 46, - VM_SUBD = 47, - VM_INCB = 48, - VM_INCD = 49, - - VM_DECB = - 50, - VM_DECD = 51, - VM_NEGB = 52, - VM_NEGD = 53, - - VM_STANDARD = 54, - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal enum VMCommands + { + VM_MOV = 0, + VM_CMP = 1, + VM_ADD = 2, + VM_SUB = 3, + VM_JZ = 4, + VM_JNZ = 5, + VM_INC = 6, + + VM_DEC = + 7, + VM_JMP = 8, + VM_XOR = 9, + VM_AND = 10, + VM_OR = 11, + VM_TEST = 12, + + VM_JS = + 13, + VM_JNS = 14, + VM_JB = 15, + VM_JBE = 16, + VM_JA = 17, + VM_JAE = 18, + + VM_PUSH = + 19, + VM_POP = 20, + VM_CALL = 21, + VM_RET = 22, + VM_NOT = 23, + VM_SHL = 24, + + VM_SHR = + 25, + VM_SAR = 26, + VM_NEG = 27, + VM_PUSHA = 28, + VM_POPA = 29, + VM_PUSHF = 30, + + VM_POPF = + 31, + VM_MOVZX = 32, + VM_MOVSX = 33, + VM_XCHG = 34, + VM_MUL = 35, + VM_DIV = 36, + + VM_ADC = + 37, + VM_SBB = 38, + VM_PRINT = 39, + + VM_MOVB = 40, + VM_MOVD = 41, + VM_CMPB = 42, + VM_CMPD = 43, + + VM_ADDB = 44, + VM_ADDD = 45, + VM_SUBB = 46, + VM_SUBD = 47, + VM_INCB = 48, + VM_INCD = 49, + + VM_DECB = + 50, + VM_DECD = 51, + VM_NEGB = 52, + VM_NEGD = 53, + + VM_STANDARD = 54, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMFlags.cs b/src/SharpCompress/Compressor/Rar/VM/VMFlags.cs similarity index 94% rename from SharpCompress/Compressor/Rar/VM/VMFlags.cs rename to src/SharpCompress/Compressor/Rar/VM/VMFlags.cs index 3b194212..2e5cd9d4 100644 --- a/SharpCompress/Compressor/Rar/VM/VMFlags.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMFlags.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal enum VMFlags - { - None = 0, - VM_FC = 1, - VM_FZ = 2, - VM_FS = 80000000, - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal enum VMFlags + { + None = 0, + VM_FC = 1, + VM_FZ = 2, + VM_FS = 80000000, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMOpType.cs b/src/SharpCompress/Compressor/Rar/VM/VMOpType.cs similarity index 95% rename from SharpCompress/Compressor/Rar/VM/VMOpType.cs rename to src/SharpCompress/Compressor/Rar/VM/VMOpType.cs index d7cf2eaa..0c26d0f7 100644 --- a/SharpCompress/Compressor/Rar/VM/VMOpType.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMOpType.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal enum VMOpType - { - VM_OPREG = 0, - VM_OPINT = 1, - VM_OPREGMEM = 2, - VM_OPNONE = 3, - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal enum VMOpType + { + VM_OPREG = 0, + VM_OPINT = 1, + VM_OPREGMEM = 2, + VM_OPNONE = 3, + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMPreparedCommand.cs b/src/SharpCompress/Compressor/Rar/VM/VMPreparedCommand.cs similarity index 96% rename from SharpCompress/Compressor/Rar/VM/VMPreparedCommand.cs rename to src/SharpCompress/Compressor/Rar/VM/VMPreparedCommand.cs index 8b8f313c..f2109150 100644 --- a/SharpCompress/Compressor/Rar/VM/VMPreparedCommand.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMPreparedCommand.cs @@ -1,17 +1,17 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal class VMPreparedCommand - { - internal VMPreparedCommand() - { - Op1 = new VMPreparedOperand(); - Op2 = new VMPreparedOperand(); - } - - internal VMCommands OpCode { get; set; } - internal bool IsByteMode { get; set; } - internal VMPreparedOperand Op1 { get; private set; } - - internal VMPreparedOperand Op2 { get; private set; } - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal class VMPreparedCommand + { + internal VMPreparedCommand() + { + Op1 = new VMPreparedOperand(); + Op2 = new VMPreparedOperand(); + } + + internal VMCommands OpCode { get; set; } + internal bool IsByteMode { get; set; } + internal VMPreparedOperand Op1 { get; private set; } + + internal VMPreparedOperand Op2 { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMPreparedOperand.cs b/src/SharpCompress/Compressor/Rar/VM/VMPreparedOperand.cs similarity index 96% rename from SharpCompress/Compressor/Rar/VM/VMPreparedOperand.cs rename to src/SharpCompress/Compressor/Rar/VM/VMPreparedOperand.cs index 35ad9eb2..c23c71d8 100644 --- a/SharpCompress/Compressor/Rar/VM/VMPreparedOperand.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMPreparedOperand.cs @@ -1,10 +1,10 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal class VMPreparedOperand - { - internal VMOpType Type { get; set; } - internal int Data { get; set; } - internal int Base { get; set; } - internal int Offset { get; set; } - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal class VMPreparedOperand + { + internal VMOpType Type { get; set; } + internal int Data { get; set; } + internal int Base { get; set; } + internal int Offset { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMPreparedProgram.cs b/src/SharpCompress/Compressor/Rar/VM/VMPreparedProgram.cs similarity index 97% rename from SharpCompress/Compressor/Rar/VM/VMPreparedProgram.cs rename to src/SharpCompress/Compressor/Rar/VM/VMPreparedProgram.cs index 6ea209f6..7e5d1fe8 100644 --- a/SharpCompress/Compressor/Rar/VM/VMPreparedProgram.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMPreparedProgram.cs @@ -1,21 +1,21 @@ -using System.Collections.Generic; - -namespace SharpCompress.Compressor.Rar.VM -{ - internal class VMPreparedProgram - { - internal List Commands = new List(); - internal List AltCommands = new List(); - - public int CommandCount { get; set; } - - internal List GlobalData = new List(); - internal List StaticData = new List(); - - // static data contained in DB operators - internal int[] InitR = new int[7]; - - internal int FilteredDataOffset { get; set; } - internal int FilteredDataSize { get; set; } - } +using System.Collections.Generic; + +namespace SharpCompress.Compressor.Rar.VM +{ + internal class VMPreparedProgram + { + internal List Commands = new List(); + internal List AltCommands = new List(); + + public int CommandCount { get; set; } + + internal List GlobalData = new List(); + internal List StaticData = new List(); + + // static data contained in DB operators + internal int[] InitR = new int[7]; + + internal int FilteredDataOffset { get; set; } + internal int FilteredDataSize { get; set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMStandardFilterSignature.cs b/src/SharpCompress/Compressor/Rar/VM/VMStandardFilterSignature.cs similarity index 96% rename from SharpCompress/Compressor/Rar/VM/VMStandardFilterSignature.cs rename to src/SharpCompress/Compressor/Rar/VM/VMStandardFilterSignature.cs index e514c1d2..5b86b2cc 100644 --- a/SharpCompress/Compressor/Rar/VM/VMStandardFilterSignature.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMStandardFilterSignature.cs @@ -1,18 +1,18 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal class VMStandardFilterSignature - { - internal VMStandardFilterSignature(int length, uint crc, VMStandardFilters type) - { - this.Length = length; - CRC = crc; - this.Type = type; - } - - internal int Length { get; private set; } - - internal uint CRC { get; private set; } - - internal VMStandardFilters Type { get; private set; } - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal class VMStandardFilterSignature + { + internal VMStandardFilterSignature(int length, uint crc, VMStandardFilters type) + { + this.Length = length; + CRC = crc; + this.Type = type; + } + + internal int Length { get; private set; } + + internal uint CRC { get; private set; } + + internal VMStandardFilters Type { get; private set; } + } } \ No newline at end of file diff --git a/SharpCompress/Compressor/Rar/VM/VMStandardFilters.cs b/src/SharpCompress/Compressor/Rar/VM/VMStandardFilters.cs similarity index 95% rename from SharpCompress/Compressor/Rar/VM/VMStandardFilters.cs rename to src/SharpCompress/Compressor/Rar/VM/VMStandardFilters.cs index bb9ee3bf..fc9db51e 100644 --- a/SharpCompress/Compressor/Rar/VM/VMStandardFilters.cs +++ b/src/SharpCompress/Compressor/Rar/VM/VMStandardFilters.cs @@ -1,14 +1,14 @@ -namespace SharpCompress.Compressor.Rar.VM -{ - internal enum VMStandardFilters - { - VMSF_NONE = 0, - VMSF_E8 = 1, - VMSF_E8E9 = 2, - VMSF_ITANIUM = 3, - VMSF_RGB = 4, - VMSF_AUDIO = 5, - VMSF_DELTA = 6, - VMSF_UPCASE = 7, - } +namespace SharpCompress.Compressor.Rar.VM +{ + internal enum VMStandardFilters + { + VMSF_NONE = 0, + VMSF_E8 = 1, + VMSF_E8E9 = 2, + VMSF_ITANIUM = 3, + VMSF_RGB = 4, + VMSF_AUDIO = 5, + VMSF_DELTA = 6, + VMSF_UPCASE = 7, + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/BigInteger.cs b/src/SharpCompress/Crypto/BigInteger.cs similarity index 96% rename from SharpCompress/Crypto/BigInteger.cs rename to src/SharpCompress/Crypto/BigInteger.cs index 4cd6926d..1071e525 100644 --- a/SharpCompress/Crypto/BigInteger.cs +++ b/src/SharpCompress/Crypto/BigInteger.cs @@ -1,3145 +1,3145 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Text; - - -namespace Org.BouncyCastle.Math -{ - public class BigInteger - { - // The primes b/w 2 and ~2^10 - /* - 3 5 7 11 13 17 19 23 29 - 31 37 41 43 47 53 59 61 67 71 - 73 79 83 89 97 101 103 107 109 113 - 127 131 137 139 149 151 157 163 167 173 - 179 181 191 193 197 199 211 223 227 229 - 233 239 241 251 257 263 269 271 277 281 - 283 293 307 311 313 317 331 337 347 349 - 353 359 367 373 379 383 389 397 401 409 - 419 421 431 433 439 443 449 457 461 463 - 467 479 487 491 499 503 509 521 523 541 - 547 557 563 569 571 577 587 593 599 601 - 607 613 617 619 631 641 643 647 653 659 - 661 673 677 683 691 701 709 719 727 733 - 739 743 751 757 761 769 773 787 797 809 - 811 821 823 827 829 839 853 857 859 863 - 877 881 883 887 907 911 919 929 937 941 - 947 953 967 971 977 983 991 997 - 1009 1013 1019 1021 1031 - */ - - // Each list has a product < 2^31 - private static readonly int[][] primeLists = new int[][] - { - new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 }, - new int[]{ 29, 31, 37, 41, 43 }, - new int[]{ 47, 53, 59, 61, 67 }, - new int[]{ 71, 73, 79, 83 }, - new int[]{ 89, 97, 101, 103 }, - - new int[]{ 107, 109, 113, 127 }, - new int[]{ 131, 137, 139, 149 }, - new int[]{ 151, 157, 163, 167 }, - new int[]{ 173, 179, 181, 191 }, - new int[]{ 193, 197, 199, 211 }, - - new int[]{ 223, 227, 229 }, - new int[]{ 233, 239, 241 }, - new int[]{ 251, 257, 263 }, - new int[]{ 269, 271, 277 }, - new int[]{ 281, 283, 293 }, - - new int[]{ 307, 311, 313 }, - new int[]{ 317, 331, 337 }, - new int[]{ 347, 349, 353 }, - new int[]{ 359, 367, 373 }, - new int[]{ 379, 383, 389 }, - - new int[]{ 397, 401, 409 }, - new int[]{ 419, 421, 431 }, - new int[]{ 433, 439, 443 }, - new int[]{ 449, 457, 461 }, - new int[]{ 463, 467, 479 }, - - new int[]{ 487, 491, 499 }, - new int[]{ 503, 509, 521 }, - new int[]{ 523, 541, 547 }, - new int[]{ 557, 563, 569 }, - new int[]{ 571, 577, 587 }, - - new int[]{ 593, 599, 601 }, - new int[]{ 607, 613, 617 }, - new int[]{ 619, 631, 641 }, - new int[]{ 643, 647, 653 }, - new int[]{ 659, 661, 673 }, - - new int[]{ 677, 683, 691 }, - new int[]{ 701, 709, 719 }, - new int[]{ 727, 733, 739 }, - new int[]{ 743, 751, 757 }, - new int[]{ 761, 769, 773 }, - - new int[]{ 787, 797, 809 }, - new int[]{ 811, 821, 823 }, - new int[]{ 827, 829, 839 }, - new int[]{ 853, 857, 859 }, - new int[]{ 863, 877, 881 }, - - new int[]{ 883, 887, 907 }, - new int[]{ 911, 919, 929 }, - new int[]{ 937, 941, 947 }, - new int[]{ 953, 967, 971 }, - new int[]{ 977, 983, 991 }, - - new int[]{ 997, 1009, 1013 }, - new int[]{ 1019, 1021, 1031 }, - }; - - private static readonly int[] primeProducts; - - private const long IMASK = 0xffffffffL; - private static readonly ulong UIMASK = (ulong)IMASK; - - private static readonly int[] ZeroMagnitude = new int[0]; - private static readonly byte[] ZeroEncoding = new byte[0]; - - public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false); - public static readonly BigInteger One = createUValueOf(1); - public static readonly BigInteger Two = createUValueOf(2); - public static readonly BigInteger Three = createUValueOf(3); - public static readonly BigInteger Ten = createUValueOf(10); - - private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time - private static readonly BigInteger radix2 = ValueOf(2); - private static readonly BigInteger radix2E = radix2.Pow(chunk2); - - private static readonly int chunk10 = 19; - private static readonly BigInteger radix10 = ValueOf(10); - private static readonly BigInteger radix10E = radix10.Pow(chunk10); - - private static readonly int chunk16 = 16; - private static readonly BigInteger radix16 = ValueOf(16); - private static readonly BigInteger radix16E = radix16.Pow(chunk16); - - private static readonly Random RandomSource = new Random(); - - private const int BitsPerByte = 8; - private const int BitsPerInt = 32; - private const int BytesPerInt = 4; - - static BigInteger() - { - primeProducts = new int[primeLists.Length]; - - for (int i = 0; i < primeLists.Length; ++i) - { - int[] primeList = primeLists[i]; - int product = 1; - for (int j = 0; j < primeList.Length; ++j) - { - product *= primeList[j]; - } - primeProducts[i] = product; - } - } - - private int sign; // -1 means -ve; +1 means +ve; 0 means 0; - private int[] magnitude; // array of ints with [0] being the most significant - private int nBits = -1; // cache BitCount() value - private int nBitLength = -1; // cache calcBitLength() value - private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.) - - private static int GetByteLength( - int nBits) - { - return (nBits + BitsPerByte - 1) / BitsPerByte; - } - - private BigInteger() - { - } - - private BigInteger( - int signum, - int[] mag, - bool checkMag) - { - if (checkMag) - { - int i = 0; - while (i < mag.Length && mag[i] == 0) - { - ++i; - } - - if (i == mag.Length) - { - // this.sign = 0; - this.magnitude = ZeroMagnitude; - } - else - { - this.sign = signum; - - if (i == 0) - { - this.magnitude = mag; - } - else - { - // strip leading 0 words - this.magnitude = new int[mag.Length - i]; - Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length); - } - } - } - else - { - this.sign = signum; - this.magnitude = mag; - } - } - - public BigInteger( - string value) - : this(value, 10) - { - } - - public BigInteger( - string str, - int radix) - { - if (str.Length == 0) - throw new FormatException("Zero length BigInteger"); - - NumberStyles style; - int chunk; - BigInteger r; - BigInteger rE; - - switch (radix) - { - case 2: - // Is there anyway to restrict to binary digits? - style = NumberStyles.Integer; - chunk = chunk2; - r = radix2; - rE = radix2E; - break; - case 10: - // This style seems to handle spaces and minus sign already (our processing redundant?) - style = NumberStyles.Integer; - chunk = chunk10; - r = radix10; - rE = radix10E; - break; - case 16: - // TODO Should this be HexNumber? - style = NumberStyles.AllowHexSpecifier; - chunk = chunk16; - r = radix16; - rE = radix16E; - break; - default: - throw new FormatException("Only bases 2, 10, or 16 allowed"); - } - - - int index = 0; - sign = 1; - - if (str[0] == '-') - { - if (str.Length == 1) - throw new FormatException("Zero length BigInteger"); - - sign = -1; - index = 1; - } - - // strip leading zeros from the string str - while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0) - { - index++; - } - - if (index >= str.Length) - { - // zero value - we're done - sign = 0; - magnitude = ZeroMagnitude; - return; - } - - ////// - // could we work out the max number of ints required to store - // str.Length digits in the given base, then allocate that - // storage in one hit?, then Generate the magnitude in one hit too? - ////// - - BigInteger b = Zero; - - - int next = index + chunk; - - if (next <= str.Length) - { - do - { - string s = str.Substring(index, chunk); - ulong i = ulong.Parse(s, style); - BigInteger bi = createUValueOf(i); - - switch (radix) - { - case 2: - // TODO Need this because we are parsing in radix 10 above - if (i > 1) - throw new FormatException("Bad character in radix 2 string: " + s); - - // TODO Parse 64 bits at a time - b = b.ShiftLeft(1); - break; - case 16: - b = b.ShiftLeft(64); - break; - default: - b = b.Multiply(rE); - break; - } - - b = b.Add(bi); - - index = next; - next += chunk; - } - while (next <= str.Length); - } - - if (index < str.Length) - { - string s = str.Substring(index); - ulong i = ulong.Parse(s, style); - BigInteger bi = createUValueOf(i); - - if (b.sign > 0) - { - if (radix == 2) - { - // NB: Can't reach here since we are parsing one char at a time - Debug.Assert(false); - - // TODO Parse all bits at once - // b = b.ShiftLeft(s.Length); - } - else if (radix == 16) - { - b = b.ShiftLeft(s.Length << 2); - } - else - { - b = b.Multiply(r.Pow(s.Length)); - } - - b = b.Add(bi); - } - else - { - b = bi; - } - } - - // Note: This is the previous (slower) algorithm - // while (index < value.Length) - // { - // char c = value[index]; - // string s = c.ToString(); - // int i = Int32.Parse(s, style); - // - // b = b.Multiply(r).Add(ValueOf(i)); - // index++; - // } - - magnitude = b.magnitude; - } - - public BigInteger( - byte[] bytes) - : this(bytes, 0, bytes.Length) - { - } - - public BigInteger( - byte[] bytes, - int offset, - int length) - { - if (length == 0) - throw new FormatException("Zero length BigInteger"); - - // TODO Move this processing into MakeMagnitude (provide sign argument) - if ((sbyte)bytes[offset] < 0) - { - this.sign = -1; - - int end = offset + length; - - int iBval; - // strip leading sign bytes - for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++) - { - } - - if (iBval >= end) - { - this.magnitude = One.magnitude; - } - else - { - int numBytes = end - iBval; - byte[] inverse = new byte[numBytes]; - - int index = 0; - while (index < numBytes) - { - inverse[index++] = (byte)~bytes[iBval++]; - } - - Debug.Assert(iBval == end); - - while (inverse[--index] == byte.MaxValue) - { - inverse[index] = byte.MinValue; - } - - inverse[index]++; - - this.magnitude = MakeMagnitude(inverse, 0, inverse.Length); - } - } - else - { - // strip leading zero bytes and return magnitude bytes - this.magnitude = MakeMagnitude(bytes, offset, length); - this.sign = this.magnitude.Length > 0 ? 1 : 0; - } - } - - private static int[] MakeMagnitude( - byte[] bytes, - int offset, - int length) - { - int end = offset + length; - - // strip leading zeros - int firstSignificant; - for (firstSignificant = offset; firstSignificant < end - && bytes[firstSignificant] == 0; firstSignificant++) - { - } - - if (firstSignificant >= end) - { - return ZeroMagnitude; - } - - int nInts = (end - firstSignificant + 3) / BytesPerInt; - int bCount = (end - firstSignificant) % BytesPerInt; - if (bCount == 0) - { - bCount = BytesPerInt; - } - - if (nInts < 1) - { - return ZeroMagnitude; - } - - int[] mag = new int[nInts]; - - int v = 0; - int magnitudeIndex = 0; - for (int i = firstSignificant; i < end; ++i) - { - v <<= 8; - v |= bytes[i] & 0xff; - bCount--; - if (bCount <= 0) - { - mag[magnitudeIndex] = v; - magnitudeIndex++; - bCount = BytesPerInt; - v = 0; - } - } - - if (magnitudeIndex < mag.Length) - { - mag[magnitudeIndex] = v; - } - - return mag; - } - - public BigInteger( - int sign, - byte[] bytes) - : this(sign, bytes, 0, bytes.Length) - { - } - - public BigInteger( - int sign, - byte[] bytes, - int offset, - int length) - { - if (sign < -1 || sign > 1) - throw new FormatException("Invalid sign value"); - - if (sign == 0) - { - //this.sign = 0; - this.magnitude = ZeroMagnitude; - } - else - { - // copy bytes - this.magnitude = MakeMagnitude(bytes, offset, length); - this.sign = this.magnitude.Length < 1 ? 0 : sign; - } - } - - public BigInteger( - int sizeInBits, - Random random) - { - if (sizeInBits < 0) - throw new ArgumentException("sizeInBits must be non-negative"); - - this.nBits = -1; - this.nBitLength = -1; - - if (sizeInBits == 0) - { - // this.sign = 0; - this.magnitude = ZeroMagnitude; - return; - } - - int nBytes = GetByteLength(sizeInBits); - byte[] b = new byte[nBytes]; - random.NextBytes(b); - - // strip off any excess bits in the MSB - b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits]; - - this.magnitude = MakeMagnitude(b, 0, b.Length); - this.sign = this.magnitude.Length < 1 ? 0 : 1; - } - - private static readonly byte[] rndMask = { 255, 127, 63, 31, 15, 7, 3, 1 }; - - public BigInteger( - int bitLength, - int certainty, - Random random) - { - if (bitLength < 2) - throw new ArithmeticException("bitLength < 2"); - - this.sign = 1; - this.nBitLength = bitLength; - - if (bitLength == 2) - { - this.magnitude = random.Next(2) == 0 - ? Two.magnitude - : Three.magnitude; - return; - } - - int nBytes = GetByteLength(bitLength); - byte[] b = new byte[nBytes]; - - int xBits = BitsPerByte * nBytes - bitLength; - byte mask = rndMask[xBits]; - - for (; ; ) - { - random.NextBytes(b); - - // strip off any excess bits in the MSB - b[0] &= mask; - - // ensure the leading bit is 1 (to meet the strength requirement) - b[0] |= (byte)(1 << (7 - xBits)); - - // ensure the trailing bit is 1 (i.e. must be odd) - b[nBytes - 1] |= 1; - - this.magnitude = MakeMagnitude(b, 0, b.Length); - this.nBits = -1; - this.mQuote = -1L; - - if (certainty < 1) - break; - - if (CheckProbablePrime(certainty, random)) - break; - - if (bitLength > 32) - { - for (int rep = 0; rep < 10000; ++rep) - { - int n = 33 + random.Next(bitLength - 2); - this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31)); - this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1); - this.mQuote = -1L; - - if (CheckProbablePrime(certainty, random)) - return; - } - } - } - } - - public BigInteger Abs() - { - return sign >= 0 ? this : Negate(); - } - - /** - * return a = a + b - b preserved. - */ - private static int[] AddMagnitudes( - int[] a, - int[] b) - { - int tI = a.Length - 1; - int vI = b.Length - 1; - long m = 0; - - while (vI >= 0) - { - m += ((long)(uint)a[tI] + (long)(uint)b[vI--]); - a[tI--] = (int)m; - m = (long)((ulong)m >> 32); - } - - if (m != 0) - { - while (tI >= 0 && ++a[tI--] == 0) - { - } - } - - return a; - } - - public BigInteger Add( - BigInteger value) - { - if (this.sign == 0) - return value; - - if (this.sign != value.sign) - { - if (value.sign == 0) - return this; - - if (value.sign < 0) - return Subtract(value.Negate()); - - return value.Subtract(Negate()); - } - - return AddToMagnitude(value.magnitude); - } - - private BigInteger AddToMagnitude( - int[] magToAdd) - { - int[] big, small; - if (this.magnitude.Length < magToAdd.Length) - { - big = magToAdd; - small = this.magnitude; - } - else - { - big = this.magnitude; - small = magToAdd; - } - - // Conservatively avoid over-allocation when no overflow possible - uint limit = uint.MaxValue; - if (big.Length == small.Length) - limit -= (uint)small[0]; - - bool possibleOverflow = (uint)big[0] >= limit; - - int[] bigCopy; - if (possibleOverflow) - { - bigCopy = new int[big.Length + 1]; - big.CopyTo(bigCopy, 1); - } - else - { - bigCopy = (int[])big.Clone(); - } - - bigCopy = AddMagnitudes(bigCopy, small); - - return new BigInteger(this.sign, bigCopy, possibleOverflow); - } - - public BigInteger And( - BigInteger value) - { - if (this.sign == 0 || value.sign == 0) - { - return Zero; - } - - int[] aMag = this.sign > 0 - ? this.magnitude - : Add(One).magnitude; - - int[] bMag = value.sign > 0 - ? value.magnitude - : value.Add(One).magnitude; - - bool resultNeg = sign < 0 && value.sign < 0; - int resultLength = System.Math.Max(aMag.Length, bMag.Length); - int[] resultMag = new int[resultLength]; - - int aStart = resultMag.Length - aMag.Length; - int bStart = resultMag.Length - bMag.Length; - - for (int i = 0; i < resultMag.Length; ++i) - { - int aWord = i >= aStart ? aMag[i - aStart] : 0; - int bWord = i >= bStart ? bMag[i - bStart] : 0; - - if (this.sign < 0) - { - aWord = ~aWord; - } - - if (value.sign < 0) - { - bWord = ~bWord; - } - - resultMag[i] = aWord & bWord; - - if (resultNeg) - { - resultMag[i] = ~resultMag[i]; - } - } - - BigInteger result = new BigInteger(1, resultMag, true); - - // TODO Optimise this case - if (resultNeg) - { - result = result.Not(); - } - - return result; - } - - public BigInteger AndNot( - BigInteger val) - { - return And(val.Not()); - } - - public int BitCount - { - get - { - if (nBits == -1) - { - if (sign < 0) - { - // TODO Optimise this case - nBits = Not().BitCount; - } - else - { - int sum = 0; - for (int i = 0; i < magnitude.Length; i++) - { - sum += bitCounts[(byte)magnitude[i]]; - sum += bitCounts[(byte)(magnitude[i] >> 8)]; - sum += bitCounts[(byte)(magnitude[i] >> 16)]; - sum += bitCounts[(byte)(magnitude[i] >> 24)]; - } - nBits = sum; - } - } - - return nBits; - } - } - - private readonly static byte[] bitCounts = - { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, - 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, - 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, - 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, - 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, - 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, - 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, - 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, - 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, - 6, 6, 7, 6, 7, 7, 8 - }; - - private int calcBitLength( - int indx, - int[] mag) - { - for (; ; ) - { - if (indx >= mag.Length) - return 0; - - if (mag[indx] != 0) - break; - - ++indx; - } - - // bit length for everything after the first int - int bitLength = 32 * ((mag.Length - indx) - 1); - - // and determine bitlength of first int - int firstMag = mag[indx]; - bitLength += BitLen(firstMag); - - // Check for negative powers of two - if (sign < 0 && ((firstMag & -firstMag) == firstMag)) - { - do - { - if (++indx >= mag.Length) - { - --bitLength; - break; - } - } - while (mag[indx] == 0); - } - - return bitLength; - } - - public int BitLength - { - get - { - if (nBitLength == -1) - { - nBitLength = sign == 0 - ? 0 - : calcBitLength(0, magnitude); - } - - return nBitLength; - } - } - - // - // BitLen(value) is the number of bits in value. - // - private static int BitLen( - int w) - { - // Binary search - decision tree (5 tests, rarely 6) - return (w < 1 << 15 ? (w < 1 << 7 - ? (w < 1 << 3 ? (w < 1 << 1 - ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) - : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 - ? (w < 1 << 4 ? 4 : 5) - : (w < 1 << 6 ? 6 : 7))) - : (w < 1 << 11 - ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) - : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 - ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) - : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 - ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) - : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); - } - - // private readonly static byte[] bitLengths = - // { - // 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, - // 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - // 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, - // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - // 8, 8, 8, 8, 8, 8, 8, 8 - // }; - - private bool QuickPow2Check() - { - return sign > 0 && nBits == 1; - } - - public int CompareTo( - object obj) - { - return CompareTo((BigInteger)obj); - } - - /** - * unsigned comparison on two arrays - note the arrays may - * start with leading zeros. - */ - private static int CompareTo( - int xIndx, - int[] x, - int yIndx, - int[] y) - { - while (xIndx != x.Length && x[xIndx] == 0) - { - xIndx++; - } - - while (yIndx != y.Length && y[yIndx] == 0) - { - yIndx++; - } - - return CompareNoLeadingZeroes(xIndx, x, yIndx, y); - } - - private static int CompareNoLeadingZeroes( - int xIndx, - int[] x, - int yIndx, - int[] y) - { - int diff = (x.Length - y.Length) - (xIndx - yIndx); - - if (diff != 0) - { - return diff < 0 ? -1 : 1; - } - - // lengths of magnitudes the same, test the magnitude values - - while (xIndx < x.Length) - { - uint v1 = (uint)x[xIndx++]; - uint v2 = (uint)y[yIndx++]; - - if (v1 != v2) - return v1 < v2 ? -1 : 1; - } - - return 0; - } - - public int CompareTo( - BigInteger value) - { - return sign < value.sign ? -1 - : sign > value.sign ? 1 - : sign == 0 ? 0 - : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude); - } - - /** - * return z = x / y - done in place (z value preserved, x contains the - * remainder) - */ - private int[] Divide( - int[] x, - int[] y) - { - int xStart = 0; - while (xStart < x.Length && x[xStart] == 0) - { - ++xStart; - } - - int yStart = 0; - while (yStart < y.Length && y[yStart] == 0) - { - ++yStart; - } - - Debug.Assert(yStart < y.Length); - - int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); - int[] count; - - if (xyCmp > 0) - { - int yBitLength = calcBitLength(yStart, y); - int xBitLength = calcBitLength(xStart, x); - int shift = xBitLength - yBitLength; - - int[] iCount; - int iCountStart = 0; - - int[] c; - int cStart = 0; - int cBitLength = yBitLength; - if (shift > 0) - { - // iCount = ShiftLeft(One.magnitude, shift); - iCount = new int[(shift >> 5) + 1]; - iCount[0] = 1 << (shift % 32); - - c = ShiftLeft(y, shift); - cBitLength += shift; - } - else - { - iCount = new int[] { 1 }; - - int len = y.Length - yStart; - c = new int[len]; - Array.Copy(y, yStart, c, 0, len); - } - - count = new int[iCount.Length]; - - for (; ; ) - { - if (cBitLength < xBitLength - || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) - { - Subtract(xStart, x, cStart, c); - AddMagnitudes(count, iCount); - - while (x[xStart] == 0) - { - if (++xStart == x.Length) - return count; - } - - //xBitLength = calcBitLength(xStart, x); - xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); - - if (xBitLength <= yBitLength) - { - if (xBitLength < yBitLength) - return count; - - xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); - - if (xyCmp <= 0) - break; - } - } - - shift = cBitLength - xBitLength; - - // NB: The case where c[cStart] is 1-bit is harmless - if (shift == 1) - { - uint firstC = (uint)c[cStart] >> 1; - uint firstX = (uint)x[xStart]; - if (firstC > firstX) - ++shift; - } - - if (shift < 2) - { - ShiftRightOneInPlace(cStart, c); - --cBitLength; - ShiftRightOneInPlace(iCountStart, iCount); - } - else - { - ShiftRightInPlace(cStart, c, shift); - cBitLength -= shift; - ShiftRightInPlace(iCountStart, iCount, shift); - } - - //cStart = c.Length - ((cBitLength + 31) / 32); - while (c[cStart] == 0) - { - ++cStart; - } - - while (iCount[iCountStart] == 0) - { - ++iCountStart; - } - } - } - else - { - count = new int[1]; - } - - if (xyCmp == 0) - { - AddMagnitudes(count, One.magnitude); - Array.Clear(x, xStart, x.Length - xStart); - } - - return count; - } - - public BigInteger Divide( - BigInteger val) - { - if (val.sign == 0) - throw new ArithmeticException("Division by zero error"); - - if (sign == 0) - return Zero; - - if (val.QuickPow2Check()) // val is power of two - { - BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1); - return val.sign == this.sign ? result : result.Negate(); - } - - int[] mag = (int[])this.magnitude.Clone(); - - return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true); - } - - public BigInteger[] DivideAndRemainder( - BigInteger val) - { - if (val.sign == 0) - throw new ArithmeticException("Division by zero error"); - - BigInteger[] biggies = new BigInteger[2]; - - if (sign == 0) - { - biggies[0] = Zero; - biggies[1] = Zero; - } - else if (val.QuickPow2Check()) // val is power of two - { - int e = val.Abs().BitLength - 1; - BigInteger quotient = this.Abs().ShiftRight(e); - int[] remainder = this.LastNBits(e); - - biggies[0] = val.sign == this.sign ? quotient : quotient.Negate(); - biggies[1] = new BigInteger(this.sign, remainder, true); - } - else - { - int[] remainder = (int[])this.magnitude.Clone(); - int[] quotient = Divide(remainder, val.magnitude); - - biggies[0] = new BigInteger(this.sign * val.sign, quotient, true); - biggies[1] = new BigInteger(this.sign, remainder, true); - } - - return biggies; - } - - public override bool Equals( - object obj) - { - if (obj == this) - return true; - - BigInteger biggie = obj as BigInteger; - if (biggie == null) - return false; - - if (biggie.sign != sign || biggie.magnitude.Length != magnitude.Length) - return false; - - for (int i = 0; i < magnitude.Length; i++) - { - if (biggie.magnitude[i] != magnitude[i]) - { - return false; - } - } - - return true; - } - - public BigInteger Gcd( - BigInteger value) - { - if (value.sign == 0) - return Abs(); - - if (sign == 0) - return value.Abs(); - - BigInteger r; - BigInteger u = this; - BigInteger v = value; - - while (v.sign != 0) - { - r = u.Mod(v); - u = v; - v = r; - } - - return u; - } - - public override int GetHashCode() - { - int hc = magnitude.Length; - if (magnitude.Length > 0) - { - hc ^= magnitude[0]; - - if (magnitude.Length > 1) - { - hc ^= magnitude[magnitude.Length - 1]; - } - } - - return sign < 0 ? ~hc : hc; - } - - // TODO Make public? - private BigInteger Inc() - { - if (this.sign == 0) - return One; - - if (this.sign < 0) - return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true); - - return AddToMagnitude(One.magnitude); - } - - public int IntValue - { - get - { - return sign == 0 ? 0 - : sign > 0 ? magnitude[magnitude.Length - 1] - : -magnitude[magnitude.Length - 1]; - } - } - - /** - * return whether or not a BigInteger is probably prime with a - * probability of 1 - (1/2)**certainty. - *

From Knuth Vol 2, pg 395.

- */ - public bool IsProbablePrime( - int certainty) - { - if (certainty <= 0) - return true; - - BigInteger n = Abs(); - - if (!n.TestBit(0)) - return n.Equals(Two); - - if (n.Equals(One)) - return false; - - return n.CheckProbablePrime(certainty, RandomSource); - } - - private bool CheckProbablePrime( - int certainty, - Random random) - { - Debug.Assert(certainty > 0); - Debug.Assert(CompareTo(Two) > 0); - Debug.Assert(TestBit(0)); - - - // Try to reduce the penalty for really small numbers - int numLists = System.Math.Min(BitLength - 1, primeLists.Length); - - for (int i = 0; i < numLists; ++i) - { - int test = Remainder(primeProducts[i]); - - int[] primeList = primeLists[i]; - for (int j = 0; j < primeList.Length; ++j) - { - int prime = primeList[j]; - int qRem = test % prime; - if (qRem == 0) - { - // We may find small numbers in the list - return BitLength < 16 && IntValue == prime; - } - } - } - - - // TODO Special case for < 10^16 (RabinMiller fixed list) - // if (BitLength < 30) - // { - // RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient - // } - - - // TODO Is it worth trying to create a hybrid of these two? - return RabinMillerTest(certainty, random); - // return SolovayStrassenTest(certainty, random); - - // bool rbTest = RabinMillerTest(certainty, random); - // bool ssTest = SolovayStrassenTest(certainty, random); - // - // Debug.Assert(rbTest == ssTest); - // - // return rbTest; - } - - internal bool RabinMillerTest( - int certainty, - Random random) - { - Debug.Assert(certainty > 0); - Debug.Assert(BitLength > 2); - Debug.Assert(TestBit(0)); - - // let n = 1 + d . 2^s - BigInteger n = this; - BigInteger nMinusOne = n.Subtract(One); - int s = nMinusOne.GetLowestSetBit(); - BigInteger r = nMinusOne.ShiftRight(s); - - Debug.Assert(s >= 1); - - do - { - // TODO Make a method for random BigIntegers in range 0 < x < n) - // - Method can be optimized by only replacing examined bits at each trial - BigInteger a; - do - { - a = new BigInteger(n.BitLength, random); - } - while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0); - - BigInteger y = a.ModPow(r, n); - - if (!y.Equals(One)) - { - int j = 0; - while (!y.Equals(nMinusOne)) - { - if (++j == s) - return false; - - y = y.ModPow(Two, n); - - if (y.Equals(One)) - return false; - } - } - - certainty -= 2; // composites pass for only 1/4 possible 'a' - } - while (certainty > 0); - - return true; - } - - // private bool SolovayStrassenTest( - // int certainty, - // Random random) - // { - // Debug.Assert(certainty > 0); - // Debug.Assert(CompareTo(Two) > 0); - // Debug.Assert(TestBit(0)); - // - // BigInteger n = this; - // BigInteger nMinusOne = n.Subtract(One); - // BigInteger e = nMinusOne.ShiftRight(1); - // - // do - // { - // BigInteger a; - // do - // { - // a = new BigInteger(nBitLength, random); - // } - // // NB: Spec says 0 < x < n, but 1 is trivial - // while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0); - // - // - // // TODO Check this is redundant given the way Jacobi() works? - //// if (!a.Gcd(n).Equals(One)) - //// return false; - // - // int x = Jacobi(a, n); - // - // if (x == 0) - // return false; - // - // BigInteger check = a.ModPow(e, n); - // - // if (x == 1 && !check.Equals(One)) - // return false; - // - // if (x == -1 && !check.Equals(nMinusOne)) - // return false; - // - // --certainty; - // } - // while (certainty > 0); - // - // return true; - // } - // - // private static int Jacobi( - // BigInteger a, - // BigInteger b) - // { - // Debug.Assert(a.sign >= 0); - // Debug.Assert(b.sign > 0); - // Debug.Assert(b.TestBit(0)); - // Debug.Assert(a.CompareTo(b) < 0); - // - // int totalS = 1; - // for (;;) - // { - // if (a.sign == 0) - // return 0; - // - // if (a.Equals(One)) - // break; - // - // int e = a.GetLowestSetBit(); - // - // int bLsw = b.magnitude[b.magnitude.Length - 1]; - // if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5)) - // totalS = -totalS; - // - // // TODO Confirm this is faster than later a1.Equals(One) test - // if (a.BitLength == e + 1) - // break; - // BigInteger a1 = a.ShiftRight(e); - //// if (a1.Equals(One)) - //// break; - // - // int a1Lsw = a1.magnitude[a1.magnitude.Length - 1]; - // if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3) - // totalS = -totalS; - // - //// a = b.Mod(a1); - // a = b.Remainder(a1); - // b = a1; - // } - // return totalS; - // } - - public long LongValue - { - get - { - if (sign == 0) - return 0; - - long v; - if (magnitude.Length > 1) - { - v = ((long)magnitude[magnitude.Length - 2] << 32) - | (magnitude[magnitude.Length - 1] & IMASK); - } - else - { - v = (magnitude[magnitude.Length - 1] & IMASK); - } - - return sign < 0 ? -v : v; - } - } - - public BigInteger Max( - BigInteger value) - { - return CompareTo(value) > 0 ? this : value; - } - - public BigInteger Min( - BigInteger value) - { - return CompareTo(value) < 0 ? this : value; - } - - public BigInteger Mod( - BigInteger m) - { - if (m.sign < 1) - throw new ArithmeticException("Modulus must be positive"); - - BigInteger biggie = Remainder(m); - - return (biggie.sign >= 0 ? biggie : biggie.Add(m)); - } - - public BigInteger ModInverse( - BigInteger m) - { - if (m.sign < 1) - throw new ArithmeticException("Modulus must be positive"); - - // TODO Too slow at the moment - // // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel - // if (m.TestBit(0)) - // { - // //The Almost Inverse Algorithm - // int k = 0; - // BigInteger B = One, C = Zero, F = this, G = m, tmp; - // - // for (;;) - // { - // // While F is even, do F=F/u, C=C*u, k=k+1. - // int zeroes = F.GetLowestSetBit(); - // if (zeroes > 0) - // { - // F = F.ShiftRight(zeroes); - // C = C.ShiftLeft(zeroes); - // k += zeroes; - // } - // - // // If F = 1, then return B,k. - // if (F.Equals(One)) - // { - // BigInteger half = m.Add(One).ShiftRight(1); - // BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m); - // return B.Multiply(halfK).Mod(m); - // } - // - // if (F.CompareTo(G) < 0) - // { - // tmp = G; G = F; F = tmp; - // tmp = B; B = C; C = tmp; - // } - // - // F = F.Add(G); - // B = B.Add(C); - // } - // } - - BigInteger x = new BigInteger(); - BigInteger gcd = ExtEuclid(this.Mod(m), m, x, null); - - if (!gcd.Equals(One)) - throw new ArithmeticException("Numbers not relatively prime."); - - if (x.sign < 0) - { - x.sign = 1; - //x = m.Subtract(x); - x.magnitude = doSubBigLil(m.magnitude, x.magnitude); - } - - return x; - } - - /** - * Calculate the numbers u1, u2, and u3 such that: - * - * u1 * a + u2 * b = u3 - * - * where u3 is the greatest common divider of a and b. - * a and b using the extended Euclid algorithm (refer p. 323 - * of The Art of Computer Programming vol 2, 2nd ed). - * This also seems to have the side effect of calculating - * some form of multiplicative inverse. - * - * @param a First number to calculate gcd for - * @param b Second number to calculate gcd for - * @param u1Out the return object for the u1 value - * @param u2Out the return object for the u2 value - * @return The greatest common divisor of a and b - */ - private static BigInteger ExtEuclid( - BigInteger a, - BigInteger b, - BigInteger u1Out, - BigInteger u2Out) - { - BigInteger u1 = One; - BigInteger u3 = a; - BigInteger v1 = Zero; - BigInteger v3 = b; - - while (v3.sign > 0) - { - BigInteger[] q = u3.DivideAndRemainder(v3); - - BigInteger tmp = v1.Multiply(q[0]); - BigInteger tn = u1.Subtract(tmp); - u1 = v1; - v1 = tn; - - u3 = v3; - v3 = q[1]; - } - - if (u1Out != null) - { - u1Out.sign = u1.sign; - u1Out.magnitude = u1.magnitude; - } - - if (u2Out != null) - { - BigInteger tmp = u1.Multiply(a); - tmp = u3.Subtract(tmp); - BigInteger res = tmp.Divide(b); - u2Out.sign = res.sign; - u2Out.magnitude = res.magnitude; - } - - return u3; - } - - private static void ZeroOut( - int[] x) - { - Array.Clear(x, 0, x.Length); - } - - public BigInteger ModPow( - BigInteger exponent, - BigInteger m) - { - if (m.sign < 1) - throw new ArithmeticException("Modulus must be positive"); - - if (m.Equals(One)) - return Zero; - - if (exponent.sign == 0) - return One; - - if (sign == 0) - return Zero; - - int[] zVal = null; - int[] yAccum = null; - int[] yVal; - - // Montgomery exponentiation is only possible if the modulus is odd, - // but AFAIK, this is always the case for crypto algo's - bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1); - long mQ = 0; - if (useMonty) - { - mQ = m.GetMQuote(); - - // tmp = this * R mod m - BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m); - zVal = tmp.magnitude; - - useMonty = (zVal.Length <= m.magnitude.Length); - - if (useMonty) - { - yAccum = new int[m.magnitude.Length + 1]; - if (zVal.Length < m.magnitude.Length) - { - int[] longZ = new int[m.magnitude.Length]; - zVal.CopyTo(longZ, longZ.Length - zVal.Length); - zVal = longZ; - } - } - } - - if (!useMonty) - { - if (magnitude.Length <= m.magnitude.Length) - { - //zAccum = new int[m.magnitude.Length * 2]; - zVal = new int[m.magnitude.Length]; - magnitude.CopyTo(zVal, zVal.Length - magnitude.Length); - } - else - { - // - // in normal practice we'll never see this... - // - BigInteger tmp = Remainder(m); - - //zAccum = new int[m.magnitude.Length * 2]; - zVal = new int[m.magnitude.Length]; - tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length); - } - - yAccum = new int[m.magnitude.Length * 2]; - } - - yVal = new int[m.magnitude.Length]; - - // - // from LSW to MSW - // - for (int i = 0; i < exponent.magnitude.Length; i++) - { - int v = exponent.magnitude[i]; - int bits = 0; - - if (i == 0) - { - while (v > 0) - { - v <<= 1; - bits++; - } - - // - // first time in initialise y - // - zVal.CopyTo(yVal, 0); - - v <<= 1; - bits++; - } - - while (v != 0) - { - if (useMonty) - { - // Montgomery square algo doesn't exist, and a normal - // square followed by a Montgomery reduction proved to - // be almost as heavy as a Montgomery mulitply. - MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); - } - else - { - Square(yAccum, yVal); - Remainder(yAccum, m.magnitude); - Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); - ZeroOut(yAccum); - } - bits++; - - if (v < 0) - { - if (useMonty) - { - MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); - } - else - { - Multiply(yAccum, yVal, zVal); - Remainder(yAccum, m.magnitude); - Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, - yVal.Length); - ZeroOut(yAccum); - } - } - - v <<= 1; - } - - while (bits < 32) - { - if (useMonty) - { - MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); - } - else - { - Square(yAccum, yVal); - Remainder(yAccum, m.magnitude); - Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); - ZeroOut(yAccum); - } - bits++; - } - } - - if (useMonty) - { - // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m - ZeroOut(zVal); - zVal[zVal.Length - 1] = 1; - MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); - } - - BigInteger result = new BigInteger(1, yVal, true); - - return exponent.sign > 0 - ? result - : result.ModInverse(m); - } - - /** - * return w with w = x * x - w is assumed to have enough space. - */ - private static int[] Square( - int[] w, - int[] x) - { - // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit - // if (w.Length != 2 * x.Length) - // throw new ArgumentException("no I don't think so..."); - - ulong u1, u2, c; - - int wBase = w.Length - 1; - - for (int i = x.Length - 1; i != 0; i--) - { - ulong v = (ulong)(uint)x[i]; - - u1 = v * v; - u2 = u1 >> 32; - u1 = (uint)u1; - - u1 += (ulong)(uint)w[wBase]; - - w[wBase] = (int)(uint)u1; - c = u2 + (u1 >> 32); - - for (int j = i - 1; j >= 0; j--) - { - --wBase; - u1 = v * (ulong)(uint)x[j]; - u2 = u1 >> 31; // multiply by 2! - u1 = (uint)(u1 << 1); // multiply by 2! - u1 += c + (ulong)(uint)w[wBase]; - - w[wBase] = (int)(uint)u1; - c = u2 + (u1 >> 32); - } - - c += (ulong)(uint)w[--wBase]; - w[wBase] = (int)(uint)c; - - if (--wBase >= 0) - { - w[wBase] = (int)(uint)(c >> 32); - } - else - { - Debug.Assert((uint)(c >> 32) == 0); - } - wBase += i; - } - - u1 = (ulong)(uint)x[0]; - u1 = u1 * u1; - u2 = u1 >> 32; - u1 = u1 & IMASK; - - u1 += (ulong)(uint)w[wBase]; - - w[wBase] = (int)(uint)u1; - if (--wBase >= 0) - { - w[wBase] = (int)(uint)(u2 + (u1 >> 32) + (ulong)(uint)w[wBase]); - } - else - { - Debug.Assert((uint)(u2 + (u1 >> 32)) == 0); - } - - return w; - } - - /** - * return x with x = y * z - x is assumed to have enough space. - */ - private static int[] Multiply( - int[] x, - int[] y, - int[] z) - { - int i = z.Length; - - if (i < 1) - return x; - - int xBase = x.Length - y.Length; - - for (; ; ) - { - long a = z[--i] & IMASK; - long val = 0; - - for (int j = y.Length - 1; j >= 0; j--) - { - val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK); - - x[xBase + j] = (int)val; - - val = (long)((ulong)val >> 32); - } - - --xBase; - - if (i < 1) - { - if (xBase >= 0) - { - x[xBase] = (int)val; - } - else - { - Debug.Assert(val == 0); - } - break; - } - - x[xBase] = (int)val; - } - - return x; - } - - private static long FastExtEuclid( - long a, - long b, - long[] uOut) - { - long u1 = 1; - long u3 = a; - long v1 = 0; - long v3 = b; - - while (v3 > 0) - { - long q, tn; - - q = u3 / v3; - - tn = u1 - (v1 * q); - u1 = v1; - v1 = tn; - - tn = u3 - (v3 * q); - u3 = v3; - v3 = tn; - } - - uOut[0] = u1; - uOut[1] = (u3 - (u1 * a)) / b; - - return u3; - } - - private static long FastModInverse( - long v, - long m) - { - if (m < 1) - throw new ArithmeticException("Modulus must be positive"); - - long[] x = new long[2]; - long gcd = FastExtEuclid(v, m, x); - - if (gcd != 1) - throw new ArithmeticException("Numbers not relatively prime."); - - if (x[0] < 0) - { - x[0] += m; - } - - return x[0]; - } - - // private static BigInteger MQuoteB = One.ShiftLeft(32); - // private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One); - - /** - * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size) - */ - private long GetMQuote() - { - Debug.Assert(this.sign > 0); - - if (mQuote != -1) - { - return mQuote; // already calculated - } - - if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0) - { - return -1; // not for even numbers - } - - long v = (((~this.magnitude[this.magnitude.Length - 1]) | 1) & 0xffffffffL); - mQuote = FastModInverse(v, 0x100000000L); - - return mQuote; - } - - /** - * Montgomery multiplication: a = x * y * R^(-1) mod m - *
- * Based algorithm 14.36 of Handbook of Applied Cryptography. - *
- *
  • m, x, y should have length n
  • - *
  • a should have length (n + 1)
  • - *
  • b = 2^32, R = b^n
  • - *
    - * The result is put in x - *
    - * NOTE: the indices of x, y, m, a different in HAC and in Java - */ - private static void MultiplyMonty( - int[] a, - int[] x, - int[] y, - int[] m, - long mQuote) - // mQuote = -m^(-1) mod b - { - if (m.Length == 1) - { - x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], (ulong)mQuote); - return; - } - - int n = m.Length; - int nMinus1 = n - 1; - long y_0 = y[nMinus1] & IMASK; - - // 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} ) - Array.Clear(a, 0, n + 1); - - // 2. for i from 0 to (n - 1) do the following: - for (int i = n; i > 0; i--) - { - long x_i = x[i - 1] & IMASK; - - // 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b - long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK; - - // 2.2 a = (a + x_i * y + u * m) / b - long prod1 = x_i * y_0; - long prod2 = u * (m[nMinus1] & IMASK); - long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK); - long carry = (long)((ulong)prod1 >> 32) + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); - for (int j = nMinus1; j > 0; j--) - { - prod1 = x_i * (y[j - 1] & IMASK); - prod2 = u * (m[j - 1] & IMASK); - tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK); - carry = (long)((ulong)carry >> 32) + (long)((ulong)prod1 >> 32) + - (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); - a[j + 1] = (int)tmp; // division by b - } - carry += (a[0] & IMASK); - a[1] = (int)carry; - a[0] = (int)((ulong)carry >> 32); // OJO!!!!! - } - - // 3. if x >= m the x = x - m - if (CompareTo(0, a, 0, m) >= 0) - { - Subtract(0, a, 0, m); - } - - // put the result in x - Array.Copy(a, 1, x, 0, n); - } - - private static uint MultiplyMontyNIsOne( - uint x, - uint y, - uint m, - ulong mQuote) - { - ulong um = m; - ulong prod1 = (ulong)x * (ulong)y; - ulong u = (prod1 * mQuote) & UIMASK; - ulong prod2 = u * um; - ulong tmp = (prod1 & UIMASK) + (prod2 & UIMASK); - ulong carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32); - - if (carry > um) - { - carry -= um; - } - - return (uint)(carry & UIMASK); - } - - public BigInteger Multiply( - BigInteger val) - { - if (sign == 0 || val.sign == 0) - return Zero; - - if (val.QuickPow2Check()) // val is power of two - { - BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1); - return val.sign > 0 ? result : result.Negate(); - } - - if (this.QuickPow2Check()) // this is power of two - { - BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1); - return this.sign > 0 ? result : result.Negate(); - } - - int resLength = (this.BitLength + val.BitLength) / BitsPerInt + 1; - int[] res = new int[resLength]; - - if (val == this) - { - Square(res, this.magnitude); - } - else - { - Multiply(res, this.magnitude, val.magnitude); - } - - return new BigInteger(sign * val.sign, res, true); - } - - public BigInteger Negate() - { - if (sign == 0) - return this; - - return new BigInteger(-sign, magnitude, false); - } - - public BigInteger NextProbablePrime() - { - if (sign < 0) - throw new ArithmeticException("Cannot be called on value < 0"); - - if (CompareTo(Two) < 0) - return Two; - - BigInteger n = Inc().SetBit(0); - - while (!n.CheckProbablePrime(100, RandomSource)) - { - n = n.Add(Two); - } - - return n; - } - - public BigInteger Not() - { - return Inc().Negate(); - } - - public BigInteger Pow(int exp) - { - if (exp < 0) - { - throw new ArithmeticException("Negative exponent"); - } - - if (exp == 0) - { - return One; - } - - if (sign == 0 || Equals(One)) - { - return this; - } - - BigInteger y = One; - BigInteger z = this; - - for (; ; ) - { - if ((exp & 0x1) == 1) - { - y = y.Multiply(z); - } - exp >>= 1; - if (exp == 0) - break; - z = z.Multiply(z); - } - - return y; - } - - public static BigInteger ProbablePrime( - int bitLength, - Random random) - { - return new BigInteger(bitLength, 100, random); - } - - private int Remainder( - int m) - { - Debug.Assert(m > 0); - - long acc = 0; - for (int pos = 0; pos < magnitude.Length; ++pos) - { - long posVal = (uint)magnitude[pos]; - acc = (acc << 32 | posVal) % m; - } - - return (int)acc; - } - - /** - * return x = x % y - done in place (y value preserved) - */ - private int[] Remainder( - int[] x, - int[] y) - { - int xStart = 0; - while (xStart < x.Length && x[xStart] == 0) - { - ++xStart; - } - - int yStart = 0; - while (yStart < y.Length && y[yStart] == 0) - { - ++yStart; - } - - Debug.Assert(yStart < y.Length); - - int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); - - if (xyCmp > 0) - { - int yBitLength = calcBitLength(yStart, y); - int xBitLength = calcBitLength(xStart, x); - int shift = xBitLength - yBitLength; - - int[] c; - int cStart = 0; - int cBitLength = yBitLength; - if (shift > 0) - { - c = ShiftLeft(y, shift); - cBitLength += shift; - Debug.Assert(c[0] != 0); - } - else - { - int len = y.Length - yStart; - c = new int[len]; - Array.Copy(y, yStart, c, 0, len); - } - - for (; ; ) - { - if (cBitLength < xBitLength - || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) - { - Subtract(xStart, x, cStart, c); - - while (x[xStart] == 0) - { - if (++xStart == x.Length) - return x; - } - - //xBitLength = calcBitLength(xStart, x); - xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); - - if (xBitLength <= yBitLength) - { - if (xBitLength < yBitLength) - return x; - - xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); - - if (xyCmp <= 0) - break; - } - } - - shift = cBitLength - xBitLength; - - // NB: The case where c[cStart] is 1-bit is harmless - if (shift == 1) - { - uint firstC = (uint)c[cStart] >> 1; - uint firstX = (uint)x[xStart]; - if (firstC > firstX) - ++shift; - } - - if (shift < 2) - { - ShiftRightOneInPlace(cStart, c); - --cBitLength; - } - else - { - ShiftRightInPlace(cStart, c, shift); - cBitLength -= shift; - } - - //cStart = c.Length - ((cBitLength + 31) / 32); - while (c[cStart] == 0) - { - ++cStart; - } - } - } - - if (xyCmp == 0) - { - Array.Clear(x, xStart, x.Length - xStart); - } - - return x; - } - - public BigInteger Remainder( - BigInteger n) - { - if (n.sign == 0) - throw new ArithmeticException("Division by zero error"); - - if (this.sign == 0) - return Zero; - - // For small values, use fast remainder method - if (n.magnitude.Length == 1) - { - int val = n.magnitude[0]; - - if (val > 0) - { - if (val == 1) - return Zero; - - // TODO Make this func work on uint, and handle val == 1? - int rem = Remainder(val); - - return rem == 0 - ? Zero - : new BigInteger(sign, new int[] { rem }, false); - } - } - - if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0) - return this; - - int[] result; - if (n.QuickPow2Check()) // n is power of two - { - // TODO Move before small values branch above? - result = LastNBits(n.Abs().BitLength - 1); - } - else - { - result = (int[])this.magnitude.Clone(); - result = Remainder(result, n.magnitude); - } - - return new BigInteger(sign, result, true); - } - - private int[] LastNBits( - int n) - { - if (n < 1) - return ZeroMagnitude; - - int numWords = (n + BitsPerInt - 1) / BitsPerInt; - numWords = System.Math.Min(numWords, this.magnitude.Length); - int[] result = new int[numWords]; - - Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords); - - int hiBits = n % 32; - if (hiBits != 0) - { - result[0] &= ~(-1 << hiBits); - } - - return result; - } - - /** - * do a left shift - this returns a new array. - */ - private static int[] ShiftLeft( - int[] mag, - int n) - { - int nInts = (int)((uint)n >> 5); - int nBits = n & 0x1f; - int magLen = mag.Length; - int[] newMag; - - if (nBits == 0) - { - newMag = new int[magLen + nInts]; - mag.CopyTo(newMag, 0); - } - else - { - int i = 0; - int nBits2 = 32 - nBits; - int highBits = (int)((uint)mag[0] >> nBits2); - - if (highBits != 0) - { - newMag = new int[magLen + nInts + 1]; - newMag[i++] = highBits; - } - else - { - newMag = new int[magLen + nInts]; - } - - int m = mag[0]; - for (int j = 0; j < magLen - 1; j++) - { - int next = mag[j + 1]; - - newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2); - m = next; - } - - newMag[i] = mag[magLen - 1] << nBits; - } - - return newMag; - } - - public BigInteger ShiftLeft( - int n) - { - if (sign == 0 || magnitude.Length == 0) - return Zero; - - if (n == 0) - return this; - - if (n < 0) - return ShiftRight(-n); - - BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true); - - if (this.nBits != -1) - { - result.nBits = sign > 0 - ? this.nBits - : this.nBits + n; - } - - if (this.nBitLength != -1) - { - result.nBitLength = this.nBitLength + n; - } - - return result; - } - - /** - * do a right shift - this does it in place. - */ - private static void ShiftRightInPlace( - int start, - int[] mag, - int n) - { - int nInts = (int)((uint)n >> 5) + start; - int nBits = n & 0x1f; - int magEnd = mag.Length - 1; - - if (nInts != start) - { - int delta = (nInts - start); - - for (int i = magEnd; i >= nInts; i--) - { - mag[i] = mag[i - delta]; - } - for (int i = nInts - 1; i >= start; i--) - { - mag[i] = 0; - } - } - - if (nBits != 0) - { - int nBits2 = 32 - nBits; - int m = mag[magEnd]; - - for (int i = magEnd; i > nInts; --i) - { - int next = mag[i - 1]; - - mag[i] = (int)((uint)m >> nBits) | (next << nBits2); - m = next; - } - - mag[nInts] = (int)((uint)mag[nInts] >> nBits); - } - } - - /** - * do a right shift by one - this does it in place. - */ - private static void ShiftRightOneInPlace( - int start, - int[] mag) - { - int i = mag.Length; - int m = mag[i - 1]; - - while (--i > start) - { - int next = mag[i - 1]; - mag[i] = ((int)((uint)m >> 1)) | (next << 31); - m = next; - } - - mag[start] = (int)((uint)mag[start] >> 1); - } - - public BigInteger ShiftRight( - int n) - { - if (n == 0) - return this; - - if (n < 0) - return ShiftLeft(-n); - - if (n >= BitLength) - return (this.sign < 0 ? One.Negate() : Zero); - - // int[] res = (int[]) this.magnitude.Clone(); - // - // ShiftRightInPlace(0, res, n); - // - // return new BigInteger(this.sign, res, true); - - int resultLength = (BitLength - n + 31) >> 5; - int[] res = new int[resultLength]; - - int numInts = n >> 5; - int numBits = n & 31; - - if (numBits == 0) - { - Array.Copy(this.magnitude, 0, res, 0, res.Length); - } - else - { - int numBits2 = 32 - numBits; - - int magPos = this.magnitude.Length - 1 - numInts; - for (int i = resultLength - 1; i >= 0; --i) - { - res[i] = (int)((uint)this.magnitude[magPos--] >> numBits); - - if (magPos >= 0) - { - res[i] |= this.magnitude[magPos] << numBits2; - } - } - } - - Debug.Assert(res[0] != 0); - - return new BigInteger(this.sign, res, false); - } - - public int SignValue - { - get { return sign; } - } - - /** - * returns x = x - y - we assume x is >= y - */ - private static int[] Subtract( - int xStart, - int[] x, - int yStart, - int[] y) - { - Debug.Assert(yStart < y.Length); - Debug.Assert(x.Length - xStart >= y.Length - yStart); - - int iT = x.Length; - int iV = y.Length; - long m; - int borrow = 0; - - do - { - m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow; - x[iT] = (int)m; - - // borrow = (m < 0) ? -1 : 0; - borrow = (int)(m >> 63); - } - while (iV > yStart); - - if (borrow != 0) - { - while (--x[--iT] == -1) - { - } - } - - return x; - } - - public BigInteger Subtract( - BigInteger n) - { - if (n.sign == 0) - return this; - - if (this.sign == 0) - return n.Negate(); - - if (this.sign != n.sign) - return Add(n.Negate()); - - int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); - if (compare == 0) - return Zero; - - BigInteger bigun, lilun; - if (compare < 0) - { - bigun = n; - lilun = this; - } - else - { - bigun = this; - lilun = n; - } - - return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); - } - - private static int[] doSubBigLil( - int[] bigMag, - int[] lilMag) - { - int[] res = (int[])bigMag.Clone(); - - return Subtract(0, res, 0, lilMag); - } - - public byte[] ToByteArray() - { - return ToByteArray(false); - } - - public byte[] ToByteArrayUnsigned() - { - return ToByteArray(true); - } - - private byte[] ToByteArray( - bool unsigned) - { - if (sign == 0) - return unsigned ? ZeroEncoding : new byte[1]; - - int nBits = (unsigned && sign > 0) - ? BitLength - : BitLength + 1; - - int nBytes = GetByteLength(nBits); - byte[] bytes = new byte[nBytes]; - - int magIndex = magnitude.Length; - int bytesIndex = bytes.Length; - - if (sign > 0) - { - while (magIndex > 1) - { - uint mag = (uint)magnitude[--magIndex]; - bytes[--bytesIndex] = (byte)mag; - bytes[--bytesIndex] = (byte)(mag >> 8); - bytes[--bytesIndex] = (byte)(mag >> 16); - bytes[--bytesIndex] = (byte)(mag >> 24); - } - - uint lastMag = (uint)magnitude[0]; - while (lastMag > byte.MaxValue) - { - bytes[--bytesIndex] = (byte)lastMag; - lastMag >>= 8; - } - - bytes[--bytesIndex] = (byte)lastMag; - } - else // sign < 0 - { - bool carry = true; - - while (magIndex > 1) - { - uint mag = ~((uint)magnitude[--magIndex]); - - if (carry) - { - carry = (++mag == uint.MinValue); - } - - bytes[--bytesIndex] = (byte)mag; - bytes[--bytesIndex] = (byte)(mag >> 8); - bytes[--bytesIndex] = (byte)(mag >> 16); - bytes[--bytesIndex] = (byte)(mag >> 24); - } - - uint lastMag = (uint)magnitude[0]; - - if (carry) - { - // Never wraps because magnitude[0] != 0 - --lastMag; - } - - while (lastMag > byte.MaxValue) - { - bytes[--bytesIndex] = (byte)~lastMag; - lastMag >>= 8; - } - - bytes[--bytesIndex] = (byte)~lastMag; - - if (bytesIndex > 0) - { - bytes[--bytesIndex] = byte.MaxValue; - } - } - - return bytes; - } - - public override string ToString() - { - return ToString(10); - } - - public string ToString( - int radix) - { - // TODO Make this method work for other radices (ideally 2 <= radix <= 16) - - switch (radix) - { - case 2: - case 10: - case 16: - break; - default: - throw new FormatException("Only bases 2, 10, 16 are allowed"); - } - - // NB: Can only happen to internally managed instances - if (magnitude == null) - return "null"; - - if (sign == 0) - return "0"; - - Debug.Assert(magnitude.Length > 0); - - StringBuilder sb = new StringBuilder(); - - if (radix == 16) - { - sb.Append(magnitude[0].ToString("x")); - - for (int i = 1; i < magnitude.Length; i++) - { - sb.Append(magnitude[i].ToString("x8")); - } - } - else if (radix == 2) - { - sb.Append('1'); - - for (int i = BitLength - 2; i >= 0; --i) - { - sb.Append(TestBit(i) ? '1' : '0'); - } - } - else - { - // This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works - var S = new List(); - BigInteger bs = ValueOf(radix); - - // The sign is handled separatly. - // Notice however that for this to work, radix 16 _MUST_ be a special case, - // unless we want to enter a recursion well. In their infinite wisdom, why did not - // the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter? - // (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.) - // BigInteger u = new BigInteger(Abs().ToString(16), 16); - BigInteger u = this.Abs(); - BigInteger b; - - while (u.sign != 0) - { - b = u.Mod(bs); - if (b.sign == 0) - { - S.Add("0"); - } - else - { - // see how to interact with different bases - S.Add(b.magnitude[0].ToString("d")); - } - u = u.Divide(bs); - } - - // Then pop the stack - for (int i = S.Count - 1; i >= 0; --i) - { - sb.Append((string)S[i]); - } - } - - string s = sb.ToString(); - - Debug.Assert(s.Length > 0); - - // Strip leading zeros. (We know this number is not all zeroes though) - if (s[0] == '0') - { - int nonZeroPos = 0; - while (s[++nonZeroPos] == '0') { } - - s = s.Substring(nonZeroPos); - } - - if (sign == -1) - { - s = "-" + s; - } - - return s; - } - - private static BigInteger createUValueOf( - ulong value) - { - int msw = (int)(value >> 32); - int lsw = (int)value; - - if (msw != 0) - return new BigInteger(1, new int[] { msw, lsw }, false); - - if (lsw != 0) - { - BigInteger n = new BigInteger(1, new int[] { lsw }, false); - // Check for a power of two - if ((lsw & -lsw) == lsw) - { - n.nBits = 1; - } - return n; - } - - return Zero; - } - - private static BigInteger createValueOf( - long value) - { - if (value < 0) - { - if (value == long.MinValue) - return createValueOf(~value).Not(); - - return createValueOf(-value).Negate(); - } - - return createUValueOf((ulong)value); - - // // store value into a byte array - // byte[] b = new byte[8]; - // for (int i = 0; i < 8; i++) - // { - // b[7 - i] = (byte)value; - // value >>= 8; - // } - // - // return new BigInteger(b); - } - - public static BigInteger ValueOf( - long value) - { - switch (value) - { - case 0: - return Zero; - case 1: - return One; - case 2: - return Two; - case 3: - return Three; - case 10: - return Ten; - } - - return createValueOf(value); - } - - public int GetLowestSetBit() - { - if (this.sign == 0) - return -1; - - int w = magnitude.Length; - - while (--w > 0) - { - if (magnitude[w] != 0) - break; - } - - int word = (int)magnitude[w]; - Debug.Assert(word != 0); - - int b = (word & 0x0000FFFF) == 0 - ? (word & 0x00FF0000) == 0 - ? 7 - : 15 - : (word & 0x000000FF) == 0 - ? 23 - : 31; - - while (b > 0) - { - if ((word << b) == int.MinValue) - break; - - b--; - } - - return ((magnitude.Length - w) * 32 - (b + 1)); - } - - public bool TestBit( - int n) - { - if (n < 0) - throw new ArithmeticException("Bit position must not be negative"); - - if (sign < 0) - return !Not().TestBit(n); - - int wordNum = n / 32; - if (wordNum >= magnitude.Length) - return false; - - int word = magnitude[magnitude.Length - 1 - wordNum]; - return ((word >> (n % 32)) & 1) > 0; - } - - public BigInteger Or( - BigInteger value) - { - if (this.sign == 0) - return value; - - if (value.sign == 0) - return this; - - int[] aMag = this.sign > 0 - ? this.magnitude - : Add(One).magnitude; - - int[] bMag = value.sign > 0 - ? value.magnitude - : value.Add(One).magnitude; - - bool resultNeg = sign < 0 || value.sign < 0; - int resultLength = System.Math.Max(aMag.Length, bMag.Length); - int[] resultMag = new int[resultLength]; - - int aStart = resultMag.Length - aMag.Length; - int bStart = resultMag.Length - bMag.Length; - - for (int i = 0; i < resultMag.Length; ++i) - { - int aWord = i >= aStart ? aMag[i - aStart] : 0; - int bWord = i >= bStart ? bMag[i - bStart] : 0; - - if (this.sign < 0) - { - aWord = ~aWord; - } - - if (value.sign < 0) - { - bWord = ~bWord; - } - - resultMag[i] = aWord | bWord; - - if (resultNeg) - { - resultMag[i] = ~resultMag[i]; - } - } - - BigInteger result = new BigInteger(1, resultMag, true); - - // TODO Optimise this case - if (resultNeg) - { - result = result.Not(); - } - - return result; - } - - public BigInteger Xor( - BigInteger value) - { - if (this.sign == 0) - return value; - - if (value.sign == 0) - return this; - - int[] aMag = this.sign > 0 - ? this.magnitude - : Add(One).magnitude; - - int[] bMag = value.sign > 0 - ? value.magnitude - : value.Add(One).magnitude; - - // TODO Can just replace with sign != value.sign? - bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0); - int resultLength = System.Math.Max(aMag.Length, bMag.Length); - int[] resultMag = new int[resultLength]; - - int aStart = resultMag.Length - aMag.Length; - int bStart = resultMag.Length - bMag.Length; - - for (int i = 0; i < resultMag.Length; ++i) - { - int aWord = i >= aStart ? aMag[i - aStart] : 0; - int bWord = i >= bStart ? bMag[i - bStart] : 0; - - if (this.sign < 0) - { - aWord = ~aWord; - } - - if (value.sign < 0) - { - bWord = ~bWord; - } - - resultMag[i] = aWord ^ bWord; - - if (resultNeg) - { - resultMag[i] = ~resultMag[i]; - } - } - - BigInteger result = new BigInteger(1, resultMag, true); - - // TODO Optimise this case - if (resultNeg) - { - result = result.Not(); - } - - return result; - } - - public BigInteger SetBit( - int n) - { - if (n < 0) - throw new ArithmeticException("Bit address less than zero"); - - if (TestBit(n)) - return this; - - // TODO Handle negative values and zero - if (sign > 0 && n < (BitLength - 1)) - return FlipExistingBit(n); - - return Or(One.ShiftLeft(n)); - } - - public BigInteger ClearBit( - int n) - { - if (n < 0) - throw new ArithmeticException("Bit address less than zero"); - - if (!TestBit(n)) - return this; - - // TODO Handle negative values - if (sign > 0 && n < (BitLength - 1)) - return FlipExistingBit(n); - - return AndNot(One.ShiftLeft(n)); - } - - public BigInteger FlipBit( - int n) - { - if (n < 0) - throw new ArithmeticException("Bit address less than zero"); - - // TODO Handle negative values and zero - if (sign > 0 && n < (BitLength - 1)) - return FlipExistingBit(n); - - return Xor(One.ShiftLeft(n)); - } - - private BigInteger FlipExistingBit( - int n) - { - Debug.Assert(sign > 0); - Debug.Assert(n >= 0); - Debug.Assert(n < BitLength - 1); - - int[] mag = (int[])this.magnitude.Clone(); - mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit - //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32)); - return new BigInteger(this.sign, mag, false); - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text; + + +namespace Org.BouncyCastle.Math +{ + public class BigInteger + { + // The primes b/w 2 and ~2^10 + /* + 3 5 7 11 13 17 19 23 29 + 31 37 41 43 47 53 59 61 67 71 + 73 79 83 89 97 101 103 107 109 113 + 127 131 137 139 149 151 157 163 167 173 + 179 181 191 193 197 199 211 223 227 229 + 233 239 241 251 257 263 269 271 277 281 + 283 293 307 311 313 317 331 337 347 349 + 353 359 367 373 379 383 389 397 401 409 + 419 421 431 433 439 443 449 457 461 463 + 467 479 487 491 499 503 509 521 523 541 + 547 557 563 569 571 577 587 593 599 601 + 607 613 617 619 631 641 643 647 653 659 + 661 673 677 683 691 701 709 719 727 733 + 739 743 751 757 761 769 773 787 797 809 + 811 821 823 827 829 839 853 857 859 863 + 877 881 883 887 907 911 919 929 937 941 + 947 953 967 971 977 983 991 997 + 1009 1013 1019 1021 1031 + */ + + // Each list has a product < 2^31 + private static readonly int[][] primeLists = new int[][] + { + new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 }, + new int[]{ 29, 31, 37, 41, 43 }, + new int[]{ 47, 53, 59, 61, 67 }, + new int[]{ 71, 73, 79, 83 }, + new int[]{ 89, 97, 101, 103 }, + + new int[]{ 107, 109, 113, 127 }, + new int[]{ 131, 137, 139, 149 }, + new int[]{ 151, 157, 163, 167 }, + new int[]{ 173, 179, 181, 191 }, + new int[]{ 193, 197, 199, 211 }, + + new int[]{ 223, 227, 229 }, + new int[]{ 233, 239, 241 }, + new int[]{ 251, 257, 263 }, + new int[]{ 269, 271, 277 }, + new int[]{ 281, 283, 293 }, + + new int[]{ 307, 311, 313 }, + new int[]{ 317, 331, 337 }, + new int[]{ 347, 349, 353 }, + new int[]{ 359, 367, 373 }, + new int[]{ 379, 383, 389 }, + + new int[]{ 397, 401, 409 }, + new int[]{ 419, 421, 431 }, + new int[]{ 433, 439, 443 }, + new int[]{ 449, 457, 461 }, + new int[]{ 463, 467, 479 }, + + new int[]{ 487, 491, 499 }, + new int[]{ 503, 509, 521 }, + new int[]{ 523, 541, 547 }, + new int[]{ 557, 563, 569 }, + new int[]{ 571, 577, 587 }, + + new int[]{ 593, 599, 601 }, + new int[]{ 607, 613, 617 }, + new int[]{ 619, 631, 641 }, + new int[]{ 643, 647, 653 }, + new int[]{ 659, 661, 673 }, + + new int[]{ 677, 683, 691 }, + new int[]{ 701, 709, 719 }, + new int[]{ 727, 733, 739 }, + new int[]{ 743, 751, 757 }, + new int[]{ 761, 769, 773 }, + + new int[]{ 787, 797, 809 }, + new int[]{ 811, 821, 823 }, + new int[]{ 827, 829, 839 }, + new int[]{ 853, 857, 859 }, + new int[]{ 863, 877, 881 }, + + new int[]{ 883, 887, 907 }, + new int[]{ 911, 919, 929 }, + new int[]{ 937, 941, 947 }, + new int[]{ 953, 967, 971 }, + new int[]{ 977, 983, 991 }, + + new int[]{ 997, 1009, 1013 }, + new int[]{ 1019, 1021, 1031 }, + }; + + private static readonly int[] primeProducts; + + private const long IMASK = 0xffffffffL; + private static readonly ulong UIMASK = (ulong)IMASK; + + private static readonly int[] ZeroMagnitude = new int[0]; + private static readonly byte[] ZeroEncoding = new byte[0]; + + public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false); + public static readonly BigInteger One = createUValueOf(1); + public static readonly BigInteger Two = createUValueOf(2); + public static readonly BigInteger Three = createUValueOf(3); + public static readonly BigInteger Ten = createUValueOf(10); + + private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time + private static readonly BigInteger radix2 = ValueOf(2); + private static readonly BigInteger radix2E = radix2.Pow(chunk2); + + private static readonly int chunk10 = 19; + private static readonly BigInteger radix10 = ValueOf(10); + private static readonly BigInteger radix10E = radix10.Pow(chunk10); + + private static readonly int chunk16 = 16; + private static readonly BigInteger radix16 = ValueOf(16); + private static readonly BigInteger radix16E = radix16.Pow(chunk16); + + private static readonly Random RandomSource = new Random(); + + private const int BitsPerByte = 8; + private const int BitsPerInt = 32; + private const int BytesPerInt = 4; + + static BigInteger() + { + primeProducts = new int[primeLists.Length]; + + for (int i = 0; i < primeLists.Length; ++i) + { + int[] primeList = primeLists[i]; + int product = 1; + for (int j = 0; j < primeList.Length; ++j) + { + product *= primeList[j]; + } + primeProducts[i] = product; + } + } + + private int sign; // -1 means -ve; +1 means +ve; 0 means 0; + private int[] magnitude; // array of ints with [0] being the most significant + private int nBits = -1; // cache BitCount() value + private int nBitLength = -1; // cache calcBitLength() value + private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.) + + private static int GetByteLength( + int nBits) + { + return (nBits + BitsPerByte - 1) / BitsPerByte; + } + + private BigInteger() + { + } + + private BigInteger( + int signum, + int[] mag, + bool checkMag) + { + if (checkMag) + { + int i = 0; + while (i < mag.Length && mag[i] == 0) + { + ++i; + } + + if (i == mag.Length) + { + // this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else + { + this.sign = signum; + + if (i == 0) + { + this.magnitude = mag; + } + else + { + // strip leading 0 words + this.magnitude = new int[mag.Length - i]; + Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length); + } + } + } + else + { + this.sign = signum; + this.magnitude = mag; + } + } + + public BigInteger( + string value) + : this(value, 10) + { + } + + public BigInteger( + string str, + int radix) + { + if (str.Length == 0) + throw new FormatException("Zero length BigInteger"); + + NumberStyles style; + int chunk; + BigInteger r; + BigInteger rE; + + switch (radix) + { + case 2: + // Is there anyway to restrict to binary digits? + style = NumberStyles.Integer; + chunk = chunk2; + r = radix2; + rE = radix2E; + break; + case 10: + // This style seems to handle spaces and minus sign already (our processing redundant?) + style = NumberStyles.Integer; + chunk = chunk10; + r = radix10; + rE = radix10E; + break; + case 16: + // TODO Should this be HexNumber? + style = NumberStyles.AllowHexSpecifier; + chunk = chunk16; + r = radix16; + rE = radix16E; + break; + default: + throw new FormatException("Only bases 2, 10, or 16 allowed"); + } + + + int index = 0; + sign = 1; + + if (str[0] == '-') + { + if (str.Length == 1) + throw new FormatException("Zero length BigInteger"); + + sign = -1; + index = 1; + } + + // strip leading zeros from the string str + while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0) + { + index++; + } + + if (index >= str.Length) + { + // zero value - we're done + sign = 0; + magnitude = ZeroMagnitude; + return; + } + + ////// + // could we work out the max number of ints required to store + // str.Length digits in the given base, then allocate that + // storage in one hit?, then Generate the magnitude in one hit too? + ////// + + BigInteger b = Zero; + + + int next = index + chunk; + + if (next <= str.Length) + { + do + { + string s = str.Substring(index, chunk); + ulong i = ulong.Parse(s, style); + BigInteger bi = createUValueOf(i); + + switch (radix) + { + case 2: + // TODO Need this because we are parsing in radix 10 above + if (i > 1) + throw new FormatException("Bad character in radix 2 string: " + s); + + // TODO Parse 64 bits at a time + b = b.ShiftLeft(1); + break; + case 16: + b = b.ShiftLeft(64); + break; + default: + b = b.Multiply(rE); + break; + } + + b = b.Add(bi); + + index = next; + next += chunk; + } + while (next <= str.Length); + } + + if (index < str.Length) + { + string s = str.Substring(index); + ulong i = ulong.Parse(s, style); + BigInteger bi = createUValueOf(i); + + if (b.sign > 0) + { + if (radix == 2) + { + // NB: Can't reach here since we are parsing one char at a time + Debug.Assert(false); + + // TODO Parse all bits at once + // b = b.ShiftLeft(s.Length); + } + else if (radix == 16) + { + b = b.ShiftLeft(s.Length << 2); + } + else + { + b = b.Multiply(r.Pow(s.Length)); + } + + b = b.Add(bi); + } + else + { + b = bi; + } + } + + // Note: This is the previous (slower) algorithm + // while (index < value.Length) + // { + // char c = value[index]; + // string s = c.ToString(); + // int i = Int32.Parse(s, style); + // + // b = b.Multiply(r).Add(ValueOf(i)); + // index++; + // } + + magnitude = b.magnitude; + } + + public BigInteger( + byte[] bytes) + : this(bytes, 0, bytes.Length) + { + } + + public BigInteger( + byte[] bytes, + int offset, + int length) + { + if (length == 0) + throw new FormatException("Zero length BigInteger"); + + // TODO Move this processing into MakeMagnitude (provide sign argument) + if ((sbyte)bytes[offset] < 0) + { + this.sign = -1; + + int end = offset + length; + + int iBval; + // strip leading sign bytes + for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++) + { + } + + if (iBval >= end) + { + this.magnitude = One.magnitude; + } + else + { + int numBytes = end - iBval; + byte[] inverse = new byte[numBytes]; + + int index = 0; + while (index < numBytes) + { + inverse[index++] = (byte)~bytes[iBval++]; + } + + Debug.Assert(iBval == end); + + while (inverse[--index] == byte.MaxValue) + { + inverse[index] = byte.MinValue; + } + + inverse[index]++; + + this.magnitude = MakeMagnitude(inverse, 0, inverse.Length); + } + } + else + { + // strip leading zero bytes and return magnitude bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length > 0 ? 1 : 0; + } + } + + private static int[] MakeMagnitude( + byte[] bytes, + int offset, + int length) + { + int end = offset + length; + + // strip leading zeros + int firstSignificant; + for (firstSignificant = offset; firstSignificant < end + && bytes[firstSignificant] == 0; firstSignificant++) + { + } + + if (firstSignificant >= end) + { + return ZeroMagnitude; + } + + int nInts = (end - firstSignificant + 3) / BytesPerInt; + int bCount = (end - firstSignificant) % BytesPerInt; + if (bCount == 0) + { + bCount = BytesPerInt; + } + + if (nInts < 1) + { + return ZeroMagnitude; + } + + int[] mag = new int[nInts]; + + int v = 0; + int magnitudeIndex = 0; + for (int i = firstSignificant; i < end; ++i) + { + v <<= 8; + v |= bytes[i] & 0xff; + bCount--; + if (bCount <= 0) + { + mag[magnitudeIndex] = v; + magnitudeIndex++; + bCount = BytesPerInt; + v = 0; + } + } + + if (magnitudeIndex < mag.Length) + { + mag[magnitudeIndex] = v; + } + + return mag; + } + + public BigInteger( + int sign, + byte[] bytes) + : this(sign, bytes, 0, bytes.Length) + { + } + + public BigInteger( + int sign, + byte[] bytes, + int offset, + int length) + { + if (sign < -1 || sign > 1) + throw new FormatException("Invalid sign value"); + + if (sign == 0) + { + //this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else + { + // copy bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length < 1 ? 0 : sign; + } + } + + public BigInteger( + int sizeInBits, + Random random) + { + if (sizeInBits < 0) + throw new ArgumentException("sizeInBits must be non-negative"); + + this.nBits = -1; + this.nBitLength = -1; + + if (sizeInBits == 0) + { + // this.sign = 0; + this.magnitude = ZeroMagnitude; + return; + } + + int nBytes = GetByteLength(sizeInBits); + byte[] b = new byte[nBytes]; + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits]; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.sign = this.magnitude.Length < 1 ? 0 : 1; + } + + private static readonly byte[] rndMask = { 255, 127, 63, 31, 15, 7, 3, 1 }; + + public BigInteger( + int bitLength, + int certainty, + Random random) + { + if (bitLength < 2) + throw new ArithmeticException("bitLength < 2"); + + this.sign = 1; + this.nBitLength = bitLength; + + if (bitLength == 2) + { + this.magnitude = random.Next(2) == 0 + ? Two.magnitude + : Three.magnitude; + return; + } + + int nBytes = GetByteLength(bitLength); + byte[] b = new byte[nBytes]; + + int xBits = BitsPerByte * nBytes - bitLength; + byte mask = rndMask[xBits]; + + for (; ; ) + { + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= mask; + + // ensure the leading bit is 1 (to meet the strength requirement) + b[0] |= (byte)(1 << (7 - xBits)); + + // ensure the trailing bit is 1 (i.e. must be odd) + b[nBytes - 1] |= 1; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.nBits = -1; + this.mQuote = -1L; + + if (certainty < 1) + break; + + if (CheckProbablePrime(certainty, random)) + break; + + if (bitLength > 32) + { + for (int rep = 0; rep < 10000; ++rep) + { + int n = 33 + random.Next(bitLength - 2); + this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31)); + this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1); + this.mQuote = -1L; + + if (CheckProbablePrime(certainty, random)) + return; + } + } + } + } + + public BigInteger Abs() + { + return sign >= 0 ? this : Negate(); + } + + /** + * return a = a + b - b preserved. + */ + private static int[] AddMagnitudes( + int[] a, + int[] b) + { + int tI = a.Length - 1; + int vI = b.Length - 1; + long m = 0; + + while (vI >= 0) + { + m += ((long)(uint)a[tI] + (long)(uint)b[vI--]); + a[tI--] = (int)m; + m = (long)((ulong)m >> 32); + } + + if (m != 0) + { + while (tI >= 0 && ++a[tI--] == 0) + { + } + } + + return a; + } + + public BigInteger Add( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (this.sign != value.sign) + { + if (value.sign == 0) + return this; + + if (value.sign < 0) + return Subtract(value.Negate()); + + return value.Subtract(Negate()); + } + + return AddToMagnitude(value.magnitude); + } + + private BigInteger AddToMagnitude( + int[] magToAdd) + { + int[] big, small; + if (this.magnitude.Length < magToAdd.Length) + { + big = magToAdd; + small = this.magnitude; + } + else + { + big = this.magnitude; + small = magToAdd; + } + + // Conservatively avoid over-allocation when no overflow possible + uint limit = uint.MaxValue; + if (big.Length == small.Length) + limit -= (uint)small[0]; + + bool possibleOverflow = (uint)big[0] >= limit; + + int[] bigCopy; + if (possibleOverflow) + { + bigCopy = new int[big.Length + 1]; + big.CopyTo(bigCopy, 1); + } + else + { + bigCopy = (int[])big.Clone(); + } + + bigCopy = AddMagnitudes(bigCopy, small); + + return new BigInteger(this.sign, bigCopy, possibleOverflow); + } + + public BigInteger And( + BigInteger value) + { + if (this.sign == 0 || value.sign == 0) + { + return Zero; + } + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 && value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord & bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger AndNot( + BigInteger val) + { + return And(val.Not()); + } + + public int BitCount + { + get + { + if (nBits == -1) + { + if (sign < 0) + { + // TODO Optimise this case + nBits = Not().BitCount; + } + else + { + int sum = 0; + for (int i = 0; i < magnitude.Length; i++) + { + sum += bitCounts[(byte)magnitude[i]]; + sum += bitCounts[(byte)(magnitude[i] >> 8)]; + sum += bitCounts[(byte)(magnitude[i] >> 16)]; + sum += bitCounts[(byte)(magnitude[i] >> 24)]; + } + nBits = sum; + } + } + + return nBits; + } + } + + private readonly static byte[] bitCounts = + { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, + 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, + 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, + 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, + 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, + 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, + 6, 6, 7, 6, 7, 7, 8 + }; + + private int calcBitLength( + int indx, + int[] mag) + { + for (; ; ) + { + if (indx >= mag.Length) + return 0; + + if (mag[indx] != 0) + break; + + ++indx; + } + + // bit length for everything after the first int + int bitLength = 32 * ((mag.Length - indx) - 1); + + // and determine bitlength of first int + int firstMag = mag[indx]; + bitLength += BitLen(firstMag); + + // Check for negative powers of two + if (sign < 0 && ((firstMag & -firstMag) == firstMag)) + { + do + { + if (++indx >= mag.Length) + { + --bitLength; + break; + } + } + while (mag[indx] == 0); + } + + return bitLength; + } + + public int BitLength + { + get + { + if (nBitLength == -1) + { + nBitLength = sign == 0 + ? 0 + : calcBitLength(0, magnitude); + } + + return nBitLength; + } + } + + // + // BitLen(value) is the number of bits in value. + // + private static int BitLen( + int w) + { + // Binary search - decision tree (5 tests, rarely 6) + return (w < 1 << 15 ? (w < 1 << 7 + ? (w < 1 << 3 ? (w < 1 << 1 + ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) + : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 + ? (w < 1 << 4 ? 4 : 5) + : (w < 1 << 6 ? 6 : 7))) + : (w < 1 << 11 + ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) + : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 + ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) + : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 + ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) + : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); + } + + // private readonly static byte[] bitLengths = + // { + // 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + // 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + // 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8 + // }; + + private bool QuickPow2Check() + { + return sign > 0 && nBits == 1; + } + + public int CompareTo( + object obj) + { + return CompareTo((BigInteger)obj); + } + + /** + * unsigned comparison on two arrays - note the arrays may + * start with leading zeros. + */ + private static int CompareTo( + int xIndx, + int[] x, + int yIndx, + int[] y) + { + while (xIndx != x.Length && x[xIndx] == 0) + { + xIndx++; + } + + while (yIndx != y.Length && y[yIndx] == 0) + { + yIndx++; + } + + return CompareNoLeadingZeroes(xIndx, x, yIndx, y); + } + + private static int CompareNoLeadingZeroes( + int xIndx, + int[] x, + int yIndx, + int[] y) + { + int diff = (x.Length - y.Length) - (xIndx - yIndx); + + if (diff != 0) + { + return diff < 0 ? -1 : 1; + } + + // lengths of magnitudes the same, test the magnitude values + + while (xIndx < x.Length) + { + uint v1 = (uint)x[xIndx++]; + uint v2 = (uint)y[yIndx++]; + + if (v1 != v2) + return v1 < v2 ? -1 : 1; + } + + return 0; + } + + public int CompareTo( + BigInteger value) + { + return sign < value.sign ? -1 + : sign > value.sign ? 1 + : sign == 0 ? 0 + : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude); + } + + /** + * return z = x / y - done in place (z value preserved, x contains the + * remainder) + */ + private int[] Divide( + int[] x, + int[] y) + { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) + { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) + { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + int[] count; + + if (xyCmp > 0) + { + int yBitLength = calcBitLength(yStart, y); + int xBitLength = calcBitLength(xStart, x); + int shift = xBitLength - yBitLength; + + int[] iCount; + int iCountStart = 0; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) + { + // iCount = ShiftLeft(One.magnitude, shift); + iCount = new int[(shift >> 5) + 1]; + iCount[0] = 1 << (shift % 32); + + c = ShiftLeft(y, shift); + cBitLength += shift; + } + else + { + iCount = new int[] { 1 }; + + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + count = new int[iCount.Length]; + + for (; ; ) + { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) + { + Subtract(xStart, x, cStart, c); + AddMagnitudes(count, iCount); + + while (x[xStart] == 0) + { + if (++xStart == x.Length) + return count; + } + + //xBitLength = calcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) + { + if (xBitLength < yBitLength) + return count; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) + { + uint firstC = (uint)c[cStart] >> 1; + uint firstX = (uint)x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) + { + ShiftRightOneInPlace(cStart, c); + --cBitLength; + ShiftRightOneInPlace(iCountStart, iCount); + } + else + { + ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + ShiftRightInPlace(iCountStart, iCount, shift); + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) + { + ++cStart; + } + + while (iCount[iCountStart] == 0) + { + ++iCountStart; + } + } + } + else + { + count = new int[1]; + } + + if (xyCmp == 0) + { + AddMagnitudes(count, One.magnitude); + Array.Clear(x, xStart, x.Length - xStart); + } + + return count; + } + + public BigInteger Divide( + BigInteger val) + { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1); + return val.sign == this.sign ? result : result.Negate(); + } + + int[] mag = (int[])this.magnitude.Clone(); + + return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true); + } + + public BigInteger[] DivideAndRemainder( + BigInteger val) + { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + BigInteger[] biggies = new BigInteger[2]; + + if (sign == 0) + { + biggies[0] = Zero; + biggies[1] = Zero; + } + else if (val.QuickPow2Check()) // val is power of two + { + int e = val.Abs().BitLength - 1; + BigInteger quotient = this.Abs().ShiftRight(e); + int[] remainder = this.LastNBits(e); + + biggies[0] = val.sign == this.sign ? quotient : quotient.Negate(); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + else + { + int[] remainder = (int[])this.magnitude.Clone(); + int[] quotient = Divide(remainder, val.magnitude); + + biggies[0] = new BigInteger(this.sign * val.sign, quotient, true); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + + return biggies; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + BigInteger biggie = obj as BigInteger; + if (biggie == null) + return false; + + if (biggie.sign != sign || biggie.magnitude.Length != magnitude.Length) + return false; + + for (int i = 0; i < magnitude.Length; i++) + { + if (biggie.magnitude[i] != magnitude[i]) + { + return false; + } + } + + return true; + } + + public BigInteger Gcd( + BigInteger value) + { + if (value.sign == 0) + return Abs(); + + if (sign == 0) + return value.Abs(); + + BigInteger r; + BigInteger u = this; + BigInteger v = value; + + while (v.sign != 0) + { + r = u.Mod(v); + u = v; + v = r; + } + + return u; + } + + public override int GetHashCode() + { + int hc = magnitude.Length; + if (magnitude.Length > 0) + { + hc ^= magnitude[0]; + + if (magnitude.Length > 1) + { + hc ^= magnitude[magnitude.Length - 1]; + } + } + + return sign < 0 ? ~hc : hc; + } + + // TODO Make public? + private BigInteger Inc() + { + if (this.sign == 0) + return One; + + if (this.sign < 0) + return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true); + + return AddToMagnitude(One.magnitude); + } + + public int IntValue + { + get + { + return sign == 0 ? 0 + : sign > 0 ? magnitude[magnitude.Length - 1] + : -magnitude[magnitude.Length - 1]; + } + } + + /** + * return whether or not a BigInteger is probably prime with a + * probability of 1 - (1/2)**certainty. + *

    From Knuth Vol 2, pg 395.

    + */ + public bool IsProbablePrime( + int certainty) + { + if (certainty <= 0) + return true; + + BigInteger n = Abs(); + + if (!n.TestBit(0)) + return n.Equals(Two); + + if (n.Equals(One)) + return false; + + return n.CheckProbablePrime(certainty, RandomSource); + } + + private bool CheckProbablePrime( + int certainty, + Random random) + { + Debug.Assert(certainty > 0); + Debug.Assert(CompareTo(Two) > 0); + Debug.Assert(TestBit(0)); + + + // Try to reduce the penalty for really small numbers + int numLists = System.Math.Min(BitLength - 1, primeLists.Length); + + for (int i = 0; i < numLists; ++i) + { + int test = Remainder(primeProducts[i]); + + int[] primeList = primeLists[i]; + for (int j = 0; j < primeList.Length; ++j) + { + int prime = primeList[j]; + int qRem = test % prime; + if (qRem == 0) + { + // We may find small numbers in the list + return BitLength < 16 && IntValue == prime; + } + } + } + + + // TODO Special case for < 10^16 (RabinMiller fixed list) + // if (BitLength < 30) + // { + // RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient + // } + + + // TODO Is it worth trying to create a hybrid of these two? + return RabinMillerTest(certainty, random); + // return SolovayStrassenTest(certainty, random); + + // bool rbTest = RabinMillerTest(certainty, random); + // bool ssTest = SolovayStrassenTest(certainty, random); + // + // Debug.Assert(rbTest == ssTest); + // + // return rbTest; + } + + internal bool RabinMillerTest( + int certainty, + Random random) + { + Debug.Assert(certainty > 0); + Debug.Assert(BitLength > 2); + Debug.Assert(TestBit(0)); + + // let n = 1 + d . 2^s + BigInteger n = this; + BigInteger nMinusOne = n.Subtract(One); + int s = nMinusOne.GetLowestSetBit(); + BigInteger r = nMinusOne.ShiftRight(s); + + Debug.Assert(s >= 1); + + do + { + // TODO Make a method for random BigIntegers in range 0 < x < n) + // - Method can be optimized by only replacing examined bits at each trial + BigInteger a; + do + { + a = new BigInteger(n.BitLength, random); + } + while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0); + + BigInteger y = a.ModPow(r, n); + + if (!y.Equals(One)) + { + int j = 0; + while (!y.Equals(nMinusOne)) + { + if (++j == s) + return false; + + y = y.ModPow(Two, n); + + if (y.Equals(One)) + return false; + } + } + + certainty -= 2; // composites pass for only 1/4 possible 'a' + } + while (certainty > 0); + + return true; + } + + // private bool SolovayStrassenTest( + // int certainty, + // Random random) + // { + // Debug.Assert(certainty > 0); + // Debug.Assert(CompareTo(Two) > 0); + // Debug.Assert(TestBit(0)); + // + // BigInteger n = this; + // BigInteger nMinusOne = n.Subtract(One); + // BigInteger e = nMinusOne.ShiftRight(1); + // + // do + // { + // BigInteger a; + // do + // { + // a = new BigInteger(nBitLength, random); + // } + // // NB: Spec says 0 < x < n, but 1 is trivial + // while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0); + // + // + // // TODO Check this is redundant given the way Jacobi() works? + //// if (!a.Gcd(n).Equals(One)) + //// return false; + // + // int x = Jacobi(a, n); + // + // if (x == 0) + // return false; + // + // BigInteger check = a.ModPow(e, n); + // + // if (x == 1 && !check.Equals(One)) + // return false; + // + // if (x == -1 && !check.Equals(nMinusOne)) + // return false; + // + // --certainty; + // } + // while (certainty > 0); + // + // return true; + // } + // + // private static int Jacobi( + // BigInteger a, + // BigInteger b) + // { + // Debug.Assert(a.sign >= 0); + // Debug.Assert(b.sign > 0); + // Debug.Assert(b.TestBit(0)); + // Debug.Assert(a.CompareTo(b) < 0); + // + // int totalS = 1; + // for (;;) + // { + // if (a.sign == 0) + // return 0; + // + // if (a.Equals(One)) + // break; + // + // int e = a.GetLowestSetBit(); + // + // int bLsw = b.magnitude[b.magnitude.Length - 1]; + // if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5)) + // totalS = -totalS; + // + // // TODO Confirm this is faster than later a1.Equals(One) test + // if (a.BitLength == e + 1) + // break; + // BigInteger a1 = a.ShiftRight(e); + //// if (a1.Equals(One)) + //// break; + // + // int a1Lsw = a1.magnitude[a1.magnitude.Length - 1]; + // if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3) + // totalS = -totalS; + // + //// a = b.Mod(a1); + // a = b.Remainder(a1); + // b = a1; + // } + // return totalS; + // } + + public long LongValue + { + get + { + if (sign == 0) + return 0; + + long v; + if (magnitude.Length > 1) + { + v = ((long)magnitude[magnitude.Length - 2] << 32) + | (magnitude[magnitude.Length - 1] & IMASK); + } + else + { + v = (magnitude[magnitude.Length - 1] & IMASK); + } + + return sign < 0 ? -v : v; + } + } + + public BigInteger Max( + BigInteger value) + { + return CompareTo(value) > 0 ? this : value; + } + + public BigInteger Min( + BigInteger value) + { + return CompareTo(value) < 0 ? this : value; + } + + public BigInteger Mod( + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + BigInteger biggie = Remainder(m); + + return (biggie.sign >= 0 ? biggie : biggie.Add(m)); + } + + public BigInteger ModInverse( + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + // TODO Too slow at the moment + // // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel + // if (m.TestBit(0)) + // { + // //The Almost Inverse Algorithm + // int k = 0; + // BigInteger B = One, C = Zero, F = this, G = m, tmp; + // + // for (;;) + // { + // // While F is even, do F=F/u, C=C*u, k=k+1. + // int zeroes = F.GetLowestSetBit(); + // if (zeroes > 0) + // { + // F = F.ShiftRight(zeroes); + // C = C.ShiftLeft(zeroes); + // k += zeroes; + // } + // + // // If F = 1, then return B,k. + // if (F.Equals(One)) + // { + // BigInteger half = m.Add(One).ShiftRight(1); + // BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m); + // return B.Multiply(halfK).Mod(m); + // } + // + // if (F.CompareTo(G) < 0) + // { + // tmp = G; G = F; F = tmp; + // tmp = B; B = C; C = tmp; + // } + // + // F = F.Add(G); + // B = B.Add(C); + // } + // } + + BigInteger x = new BigInteger(); + BigInteger gcd = ExtEuclid(this.Mod(m), m, x, null); + + if (!gcd.Equals(One)) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x.sign < 0) + { + x.sign = 1; + //x = m.Subtract(x); + x.magnitude = doSubBigLil(m.magnitude, x.magnitude); + } + + return x; + } + + /** + * Calculate the numbers u1, u2, and u3 such that: + * + * u1 * a + u2 * b = u3 + * + * where u3 is the greatest common divider of a and b. + * a and b using the extended Euclid algorithm (refer p. 323 + * of The Art of Computer Programming vol 2, 2nd ed). + * This also seems to have the side effect of calculating + * some form of multiplicative inverse. + * + * @param a First number to calculate gcd for + * @param b Second number to calculate gcd for + * @param u1Out the return object for the u1 value + * @param u2Out the return object for the u2 value + * @return The greatest common divisor of a and b + */ + private static BigInteger ExtEuclid( + BigInteger a, + BigInteger b, + BigInteger u1Out, + BigInteger u2Out) + { + BigInteger u1 = One; + BigInteger u3 = a; + BigInteger v1 = Zero; + BigInteger v3 = b; + + while (v3.sign > 0) + { + BigInteger[] q = u3.DivideAndRemainder(v3); + + BigInteger tmp = v1.Multiply(q[0]); + BigInteger tn = u1.Subtract(tmp); + u1 = v1; + v1 = tn; + + u3 = v3; + v3 = q[1]; + } + + if (u1Out != null) + { + u1Out.sign = u1.sign; + u1Out.magnitude = u1.magnitude; + } + + if (u2Out != null) + { + BigInteger tmp = u1.Multiply(a); + tmp = u3.Subtract(tmp); + BigInteger res = tmp.Divide(b); + u2Out.sign = res.sign; + u2Out.magnitude = res.magnitude; + } + + return u3; + } + + private static void ZeroOut( + int[] x) + { + Array.Clear(x, 0, x.Length); + } + + public BigInteger ModPow( + BigInteger exponent, + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + if (m.Equals(One)) + return Zero; + + if (exponent.sign == 0) + return One; + + if (sign == 0) + return Zero; + + int[] zVal = null; + int[] yAccum = null; + int[] yVal; + + // Montgomery exponentiation is only possible if the modulus is odd, + // but AFAIK, this is always the case for crypto algo's + bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1); + long mQ = 0; + if (useMonty) + { + mQ = m.GetMQuote(); + + // tmp = this * R mod m + BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m); + zVal = tmp.magnitude; + + useMonty = (zVal.Length <= m.magnitude.Length); + + if (useMonty) + { + yAccum = new int[m.magnitude.Length + 1]; + if (zVal.Length < m.magnitude.Length) + { + int[] longZ = new int[m.magnitude.Length]; + zVal.CopyTo(longZ, longZ.Length - zVal.Length); + zVal = longZ; + } + } + } + + if (!useMonty) + { + if (magnitude.Length <= m.magnitude.Length) + { + //zAccum = new int[m.magnitude.Length * 2]; + zVal = new int[m.magnitude.Length]; + magnitude.CopyTo(zVal, zVal.Length - magnitude.Length); + } + else + { + // + // in normal practice we'll never see this... + // + BigInteger tmp = Remainder(m); + + //zAccum = new int[m.magnitude.Length * 2]; + zVal = new int[m.magnitude.Length]; + tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length); + } + + yAccum = new int[m.magnitude.Length * 2]; + } + + yVal = new int[m.magnitude.Length]; + + // + // from LSW to MSW + // + for (int i = 0; i < exponent.magnitude.Length; i++) + { + int v = exponent.magnitude[i]; + int bits = 0; + + if (i == 0) + { + while (v > 0) + { + v <<= 1; + bits++; + } + + // + // first time in initialise y + // + zVal.CopyTo(yVal, 0); + + v <<= 1; + bits++; + } + + while (v != 0) + { + if (useMonty) + { + // Montgomery square algo doesn't exist, and a normal + // square followed by a Montgomery reduction proved to + // be almost as heavy as a Montgomery mulitply. + MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); + } + else + { + Square(yAccum, yVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); + ZeroOut(yAccum); + } + bits++; + + if (v < 0) + { + if (useMonty) + { + MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); + } + else + { + Multiply(yAccum, yVal, zVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, + yVal.Length); + ZeroOut(yAccum); + } + } + + v <<= 1; + } + + while (bits < 32) + { + if (useMonty) + { + MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); + } + else + { + Square(yAccum, yVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); + ZeroOut(yAccum); + } + bits++; + } + } + + if (useMonty) + { + // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m + ZeroOut(zVal); + zVal[zVal.Length - 1] = 1; + MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); + } + + BigInteger result = new BigInteger(1, yVal, true); + + return exponent.sign > 0 + ? result + : result.ModInverse(m); + } + + /** + * return w with w = x * x - w is assumed to have enough space. + */ + private static int[] Square( + int[] w, + int[] x) + { + // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit + // if (w.Length != 2 * x.Length) + // throw new ArgumentException("no I don't think so..."); + + ulong u1, u2, c; + + int wBase = w.Length - 1; + + for (int i = x.Length - 1; i != 0; i--) + { + ulong v = (ulong)(uint)x[i]; + + u1 = v * v; + u2 = u1 >> 32; + u1 = (uint)u1; + + u1 += (ulong)(uint)w[wBase]; + + w[wBase] = (int)(uint)u1; + c = u2 + (u1 >> 32); + + for (int j = i - 1; j >= 0; j--) + { + --wBase; + u1 = v * (ulong)(uint)x[j]; + u2 = u1 >> 31; // multiply by 2! + u1 = (uint)(u1 << 1); // multiply by 2! + u1 += c + (ulong)(uint)w[wBase]; + + w[wBase] = (int)(uint)u1; + c = u2 + (u1 >> 32); + } + + c += (ulong)(uint)w[--wBase]; + w[wBase] = (int)(uint)c; + + if (--wBase >= 0) + { + w[wBase] = (int)(uint)(c >> 32); + } + else + { + Debug.Assert((uint)(c >> 32) == 0); + } + wBase += i; + } + + u1 = (ulong)(uint)x[0]; + u1 = u1 * u1; + u2 = u1 >> 32; + u1 = u1 & IMASK; + + u1 += (ulong)(uint)w[wBase]; + + w[wBase] = (int)(uint)u1; + if (--wBase >= 0) + { + w[wBase] = (int)(uint)(u2 + (u1 >> 32) + (ulong)(uint)w[wBase]); + } + else + { + Debug.Assert((uint)(u2 + (u1 >> 32)) == 0); + } + + return w; + } + + /** + * return x with x = y * z - x is assumed to have enough space. + */ + private static int[] Multiply( + int[] x, + int[] y, + int[] z) + { + int i = z.Length; + + if (i < 1) + return x; + + int xBase = x.Length - y.Length; + + for (; ; ) + { + long a = z[--i] & IMASK; + long val = 0; + + for (int j = y.Length - 1; j >= 0; j--) + { + val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK); + + x[xBase + j] = (int)val; + + val = (long)((ulong)val >> 32); + } + + --xBase; + + if (i < 1) + { + if (xBase >= 0) + { + x[xBase] = (int)val; + } + else + { + Debug.Assert(val == 0); + } + break; + } + + x[xBase] = (int)val; + } + + return x; + } + + private static long FastExtEuclid( + long a, + long b, + long[] uOut) + { + long u1 = 1; + long u3 = a; + long v1 = 0; + long v3 = b; + + while (v3 > 0) + { + long q, tn; + + q = u3 / v3; + + tn = u1 - (v1 * q); + u1 = v1; + v1 = tn; + + tn = u3 - (v3 * q); + u3 = v3; + v3 = tn; + } + + uOut[0] = u1; + uOut[1] = (u3 - (u1 * a)) / b; + + return u3; + } + + private static long FastModInverse( + long v, + long m) + { + if (m < 1) + throw new ArithmeticException("Modulus must be positive"); + + long[] x = new long[2]; + long gcd = FastExtEuclid(v, m, x); + + if (gcd != 1) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x[0] < 0) + { + x[0] += m; + } + + return x[0]; + } + + // private static BigInteger MQuoteB = One.ShiftLeft(32); + // private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One); + + /** + * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size) + */ + private long GetMQuote() + { + Debug.Assert(this.sign > 0); + + if (mQuote != -1) + { + return mQuote; // already calculated + } + + if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0) + { + return -1; // not for even numbers + } + + long v = (((~this.magnitude[this.magnitude.Length - 1]) | 1) & 0xffffffffL); + mQuote = FastModInverse(v, 0x100000000L); + + return mQuote; + } + + /** + * Montgomery multiplication: a = x * y * R^(-1) mod m + *
    + * Based algorithm 14.36 of Handbook of Applied Cryptography. + *
    + *
  • m, x, y should have length n
  • + *
  • a should have length (n + 1)
  • + *
  • b = 2^32, R = b^n
  • + *
    + * The result is put in x + *
    + * NOTE: the indices of x, y, m, a different in HAC and in Java + */ + private static void MultiplyMonty( + int[] a, + int[] x, + int[] y, + int[] m, + long mQuote) + // mQuote = -m^(-1) mod b + { + if (m.Length == 1) + { + x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], (ulong)mQuote); + return; + } + + int n = m.Length; + int nMinus1 = n - 1; + long y_0 = y[nMinus1] & IMASK; + + // 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} ) + Array.Clear(a, 0, n + 1); + + // 2. for i from 0 to (n - 1) do the following: + for (int i = n; i > 0; i--) + { + long x_i = x[i - 1] & IMASK; + + // 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b + long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK; + + // 2.2 a = (a + x_i * y + u * m) / b + long prod1 = x_i * y_0; + long prod2 = u * (m[nMinus1] & IMASK); + long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK); + long carry = (long)((ulong)prod1 >> 32) + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); + for (int j = nMinus1; j > 0; j--) + { + prod1 = x_i * (y[j - 1] & IMASK); + prod2 = u * (m[j - 1] & IMASK); + tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK); + carry = (long)((ulong)carry >> 32) + (long)((ulong)prod1 >> 32) + + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); + a[j + 1] = (int)tmp; // division by b + } + carry += (a[0] & IMASK); + a[1] = (int)carry; + a[0] = (int)((ulong)carry >> 32); // OJO!!!!! + } + + // 3. if x >= m the x = x - m + if (CompareTo(0, a, 0, m) >= 0) + { + Subtract(0, a, 0, m); + } + + // put the result in x + Array.Copy(a, 1, x, 0, n); + } + + private static uint MultiplyMontyNIsOne( + uint x, + uint y, + uint m, + ulong mQuote) + { + ulong um = m; + ulong prod1 = (ulong)x * (ulong)y; + ulong u = (prod1 * mQuote) & UIMASK; + ulong prod2 = u * um; + ulong tmp = (prod1 & UIMASK) + (prod2 & UIMASK); + ulong carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32); + + if (carry > um) + { + carry -= um; + } + + return (uint)(carry & UIMASK); + } + + public BigInteger Multiply( + BigInteger val) + { + if (sign == 0 || val.sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1); + return val.sign > 0 ? result : result.Negate(); + } + + if (this.QuickPow2Check()) // this is power of two + { + BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1); + return this.sign > 0 ? result : result.Negate(); + } + + int resLength = (this.BitLength + val.BitLength) / BitsPerInt + 1; + int[] res = new int[resLength]; + + if (val == this) + { + Square(res, this.magnitude); + } + else + { + Multiply(res, this.magnitude, val.magnitude); + } + + return new BigInteger(sign * val.sign, res, true); + } + + public BigInteger Negate() + { + if (sign == 0) + return this; + + return new BigInteger(-sign, magnitude, false); + } + + public BigInteger NextProbablePrime() + { + if (sign < 0) + throw new ArithmeticException("Cannot be called on value < 0"); + + if (CompareTo(Two) < 0) + return Two; + + BigInteger n = Inc().SetBit(0); + + while (!n.CheckProbablePrime(100, RandomSource)) + { + n = n.Add(Two); + } + + return n; + } + + public BigInteger Not() + { + return Inc().Negate(); + } + + public BigInteger Pow(int exp) + { + if (exp < 0) + { + throw new ArithmeticException("Negative exponent"); + } + + if (exp == 0) + { + return One; + } + + if (sign == 0 || Equals(One)) + { + return this; + } + + BigInteger y = One; + BigInteger z = this; + + for (; ; ) + { + if ((exp & 0x1) == 1) + { + y = y.Multiply(z); + } + exp >>= 1; + if (exp == 0) + break; + z = z.Multiply(z); + } + + return y; + } + + public static BigInteger ProbablePrime( + int bitLength, + Random random) + { + return new BigInteger(bitLength, 100, random); + } + + private int Remainder( + int m) + { + Debug.Assert(m > 0); + + long acc = 0; + for (int pos = 0; pos < magnitude.Length; ++pos) + { + long posVal = (uint)magnitude[pos]; + acc = (acc << 32 | posVal) % m; + } + + return (int)acc; + } + + /** + * return x = x % y - done in place (y value preserved) + */ + private int[] Remainder( + int[] x, + int[] y) + { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) + { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) + { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp > 0) + { + int yBitLength = calcBitLength(yStart, y); + int xBitLength = calcBitLength(xStart, x); + int shift = xBitLength - yBitLength; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) + { + c = ShiftLeft(y, shift); + cBitLength += shift; + Debug.Assert(c[0] != 0); + } + else + { + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + for (; ; ) + { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) + { + Subtract(xStart, x, cStart, c); + + while (x[xStart] == 0) + { + if (++xStart == x.Length) + return x; + } + + //xBitLength = calcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) + { + if (xBitLength < yBitLength) + return x; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) + { + uint firstC = (uint)c[cStart] >> 1; + uint firstX = (uint)x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) + { + ShiftRightOneInPlace(cStart, c); + --cBitLength; + } + else + { + ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) + { + ++cStart; + } + } + } + + if (xyCmp == 0) + { + Array.Clear(x, xStart, x.Length - xStart); + } + + return x; + } + + public BigInteger Remainder( + BigInteger n) + { + if (n.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (this.sign == 0) + return Zero; + + // For small values, use fast remainder method + if (n.magnitude.Length == 1) + { + int val = n.magnitude[0]; + + if (val > 0) + { + if (val == 1) + return Zero; + + // TODO Make this func work on uint, and handle val == 1? + int rem = Remainder(val); + + return rem == 0 + ? Zero + : new BigInteger(sign, new int[] { rem }, false); + } + } + + if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0) + return this; + + int[] result; + if (n.QuickPow2Check()) // n is power of two + { + // TODO Move before small values branch above? + result = LastNBits(n.Abs().BitLength - 1); + } + else + { + result = (int[])this.magnitude.Clone(); + result = Remainder(result, n.magnitude); + } + + return new BigInteger(sign, result, true); + } + + private int[] LastNBits( + int n) + { + if (n < 1) + return ZeroMagnitude; + + int numWords = (n + BitsPerInt - 1) / BitsPerInt; + numWords = System.Math.Min(numWords, this.magnitude.Length); + int[] result = new int[numWords]; + + Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords); + + int hiBits = n % 32; + if (hiBits != 0) + { + result[0] &= ~(-1 << hiBits); + } + + return result; + } + + /** + * do a left shift - this returns a new array. + */ + private static int[] ShiftLeft( + int[] mag, + int n) + { + int nInts = (int)((uint)n >> 5); + int nBits = n & 0x1f; + int magLen = mag.Length; + int[] newMag; + + if (nBits == 0) + { + newMag = new int[magLen + nInts]; + mag.CopyTo(newMag, 0); + } + else + { + int i = 0; + int nBits2 = 32 - nBits; + int highBits = (int)((uint)mag[0] >> nBits2); + + if (highBits != 0) + { + newMag = new int[magLen + nInts + 1]; + newMag[i++] = highBits; + } + else + { + newMag = new int[magLen + nInts]; + } + + int m = mag[0]; + for (int j = 0; j < magLen - 1; j++) + { + int next = mag[j + 1]; + + newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2); + m = next; + } + + newMag[i] = mag[magLen - 1] << nBits; + } + + return newMag; + } + + public BigInteger ShiftLeft( + int n) + { + if (sign == 0 || magnitude.Length == 0) + return Zero; + + if (n == 0) + return this; + + if (n < 0) + return ShiftRight(-n); + + BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true); + + if (this.nBits != -1) + { + result.nBits = sign > 0 + ? this.nBits + : this.nBits + n; + } + + if (this.nBitLength != -1) + { + result.nBitLength = this.nBitLength + n; + } + + return result; + } + + /** + * do a right shift - this does it in place. + */ + private static void ShiftRightInPlace( + int start, + int[] mag, + int n) + { + int nInts = (int)((uint)n >> 5) + start; + int nBits = n & 0x1f; + int magEnd = mag.Length - 1; + + if (nInts != start) + { + int delta = (nInts - start); + + for (int i = magEnd; i >= nInts; i--) + { + mag[i] = mag[i - delta]; + } + for (int i = nInts - 1; i >= start; i--) + { + mag[i] = 0; + } + } + + if (nBits != 0) + { + int nBits2 = 32 - nBits; + int m = mag[magEnd]; + + for (int i = magEnd; i > nInts; --i) + { + int next = mag[i - 1]; + + mag[i] = (int)((uint)m >> nBits) | (next << nBits2); + m = next; + } + + mag[nInts] = (int)((uint)mag[nInts] >> nBits); + } + } + + /** + * do a right shift by one - this does it in place. + */ + private static void ShiftRightOneInPlace( + int start, + int[] mag) + { + int i = mag.Length; + int m = mag[i - 1]; + + while (--i > start) + { + int next = mag[i - 1]; + mag[i] = ((int)((uint)m >> 1)) | (next << 31); + m = next; + } + + mag[start] = (int)((uint)mag[start] >> 1); + } + + public BigInteger ShiftRight( + int n) + { + if (n == 0) + return this; + + if (n < 0) + return ShiftLeft(-n); + + if (n >= BitLength) + return (this.sign < 0 ? One.Negate() : Zero); + + // int[] res = (int[]) this.magnitude.Clone(); + // + // ShiftRightInPlace(0, res, n); + // + // return new BigInteger(this.sign, res, true); + + int resultLength = (BitLength - n + 31) >> 5; + int[] res = new int[resultLength]; + + int numInts = n >> 5; + int numBits = n & 31; + + if (numBits == 0) + { + Array.Copy(this.magnitude, 0, res, 0, res.Length); + } + else + { + int numBits2 = 32 - numBits; + + int magPos = this.magnitude.Length - 1 - numInts; + for (int i = resultLength - 1; i >= 0; --i) + { + res[i] = (int)((uint)this.magnitude[magPos--] >> numBits); + + if (magPos >= 0) + { + res[i] |= this.magnitude[magPos] << numBits2; + } + } + } + + Debug.Assert(res[0] != 0); + + return new BigInteger(this.sign, res, false); + } + + public int SignValue + { + get { return sign; } + } + + /** + * returns x = x - y - we assume x is >= y + */ + private static int[] Subtract( + int xStart, + int[] x, + int yStart, + int[] y) + { + Debug.Assert(yStart < y.Length); + Debug.Assert(x.Length - xStart >= y.Length - yStart); + + int iT = x.Length; + int iV = y.Length; + long m; + int borrow = 0; + + do + { + m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow; + x[iT] = (int)m; + + // borrow = (m < 0) ? -1 : 0; + borrow = (int)(m >> 63); + } + while (iV > yStart); + + if (borrow != 0) + { + while (--x[--iT] == -1) + { + } + } + + return x; + } + + public BigInteger Subtract( + BigInteger n) + { + if (n.sign == 0) + return this; + + if (this.sign == 0) + return n.Negate(); + + if (this.sign != n.sign) + return Add(n.Negate()); + + int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); + if (compare == 0) + return Zero; + + BigInteger bigun, lilun; + if (compare < 0) + { + bigun = n; + lilun = this; + } + else + { + bigun = this; + lilun = n; + } + + return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); + } + + private static int[] doSubBigLil( + int[] bigMag, + int[] lilMag) + { + int[] res = (int[])bigMag.Clone(); + + return Subtract(0, res, 0, lilMag); + } + + public byte[] ToByteArray() + { + return ToByteArray(false); + } + + public byte[] ToByteArrayUnsigned() + { + return ToByteArray(true); + } + + private byte[] ToByteArray( + bool unsigned) + { + if (sign == 0) + return unsigned ? ZeroEncoding : new byte[1]; + + int nBits = (unsigned && sign > 0) + ? BitLength + : BitLength + 1; + + int nBytes = GetByteLength(nBits); + byte[] bytes = new byte[nBytes]; + + int magIndex = magnitude.Length; + int bytesIndex = bytes.Length; + + if (sign > 0) + { + while (magIndex > 1) + { + uint mag = (uint)magnitude[--magIndex]; + bytes[--bytesIndex] = (byte)mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint)magnitude[0]; + while (lastMag > byte.MaxValue) + { + bytes[--bytesIndex] = (byte)lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte)lastMag; + } + else // sign < 0 + { + bool carry = true; + + while (magIndex > 1) + { + uint mag = ~((uint)magnitude[--magIndex]); + + if (carry) + { + carry = (++mag == uint.MinValue); + } + + bytes[--bytesIndex] = (byte)mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint)magnitude[0]; + + if (carry) + { + // Never wraps because magnitude[0] != 0 + --lastMag; + } + + while (lastMag > byte.MaxValue) + { + bytes[--bytesIndex] = (byte)~lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte)~lastMag; + + if (bytesIndex > 0) + { + bytes[--bytesIndex] = byte.MaxValue; + } + } + + return bytes; + } + + public override string ToString() + { + return ToString(10); + } + + public string ToString( + int radix) + { + // TODO Make this method work for other radices (ideally 2 <= radix <= 16) + + switch (radix) + { + case 2: + case 10: + case 16: + break; + default: + throw new FormatException("Only bases 2, 10, 16 are allowed"); + } + + // NB: Can only happen to internally managed instances + if (magnitude == null) + return "null"; + + if (sign == 0) + return "0"; + + Debug.Assert(magnitude.Length > 0); + + StringBuilder sb = new StringBuilder(); + + if (radix == 16) + { + sb.Append(magnitude[0].ToString("x")); + + for (int i = 1; i < magnitude.Length; i++) + { + sb.Append(magnitude[i].ToString("x8")); + } + } + else if (radix == 2) + { + sb.Append('1'); + + for (int i = BitLength - 2; i >= 0; --i) + { + sb.Append(TestBit(i) ? '1' : '0'); + } + } + else + { + // This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works + var S = new List(); + BigInteger bs = ValueOf(radix); + + // The sign is handled separatly. + // Notice however that for this to work, radix 16 _MUST_ be a special case, + // unless we want to enter a recursion well. In their infinite wisdom, why did not + // the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter? + // (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.) + // BigInteger u = new BigInteger(Abs().ToString(16), 16); + BigInteger u = this.Abs(); + BigInteger b; + + while (u.sign != 0) + { + b = u.Mod(bs); + if (b.sign == 0) + { + S.Add("0"); + } + else + { + // see how to interact with different bases + S.Add(b.magnitude[0].ToString("d")); + } + u = u.Divide(bs); + } + + // Then pop the stack + for (int i = S.Count - 1; i >= 0; --i) + { + sb.Append((string)S[i]); + } + } + + string s = sb.ToString(); + + Debug.Assert(s.Length > 0); + + // Strip leading zeros. (We know this number is not all zeroes though) + if (s[0] == '0') + { + int nonZeroPos = 0; + while (s[++nonZeroPos] == '0') { } + + s = s.Substring(nonZeroPos); + } + + if (sign == -1) + { + s = "-" + s; + } + + return s; + } + + private static BigInteger createUValueOf( + ulong value) + { + int msw = (int)(value >> 32); + int lsw = (int)value; + + if (msw != 0) + return new BigInteger(1, new int[] { msw, lsw }, false); + + if (lsw != 0) + { + BigInteger n = new BigInteger(1, new int[] { lsw }, false); + // Check for a power of two + if ((lsw & -lsw) == lsw) + { + n.nBits = 1; + } + return n; + } + + return Zero; + } + + private static BigInteger createValueOf( + long value) + { + if (value < 0) + { + if (value == long.MinValue) + return createValueOf(~value).Not(); + + return createValueOf(-value).Negate(); + } + + return createUValueOf((ulong)value); + + // // store value into a byte array + // byte[] b = new byte[8]; + // for (int i = 0; i < 8; i++) + // { + // b[7 - i] = (byte)value; + // value >>= 8; + // } + // + // return new BigInteger(b); + } + + public static BigInteger ValueOf( + long value) + { + switch (value) + { + case 0: + return Zero; + case 1: + return One; + case 2: + return Two; + case 3: + return Three; + case 10: + return Ten; + } + + return createValueOf(value); + } + + public int GetLowestSetBit() + { + if (this.sign == 0) + return -1; + + int w = magnitude.Length; + + while (--w > 0) + { + if (magnitude[w] != 0) + break; + } + + int word = (int)magnitude[w]; + Debug.Assert(word != 0); + + int b = (word & 0x0000FFFF) == 0 + ? (word & 0x00FF0000) == 0 + ? 7 + : 15 + : (word & 0x000000FF) == 0 + ? 23 + : 31; + + while (b > 0) + { + if ((word << b) == int.MinValue) + break; + + b--; + } + + return ((magnitude.Length - w) * 32 - (b + 1)); + } + + public bool TestBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit position must not be negative"); + + if (sign < 0) + return !Not().TestBit(n); + + int wordNum = n / 32; + if (wordNum >= magnitude.Length) + return false; + + int word = magnitude[magnitude.Length - 1 - wordNum]; + return ((word >> (n % 32)) & 1) > 0; + } + + public BigInteger Or( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 || value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord | bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger Xor( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + // TODO Can just replace with sign != value.sign? + bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0); + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord ^ bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger SetBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (TestBit(n)) + return this; + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Or(One.ShiftLeft(n)); + } + + public BigInteger ClearBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (!TestBit(n)) + return this; + + // TODO Handle negative values + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return AndNot(One.ShiftLeft(n)); + } + + public BigInteger FlipBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Xor(One.ShiftLeft(n)); + } + + private BigInteger FlipExistingBit( + int n) + { + Debug.Assert(sign > 0); + Debug.Assert(n >= 0); + Debug.Assert(n < BitLength - 1); + + int[] mag = (int[])this.magnitude.Clone(); + mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit + //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32)); + return new BigInteger(this.sign, mag, false); + } + } +} diff --git a/SharpCompress/Crypto/BufferedBlockCipher.cs b/src/SharpCompress/Crypto/BufferedBlockCipher.cs similarity index 96% rename from SharpCompress/Crypto/BufferedBlockCipher.cs rename to src/SharpCompress/Crypto/BufferedBlockCipher.cs index c7c06b3b..64242caf 100644 --- a/SharpCompress/Crypto/BufferedBlockCipher.cs +++ b/src/SharpCompress/Crypto/BufferedBlockCipher.cs @@ -1,376 +1,376 @@ -using System; - - -namespace Org.BouncyCastle.Crypto -{ - /** - * A wrapper class that allows block ciphers to be used to process data in - * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the - * buffer is full and more data is being added, or on a doFinal. - *

    - * Note: in the case where the underlying cipher is either a CFB cipher or an - * OFB one the last block may not be a multiple of the block size. - *

    - */ - public class BufferedBlockCipher - : BufferedCipherBase - { - internal byte[] buf; - internal int bufOff; - internal bool forEncryption; - internal IBlockCipher cipher; - - /** - * constructor for subclasses - */ - protected BufferedBlockCipher() - { - } - - /** - * Create a buffered block cipher without padding. - * - * @param cipher the underlying block cipher this buffering object wraps. - * false otherwise. - */ - public BufferedBlockCipher( - IBlockCipher cipher) - { - if (cipher == null) - throw new ArgumentNullException("cipher"); - - this.cipher = cipher; - buf = new byte[cipher.GetBlockSize()]; - bufOff = 0; - } - - public override string AlgorithmName - { - get { return cipher.AlgorithmName; } - } - - /** - * initialise the cipher. - * - * @param forEncryption if true the cipher is initialised for - * encryption, if false for decryption. - * @param param the key and other data required by the cipher. - * @exception ArgumentException if the parameters argument is - * inappropriate. - */ - // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper - public override void Init( - bool forEncryption, - ICipherParameters parameters) - { - this.forEncryption = forEncryption; - - //if (parameters is ParametersWithRandom) - //{ - // parameters = ((ParametersWithRandom) parameters).Parameters; - //} - - Reset(); - - cipher.Init(forEncryption, parameters); - } - - /** - * return the blocksize for the underlying cipher. - * - * @return the blocksize for the underlying cipher. - */ - public override int GetBlockSize() - { - return cipher.GetBlockSize(); - } - - /** - * return the size of the output buffer required for an update - * an input of len bytes. - * - * @param len the length of the input. - * @return the space required to accommodate a call to update - * with len bytes of input. - */ - public override int GetUpdateOutputSize( - int length) - { - int total = length + bufOff; - int leftOver = total % buf.Length; - return total - leftOver; - } - - /** - * return the size of the output buffer required for an update plus a - * doFinal with an input of len bytes. - * - * @param len the length of the input. - * @return the space required to accommodate a call to update and doFinal - * with len bytes of input. - */ - public override int GetOutputSize( - int length) - { - // Note: Can assume IsPartialBlockOkay is true for purposes of this calculation - return length + bufOff; - } - - /** - * process a single byte, producing an output block if neccessary. - * - * @param in the input byte. - * @param out the space for any output that might be produced. - * @param outOff the offset from which the output will be copied. - * @return the number of output bytes copied to out. - * @exception DataLengthException if there isn't enough space in out. - * @exception InvalidOperationException if the cipher isn't initialised. - */ - public override int ProcessByte( - byte input, - byte[] output, - int outOff) - { - buf[bufOff++] = input; - - if (bufOff == buf.Length) - { - if ((outOff + buf.Length) > output.Length) - throw new DataLengthException("output buffer too short"); - - bufOff = 0; - return cipher.ProcessBlock(buf, 0, output, outOff); - } - - return 0; - } - - public override byte[] ProcessByte( - byte input) - { - int outLength = GetUpdateOutputSize(1); - - byte[] outBytes = outLength > 0 ? new byte[outLength] : null; - - int pos = ProcessByte(input, outBytes, 0); - - if (outLength > 0 && pos < outLength) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - - return outBytes; - } - - public override byte[] ProcessBytes( - byte[] input, - int inOff, - int length) - { - if (input == null) - throw new ArgumentNullException("input"); - if (length < 1) - return null; - - int outLength = GetUpdateOutputSize(length); - - byte[] outBytes = outLength > 0 ? new byte[outLength] : null; - - int pos = ProcessBytes(input, inOff, length, outBytes, 0); - - if (outLength > 0 && pos < outLength) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - - return outBytes; - } - - /** - * process an array of bytes, producing output if necessary. - * - * @param in the input byte array. - * @param inOff the offset at which the input data starts. - * @param len the number of bytes to be copied out of the input array. - * @param out the space for any output that might be produced. - * @param outOff the offset from which the output will be copied. - * @return the number of output bytes copied to out. - * @exception DataLengthException if there isn't enough space in out. - * @exception InvalidOperationException if the cipher isn't initialised. - */ - public override int ProcessBytes( - byte[] input, - int inOff, - int length, - byte[] output, - int outOff) - { - if (length < 1) - { - if (length < 0) - throw new ArgumentException("Can't have a negative input length!"); - - return 0; - } - - int blockSize = GetBlockSize(); - int outLength = GetUpdateOutputSize(length); - - if (outLength > 0) - { - if ((outOff + outLength) > output.Length) - { - throw new DataLengthException("output buffer too short"); - } - } - - int resultLen = 0; - int gapLen = buf.Length - bufOff; - if (length > gapLen) - { - Array.Copy(input, inOff, buf, bufOff, gapLen); - resultLen += cipher.ProcessBlock(buf, 0, output, outOff); - bufOff = 0; - length -= gapLen; - inOff += gapLen; - while (length > buf.Length) - { - resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen); - length -= blockSize; - inOff += blockSize; - } - } - Array.Copy(input, inOff, buf, bufOff, length); - bufOff += length; - if (bufOff == buf.Length) - { - resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); - bufOff = 0; - } - return resultLen; - } - - public override byte[] DoFinal() - { - byte[] outBytes = EmptyBuffer; - - int length = GetOutputSize(0); - if (length > 0) - { - outBytes = new byte[length]; - - int pos = DoFinal(outBytes, 0); - if (pos < outBytes.Length) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - } - else - { - Reset(); - } - - return outBytes; - } - - public override byte[] DoFinal( - byte[] input, - int inOff, - int inLen) - { - if (input == null) - throw new ArgumentNullException("input"); - - int length = GetOutputSize(inLen); - - byte[] outBytes = EmptyBuffer; - - if (length > 0) - { - outBytes = new byte[length]; - - int pos = (inLen > 0) - ? ProcessBytes(input, inOff, inLen, outBytes, 0) - : 0; - - pos += DoFinal(outBytes, pos); - - if (pos < outBytes.Length) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - } - else - { - Reset(); - } - - return outBytes; - } - - /** - * Process the last block in the buffer. - * - * @param out the array the block currently being held is copied into. - * @param outOff the offset at which the copying starts. - * @return the number of output bytes copied to out. - * @exception DataLengthException if there is insufficient space in out for - * the output, or the input is not block size aligned and should be. - * @exception InvalidOperationException if the underlying cipher is not - * initialised. - * @exception InvalidCipherTextException if padding is expected and not found. - * @exception DataLengthException if the input is not block size - * aligned. - */ - public override int DoFinal( - byte[] output, - int outOff) - { - try - { - if (bufOff != 0) - { - if (!cipher.IsPartialBlockOkay) - { - throw new DataLengthException("data not block size aligned"); - } - - if (outOff + bufOff > output.Length) - { - throw new DataLengthException("output buffer too short for DoFinal()"); - } - - // NB: Can't copy directly, or we may write too much output - cipher.ProcessBlock(buf, 0, buf, 0); - Array.Copy(buf, 0, output, outOff, bufOff); - } - - return bufOff; - } - finally - { - Reset(); - } - } - - /** - * Reset the buffer and cipher. After resetting the object is in the same - * state as it was after the last init (if there was one). - */ - public override void Reset() - { - Array.Clear(buf, 0, buf.Length); - bufOff = 0; - - cipher.Reset(); - } - } -} +using System; + + +namespace Org.BouncyCastle.Crypto +{ + /** + * A wrapper class that allows block ciphers to be used to process data in + * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the + * buffer is full and more data is being added, or on a doFinal. + *

    + * Note: in the case where the underlying cipher is either a CFB cipher or an + * OFB one the last block may not be a multiple of the block size. + *

    + */ + public class BufferedBlockCipher + : BufferedCipherBase + { + internal byte[] buf; + internal int bufOff; + internal bool forEncryption; + internal IBlockCipher cipher; + + /** + * constructor for subclasses + */ + protected BufferedBlockCipher() + { + } + + /** + * Create a buffered block cipher without padding. + * + * @param cipher the underlying block cipher this buffering object wraps. + * false otherwise. + */ + public BufferedBlockCipher( + IBlockCipher cipher) + { + if (cipher == null) + throw new ArgumentNullException("cipher"); + + this.cipher = cipher; + buf = new byte[cipher.GetBlockSize()]; + bufOff = 0; + } + + public override string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + //if (parameters is ParametersWithRandom) + //{ + // parameters = ((ParametersWithRandom) parameters).Parameters; + //} + + Reset(); + + cipher.Init(forEncryption, parameters); + } + + /** + * return the blocksize for the underlying cipher. + * + * @return the blocksize for the underlying cipher. + */ + public override int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public override int GetUpdateOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + return total - leftOver; + } + + /** + * return the size of the output buffer required for an update plus a + * doFinal with an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with len bytes of input. + */ + public override int GetOutputSize( + int length) + { + // Note: Can assume IsPartialBlockOkay is true for purposes of this calculation + return length + bufOff; + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + buf[bufOff++] = input; + + if (bufOff == buf.Length) + { + if ((outOff + buf.Length) > output.Length) + throw new DataLengthException("output buffer too short"); + + bufOff = 0; + return cipher.ProcessBlock(buf, 0, output, outOff); + } + + return 0; + } + + public override byte[] ProcessByte( + byte input) + { + int outLength = GetUpdateOutputSize(1); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessByte(input, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (input == null) + throw new ArgumentNullException("input"); + if (length < 1) + return null; + + int outLength = GetUpdateOutputSize(length); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessBytes(input, inOff, length, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param len the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (length < 1) + { + if (length < 0) + throw new ArgumentException("Can't have a negative input length!"); + + return 0; + } + + int blockSize = GetBlockSize(); + int outLength = GetUpdateOutputSize(length); + + if (outLength > 0) + { + if ((outOff + outLength) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.Length - bufOff; + if (length > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + resultLen += cipher.ProcessBlock(buf, 0, output, outOff); + bufOff = 0; + length -= gapLen; + inOff += gapLen; + while (length > buf.Length) + { + resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen); + length -= blockSize; + inOff += blockSize; + } + } + Array.Copy(input, inOff, buf, bufOff, length); + bufOff += length; + if (bufOff == buf.Length) + { + resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); + bufOff = 0; + } + return resultLen; + } + + public override byte[] DoFinal() + { + byte[] outBytes = EmptyBuffer; + + int length = GetOutputSize(0); + if (length > 0) + { + outBytes = new byte[length]; + + int pos = DoFinal(outBytes, 0); + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + else + { + Reset(); + } + + return outBytes; + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int inLen) + { + if (input == null) + throw new ArgumentNullException("input"); + + int length = GetOutputSize(inLen); + + byte[] outBytes = EmptyBuffer; + + if (length > 0) + { + outBytes = new byte[length]; + + int pos = (inLen > 0) + ? ProcessBytes(input, inOff, inLen, outBytes, 0) + : 0; + + pos += DoFinal(outBytes, pos); + + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + else + { + Reset(); + } + + return outBytes; + } + + /** + * Process the last block in the buffer. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output, or the input is not block size aligned and should be. + * @exception InvalidOperationException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if padding is expected and not found. + * @exception DataLengthException if the input is not block size + * aligned. + */ + public override int DoFinal( + byte[] output, + int outOff) + { + try + { + if (bufOff != 0) + { + if (!cipher.IsPartialBlockOkay) + { + throw new DataLengthException("data not block size aligned"); + } + + if (outOff + bufOff > output.Length) + { + throw new DataLengthException("output buffer too short for DoFinal()"); + } + + // NB: Can't copy directly, or we may write too much output + cipher.ProcessBlock(buf, 0, buf, 0); + Array.Copy(buf, 0, output, outOff, bufOff); + } + + return bufOff; + } + finally + { + Reset(); + } + } + + /** + * Reset the buffer and cipher. After resetting the object is in the same + * state as it was after the last init (if there was one). + */ + public override void Reset() + { + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + cipher.Reset(); + } + } +} diff --git a/SharpCompress/Crypto/BufferedCipherBase.cs b/src/SharpCompress/Crypto/BufferedCipherBase.cs similarity index 95% rename from SharpCompress/Crypto/BufferedCipherBase.cs rename to src/SharpCompress/Crypto/BufferedCipherBase.cs index f87f38c2..9d861021 100644 --- a/SharpCompress/Crypto/BufferedCipherBase.cs +++ b/src/SharpCompress/Crypto/BufferedCipherBase.cs @@ -1,113 +1,113 @@ -using System; - -namespace Org.BouncyCastle.Crypto -{ - public abstract class BufferedCipherBase - : IBufferedCipher - { - protected static readonly byte[] EmptyBuffer = new byte[0]; - - public abstract string AlgorithmName { get; } - - public abstract void Init(bool forEncryption, ICipherParameters parameters); - - public abstract int GetBlockSize(); - - public abstract int GetOutputSize(int inputLen); - public abstract int GetUpdateOutputSize(int inputLen); - - public abstract byte[] ProcessByte(byte input); - - public virtual int ProcessByte( - byte input, - byte[] output, - int outOff) - { - byte[] outBytes = ProcessByte(input); - if (outBytes == null) - return 0; - if (outOff + outBytes.Length > output.Length) - throw new DataLengthException("output buffer too short"); - outBytes.CopyTo(output, outOff); - return outBytes.Length; - } - - public virtual byte[] ProcessBytes( - byte[] input) - { - return ProcessBytes(input, 0, input.Length); - } - - public abstract byte[] ProcessBytes(byte[] input, int inOff, int length); - - public virtual int ProcessBytes( - byte[] input, - byte[] output, - int outOff) - { - return ProcessBytes(input, 0, input.Length, output, outOff); - } - - public virtual int ProcessBytes( - byte[] input, - int inOff, - int length, - byte[] output, - int outOff) - { - byte[] outBytes = ProcessBytes(input, inOff, length); - if (outBytes == null) - return 0; - if (outOff + outBytes.Length > output.Length) - throw new DataLengthException("output buffer too short"); - outBytes.CopyTo(output, outOff); - return outBytes.Length; - } - - public abstract byte[] DoFinal(); - - public virtual byte[] DoFinal( - byte[] input) - { - return DoFinal(input, 0, input.Length); - } - - public abstract byte[] DoFinal( - byte[] input, - int inOff, - int length); - - public virtual int DoFinal( - byte[] output, - int outOff) - { - byte[] outBytes = DoFinal(); - if (outOff + outBytes.Length > output.Length) - throw new DataLengthException("output buffer too short"); - outBytes.CopyTo(output, outOff); - return outBytes.Length; - } - - public virtual int DoFinal( - byte[] input, - byte[] output, - int outOff) - { - return DoFinal(input, 0, input.Length, output, outOff); - } - - public virtual int DoFinal( - byte[] input, - int inOff, - int length, - byte[] output, - int outOff) - { - int len = ProcessBytes(input, inOff, length, output, outOff); - len += DoFinal(output, outOff + len); - return len; - } - - public abstract void Reset(); - } -} +using System; + +namespace Org.BouncyCastle.Crypto +{ + public abstract class BufferedCipherBase + : IBufferedCipher + { + protected static readonly byte[] EmptyBuffer = new byte[0]; + + public abstract string AlgorithmName { get; } + + public abstract void Init(bool forEncryption, ICipherParameters parameters); + + public abstract int GetBlockSize(); + + public abstract int GetOutputSize(int inputLen); + public abstract int GetUpdateOutputSize(int inputLen); + + public abstract byte[] ProcessByte(byte input); + + public virtual int ProcessByte( + byte input, + byte[] output, + int outOff) + { + byte[] outBytes = ProcessByte(input); + if (outBytes == null) + return 0; + if (outOff + outBytes.Length > output.Length) + throw new DataLengthException("output buffer too short"); + outBytes.CopyTo(output, outOff); + return outBytes.Length; + } + + public virtual byte[] ProcessBytes( + byte[] input) + { + return ProcessBytes(input, 0, input.Length); + } + + public abstract byte[] ProcessBytes(byte[] input, int inOff, int length); + + public virtual int ProcessBytes( + byte[] input, + byte[] output, + int outOff) + { + return ProcessBytes(input, 0, input.Length, output, outOff); + } + + public virtual int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + byte[] outBytes = ProcessBytes(input, inOff, length); + if (outBytes == null) + return 0; + if (outOff + outBytes.Length > output.Length) + throw new DataLengthException("output buffer too short"); + outBytes.CopyTo(output, outOff); + return outBytes.Length; + } + + public abstract byte[] DoFinal(); + + public virtual byte[] DoFinal( + byte[] input) + { + return DoFinal(input, 0, input.Length); + } + + public abstract byte[] DoFinal( + byte[] input, + int inOff, + int length); + + public virtual int DoFinal( + byte[] output, + int outOff) + { + byte[] outBytes = DoFinal(); + if (outOff + outBytes.Length > output.Length) + throw new DataLengthException("output buffer too short"); + outBytes.CopyTo(output, outOff); + return outBytes.Length; + } + + public virtual int DoFinal( + byte[] input, + byte[] output, + int outOff) + { + return DoFinal(input, 0, input.Length, output, outOff); + } + + public virtual int DoFinal( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + int len = ProcessBytes(input, inOff, length, output, outOff); + len += DoFinal(output, outOff + len); + return len; + } + + public abstract void Reset(); + } +} diff --git a/SharpCompress/Crypto/CryptoException.cs b/src/SharpCompress/Crypto/CryptoException.cs similarity index 94% rename from SharpCompress/Crypto/CryptoException.cs rename to src/SharpCompress/Crypto/CryptoException.cs index 36ecae2d..7eb42a74 100644 --- a/SharpCompress/Crypto/CryptoException.cs +++ b/src/SharpCompress/Crypto/CryptoException.cs @@ -1,25 +1,25 @@ -using System; - -namespace Org.BouncyCastle.Crypto -{ - public class CryptoException - : Exception - { - public CryptoException() - { - } - - public CryptoException( - string message) - : base(message) - { - } - - public CryptoException( - string message, - Exception exception) - : base(message, exception) - { - } - } +using System; + +namespace Org.BouncyCastle.Crypto +{ + public class CryptoException + : Exception + { + public CryptoException() + { + } + + public CryptoException( + string message) + : base(message) + { + } + + public CryptoException( + string message, + Exception exception) + : base(message, exception) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/DataLengthException.cs b/src/SharpCompress/Crypto/DataLengthException.cs similarity index 95% rename from SharpCompress/Crypto/DataLengthException.cs rename to src/SharpCompress/Crypto/DataLengthException.cs index 02b482cd..63e9094f 100644 --- a/SharpCompress/Crypto/DataLengthException.cs +++ b/src/SharpCompress/Crypto/DataLengthException.cs @@ -1,33 +1,33 @@ -using System; - -namespace Org.BouncyCastle.Crypto -{ - public class DataLengthException - : CryptoException - { - /** - * base constructor. - */ - public DataLengthException() - { - } - - /** - * create a DataLengthException with the given message. - * - * @param message the message to be carried with the exception. - */ - public DataLengthException( - string message) - : base(message) - { - } - - public DataLengthException( - string message, - Exception exception) - : base(message, exception) - { - } - } +using System; + +namespace Org.BouncyCastle.Crypto +{ + public class DataLengthException + : CryptoException + { + /** + * base constructor. + */ + public DataLengthException() + { + } + + /** + * create a DataLengthException with the given message. + * + * @param message the message to be carried with the exception. + */ + public DataLengthException( + string message) + : base(message) + { + } + + public DataLengthException( + string message, + Exception exception) + : base(message, exception) + { + } + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/GeneralDigest.cs b/src/SharpCompress/Crypto/GeneralDigest.cs similarity index 95% rename from SharpCompress/Crypto/GeneralDigest.cs rename to src/SharpCompress/Crypto/GeneralDigest.cs index d138cbd3..67ad5091 100644 --- a/SharpCompress/Crypto/GeneralDigest.cs +++ b/src/SharpCompress/Crypto/GeneralDigest.cs @@ -1,128 +1,128 @@ -using System; - -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Digests -{ - /** - * base implementation of MD4 family style digest as outlined in - * "Handbook of Applied Cryptography", pages 344 - 347. - */ - public abstract class GeneralDigest - : IDigest, IMemoable - { - private const int BYTE_LENGTH = 64; - - private byte[] xBuf; - private int xBufOff; - - private long byteCount; - - internal GeneralDigest() - { - xBuf = new byte[4]; - } - - internal GeneralDigest(GeneralDigest t) - { - xBuf = new byte[t.xBuf.Length]; - CopyIn(t); - } - - protected void CopyIn(GeneralDigest t) - { - Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length); - - xBufOff = t.xBufOff; - byteCount = t.byteCount; - } - - public void Update(byte input) - { - xBuf[xBufOff++] = input; - - if (xBufOff == xBuf.Length) - { - ProcessWord(xBuf, 0); - xBufOff = 0; - } - - byteCount++; - } - - public void BlockUpdate( - byte[] input, - int inOff, - int length) - { - // - // fill the current word - // - while ((xBufOff != 0) && (length > 0)) - { - Update(input[inOff]); - inOff++; - length--; - } - - // - // process whole words. - // - while (length > xBuf.Length) - { - ProcessWord(input, inOff); - - inOff += xBuf.Length; - length -= xBuf.Length; - byteCount += xBuf.Length; - } - - // - // load in the remainder. - // - while (length > 0) - { - Update(input[inOff]); - - inOff++; - length--; - } - } - - public void Finish() - { - long bitLength = (byteCount << 3); - - // - // add the pad bytes. - // - Update((byte)128); - - while (xBufOff != 0) - Update((byte)0); - ProcessLength(bitLength); - ProcessBlock(); - } - - public virtual void Reset() - { - byteCount = 0; - xBufOff = 0; - Array.Clear(xBuf, 0, xBuf.Length); - } - - public int GetByteLength() - { - return BYTE_LENGTH; - } - - internal abstract void ProcessWord(byte[] input, int inOff); - internal abstract void ProcessLength(long bitLength); - internal abstract void ProcessBlock(); - public abstract string AlgorithmName { get; } - public abstract int GetDigestSize(); - public abstract int DoFinal(byte[] output, int outOff); - public abstract IMemoable Copy(); - public abstract void Reset(IMemoable t); - } +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * base implementation of MD4 family style digest as outlined in + * "Handbook of Applied Cryptography", pages 344 - 347. + */ + public abstract class GeneralDigest + : IDigest, IMemoable + { + private const int BYTE_LENGTH = 64; + + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + internal GeneralDigest() + { + xBuf = new byte[4]; + } + + internal GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.Length]; + CopyIn(t); + } + + protected void CopyIn(GeneralDigest t) + { + Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void Update(byte input) + { + xBuf[xBufOff++] = input; + + if (xBufOff == xBuf.Length) + { + ProcessWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + // + // fill the current word + // + while ((xBufOff != 0) && (length > 0)) + { + Update(input[inOff]); + inOff++; + length--; + } + + // + // process whole words. + // + while (length > xBuf.Length) + { + ProcessWord(input, inOff); + + inOff += xBuf.Length; + length -= xBuf.Length; + byteCount += xBuf.Length; + } + + // + // load in the remainder. + // + while (length > 0) + { + Update(input[inOff]); + + inOff++; + length--; + } + } + + public void Finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + Update((byte)128); + + while (xBufOff != 0) + Update((byte)0); + ProcessLength(bitLength); + ProcessBlock(); + } + + public virtual void Reset() + { + byteCount = 0; + xBufOff = 0; + Array.Clear(xBuf, 0, xBuf.Length); + } + + public int GetByteLength() + { + return BYTE_LENGTH; + } + + internal abstract void ProcessWord(byte[] input, int inOff); + internal abstract void ProcessLength(long bitLength); + internal abstract void ProcessBlock(); + public abstract string AlgorithmName { get; } + public abstract int GetDigestSize(); + public abstract int DoFinal(byte[] output, int outOff); + public abstract IMemoable Copy(); + public abstract void Reset(IMemoable t); + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/HMac.cs b/src/SharpCompress/Crypto/HMac.cs similarity index 95% rename from SharpCompress/Crypto/HMac.cs rename to src/SharpCompress/Crypto/HMac.cs index ecbd72f3..3f9b0cef 100644 --- a/SharpCompress/Crypto/HMac.cs +++ b/src/SharpCompress/Crypto/HMac.cs @@ -1,134 +1,134 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Crypto.Macs -{ - /** - * HMAC implementation based on RFC2104 - * - * H(K XOR opad, H(K XOR ipad, text)) - */ - public class HMac - : IMac - { - private const byte IPAD = (byte)0x36; - private const byte OPAD = (byte)0x5C; - - private readonly IDigest digest; - private readonly int digestSize; - private readonly int blockLength; - - private readonly byte[] inputPad; - private readonly byte[] outputPad; - - public HMac( - IDigest digest) - { - this.digest = digest; - this.digestSize = digest.GetDigestSize(); - this.blockLength = digest.GetByteLength(); - this.inputPad = new byte[blockLength]; - this.outputPad = new byte[blockLength]; - } - - public string AlgorithmName - { - get { return digest.AlgorithmName + "/HMAC"; } - } - - public IDigest GetUnderlyingDigest() - { - return digest; - } - - public void Init( - ICipherParameters parameters) - { - digest.Reset(); - - byte[] key = ((KeyParameter)parameters).GetKey(); - int keyLength = key.Length; - - if (keyLength > blockLength) - { - digest.BlockUpdate(key, 0, key.Length); - digest.DoFinal(inputPad, 0); - - keyLength = digestSize; - } - else - { - Array.Copy(key, 0, inputPad, 0, keyLength); - } - - Array.Clear(inputPad, keyLength, blockLength - keyLength); - Array.Copy(inputPad, 0, outputPad, 0, blockLength); - - xor(inputPad, IPAD); - xor(outputPad, OPAD); - - // Initialise the digest - digest.BlockUpdate(inputPad, 0, inputPad.Length); - } - - public int GetMacSize() - { - return digestSize; - } - - public void Update( - byte input) - { - digest.Update(input); - } - - public void BlockUpdate( - byte[] input, - int inOff, - int len) - { - digest.BlockUpdate(input, inOff, len); - } - - public int DoFinal( - byte[] output, - int outOff) - { - byte[] tmp = new byte[digestSize]; - digest.DoFinal(tmp, 0); - - digest.BlockUpdate(outputPad, 0, outputPad.Length); - digest.BlockUpdate(tmp, 0, tmp.Length); - - int len = digest.DoFinal(output, outOff); - - // Initialise the digest - digest.BlockUpdate(inputPad, 0, inputPad.Length); - - return len; - } - - /** - * Reset the mac generator. - */ - public void Reset() - { - // Reset underlying digest - digest.Reset(); - - // Initialise the digest - digest.BlockUpdate(inputPad, 0, inputPad.Length); - } - - private static void xor(byte[] a, byte n) - { - for (int i = 0; i < a.Length; ++i) - { - a[i] ^= n; - } - } - } -} +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * HMAC implementation based on RFC2104 + * + * H(K XOR opad, H(K XOR ipad, text)) + */ + public class HMac + : IMac + { + private const byte IPAD = (byte)0x36; + private const byte OPAD = (byte)0x5C; + + private readonly IDigest digest; + private readonly int digestSize; + private readonly int blockLength; + + private readonly byte[] inputPad; + private readonly byte[] outputPad; + + public HMac( + IDigest digest) + { + this.digest = digest; + this.digestSize = digest.GetDigestSize(); + this.blockLength = digest.GetByteLength(); + this.inputPad = new byte[blockLength]; + this.outputPad = new byte[blockLength]; + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "/HMAC"; } + } + + public IDigest GetUnderlyingDigest() + { + return digest; + } + + public void Init( + ICipherParameters parameters) + { + digest.Reset(); + + byte[] key = ((KeyParameter)parameters).GetKey(); + int keyLength = key.Length; + + if (keyLength > blockLength) + { + digest.BlockUpdate(key, 0, key.Length); + digest.DoFinal(inputPad, 0); + + keyLength = digestSize; + } + else + { + Array.Copy(key, 0, inputPad, 0, keyLength); + } + + Array.Clear(inputPad, keyLength, blockLength - keyLength); + Array.Copy(inputPad, 0, outputPad, 0, blockLength); + + xor(inputPad, IPAD); + xor(outputPad, OPAD); + + // Initialise the digest + digest.BlockUpdate(inputPad, 0, inputPad.Length); + } + + public int GetMacSize() + { + return digestSize; + } + + public void Update( + byte input) + { + digest.Update(input); + } + + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + digest.BlockUpdate(input, inOff, len); + } + + public int DoFinal( + byte[] output, + int outOff) + { + byte[] tmp = new byte[digestSize]; + digest.DoFinal(tmp, 0); + + digest.BlockUpdate(outputPad, 0, outputPad.Length); + digest.BlockUpdate(tmp, 0, tmp.Length); + + int len = digest.DoFinal(output, outOff); + + // Initialise the digest + digest.BlockUpdate(inputPad, 0, inputPad.Length); + + return len; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + // Reset underlying digest + digest.Reset(); + + // Initialise the digest + digest.BlockUpdate(inputPad, 0, inputPad.Length); + } + + private static void xor(byte[] a, byte n) + { + for (int i = 0; i < a.Length; ++i) + { + a[i] ^= n; + } + } + } +} diff --git a/SharpCompress/Crypto/IBlockCipher.cs b/src/SharpCompress/Crypto/IBlockCipher.cs similarity index 97% rename from SharpCompress/Crypto/IBlockCipher.cs rename to src/SharpCompress/Crypto/IBlockCipher.cs index cdb1d493..7aeb73c6 100644 --- a/SharpCompress/Crypto/IBlockCipher.cs +++ b/src/SharpCompress/Crypto/IBlockCipher.cs @@ -1,35 +1,35 @@ - -namespace Org.BouncyCastle.Crypto -{ - /// Base interface for a symmetric key block cipher. - public interface IBlockCipher - { - /// The name of the algorithm this cipher implements. - string AlgorithmName { get; } - - /// Initialise the cipher. - /// Initialise for encryption if true, for decryption if false. - /// The key or other data required by the cipher. - void Init(bool forEncryption, ICipherParameters parameters); - - /// The block size for this cipher, in bytes. - int GetBlockSize(); - - /// Indicates whether this cipher can handle partial blocks. - bool IsPartialBlockOkay { get; } - - /// Process a block. - /// The input buffer. - /// The offset into inBuf that the input block begins. - /// The output buffer. - /// The offset into outBuf to write the output block. - /// If input block is wrong size, or outBuf too small. - /// The number of bytes processed and produced. - int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff); - - /// - /// Reset the cipher to the same state as it was after the last init (if there was one). - /// - void Reset(); - } + +namespace Org.BouncyCastle.Crypto +{ + /// Base interface for a symmetric key block cipher. + public interface IBlockCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// Initialise for encryption if true, for decryption if false. + /// The key or other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); + + /// The block size for this cipher, in bytes. + int GetBlockSize(); + + /// Indicates whether this cipher can handle partial blocks. + bool IsPartialBlockOkay { get; } + + /// Process a block. + /// The input buffer. + /// The offset into inBuf that the input block begins. + /// The output buffer. + /// The offset into outBuf to write the output block. + /// If input block is wrong size, or outBuf too small. + /// The number of bytes processed and produced. + int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff); + + /// + /// Reset the cipher to the same state as it was after the last init (if there was one). + /// + void Reset(); + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/IBufferedCipher.cs b/src/SharpCompress/Crypto/IBufferedCipher.cs similarity index 97% rename from SharpCompress/Crypto/IBufferedCipher.cs rename to src/SharpCompress/Crypto/IBufferedCipher.cs index 207b9f09..69dec959 100644 --- a/SharpCompress/Crypto/IBufferedCipher.cs +++ b/src/SharpCompress/Crypto/IBufferedCipher.cs @@ -1,44 +1,44 @@ -using System; - -namespace Org.BouncyCastle.Crypto -{ - /// Block cipher engines are expected to conform to this interface. - public interface IBufferedCipher - { - /// The name of the algorithm this cipher implements. - string AlgorithmName { get; } - - /// Initialise the cipher. - /// If true the cipher is initialised for encryption, - /// if false for decryption. - /// The key and other data required by the cipher. - void Init(bool forEncryption, ICipherParameters parameters); - - int GetBlockSize(); - - int GetOutputSize(int inputLen); - - int GetUpdateOutputSize(int inputLen); - - byte[] ProcessByte(byte input); - int ProcessByte(byte input, byte[] output, int outOff); - - byte[] ProcessBytes(byte[] input); - byte[] ProcessBytes(byte[] input, int inOff, int length); - int ProcessBytes(byte[] input, byte[] output, int outOff); - int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff); - - byte[] DoFinal(); - byte[] DoFinal(byte[] input); - byte[] DoFinal(byte[] input, int inOff, int length); - int DoFinal(byte[] output, int outOff); - int DoFinal(byte[] input, byte[] output, int outOff); - int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff); - - /// - /// Reset the cipher. After resetting the cipher is in the same state - /// as it was after the last init (if there was one). - /// - void Reset(); - } -} +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// Block cipher engines are expected to conform to this interface. + public interface IBufferedCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// If true the cipher is initialised for encryption, + /// if false for decryption. + /// The key and other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); + + int GetBlockSize(); + + int GetOutputSize(int inputLen); + + int GetUpdateOutputSize(int inputLen); + + byte[] ProcessByte(byte input); + int ProcessByte(byte input, byte[] output, int outOff); + + byte[] ProcessBytes(byte[] input); + byte[] ProcessBytes(byte[] input, int inOff, int length); + int ProcessBytes(byte[] input, byte[] output, int outOff); + int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff); + + byte[] DoFinal(); + byte[] DoFinal(byte[] input); + byte[] DoFinal(byte[] input, int inOff, int length); + int DoFinal(byte[] output, int outOff); + int DoFinal(byte[] input, byte[] output, int outOff); + int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff); + + /// + /// Reset the cipher. After resetting the cipher is in the same state + /// as it was after the last init (if there was one). + /// + void Reset(); + } +} diff --git a/SharpCompress/Crypto/ICipherParameters.cs b/src/SharpCompress/Crypto/ICipherParameters.cs similarity index 93% rename from SharpCompress/Crypto/ICipherParameters.cs rename to src/SharpCompress/Crypto/ICipherParameters.cs index 995fd606..bbc78dd3 100644 --- a/SharpCompress/Crypto/ICipherParameters.cs +++ b/src/SharpCompress/Crypto/ICipherParameters.cs @@ -1,7 +1,7 @@ - -namespace Org.BouncyCastle.Crypto -{ - public interface ICipherParameters - { - } + +namespace Org.BouncyCastle.Crypto +{ + public interface ICipherParameters + { + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/IDigest.cs b/src/SharpCompress/Crypto/IDigest.cs similarity index 96% rename from SharpCompress/Crypto/IDigest.cs rename to src/SharpCompress/Crypto/IDigest.cs index 9b2bfffb..a42f3a77 100644 --- a/SharpCompress/Crypto/IDigest.cs +++ b/src/SharpCompress/Crypto/IDigest.cs @@ -1,56 +1,56 @@ -namespace Org.BouncyCastle.Crypto -{ - public interface IDigest - { - /** - * return the algorithm name - * - * @return the algorithm name - */ - string AlgorithmName { get; } - - /** - * return the size, in bytes, of the digest produced by this message digest. - * - * @return the size, in bytes, of the digest produced by this message digest. - */ - int GetDigestSize(); - - /** - * return the size, in bytes, of the internal buffer used by this digest. - * - * @return the size, in bytes, of the internal buffer used by this digest. - */ - int GetByteLength(); - - /** - * update the message digest with a single byte. - * - * @param inByte the input byte to be entered. - */ - void Update(byte input); - - /** - * update the message digest with a block of bytes. - * - * @param input the byte array containing the data. - * @param inOff the offset into the byte array where the data starts. - * @param len the length of the data. - */ - void BlockUpdate(byte[] input, int inOff, int length); - - /** - * Close the digest, producing the final digest value. The doFinal - * call leaves the digest reset. - * - * @param output the array the digest is to be copied into. - * @param outOff the offset into the out array the digest is to start at. - */ - int DoFinal(byte[] output, int outOff); - - /** - * reset the digest back to it's initial state. - */ - void Reset(); - } +namespace Org.BouncyCastle.Crypto +{ + public interface IDigest + { + /** + * return the algorithm name + * + * @return the algorithm name + */ + string AlgorithmName { get; } + + /** + * return the size, in bytes, of the digest produced by this message digest. + * + * @return the size, in bytes, of the digest produced by this message digest. + */ + int GetDigestSize(); + + /** + * return the size, in bytes, of the internal buffer used by this digest. + * + * @return the size, in bytes, of the internal buffer used by this digest. + */ + int GetByteLength(); + + /** + * update the message digest with a single byte. + * + * @param inByte the input byte to be entered. + */ + void Update(byte input); + + /** + * update the message digest with a block of bytes. + * + * @param input the byte array containing the data. + * @param inOff the offset into the byte array where the data starts. + * @param len the length of the data. + */ + void BlockUpdate(byte[] input, int inOff, int length); + + /** + * Close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * + * @param output the array the digest is to be copied into. + * @param outOff the offset into the out array the digest is to start at. + */ + int DoFinal(byte[] output, int outOff); + + /** + * reset the digest back to it's initial state. + */ + void Reset(); + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/IMac.cs b/src/SharpCompress/Crypto/IMac.cs similarity index 97% rename from SharpCompress/Crypto/IMac.cs rename to src/SharpCompress/Crypto/IMac.cs index 4305d6b0..a09920bf 100644 --- a/SharpCompress/Crypto/IMac.cs +++ b/src/SharpCompress/Crypto/IMac.cs @@ -1,64 +1,64 @@ -namespace Org.BouncyCastle.Crypto -{ - public interface IMac - { - /** - * Initialise the MAC. - * - * @param param the key and other data required by the MAC. - * @exception ArgumentException if the parameters argument is - * inappropriate. - */ - void Init(ICipherParameters parameters); - - /** - * Return the name of the algorithm the MAC implements. - * - * @return the name of the algorithm the MAC implements. - */ - string AlgorithmName { get; } - - /** - * Return the block size for this MAC (in bytes). - * - * @return the block size for this MAC in bytes. - */ - int GetMacSize(); - - /** - * add a single byte to the mac for processing. - * - * @param in the byte to be processed. - * @exception InvalidOperationException if the MAC is not initialised. - */ - void Update(byte input); - - /** - * @param in the array containing the input. - * @param inOff the index in the array the data begins at. - * @param len the length of the input starting at inOff. - * @exception InvalidOperationException if the MAC is not initialised. - * @exception DataLengthException if there isn't enough data in in. - */ - void BlockUpdate(byte[] input, int inOff, int len); - - /** - * Compute the final stage of the MAC writing the output to the out - * parameter. - *

    - * doFinal leaves the MAC in the same state it was after the last init. - *

    - * @param out the array the MAC is to be output to. - * @param outOff the offset into the out buffer the output is to start at. - * @exception DataLengthException if there isn't enough space in out. - * @exception InvalidOperationException if the MAC is not initialised. - */ - int DoFinal(byte[] output, int outOff); - - /** - * Reset the MAC. At the end of resetting the MAC should be in the - * in the same state it was after the last init (if there was one). - */ - void Reset(); - } +namespace Org.BouncyCastle.Crypto +{ + public interface IMac + { + /** + * Initialise the MAC. + * + * @param param the key and other data required by the MAC. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + void Init(ICipherParameters parameters); + + /** + * Return the name of the algorithm the MAC implements. + * + * @return the name of the algorithm the MAC implements. + */ + string AlgorithmName { get; } + + /** + * Return the block size for this MAC (in bytes). + * + * @return the block size for this MAC in bytes. + */ + int GetMacSize(); + + /** + * add a single byte to the mac for processing. + * + * @param in the byte to be processed. + * @exception InvalidOperationException if the MAC is not initialised. + */ + void Update(byte input); + + /** + * @param in the array containing the input. + * @param inOff the index in the array the data begins at. + * @param len the length of the input starting at inOff. + * @exception InvalidOperationException if the MAC is not initialised. + * @exception DataLengthException if there isn't enough data in in. + */ + void BlockUpdate(byte[] input, int inOff, int len); + + /** + * Compute the final stage of the MAC writing the output to the out + * parameter. + *

    + * doFinal leaves the MAC in the same state it was after the last init. + *

    + * @param out the array the MAC is to be output to. + * @param outOff the offset into the out buffer the output is to start at. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the MAC is not initialised. + */ + int DoFinal(byte[] output, int outOff); + + /** + * Reset the MAC. At the end of resetting the MAC should be in the + * in the same state it was after the last init (if there was one). + */ + void Reset(); + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/IMemoable.cs b/src/SharpCompress/Crypto/IMemoable.cs similarity index 100% rename from SharpCompress/Crypto/IMemoable.cs rename to src/SharpCompress/Crypto/IMemoable.cs diff --git a/SharpCompress/Crypto/KeyParameter.cs b/src/SharpCompress/Crypto/KeyParameter.cs similarity index 96% rename from SharpCompress/Crypto/KeyParameter.cs rename to src/SharpCompress/Crypto/KeyParameter.cs index f10a2953..9cf4bc8c 100644 --- a/SharpCompress/Crypto/KeyParameter.cs +++ b/src/SharpCompress/Crypto/KeyParameter.cs @@ -1,40 +1,40 @@ -using System; - -namespace Org.BouncyCastle.Crypto.Parameters -{ - public class KeyParameter - : ICipherParameters - { - private readonly byte[] key; - - public KeyParameter( - byte[] key) - { - if (key == null) - throw new ArgumentNullException("key"); - - this.key = (byte[])key.Clone(); - } - - public KeyParameter( - byte[] key, - int keyOff, - int keyLen) - { - if (key == null) - throw new ArgumentNullException("key"); - if (keyOff < 0 || keyOff > key.Length) - throw new ArgumentOutOfRangeException("keyOff"); - if (keyLen < 0 || (keyOff + keyLen) > key.Length) - throw new ArgumentOutOfRangeException("keyLen"); - - this.key = new byte[keyLen]; - Array.Copy(key, keyOff, this.key, 0, keyLen); - } - - public byte[] GetKey() - { - return (byte[])key.Clone(); - } - } +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class KeyParameter + : ICipherParameters + { + private readonly byte[] key; + + public KeyParameter( + byte[] key) + { + if (key == null) + throw new ArgumentNullException("key"); + + this.key = (byte[])key.Clone(); + } + + public KeyParameter( + byte[] key, + int keyOff, + int keyLen) + { + if (key == null) + throw new ArgumentNullException("key"); + if (keyOff < 0 || keyOff > key.Length) + throw new ArgumentOutOfRangeException("keyOff"); + if (keyLen < 0 || (keyOff + keyLen) > key.Length) + throw new ArgumentOutOfRangeException("keyLen"); + + this.key = new byte[keyLen]; + Array.Copy(key, keyOff, this.key, 0, keyLen); + } + + public byte[] GetKey() + { + return (byte[])key.Clone(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/PBKDF2.cs b/src/SharpCompress/Crypto/PBKDF2.cs similarity index 96% rename from SharpCompress/Crypto/PBKDF2.cs rename to src/SharpCompress/Crypto/PBKDF2.cs index 7cb772ef..82dbdc6b 100644 --- a/SharpCompress/Crypto/PBKDF2.cs +++ b/src/SharpCompress/Crypto/PBKDF2.cs @@ -1,119 +1,119 @@ -using System; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Macs; -using Org.BouncyCastle.Crypto.Parameters; - -namespace SharpCompress.Crypto -{ - //Gathered from: - //http://stackoverflow.com/questions/3210795/pbkdf2-in-bouncy-castle-c-sharp and Rfc2898DeriveBytes - internal class PBKDF2 - { - private readonly IMac hMac = new HMac(new Sha1Digest()); - private readonly byte[] state = new byte[20]; - private int endIndex; - private int startIndex; - private uint block = 1u; - private readonly byte[] password; - private readonly byte[] salt; - private readonly int iterations; - - - public PBKDF2(byte[] password, byte[] salt, int iterations) - { - this.password = password; - this.salt = salt; - this.iterations = iterations; - } - - public byte[] GetBytes(int cb) - { - if (cb <= 0) - { - throw new ArgumentOutOfRangeException("cb"); - } - byte[] array = new byte[cb]; - int i = 0; - int num = endIndex - startIndex; - if (num > 0) - { - if (cb < num) - { - Buffer.BlockCopy(state, startIndex, array, 0, cb); - startIndex += cb; - return array; - } - Buffer.BlockCopy(state, startIndex, array, 0, num); - startIndex = (endIndex = 0); - i += num; - } - while (i < cb) - { - byte[] src = Hash(); - int num2 = cb - i; - if (num2 <= 20) - { - Buffer.BlockCopy(src, 0, array, i, num2); - i += num2; - Buffer.BlockCopy(src, num2, state, startIndex, 20 - num2); - endIndex += 20 - num2; - return array; - } - Buffer.BlockCopy(src, 0, array, i, 20); - i += 20; - } - return array; - } - - private byte[] Hash() - { - byte[] array = UIntToOctet(block); - ICipherParameters param = new KeyParameter(password); - - hMac.Init(param); - hMac.BlockUpdate(salt, 0, salt.Length); - - hMac.BlockUpdate(array, 0, array.Length); - byte[] array2 = new byte[20]; - hMac.DoFinal(array2, 0); - - hMac.Init(param); - - byte[] array3 = new byte[20]; - Buffer.BlockCopy(array2, 0, array3, 0, 20); - int num = 2; - while (num <= (long)((ulong)iterations)) - { - hMac.BlockUpdate(array2, 0, array2.Length); - hMac.DoFinal(array2, 0); - for (int i = 0; i < 20; i++) - { - array3[i] ^= array2[i]; - } - num++; - } - block += 1u; - return array3; - } - - internal static byte[] UIntToOctet(uint i) - { - byte[] bytes = BitConverter.GetBytes(i); - byte[] result = new[] - { - bytes[3], - bytes[2], - bytes[1], - bytes[0] - }; - if (!BitConverter.IsLittleEndian) - { - return bytes; - } - return result; - } - - } -} - +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; + +namespace SharpCompress.Crypto +{ + //Gathered from: + //http://stackoverflow.com/questions/3210795/pbkdf2-in-bouncy-castle-c-sharp and Rfc2898DeriveBytes + internal class PBKDF2 + { + private readonly IMac hMac = new HMac(new Sha1Digest()); + private readonly byte[] state = new byte[20]; + private int endIndex; + private int startIndex; + private uint block = 1u; + private readonly byte[] password; + private readonly byte[] salt; + private readonly int iterations; + + + public PBKDF2(byte[] password, byte[] salt, int iterations) + { + this.password = password; + this.salt = salt; + this.iterations = iterations; + } + + public byte[] GetBytes(int cb) + { + if (cb <= 0) + { + throw new ArgumentOutOfRangeException("cb"); + } + byte[] array = new byte[cb]; + int i = 0; + int num = endIndex - startIndex; + if (num > 0) + { + if (cb < num) + { + Buffer.BlockCopy(state, startIndex, array, 0, cb); + startIndex += cb; + return array; + } + Buffer.BlockCopy(state, startIndex, array, 0, num); + startIndex = (endIndex = 0); + i += num; + } + while (i < cb) + { + byte[] src = Hash(); + int num2 = cb - i; + if (num2 <= 20) + { + Buffer.BlockCopy(src, 0, array, i, num2); + i += num2; + Buffer.BlockCopy(src, num2, state, startIndex, 20 - num2); + endIndex += 20 - num2; + return array; + } + Buffer.BlockCopy(src, 0, array, i, 20); + i += 20; + } + return array; + } + + private byte[] Hash() + { + byte[] array = UIntToOctet(block); + ICipherParameters param = new KeyParameter(password); + + hMac.Init(param); + hMac.BlockUpdate(salt, 0, salt.Length); + + hMac.BlockUpdate(array, 0, array.Length); + byte[] array2 = new byte[20]; + hMac.DoFinal(array2, 0); + + hMac.Init(param); + + byte[] array3 = new byte[20]; + Buffer.BlockCopy(array2, 0, array3, 0, 20); + int num = 2; + while (num <= (long)((ulong)iterations)) + { + hMac.BlockUpdate(array2, 0, array2.Length); + hMac.DoFinal(array2, 0); + for (int i = 0; i < 20; i++) + { + array3[i] ^= array2[i]; + } + num++; + } + block += 1u; + return array3; + } + + internal static byte[] UIntToOctet(uint i) + { + byte[] bytes = BitConverter.GetBytes(i); + byte[] result = new[] + { + bytes[3], + bytes[2], + bytes[1], + bytes[0] + }; + if (!BitConverter.IsLittleEndian) + { + return bytes; + } + return result; + } + + } +} + diff --git a/SharpCompress/Crypto/Pack.cs b/src/SharpCompress/Crypto/Pack.cs similarity index 96% rename from SharpCompress/Crypto/Pack.cs rename to src/SharpCompress/Crypto/Pack.cs index 6bc20995..5e875edb 100644 --- a/SharpCompress/Crypto/Pack.cs +++ b/src/SharpCompress/Crypto/Pack.cs @@ -1,129 +1,129 @@ -namespace Org.BouncyCastle.Crypto.Utilities -{ - internal sealed class Pack - { - private Pack() - { - } - - internal static void UInt32_To_BE(uint n, byte[] bs) - { - bs[0] = (byte)(n >> 24); - bs[1] = (byte)(n >> 16); - bs[2] = (byte)(n >> 8); - bs[3] = (byte)(n); - } - - internal static void UInt32_To_BE(uint n, byte[] bs, int off) - { - bs[off] = (byte)(n >> 24); - bs[++off] = (byte)(n >> 16); - bs[++off] = (byte)(n >> 8); - bs[++off] = (byte)(n); - } - - internal static uint BE_To_UInt32(byte[] bs) - { - uint n = (uint)bs[0] << 24; - n |= (uint)bs[1] << 16; - n |= (uint)bs[2] << 8; - n |= (uint)bs[3]; - return n; - } - - internal static uint BE_To_UInt32(byte[] bs, int off) - { - uint n = (uint)bs[off] << 24; - n |= (uint)bs[++off] << 16; - n |= (uint)bs[++off] << 8; - n |= (uint)bs[++off]; - return n; - } - - internal static ulong BE_To_UInt64(byte[] bs) - { - uint hi = BE_To_UInt32(bs); - uint lo = BE_To_UInt32(bs, 4); - return ((ulong)hi << 32) | (ulong)lo; - } - - internal static ulong BE_To_UInt64(byte[] bs, int off) - { - uint hi = BE_To_UInt32(bs, off); - uint lo = BE_To_UInt32(bs, off + 4); - return ((ulong)hi << 32) | (ulong)lo; - } - - internal static void UInt64_To_BE(ulong n, byte[] bs) - { - UInt32_To_BE((uint)(n >> 32), bs); - UInt32_To_BE((uint)(n), bs, 4); - } - - internal static void UInt64_To_BE(ulong n, byte[] bs, int off) - { - UInt32_To_BE((uint)(n >> 32), bs, off); - UInt32_To_BE((uint)(n), bs, off + 4); - } - - internal static void UInt32_To_LE(uint n, byte[] bs) - { - bs[0] = (byte)(n); - bs[1] = (byte)(n >> 8); - bs[2] = (byte)(n >> 16); - bs[3] = (byte)(n >> 24); - } - - internal static void UInt32_To_LE(uint n, byte[] bs, int off) - { - bs[off] = (byte)(n); - bs[++off] = (byte)(n >> 8); - bs[++off] = (byte)(n >> 16); - bs[++off] = (byte)(n >> 24); - } - - internal static uint LE_To_UInt32(byte[] bs) - { - uint n = (uint)bs[0]; - n |= (uint)bs[1] << 8; - n |= (uint)bs[2] << 16; - n |= (uint)bs[3] << 24; - return n; - } - - internal static uint LE_To_UInt32(byte[] bs, int off) - { - uint n = (uint)bs[off]; - n |= (uint)bs[++off] << 8; - n |= (uint)bs[++off] << 16; - n |= (uint)bs[++off] << 24; - return n; - } - - internal static ulong LE_To_UInt64(byte[] bs) - { - uint lo = LE_To_UInt32(bs); - uint hi = LE_To_UInt32(bs, 4); - return ((ulong)hi << 32) | (ulong)lo; - } - - internal static ulong LE_To_UInt64(byte[] bs, int off) - { - uint lo = LE_To_UInt32(bs, off); - uint hi = LE_To_UInt32(bs, off + 4); - return ((ulong)hi << 32) | (ulong)lo; - } - - internal static void UInt64_To_LE(ulong n, byte[] bs) - { - UInt32_To_LE((uint)(n), bs); - UInt32_To_LE((uint)(n >> 32), bs, 4); - } - - internal static void UInt64_To_LE(ulong n, byte[] bs, int off) - { - UInt32_To_LE((uint)(n), bs, off); - UInt32_To_LE((uint)(n >> 32), bs, off + 4); - } - } +namespace Org.BouncyCastle.Crypto.Utilities +{ + internal sealed class Pack + { + private Pack() + { + } + + internal static void UInt32_To_BE(uint n, byte[] bs) + { + bs[0] = (byte)(n >> 24); + bs[1] = (byte)(n >> 16); + bs[2] = (byte)(n >> 8); + bs[3] = (byte)(n); + } + + internal static void UInt32_To_BE(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n >> 24); + bs[++off] = (byte)(n >> 16); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n); + } + + internal static uint BE_To_UInt32(byte[] bs) + { + uint n = (uint)bs[0] << 24; + n |= (uint)bs[1] << 16; + n |= (uint)bs[2] << 8; + n |= (uint)bs[3]; + return n; + } + + internal static uint BE_To_UInt32(byte[] bs, int off) + { + uint n = (uint)bs[off] << 24; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off]; + return n; + } + + internal static ulong BE_To_UInt64(byte[] bs) + { + uint hi = BE_To_UInt32(bs); + uint lo = BE_To_UInt32(bs, 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static ulong BE_To_UInt64(byte[] bs, int off) + { + uint hi = BE_To_UInt32(bs, off); + uint lo = BE_To_UInt32(bs, off + 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static void UInt64_To_BE(ulong n, byte[] bs) + { + UInt32_To_BE((uint)(n >> 32), bs); + UInt32_To_BE((uint)(n), bs, 4); + } + + internal static void UInt64_To_BE(ulong n, byte[] bs, int off) + { + UInt32_To_BE((uint)(n >> 32), bs, off); + UInt32_To_BE((uint)(n), bs, off + 4); + } + + internal static void UInt32_To_LE(uint n, byte[] bs) + { + bs[0] = (byte)(n); + bs[1] = (byte)(n >> 8); + bs[2] = (byte)(n >> 16); + bs[3] = (byte)(n >> 24); + } + + internal static void UInt32_To_LE(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[++off] = (byte)(n >> 8); + bs[++off] = (byte)(n >> 16); + bs[++off] = (byte)(n >> 24); + } + + internal static uint LE_To_UInt32(byte[] bs) + { + uint n = (uint)bs[0]; + n |= (uint)bs[1] << 8; + n |= (uint)bs[2] << 16; + n |= (uint)bs[3] << 24; + return n; + } + + internal static uint LE_To_UInt32(byte[] bs, int off) + { + uint n = (uint)bs[off]; + n |= (uint)bs[++off] << 8; + n |= (uint)bs[++off] << 16; + n |= (uint)bs[++off] << 24; + return n; + } + + internal static ulong LE_To_UInt64(byte[] bs) + { + uint lo = LE_To_UInt32(bs); + uint hi = LE_To_UInt32(bs, 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static ulong LE_To_UInt64(byte[] bs, int off) + { + uint lo = LE_To_UInt32(bs, off); + uint hi = LE_To_UInt32(bs, off + 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static void UInt64_To_LE(ulong n, byte[] bs) + { + UInt32_To_LE((uint)(n), bs); + UInt32_To_LE((uint)(n >> 32), bs, 4); + } + + internal static void UInt64_To_LE(ulong n, byte[] bs, int off) + { + UInt32_To_LE((uint)(n), bs, off); + UInt32_To_LE((uint)(n >> 32), bs, off + 4); + } + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/RijndaelEngine.cs b/src/SharpCompress/Crypto/RijndaelEngine.cs similarity index 97% rename from SharpCompress/Crypto/RijndaelEngine.cs rename to src/SharpCompress/Crypto/RijndaelEngine.cs index e80215d3..7e3f14e9 100644 --- a/SharpCompress/Crypto/RijndaelEngine.cs +++ b/src/SharpCompress/Crypto/RijndaelEngine.cs @@ -1,740 +1,740 @@ -using System; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Crypto.Engines -{ - public class RijndaelEngine - : IBlockCipher - { - private static readonly int MAXROUNDS = 14; - - private static readonly int MAXKC = (256 / 4); - - private static readonly byte[] Logtable = - { - 0, 0, 25, 1, 50, 2, 26, 198, - 75, 199, 27, 104, 51, 238, 223, 3, - 100, 4, 224, 14, 52, 141, 129, 239, - 76, 113, 8, 200, 248, 105, 28, 193, - 125, 194, 29, 181, 249, 185, 39, 106, - 77, 228, 166, 114, 154, 201, 9, 120, - 101, 47, 138, 5, 33, 15, 225, 36, - 18, 240, 130, 69, 53, 147, 218, 142, - 150, 143, 219, 189, 54, 208, 206, 148, - 19, 92, 210, 241, 64, 70, 131, 56, - 102, 221, 253, 48, 191, 6, 139, 98, - 179, 37, 226, 152, 34, 136, 145, 16, - 126, 110, 72, 195, 163, 182, 30, 66, - 58, 107, 40, 84, 250, 133, 61, 186, - 43, 121, 10, 21, 155, 159, 94, 202, - 78, 212, 172, 229, 243, 115, 167, 87, - 175, 88, 168, 80, 244, 234, 214, 116, - 79, 174, 233, 213, 231, 230, 173, 232, - 44, 215, 117, 122, 235, 22, 11, 245, - 89, 203, 95, 176, 156, 169, 81, 160, - 127, 12, 246, 111, 23, 196, 73, 236, - 216, 67, 31, 45, 164, 118, 123, 183, - 204, 187, 62, 90, 251, 96, 177, 134, - 59, 82, 161, 108, 170, 85, 41, 157, - 151, 178, 135, 144, 97, 190, 220, 252, - 188, 149, 207, 205, 55, 63, 91, 209, - 83, 57, 132, 60, 65, 162, 109, 71, - 20, 42, 158, 93, 86, 242, 211, 171, - 68, 17, 146, 217, 35, 32, 46, 137, - 180, 124, 184, 38, 119, 153, 227, 165, - 103, 74, 237, 222, 197, 49, 254, 24, - 13, 99, 140, 128, 192, 247, 112, 7 - }; - - private static readonly byte[] Alogtable = - { - 0, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, - 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, - 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, - 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, - 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, - 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, - 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, - 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, - 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, - 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, - 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, - 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, - 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, - 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, - 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, - 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, - 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, - 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, - 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, - 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, - 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, - 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, - 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, - 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, - 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, - 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, - 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, - 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, - 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, - 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, - 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, - 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, - }; - - private static readonly byte[] S = - { - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, - 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, - 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, - 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, - 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, - 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, - 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, - 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, - 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, - 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, - 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, - 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22, - }; - - private static readonly byte[] Si = - { - 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, - 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, - 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, - 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, - 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, - 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, - 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, - 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, - 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, - 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, - 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, - 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, - 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, - 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, - 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, - 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125, - }; - - private static readonly byte[] rcon = - { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, - 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 - }; - - static readonly byte[][] shifts0 = new byte[][] - { - new byte[]{ 0, 8, 16, 24 }, - new byte[]{ 0, 8, 16, 24 }, - new byte[]{ 0, 8, 16, 24 }, - new byte[]{ 0, 8, 16, 32 }, - new byte[]{ 0, 8, 24, 32 } - }; - - static readonly byte[][] shifts1 = - { - new byte[]{ 0, 24, 16, 8 }, - new byte[]{ 0, 32, 24, 16 }, - new byte[]{ 0, 40, 32, 24 }, - new byte[]{ 0, 48, 40, 24 }, - new byte[]{ 0, 56, 40, 32 } - }; - - /** - * multiply two elements of GF(2^m) - * needed for MixColumn and InvMixColumn - */ - private byte Mul0x2( - int b) - { - if (b != 0) - { - return Alogtable[25 + (Logtable[b] & 0xff)]; - } - else - { - return 0; - } - } - - private byte Mul0x3( - int b) - { - if (b != 0) - { - return Alogtable[1 + (Logtable[b] & 0xff)]; - } - else - { - return 0; - } - } - - private byte Mul0x9( - int b) - { - if (b >= 0) - { - return Alogtable[199 + b]; - } - else - { - return 0; - } - } - - private byte Mul0xb( - int b) - { - if (b >= 0) - { - return Alogtable[104 + b]; - } - else - { - return 0; - } - } - - private byte Mul0xd( - int b) - { - if (b >= 0) - { - return Alogtable[238 + b]; - } - else - { - return 0; - } - } - - private byte Mul0xe( - int b) - { - if (b >= 0) - { - return Alogtable[223 + b]; - } - else - { - return 0; - } - } - - /** - * xor corresponding text input and round key input bytes - */ - private void KeyAddition( - long[] rk) - { - A0 ^= rk[0]; - A1 ^= rk[1]; - A2 ^= rk[2]; - A3 ^= rk[3]; - } - - private long Shift( - long r, - int shift) - { - //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK; - - ulong temp = (ulong)r >> shift; - - // NB: This corrects for Mono Bug #79087 (fixed in 1.1.17) - if (shift > 31) - { - temp &= 0xFFFFFFFFUL; - } - - return ((long)temp | (r << (BC - shift))) & BC_MASK; - } - - /** - * Row 0 remains unchanged - * The other three rows are shifted a variable amount - */ - private void ShiftRow( - byte[] shiftsSC) - { - A1 = Shift(A1, shiftsSC[1]); - A2 = Shift(A2, shiftsSC[2]); - A3 = Shift(A3, shiftsSC[3]); - } - - private long ApplyS( - long r, - byte[] box) - { - long res = 0; - - for (int j = 0; j < BC; j += 8) - { - res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j; - } - - return res; - } - - /** - * Replace every byte of the input by the byte at that place - * in the nonlinear S-box - */ - private void Substitution( - byte[] box) - { - A0 = ApplyS(A0, box); - A1 = ApplyS(A1, box); - A2 = ApplyS(A2, box); - A3 = ApplyS(A3, box); - } - - /** - * Mix the bytes of every column in a linear way - */ - private void MixColumn() - { - long r0, r1, r2, r3; - - r0 = r1 = r2 = r3 = 0; - - for (int j = 0; j < BC; j += 8) - { - int a0 = (int)((A0 >> j) & 0xff); - int a1 = (int)((A1 >> j) & 0xff); - int a2 = (int)((A2 >> j) & 0xff); - int a3 = (int)((A3 >> j) & 0xff); - - r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; - - r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; - - r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; - - r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; - } - - A0 = r0; - A1 = r1; - A2 = r2; - A3 = r3; - } - - /** - * Mix the bytes of every column in a linear way - * This is the opposite operation of Mixcolumn - */ - private void InvMixColumn() - { - long r0, r1, r2, r3; - - r0 = r1 = r2 = r3 = 0; - for (int j = 0; j < BC; j += 8) - { - int a0 = (int)((A0 >> j) & 0xff); - int a1 = (int)((A1 >> j) & 0xff); - int a2 = (int)((A2 >> j) & 0xff); - int a3 = (int)((A3 >> j) & 0xff); - - // - // pre-lookup the log table - // - a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1; - a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1; - a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1; - a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1; - - r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j; - - r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j; - - r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j; - - r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j; - } - - A0 = r0; - A1 = r1; - A2 = r2; - A3 = r3; - } - - /** - * Calculate the necessary round keys - * The number of calculations depends on keyBits and blockBits - */ - private long[][] GenerateWorkingKey( - byte[] key) - { - int KC; - int t, rconpointer = 0; - int keyBits = key.Length * 8; - byte[,] tk = new byte[4, MAXKC]; - //long[,] W = new long[MAXROUNDS+1,4]; - long[][] W = new long[MAXROUNDS + 1][]; - - for (int i = 0; i < MAXROUNDS + 1; i++) - W[i] = new long[4]; - - switch (keyBits) - { - case 128: - KC = 4; - break; - case 160: - KC = 5; - break; - case 192: - KC = 6; - break; - case 224: - KC = 7; - break; - case 256: - KC = 8; - break; - default: - throw new ArgumentException("Key length not 128/160/192/224/256 bits."); - } - - if (keyBits >= blockBits) - { - ROUNDS = KC + 6; - } - else - { - ROUNDS = (BC / 8) + 6; - } - - // - // copy the key into the processing area - // - int index = 0; - - for (int i = 0; i < key.Length; i++) - { - tk[i % 4, i / 4] = key[index++]; - } - - t = 0; - - // - // copy values into round key array - // - for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) - { - for (int i = 0; i < 4; i++) - { - W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % BC); - } - } - - // - // while not enough round key material calculated - // calculate new values - // - while (t < (ROUNDS + 1) * (BC / 8)) - { - for (int i = 0; i < 4; i++) - { - tk[i, 0] ^= S[tk[(i + 1) % 4, KC - 1] & 0xff]; - } - tk[0, 0] ^= (byte)rcon[rconpointer++]; - - if (KC <= 6) - { - for (int j = 1; j < KC; j++) - { - for (int i = 0; i < 4; i++) - { - tk[i, j] ^= tk[i, j - 1]; - } - } - } - else - { - for (int j = 1; j < 4; j++) - { - for (int i = 0; i < 4; i++) - { - tk[i, j] ^= tk[i, j - 1]; - } - } - for (int i = 0; i < 4; i++) - { - tk[i, 4] ^= S[tk[i, 3] & 0xff]; - } - for (int j = 5; j < KC; j++) - { - for (int i = 0; i < 4; i++) - { - tk[i, j] ^= tk[i, j - 1]; - } - } - } - - // - // copy values into round key array - // - for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) - { - for (int i = 0; i < 4; i++) - { - W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % (BC)); - } - } - } - return W; - } - - private int BC; - private long BC_MASK; - private int ROUNDS; - private int blockBits; - private long[][] workingKey; - private long A0, A1, A2, A3; - private bool forEncryption; - private byte[] shifts0SC; - private byte[] shifts1SC; - - /** - * default constructor - 128 bit block size. - */ - public RijndaelEngine() : this(128) { } - - /** - * basic constructor - set the cipher up for a given blocksize - * - * @param blocksize the blocksize in bits, must be 128, 192, or 256. - */ - public RijndaelEngine( - int blockBits) - { - switch (blockBits) - { - case 128: - BC = 32; - BC_MASK = 0xffffffffL; - shifts0SC = shifts0[0]; - shifts1SC = shifts1[0]; - break; - case 160: - BC = 40; - BC_MASK = 0xffffffffffL; - shifts0SC = shifts0[1]; - shifts1SC = shifts1[1]; - break; - case 192: - BC = 48; - BC_MASK = 0xffffffffffffL; - shifts0SC = shifts0[2]; - shifts1SC = shifts1[2]; - break; - case 224: - BC = 56; - BC_MASK = 0xffffffffffffffL; - shifts0SC = shifts0[3]; - shifts1SC = shifts1[3]; - break; - case 256: - BC = 64; - BC_MASK = unchecked((long)0xffffffffffffffffL); - shifts0SC = shifts0[4]; - shifts1SC = shifts1[4]; - break; - default: - throw new ArgumentException("unknown blocksize to Rijndael"); - } - - this.blockBits = blockBits; - } - - /** - * initialise a Rijndael cipher. - * - * @param forEncryption whether or not we are for encryption. - * @param parameters the parameters required to set up the cipher. - * @exception ArgumentException if the parameters argument is - * inappropriate. - */ - public void Init( - bool forEncryption, - ICipherParameters parameters) - { - var parameter = parameters as KeyParameter; - if (parameter != null) - { - workingKey = GenerateWorkingKey(parameter.GetKey()); - this.forEncryption = forEncryption; - return; - } - - throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString()); - } - - public string AlgorithmName - { - get { return "Rijndael"; } - } - - public bool IsPartialBlockOkay - { - get { return false; } - } - - public int GetBlockSize() - { - return BC / 2; - } - - public int ProcessBlock( - byte[] input, - int inOff, - byte[] output, - int outOff) - { - if (workingKey == null) - { - throw new InvalidOperationException("Rijndael engine not initialised"); - } - - if ((inOff + (BC / 2)) > input.Length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + (BC / 2)) > output.Length) - { - throw new DataLengthException("output buffer too short"); - } - - UnPackBlock(input, inOff); - - if (forEncryption) - { - EncryptBlock(workingKey); - } - else - { - DecryptBlock(workingKey); - } - - PackBlock(output, outOff); - - return BC / 2; - } - - public void Reset() - { - } - - private void UnPackBlock( - byte[] bytes, - int off) - { - int index = off; - - A0 = (long)(bytes[index++] & 0xff); - A1 = (long)(bytes[index++] & 0xff); - A2 = (long)(bytes[index++] & 0xff); - A3 = (long)(bytes[index++] & 0xff); - - for (int j = 8; j != BC; j += 8) - { - A0 |= (long)(bytes[index++] & 0xff) << j; - A1 |= (long)(bytes[index++] & 0xff) << j; - A2 |= (long)(bytes[index++] & 0xff) << j; - A3 |= (long)(bytes[index++] & 0xff) << j; - } - } - - private void PackBlock( - byte[] bytes, - int off) - { - int index = off; - - for (int j = 0; j != BC; j += 8) - { - bytes[index++] = (byte)(A0 >> j); - bytes[index++] = (byte)(A1 >> j); - bytes[index++] = (byte)(A2 >> j); - bytes[index++] = (byte)(A3 >> j); - } - } - - private void EncryptBlock( - long[][] rk) - { - int r; - - // - // begin with a key addition - // - KeyAddition(rk[0]); - - // - // ROUNDS-1 ordinary rounds - // - for (r = 1; r < ROUNDS; r++) - { - Substitution(S); - ShiftRow(shifts0SC); - MixColumn(); - KeyAddition(rk[r]); - } - - // - // Last round is special: there is no MixColumn - // - Substitution(S); - ShiftRow(shifts0SC); - KeyAddition(rk[ROUNDS]); - } - - private void DecryptBlock( - long[][] rk) - { - int r; - - // To decrypt: apply the inverse operations of the encrypt routine, - // in opposite order - // - // (KeyAddition is an involution: it 's equal to its inverse) - // (the inverse of Substitution with table S is Substitution with the inverse table of S) - // (the inverse of Shiftrow is Shiftrow over a suitable distance) - // - - // First the special round: - // without InvMixColumn - // with extra KeyAddition - // - KeyAddition(rk[ROUNDS]); - Substitution(Si); - ShiftRow(shifts1SC); - - // - // ROUNDS-1 ordinary rounds - // - for (r = ROUNDS - 1; r > 0; r--) - { - KeyAddition(rk[r]); - InvMixColumn(); - Substitution(Si); - ShiftRow(shifts1SC); - } - - // - // End with the extra key addition - // - KeyAddition(rk[0]); - } - } +using System; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + public class RijndaelEngine + : IBlockCipher + { + private static readonly int MAXROUNDS = 14; + + private static readonly int MAXKC = (256 / 4); + + private static readonly byte[] Logtable = + { + 0, 0, 25, 1, 50, 2, 26, 198, + 75, 199, 27, 104, 51, 238, 223, 3, + 100, 4, 224, 14, 52, 141, 129, 239, + 76, 113, 8, 200, 248, 105, 28, 193, + 125, 194, 29, 181, 249, 185, 39, 106, + 77, 228, 166, 114, 154, 201, 9, 120, + 101, 47, 138, 5, 33, 15, 225, 36, + 18, 240, 130, 69, 53, 147, 218, 142, + 150, 143, 219, 189, 54, 208, 206, 148, + 19, 92, 210, 241, 64, 70, 131, 56, + 102, 221, 253, 48, 191, 6, 139, 98, + 179, 37, 226, 152, 34, 136, 145, 16, + 126, 110, 72, 195, 163, 182, 30, 66, + 58, 107, 40, 84, 250, 133, 61, 186, + 43, 121, 10, 21, 155, 159, 94, 202, + 78, 212, 172, 229, 243, 115, 167, 87, + 175, 88, 168, 80, 244, 234, 214, 116, + 79, 174, 233, 213, 231, 230, 173, 232, + 44, 215, 117, 122, 235, 22, 11, 245, + 89, 203, 95, 176, 156, 169, 81, 160, + 127, 12, 246, 111, 23, 196, 73, 236, + 216, 67, 31, 45, 164, 118, 123, 183, + 204, 187, 62, 90, 251, 96, 177, 134, + 59, 82, 161, 108, 170, 85, 41, 157, + 151, 178, 135, 144, 97, 190, 220, 252, + 188, 149, 207, 205, 55, 63, 91, 209, + 83, 57, 132, 60, 65, 162, 109, 71, + 20, 42, 158, 93, 86, 242, 211, 171, + 68, 17, 146, 217, 35, 32, 46, 137, + 180, 124, 184, 38, 119, 153, 227, 165, + 103, 74, 237, 222, 197, 49, 254, 24, + 13, 99, 140, 128, 192, 247, 112, 7 + }; + + private static readonly byte[] Alogtable = + { + 0, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, + 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, + 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, + 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, + 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, + 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, + 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, + 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, + 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, + 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, + 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, + 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, + 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, + 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, + 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, + 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, + 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, + 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, + 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, + 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, + 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, + 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, + 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, + 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, + 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, + 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, + 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, + 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, + 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, + 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, + 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, + 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, + }; + + private static readonly byte[] S = + { + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, + 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, + 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, + 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, + 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, + 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, + 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, + 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22, + }; + + private static readonly byte[] Si = + { + 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, + 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, + 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, + 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, + 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, + 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, + 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, + 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, + 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, + 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, + 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, + 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, + 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, + 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, + 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, + 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125, + }; + + private static readonly byte[] rcon = + { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 + }; + + static readonly byte[][] shifts0 = new byte[][] + { + new byte[]{ 0, 8, 16, 24 }, + new byte[]{ 0, 8, 16, 24 }, + new byte[]{ 0, 8, 16, 24 }, + new byte[]{ 0, 8, 16, 32 }, + new byte[]{ 0, 8, 24, 32 } + }; + + static readonly byte[][] shifts1 = + { + new byte[]{ 0, 24, 16, 8 }, + new byte[]{ 0, 32, 24, 16 }, + new byte[]{ 0, 40, 32, 24 }, + new byte[]{ 0, 48, 40, 24 }, + new byte[]{ 0, 56, 40, 32 } + }; + + /** + * multiply two elements of GF(2^m) + * needed for MixColumn and InvMixColumn + */ + private byte Mul0x2( + int b) + { + if (b != 0) + { + return Alogtable[25 + (Logtable[b] & 0xff)]; + } + else + { + return 0; + } + } + + private byte Mul0x3( + int b) + { + if (b != 0) + { + return Alogtable[1 + (Logtable[b] & 0xff)]; + } + else + { + return 0; + } + } + + private byte Mul0x9( + int b) + { + if (b >= 0) + { + return Alogtable[199 + b]; + } + else + { + return 0; + } + } + + private byte Mul0xb( + int b) + { + if (b >= 0) + { + return Alogtable[104 + b]; + } + else + { + return 0; + } + } + + private byte Mul0xd( + int b) + { + if (b >= 0) + { + return Alogtable[238 + b]; + } + else + { + return 0; + } + } + + private byte Mul0xe( + int b) + { + if (b >= 0) + { + return Alogtable[223 + b]; + } + else + { + return 0; + } + } + + /** + * xor corresponding text input and round key input bytes + */ + private void KeyAddition( + long[] rk) + { + A0 ^= rk[0]; + A1 ^= rk[1]; + A2 ^= rk[2]; + A3 ^= rk[3]; + } + + private long Shift( + long r, + int shift) + { + //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK; + + ulong temp = (ulong)r >> shift; + + // NB: This corrects for Mono Bug #79087 (fixed in 1.1.17) + if (shift > 31) + { + temp &= 0xFFFFFFFFUL; + } + + return ((long)temp | (r << (BC - shift))) & BC_MASK; + } + + /** + * Row 0 remains unchanged + * The other three rows are shifted a variable amount + */ + private void ShiftRow( + byte[] shiftsSC) + { + A1 = Shift(A1, shiftsSC[1]); + A2 = Shift(A2, shiftsSC[2]); + A3 = Shift(A3, shiftsSC[3]); + } + + private long ApplyS( + long r, + byte[] box) + { + long res = 0; + + for (int j = 0; j < BC; j += 8) + { + res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j; + } + + return res; + } + + /** + * Replace every byte of the input by the byte at that place + * in the nonlinear S-box + */ + private void Substitution( + byte[] box) + { + A0 = ApplyS(A0, box); + A1 = ApplyS(A1, box); + A2 = ApplyS(A2, box); + A3 = ApplyS(A3, box); + } + + /** + * Mix the bytes of every column in a linear way + */ + private void MixColumn() + { + long r0, r1, r2, r3; + + r0 = r1 = r2 = r3 = 0; + + for (int j = 0; j < BC; j += 8) + { + int a0 = (int)((A0 >> j) & 0xff); + int a1 = (int)((A1 >> j) & 0xff); + int a2 = (int)((A2 >> j) & 0xff); + int a3 = (int)((A3 >> j) & 0xff); + + r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; + + r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; + + r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; + + r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Mix the bytes of every column in a linear way + * This is the opposite operation of Mixcolumn + */ + private void InvMixColumn() + { + long r0, r1, r2, r3; + + r0 = r1 = r2 = r3 = 0; + for (int j = 0; j < BC; j += 8) + { + int a0 = (int)((A0 >> j) & 0xff); + int a1 = (int)((A1 >> j) & 0xff); + int a2 = (int)((A2 >> j) & 0xff); + int a3 = (int)((A3 >> j) & 0xff); + + // + // pre-lookup the log table + // + a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1; + a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1; + a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1; + a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1; + + r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j; + + r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j; + + r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j; + + r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + private long[][] GenerateWorkingKey( + byte[] key) + { + int KC; + int t, rconpointer = 0; + int keyBits = key.Length * 8; + byte[,] tk = new byte[4, MAXKC]; + //long[,] W = new long[MAXROUNDS+1,4]; + long[][] W = new long[MAXROUNDS + 1][]; + + for (int i = 0; i < MAXROUNDS + 1; i++) + W[i] = new long[4]; + + switch (keyBits) + { + case 128: + KC = 4; + break; + case 160: + KC = 5; + break; + case 192: + KC = 6; + break; + case 224: + KC = 7; + break; + case 256: + KC = 8; + break; + default: + throw new ArgumentException("Key length not 128/160/192/224/256 bits."); + } + + if (keyBits >= blockBits) + { + ROUNDS = KC + 6; + } + else + { + ROUNDS = (BC / 8) + 6; + } + + // + // copy the key into the processing area + // + int index = 0; + + for (int i = 0; i < key.Length; i++) + { + tk[i % 4, i / 4] = key[index++]; + } + + t = 0; + + // + // copy values into round key array + // + for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) + { + for (int i = 0; i < 4; i++) + { + W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % BC); + } + } + + // + // while not enough round key material calculated + // calculate new values + // + while (t < (ROUNDS + 1) * (BC / 8)) + { + for (int i = 0; i < 4; i++) + { + tk[i, 0] ^= S[tk[(i + 1) % 4, KC - 1] & 0xff]; + } + tk[0, 0] ^= (byte)rcon[rconpointer++]; + + if (KC <= 6) + { + for (int j = 1; j < KC; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i, j] ^= tk[i, j - 1]; + } + } + } + else + { + for (int j = 1; j < 4; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i, j] ^= tk[i, j - 1]; + } + } + for (int i = 0; i < 4; i++) + { + tk[i, 4] ^= S[tk[i, 3] & 0xff]; + } + for (int j = 5; j < KC; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i, j] ^= tk[i, j - 1]; + } + } + } + + // + // copy values into round key array + // + for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) + { + for (int i = 0; i < 4; i++) + { + W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % (BC)); + } + } + } + return W; + } + + private int BC; + private long BC_MASK; + private int ROUNDS; + private int blockBits; + private long[][] workingKey; + private long A0, A1, A2, A3; + private bool forEncryption; + private byte[] shifts0SC; + private byte[] shifts1SC; + + /** + * default constructor - 128 bit block size. + */ + public RijndaelEngine() : this(128) { } + + /** + * basic constructor - set the cipher up for a given blocksize + * + * @param blocksize the blocksize in bits, must be 128, 192, or 256. + */ + public RijndaelEngine( + int blockBits) + { + switch (blockBits) + { + case 128: + BC = 32; + BC_MASK = 0xffffffffL; + shifts0SC = shifts0[0]; + shifts1SC = shifts1[0]; + break; + case 160: + BC = 40; + BC_MASK = 0xffffffffffL; + shifts0SC = shifts0[1]; + shifts1SC = shifts1[1]; + break; + case 192: + BC = 48; + BC_MASK = 0xffffffffffffL; + shifts0SC = shifts0[2]; + shifts1SC = shifts1[2]; + break; + case 224: + BC = 56; + BC_MASK = 0xffffffffffffffL; + shifts0SC = shifts0[3]; + shifts1SC = shifts1[3]; + break; + case 256: + BC = 64; + BC_MASK = unchecked((long)0xffffffffffffffffL); + shifts0SC = shifts0[4]; + shifts1SC = shifts1[4]; + break; + default: + throw new ArgumentException("unknown blocksize to Rijndael"); + } + + this.blockBits = blockBits; + } + + /** + * initialise a Rijndael cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + var parameter = parameters as KeyParameter; + if (parameter != null) + { + workingKey = GenerateWorkingKey(parameter.GetKey()); + this.forEncryption = forEncryption; + return; + } + + throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString()); + } + + public string AlgorithmName + { + get { return "Rijndael"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BC / 2; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + { + throw new InvalidOperationException("Rijndael engine not initialised"); + } + + if ((inOff + (BC / 2)) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (BC / 2)) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + UnPackBlock(input, inOff); + + if (forEncryption) + { + EncryptBlock(workingKey); + } + else + { + DecryptBlock(workingKey); + } + + PackBlock(output, outOff); + + return BC / 2; + } + + public void Reset() + { + } + + private void UnPackBlock( + byte[] bytes, + int off) + { + int index = off; + + A0 = (long)(bytes[index++] & 0xff); + A1 = (long)(bytes[index++] & 0xff); + A2 = (long)(bytes[index++] & 0xff); + A3 = (long)(bytes[index++] & 0xff); + + for (int j = 8; j != BC; j += 8) + { + A0 |= (long)(bytes[index++] & 0xff) << j; + A1 |= (long)(bytes[index++] & 0xff) << j; + A2 |= (long)(bytes[index++] & 0xff) << j; + A3 |= (long)(bytes[index++] & 0xff) << j; + } + } + + private void PackBlock( + byte[] bytes, + int off) + { + int index = off; + + for (int j = 0; j != BC; j += 8) + { + bytes[index++] = (byte)(A0 >> j); + bytes[index++] = (byte)(A1 >> j); + bytes[index++] = (byte)(A2 >> j); + bytes[index++] = (byte)(A3 >> j); + } + } + + private void EncryptBlock( + long[][] rk) + { + int r; + + // + // begin with a key addition + // + KeyAddition(rk[0]); + + // + // ROUNDS-1 ordinary rounds + // + for (r = 1; r < ROUNDS; r++) + { + Substitution(S); + ShiftRow(shifts0SC); + MixColumn(); + KeyAddition(rk[r]); + } + + // + // Last round is special: there is no MixColumn + // + Substitution(S); + ShiftRow(shifts0SC); + KeyAddition(rk[ROUNDS]); + } + + private void DecryptBlock( + long[][] rk) + { + int r; + + // To decrypt: apply the inverse operations of the encrypt routine, + // in opposite order + // + // (KeyAddition is an involution: it 's equal to its inverse) + // (the inverse of Substitution with table S is Substitution with the inverse table of S) + // (the inverse of Shiftrow is Shiftrow over a suitable distance) + // + + // First the special round: + // without InvMixColumn + // with extra KeyAddition + // + KeyAddition(rk[ROUNDS]); + Substitution(Si); + ShiftRow(shifts1SC); + + // + // ROUNDS-1 ordinary rounds + // + for (r = ROUNDS - 1; r > 0; r--) + { + KeyAddition(rk[r]); + InvMixColumn(); + Substitution(Si); + ShiftRow(shifts1SC); + } + + // + // End with the extra key addition + // + KeyAddition(rk[0]); + } + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/Sha1Digest.cs b/src/SharpCompress/Crypto/Sha1Digest.cs similarity index 96% rename from SharpCompress/Crypto/Sha1Digest.cs rename to src/SharpCompress/Crypto/Sha1Digest.cs index bb16c43a..4ae357e2 100644 --- a/SharpCompress/Crypto/Sha1Digest.cs +++ b/src/SharpCompress/Crypto/Sha1Digest.cs @@ -1,284 +1,284 @@ -using System; - -using Org.BouncyCastle.Crypto.Utilities; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Digests -{ - - /** - * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. - * - * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 - * is the "endianness" of the word processing! - */ - public class Sha1Digest - : GeneralDigest - { - private const int DigestLength = 20; - - private uint H1, H2, H3, H4, H5; - - private uint[] X = new uint[80]; - private int xOff; - - public Sha1Digest() - { - Reset(); - } - - /** - * Copy constructor. This will copy the state of the provided - * message digest. - */ - public Sha1Digest(Sha1Digest t) - : base(t) - { - CopyIn(t); - } - - private void CopyIn(Sha1Digest t) - { - base.CopyIn(t); - - H1 = t.H1; - H2 = t.H2; - H3 = t.H3; - H4 = t.H4; - H5 = t.H5; - - Array.Copy(t.X, 0, X, 0, t.X.Length); - xOff = t.xOff; - } - - public override string AlgorithmName - { - get { return "SHA-1"; } - } - - public override int GetDigestSize() - { - return DigestLength; - } - - internal override void ProcessWord( - byte[] input, - int inOff) - { - X[xOff] = Pack.BE_To_UInt32(input, inOff); - - if (++xOff == 16) - { - ProcessBlock(); - } - } - - internal override void ProcessLength(long bitLength) - { - if (xOff > 14) - { - ProcessBlock(); - } - - X[14] = (uint)((ulong)bitLength >> 32); - X[15] = (uint)((ulong)bitLength); - } - - public override int DoFinal( - byte[] output, - int outOff) - { - Finish(); - - Pack.UInt32_To_BE(H1, output, outOff); - Pack.UInt32_To_BE(H2, output, outOff + 4); - Pack.UInt32_To_BE(H3, output, outOff + 8); - Pack.UInt32_To_BE(H4, output, outOff + 12); - Pack.UInt32_To_BE(H5, output, outOff + 16); - - Reset(); - - return DigestLength; - } - - /** - * reset the chaining variables - */ - public override void Reset() - { - base.Reset(); - - H1 = 0x67452301; - H2 = 0xefcdab89; - H3 = 0x98badcfe; - H4 = 0x10325476; - H5 = 0xc3d2e1f0; - - xOff = 0; - Array.Clear(X, 0, X.Length); - } - - // - // Additive constants - // - private const uint Y1 = 0x5a827999; - private const uint Y2 = 0x6ed9eba1; - private const uint Y3 = 0x8f1bbcdc; - private const uint Y4 = 0xca62c1d6; - - private static uint F(uint u, uint v, uint w) - { - return (u & v) | (~u & w); - } - - private static uint H(uint u, uint v, uint w) - { - return u ^ v ^ w; - } - - private static uint G(uint u, uint v, uint w) - { - return (u & v) | (u & w) | (v & w); - } - - internal override void ProcessBlock() - { - // - // expand 16 word block into 80 word block. - // - for (int i = 16; i < 80; i++) - { - uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; - X[i] = t << 1 | t >> 31; - } - - // - // set up working variables. - // - uint A = H1; - uint B = H2; - uint C = H3; - uint D = H4; - uint E = H5; - - // - // round 1 - // - int idx = 0; - - for (int j = 0; j < 4; j++) - { - // E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1 - // B = rotateLeft(B, 30) - E += (A << 5 | (A >> 27)) + F(B, C, D) + X[idx++] + Y1; - B = B << 30 | (B >> 2); - - D += (E << 5 | (E >> 27)) + F(A, B, C) + X[idx++] + Y1; - A = A << 30 | (A >> 2); - - C += (D << 5 | (D >> 27)) + F(E, A, B) + X[idx++] + Y1; - E = E << 30 | (E >> 2); - - B += (C << 5 | (C >> 27)) + F(D, E, A) + X[idx++] + Y1; - D = D << 30 | (D >> 2); - - A += (B << 5 | (B >> 27)) + F(C, D, E) + X[idx++] + Y1; - C = C << 30 | (C >> 2); - } - - // - // round 2 - // - for (int j = 0; j < 4; j++) - { - // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2 - // B = rotateLeft(B, 30) - E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y2; - B = B << 30 | (B >> 2); - - D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y2; - A = A << 30 | (A >> 2); - - C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y2; - E = E << 30 | (E >> 2); - - B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y2; - D = D << 30 | (D >> 2); - - A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y2; - C = C << 30 | (C >> 2); - } - - // - // round 3 - // - for (int j = 0; j < 4; j++) - { - // E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3 - // B = rotateLeft(B, 30) - E += (A << 5 | (A >> 27)) + G(B, C, D) + X[idx++] + Y3; - B = B << 30 | (B >> 2); - - D += (E << 5 | (E >> 27)) + G(A, B, C) + X[idx++] + Y3; - A = A << 30 | (A >> 2); - - C += (D << 5 | (D >> 27)) + G(E, A, B) + X[idx++] + Y3; - E = E << 30 | (E >> 2); - - B += (C << 5 | (C >> 27)) + G(D, E, A) + X[idx++] + Y3; - D = D << 30 | (D >> 2); - - A += (B << 5 | (B >> 27)) + G(C, D, E) + X[idx++] + Y3; - C = C << 30 | (C >> 2); - } - - // - // round 4 - // - for (int j = 0; j < 4; j++) - { - // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4 - // B = rotateLeft(B, 30) - E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y4; - B = B << 30 | (B >> 2); - - D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y4; - A = A << 30 | (A >> 2); - - C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y4; - E = E << 30 | (E >> 2); - - B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y4; - D = D << 30 | (D >> 2); - - A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y4; - C = C << 30 | (C >> 2); - } - - H1 += A; - H2 += B; - H3 += C; - H4 += D; - H5 += E; - - // - // reset start of the buffer. - // - xOff = 0; - Array.Clear(X, 0, 16); - } - - public override IMemoable Copy() - { - return new Sha1Digest(this); - } - - public override void Reset(IMemoable other) - { - Sha1Digest d = (Sha1Digest)other; - - CopyIn(d); - } - - } +using System; + +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Digests +{ + + /** + * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. + * + * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 + * is the "endianness" of the word processing! + */ + public class Sha1Digest + : GeneralDigest + { + private const int DigestLength = 20; + + private uint H1, H2, H3, H4, H5; + + private uint[] X = new uint[80]; + private int xOff; + + public Sha1Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha1Digest(Sha1Digest t) + : base(t) + { + CopyIn(t); + } + + private void CopyIn(Sha1Digest t) + { + base.CopyIn(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "SHA-1"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff] = Pack.BE_To_UInt32(input, inOff); + + if (++xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength(long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (uint)((ulong)bitLength >> 32); + X[15] = (uint)((ulong)bitLength); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + Pack.UInt32_To_BE(H1, output, outOff); + Pack.UInt32_To_BE(H2, output, outOff + 4); + Pack.UInt32_To_BE(H3, output, outOff + 8); + Pack.UInt32_To_BE(H4, output, outOff + 12); + Pack.UInt32_To_BE(H5, output, outOff + 16); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables + */ + public override void Reset() + { + base.Reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + H5 = 0xc3d2e1f0; + + xOff = 0; + Array.Clear(X, 0, X.Length); + } + + // + // Additive constants + // + private const uint Y1 = 0x5a827999; + private const uint Y2 = 0x6ed9eba1; + private const uint Y3 = 0x8f1bbcdc; + private const uint Y4 = 0xca62c1d6; + + private static uint F(uint u, uint v, uint w) + { + return (u & v) | (~u & w); + } + + private static uint H(uint u, uint v, uint w) + { + return u ^ v ^ w; + } + + private static uint G(uint u, uint v, uint w) + { + return (u & v) | (u & w) | (v & w); + } + + internal override void ProcessBlock() + { + // + // expand 16 word block into 80 word block. + // + for (int i = 16; i < 80; i++) + { + uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; + X[i] = t << 1 | t >> 31; + } + + // + // set up working variables. + // + uint A = H1; + uint B = H2; + uint C = H3; + uint D = H4; + uint E = H5; + + // + // round 1 + // + int idx = 0; + + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1 + // B = rotateLeft(B, 30) + E += (A << 5 | (A >> 27)) + F(B, C, D) + X[idx++] + Y1; + B = B << 30 | (B >> 2); + + D += (E << 5 | (E >> 27)) + F(A, B, C) + X[idx++] + Y1; + A = A << 30 | (A >> 2); + + C += (D << 5 | (D >> 27)) + F(E, A, B) + X[idx++] + Y1; + E = E << 30 | (E >> 2); + + B += (C << 5 | (C >> 27)) + F(D, E, A) + X[idx++] + Y1; + D = D << 30 | (D >> 2); + + A += (B << 5 | (B >> 27)) + F(C, D, E) + X[idx++] + Y1; + C = C << 30 | (C >> 2); + } + + // + // round 2 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2 + // B = rotateLeft(B, 30) + E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y2; + B = B << 30 | (B >> 2); + + D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y2; + A = A << 30 | (A >> 2); + + C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y2; + E = E << 30 | (E >> 2); + + B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y2; + D = D << 30 | (D >> 2); + + A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y2; + C = C << 30 | (C >> 2); + } + + // + // round 3 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3 + // B = rotateLeft(B, 30) + E += (A << 5 | (A >> 27)) + G(B, C, D) + X[idx++] + Y3; + B = B << 30 | (B >> 2); + + D += (E << 5 | (E >> 27)) + G(A, B, C) + X[idx++] + Y3; + A = A << 30 | (A >> 2); + + C += (D << 5 | (D >> 27)) + G(E, A, B) + X[idx++] + Y3; + E = E << 30 | (E >> 2); + + B += (C << 5 | (C >> 27)) + G(D, E, A) + X[idx++] + Y3; + D = D << 30 | (D >> 2); + + A += (B << 5 | (B >> 27)) + G(C, D, E) + X[idx++] + Y3; + C = C << 30 | (C >> 2); + } + + // + // round 4 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4 + // B = rotateLeft(B, 30) + E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y4; + B = B << 30 | (B >> 2); + + D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y4; + A = A << 30 | (A >> 2); + + C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y4; + E = E << 30 | (E >> 2); + + B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y4; + D = D << 30 | (D >> 2); + + A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y4; + C = C << 30 | (C >> 2); + } + + H1 += A; + H2 += B; + H3 += C; + H4 += D; + H5 += E; + + // + // reset start of the buffer. + // + xOff = 0; + Array.Clear(X, 0, 16); + } + + public override IMemoable Copy() + { + return new Sha1Digest(this); + } + + public override void Reset(IMemoable other) + { + Sha1Digest d = (Sha1Digest)other; + + CopyIn(d); + } + + } } \ No newline at end of file diff --git a/SharpCompress/Crypto/Sha256Digest.cs b/src/SharpCompress/Crypto/Sha256Digest.cs similarity index 100% rename from SharpCompress/Crypto/Sha256Digest.cs rename to src/SharpCompress/Crypto/Sha256Digest.cs diff --git a/SharpCompress/EnumExtensions.cs b/src/SharpCompress/EnumExtensions.cs similarity index 95% rename from SharpCompress/EnumExtensions.cs rename to src/SharpCompress/EnumExtensions.cs index e72da2a6..beafa34f 100644 --- a/SharpCompress/EnumExtensions.cs +++ b/src/SharpCompress/EnumExtensions.cs @@ -1,15 +1,15 @@ -using System; - -namespace SharpCompress -{ - internal static class EnumExtensions - { - public static bool HasFlag(this Enum enumRef, Enum flag) - { - long value = Convert.ToInt64(enumRef); - long flagVal = Convert.ToInt64(flag); - - return (value & flagVal) == flagVal; - } - } +using System; + +namespace SharpCompress +{ + internal static class EnumExtensions + { + public static bool HasFlag(this Enum enumRef, Enum flag) + { + long value = Convert.ToInt64(enumRef); + long flagVal = Convert.ToInt64(flag); + + return (value & flagVal) == flagVal; + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/AppendingStream.cs b/src/SharpCompress/IO/AppendingStream.cs similarity index 96% rename from SharpCompress/IO/AppendingStream.cs rename to src/SharpCompress/IO/AppendingStream.cs index 01eccc38..ca47ca83 100644 --- a/SharpCompress/IO/AppendingStream.cs +++ b/src/SharpCompress/IO/AppendingStream.cs @@ -1,99 +1,99 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace SharpCompress.IO -{ - public class ReadOnlyAppendingStream : Stream - { - private readonly Queue streams; - private Stream current; - - public ReadOnlyAppendingStream(IEnumerable streams) - { - this.streams = new Queue(streams); - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotImplementedException(); - } - - public override long Length - { - get { throw new NotImplementedException(); } - } - - public override long Position - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (current == null && streams.Count == 0) - { - return -1; - } - if (current == null) - { - current = streams.Dequeue(); - } - int totalRead = 0; - while (totalRead < count) - { - int read = current.Read(buffer, offset + totalRead, count - totalRead); - if (read <= 0) - { - if (streams.Count == 0) - { - return totalRead; - } - else - { - current = streams.Dequeue(); - } - } - totalRead += read; - } - return totalRead; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress.IO +{ + public class ReadOnlyAppendingStream : Stream + { + private readonly Queue streams; + private Stream current; + + public ReadOnlyAppendingStream(IEnumerable streams) + { + this.streams = new Queue(streams); + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override long Length + { + get { throw new NotImplementedException(); } + } + + public override long Position + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (current == null && streams.Count == 0) + { + return -1; + } + if (current == null) + { + current = streams.Dequeue(); + } + int totalRead = 0; + while (totalRead < count) + { + int read = current.Read(buffer, offset + totalRead, count - totalRead); + if (read <= 0) + { + if (streams.Count == 0) + { + return totalRead; + } + else + { + current = streams.Dequeue(); + } + } + totalRead += read; + } + return totalRead; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + } +} diff --git a/SharpCompress/IO/CountingWritableSubStream.cs b/src/SharpCompress/IO/CountingWritableSubStream.cs similarity index 95% rename from SharpCompress/IO/CountingWritableSubStream.cs rename to src/SharpCompress/IO/CountingWritableSubStream.cs index ef493445..3b9d2c7a 100644 --- a/SharpCompress/IO/CountingWritableSubStream.cs +++ b/src/SharpCompress/IO/CountingWritableSubStream.cs @@ -1,68 +1,68 @@ -using System; -using System.IO; - -namespace SharpCompress.IO -{ - internal class CountingWritableSubStream : Stream - { - private Stream writableStream; - - internal CountingWritableSubStream(Stream stream) - { - writableStream = stream; - } - - public uint Count { get; private set; } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override void Flush() - { - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - writableStream.Write(buffer, offset, count); - Count += (uint) count; - } - } +using System; +using System.IO; + +namespace SharpCompress.IO +{ + internal class CountingWritableSubStream : Stream + { + private Stream writableStream; + + internal CountingWritableSubStream(Stream stream) + { + writableStream = stream; + } + + public uint Count { get; private set; } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + writableStream.Write(buffer, offset, count); + Count += (uint) count; + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/ListeningStream.cs b/src/SharpCompress/IO/ListeningStream.cs similarity index 96% rename from SharpCompress/IO/ListeningStream.cs rename to src/SharpCompress/IO/ListeningStream.cs index a4353c85..49a4a5d0 100644 --- a/SharpCompress/IO/ListeningStream.cs +++ b/src/SharpCompress/IO/ListeningStream.cs @@ -1,81 +1,81 @@ -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.IO -{ - internal class ListeningStream : Stream - { - private long currentEntryTotalReadBytes; - private IExtractionListener listener; - - public ListeningStream(IExtractionListener listener, Stream stream) - { - Stream = stream; - this.listener = listener; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - Stream.Dispose(); - } - } - - public Stream Stream { get; private set; } - - public override bool CanRead - { - get { return Stream.CanRead; } - } - - public override bool CanSeek - { - get { return Stream.CanSeek; } - } - - public override bool CanWrite - { - get { return Stream.CanWrite; } - } - - public override void Flush() - { - Stream.Flush(); - } - - public override long Length - { - get { return Stream.Length; } - } - - public override long Position - { - get { return Stream.Position; } - set { Stream.Position = value; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - int read = Stream.Read(buffer, offset, count); - currentEntryTotalReadBytes += read; - listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return Stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - Stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Stream.Write(buffer, offset, count); - } - } +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.IO +{ + internal class ListeningStream : Stream + { + private long currentEntryTotalReadBytes; + private IExtractionListener listener; + + public ListeningStream(IExtractionListener listener, Stream stream) + { + Stream = stream; + this.listener = listener; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Stream.Dispose(); + } + } + + public Stream Stream { get; private set; } + + public override bool CanRead + { + get { return Stream.CanRead; } + } + + public override bool CanSeek + { + get { return Stream.CanSeek; } + } + + public override bool CanWrite + { + get { return Stream.CanWrite; } + } + + public override void Flush() + { + Stream.Flush(); + } + + public override long Length + { + get { return Stream.Length; } + } + + public override long Position + { + get { return Stream.Position; } + set { Stream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int read = Stream.Read(buffer, offset, count); + currentEntryTotalReadBytes += read; + listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); + return read; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return Stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + Stream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Stream.Write(buffer, offset, count); + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/MarkingBinaryReader.cs b/src/SharpCompress/IO/MarkingBinaryReader.cs similarity index 96% rename from SharpCompress/IO/MarkingBinaryReader.cs rename to src/SharpCompress/IO/MarkingBinaryReader.cs index 1f624d30..68c26035 100644 --- a/SharpCompress/IO/MarkingBinaryReader.cs +++ b/src/SharpCompress/IO/MarkingBinaryReader.cs @@ -1,134 +1,134 @@ -using System; -using System.IO; -using System.Linq; - -namespace SharpCompress.IO -{ - internal class MarkingBinaryReader : BinaryReader - { - - public MarkingBinaryReader(Stream stream) - : base(stream) - { - } - - public long CurrentReadByteCount { get; private set; } - - public void Mark() - { - CurrentReadByteCount = 0; - } - - public override int Read() - { - throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int index, int count) - { - throw new NotSupportedException(); - } - - public override int Read(char[] buffer, int index, int count) - { - throw new NotSupportedException(); - } - - public override bool ReadBoolean() - { - return BitConverter.ToBoolean(ReadBytes(1), 0); - } - - public override byte ReadByte() - { - return ReadBytes(1).Single(); - } - - public override byte[] ReadBytes(int count) - { - CurrentReadByteCount += count; - var bytes = base.ReadBytes(count); - if (bytes.Length != count) - { - throw new EndOfStreamException(string.Format("Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", count, bytes.Length)); - } - return bytes; - } - - public override char ReadChar() - { - throw new NotSupportedException(); - } - - public override char[] ReadChars(int count) - { - throw new NotSupportedException(); - } - - public override decimal ReadDecimal() - { - return ByteArrayToDecimal(ReadBytes(16), 0); - } - - private decimal ByteArrayToDecimal(byte[] src, int offset) - { - //http://stackoverflow.com/a/16984356/385387 - var i1 = BitConverter.ToInt32(src, offset); - var i2 = BitConverter.ToInt32(src, offset + 4); - var i3 = BitConverter.ToInt32(src, offset + 8); - var i4 = BitConverter.ToInt32(src, offset + 12); - - return new decimal(new[] { i1, i2, i3, i4 }); - } - - public override double ReadDouble() - { - return BitConverter.ToDouble(ReadBytes(8), 0); - } - - public override short ReadInt16() - { - return BitConverter.ToInt16(ReadBytes(2), 0); - } - - public override int ReadInt32() - { - return BitConverter.ToInt32(ReadBytes(4), 0); - } - - public override long ReadInt64() - { - return BitConverter.ToInt64(ReadBytes(8), 0); - } - - public override sbyte ReadSByte() - { - return (sbyte)ReadByte(); - } - - public override float ReadSingle() - { - return BitConverter.ToSingle(ReadBytes(4), 0); - } - - public override string ReadString() - { - throw new NotSupportedException(); - } - - public override ushort ReadUInt16() - { - return BitConverter.ToUInt16(ReadBytes(2), 0); - } - - public override uint ReadUInt32() - { - return BitConverter.ToUInt32(ReadBytes(4), 0); - } - - public override ulong ReadUInt64() - { - return BitConverter.ToUInt64(ReadBytes(8), 0); - } - } +using System; +using System.IO; +using System.Linq; + +namespace SharpCompress.IO +{ + internal class MarkingBinaryReader : BinaryReader + { + + public MarkingBinaryReader(Stream stream) + : base(stream) + { + } + + public long CurrentReadByteCount { get; private set; } + + public void Mark() + { + CurrentReadByteCount = 0; + } + + public override int Read() + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int index, int count) + { + throw new NotSupportedException(); + } + + public override int Read(char[] buffer, int index, int count) + { + throw new NotSupportedException(); + } + + public override bool ReadBoolean() + { + return BitConverter.ToBoolean(ReadBytes(1), 0); + } + + public override byte ReadByte() + { + return ReadBytes(1).Single(); + } + + public override byte[] ReadBytes(int count) + { + CurrentReadByteCount += count; + var bytes = base.ReadBytes(count); + if (bytes.Length != count) + { + throw new EndOfStreamException(string.Format("Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", count, bytes.Length)); + } + return bytes; + } + + public override char ReadChar() + { + throw new NotSupportedException(); + } + + public override char[] ReadChars(int count) + { + throw new NotSupportedException(); + } + + public override decimal ReadDecimal() + { + return ByteArrayToDecimal(ReadBytes(16), 0); + } + + private decimal ByteArrayToDecimal(byte[] src, int offset) + { + //http://stackoverflow.com/a/16984356/385387 + var i1 = BitConverter.ToInt32(src, offset); + var i2 = BitConverter.ToInt32(src, offset + 4); + var i3 = BitConverter.ToInt32(src, offset + 8); + var i4 = BitConverter.ToInt32(src, offset + 12); + + return new decimal(new[] { i1, i2, i3, i4 }); + } + + public override double ReadDouble() + { + return BitConverter.ToDouble(ReadBytes(8), 0); + } + + public override short ReadInt16() + { + return BitConverter.ToInt16(ReadBytes(2), 0); + } + + public override int ReadInt32() + { + return BitConverter.ToInt32(ReadBytes(4), 0); + } + + public override long ReadInt64() + { + return BitConverter.ToInt64(ReadBytes(8), 0); + } + + public override sbyte ReadSByte() + { + return (sbyte)ReadByte(); + } + + public override float ReadSingle() + { + return BitConverter.ToSingle(ReadBytes(4), 0); + } + + public override string ReadString() + { + throw new NotSupportedException(); + } + + public override ushort ReadUInt16() + { + return BitConverter.ToUInt16(ReadBytes(2), 0); + } + + public override uint ReadUInt32() + { + return BitConverter.ToUInt32(ReadBytes(4), 0); + } + + public override ulong ReadUInt64() + { + return BitConverter.ToUInt64(ReadBytes(8), 0); + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/NonDisposingStream.cs b/src/SharpCompress/IO/NonDisposingStream.cs similarity index 95% rename from SharpCompress/IO/NonDisposingStream.cs rename to src/SharpCompress/IO/NonDisposingStream.cs index 95094d1f..d19ea095 100644 --- a/SharpCompress/IO/NonDisposingStream.cs +++ b/src/SharpCompress/IO/NonDisposingStream.cs @@ -1,70 +1,70 @@ -using System.IO; - -namespace SharpCompress.IO -{ - internal class NonDisposingStream : Stream - { - public NonDisposingStream(Stream stream) - { - Stream = stream; - } - - protected override void Dispose(bool disposing) - { - //don't dispose anything - } - - public Stream Stream { get; private set; } - - public override bool CanRead - { - get { return Stream.CanRead; } - } - - public override bool CanSeek - { - get { return Stream.CanSeek; } - } - - public override bool CanWrite - { - get { return Stream.CanWrite; } - } - - public override void Flush() - { - Stream.Flush(); - } - - public override long Length - { - get { return Stream.Length; } - } - - public override long Position - { - get { return Stream.Position; } - set { Stream.Position = value; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - return Stream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return Stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - Stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Stream.Write(buffer, offset, count); - } - } +using System.IO; + +namespace SharpCompress.IO +{ + internal class NonDisposingStream : Stream + { + public NonDisposingStream(Stream stream) + { + Stream = stream; + } + + protected override void Dispose(bool disposing) + { + //don't dispose anything + } + + public Stream Stream { get; private set; } + + public override bool CanRead + { + get { return Stream.CanRead; } + } + + public override bool CanSeek + { + get { return Stream.CanSeek; } + } + + public override bool CanWrite + { + get { return Stream.CanWrite; } + } + + public override void Flush() + { + Stream.Flush(); + } + + public override long Length + { + get { return Stream.Length; } + } + + public override long Position + { + get { return Stream.Position; } + set { Stream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return Stream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return Stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + Stream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Stream.Write(buffer, offset, count); + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/ReadOnlySubStream.cs b/src/SharpCompress/IO/ReadOnlySubStream.cs similarity index 96% rename from SharpCompress/IO/ReadOnlySubStream.cs rename to src/SharpCompress/IO/ReadOnlySubStream.cs index 21b7dd76..8126d61d 100644 --- a/SharpCompress/IO/ReadOnlySubStream.cs +++ b/src/SharpCompress/IO/ReadOnlySubStream.cs @@ -1,94 +1,94 @@ -using System.IO; - -namespace SharpCompress.IO -{ - internal class ReadOnlySubStream : Stream - { - public ReadOnlySubStream(Stream stream, long bytesToRead) - : this(stream, null, bytesToRead) - { - } - - public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) - { - Stream = stream; - if (origin != null) - { - stream.Position = origin.Value; - } - BytesLeftToRead = bytesToRead; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - //Stream.Dispose(); - } - } - - private long BytesLeftToRead { get; set; } - - public Stream Stream { get; private set; } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new System.NotSupportedException(); - } - - public override long Length - { - get { throw new System.NotSupportedException(); } - } - - public override long Position - { - get { throw new System.NotSupportedException(); } - set { throw new System.NotSupportedException(); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (BytesLeftToRead < count) - { - count = (int)BytesLeftToRead; - } - int read = Stream.Read(buffer, offset, count); - if (read > 0) - { - BytesLeftToRead -= read; - } - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new System.NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new System.NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new System.NotSupportedException(); - } - } +using System.IO; + +namespace SharpCompress.IO +{ + internal class ReadOnlySubStream : Stream + { + public ReadOnlySubStream(Stream stream, long bytesToRead) + : this(stream, null, bytesToRead) + { + } + + public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) + { + Stream = stream; + if (origin != null) + { + stream.Position = origin.Value; + } + BytesLeftToRead = bytesToRead; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + //Stream.Dispose(); + } + } + + private long BytesLeftToRead { get; set; } + + public Stream Stream { get; private set; } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new System.NotSupportedException(); + } + + public override long Length + { + get { throw new System.NotSupportedException(); } + } + + public override long Position + { + get { throw new System.NotSupportedException(); } + set { throw new System.NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (BytesLeftToRead < count) + { + count = (int)BytesLeftToRead; + } + int read = Stream.Read(buffer, offset, count); + if (read > 0) + { + BytesLeftToRead -= read; + } + return read; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new System.NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new System.NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new System.NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/RewindableStream.cs b/src/SharpCompress/IO/RewindableStream.cs similarity index 96% rename from SharpCompress/IO/RewindableStream.cs rename to src/SharpCompress/IO/RewindableStream.cs index 7946eec6..054888f7 100644 --- a/SharpCompress/IO/RewindableStream.cs +++ b/src/SharpCompress/IO/RewindableStream.cs @@ -1,163 +1,163 @@ -using System.IO; - -namespace SharpCompress.IO -{ - internal class RewindableStream : Stream - { - private readonly Stream stream; - private MemoryStream bufferStream = new MemoryStream(); - private bool isRewound; - private bool isDisposed; - - public RewindableStream(Stream stream) - { - this.stream = stream; - } - - internal bool IsRecording { get; private set; } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - if (disposing) - { - stream.Dispose(); - } - } - - public void Rewind(bool stopRecording) - { - isRewound = true; - IsRecording = !stopRecording; - bufferStream.Position = 0; - } - - public void Rewind(MemoryStream buffer) - { - if (bufferStream.Position >= buffer.Length) - { - bufferStream.Position -= buffer.Length; - } - else - { - bufferStream.TransferTo(buffer); - bufferStream = buffer; - bufferStream.Position = 0; - } - isRewound = true; - } - - public void StartRecording() - { - //if (isRewound && bufferStream.Position != 0) - // throw new System.NotImplementedException(); - if (bufferStream.Position != 0) - { - byte[] data = bufferStream.ToArray(); - long position = bufferStream.Position; - bufferStream.SetLength(0); - bufferStream.Write(data, (int)position, data.Length - (int)position); - bufferStream.Position = 0; - } - IsRecording = true; - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new System.NotSupportedException(); - } - - public override long Length - { - get { throw new System.NotSupportedException(); } - } - - public override long Position - { - get { return stream.Position + bufferStream.Position - bufferStream.Length; } - set - { - if (!isRewound) - { - stream.Position = value; - } - else if (value < stream.Position - bufferStream.Length || value >= stream.Position) - { - stream.Position = value; - isRewound = false; - bufferStream.SetLength(0); - } - else - { - bufferStream.Position = value - stream.Position + bufferStream.Length; - } - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - int read; - if (isRewound && bufferStream.Position != bufferStream.Length) - { - read = bufferStream.Read(buffer, offset, count); - if (read < count) - { - int tempRead = stream.Read(buffer, offset + read, count - read); - if (IsRecording) - { - bufferStream.Write(buffer, offset + read, tempRead); - } - read += tempRead; - } - if (bufferStream.Position == bufferStream.Length && !IsRecording) - { - isRewound = false; - bufferStream.SetLength(0); - } - return read; - } - - read = stream.Read(buffer, offset, count); - if (IsRecording) - { - bufferStream.Write(buffer, offset, read); - } - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new System.NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new System.NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new System.NotSupportedException(); - } - } +using System.IO; + +namespace SharpCompress.IO +{ + internal class RewindableStream : Stream + { + private readonly Stream stream; + private MemoryStream bufferStream = new MemoryStream(); + private bool isRewound; + private bool isDisposed; + + public RewindableStream(Stream stream) + { + this.stream = stream; + } + + internal bool IsRecording { get; private set; } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + if (disposing) + { + stream.Dispose(); + } + } + + public void Rewind(bool stopRecording) + { + isRewound = true; + IsRecording = !stopRecording; + bufferStream.Position = 0; + } + + public void Rewind(MemoryStream buffer) + { + if (bufferStream.Position >= buffer.Length) + { + bufferStream.Position -= buffer.Length; + } + else + { + bufferStream.TransferTo(buffer); + bufferStream = buffer; + bufferStream.Position = 0; + } + isRewound = true; + } + + public void StartRecording() + { + //if (isRewound && bufferStream.Position != 0) + // throw new System.NotImplementedException(); + if (bufferStream.Position != 0) + { + byte[] data = bufferStream.ToArray(); + long position = bufferStream.Position; + bufferStream.SetLength(0); + bufferStream.Write(data, (int)position, data.Length - (int)position); + bufferStream.Position = 0; + } + IsRecording = true; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new System.NotSupportedException(); + } + + public override long Length + { + get { throw new System.NotSupportedException(); } + } + + public override long Position + { + get { return stream.Position + bufferStream.Position - bufferStream.Length; } + set + { + if (!isRewound) + { + stream.Position = value; + } + else if (value < stream.Position - bufferStream.Length || value >= stream.Position) + { + stream.Position = value; + isRewound = false; + bufferStream.SetLength(0); + } + else + { + bufferStream.Position = value - stream.Position + bufferStream.Length; + } + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int read; + if (isRewound && bufferStream.Position != bufferStream.Length) + { + read = bufferStream.Read(buffer, offset, count); + if (read < count) + { + int tempRead = stream.Read(buffer, offset + read, count - read); + if (IsRecording) + { + bufferStream.Write(buffer, offset + read, tempRead); + } + read += tempRead; + } + if (bufferStream.Position == bufferStream.Length && !IsRecording) + { + isRewound = false; + bufferStream.SetLength(0); + } + return read; + } + + read = stream.Read(buffer, offset, count); + if (IsRecording) + { + bufferStream.Write(buffer, offset, read); + } + return read; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new System.NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new System.NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new System.NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/IO/StreamingMode.cs b/src/SharpCompress/IO/StreamingMode.cs similarity index 94% rename from SharpCompress/IO/StreamingMode.cs rename to src/SharpCompress/IO/StreamingMode.cs index 95ca3d8c..2497e2d8 100644 --- a/SharpCompress/IO/StreamingMode.cs +++ b/src/SharpCompress/IO/StreamingMode.cs @@ -1,8 +1,8 @@ -namespace SharpCompress.IO -{ - internal enum StreamingMode - { - Streaming, - Seekable, - } +namespace SharpCompress.IO +{ + internal enum StreamingMode + { + Streaming, + Seekable, + } } \ No newline at end of file diff --git a/SharpCompress/LazyReadOnlyCollection.cs b/src/SharpCompress/LazyReadOnlyCollection.cs similarity index 95% rename from SharpCompress/LazyReadOnlyCollection.cs rename to src/SharpCompress/LazyReadOnlyCollection.cs index 7c1ddd8c..7dfbcc9c 100644 --- a/SharpCompress/LazyReadOnlyCollection.cs +++ b/src/SharpCompress/LazyReadOnlyCollection.cs @@ -1,159 +1,159 @@ -using System; -using System.Collections.Generic; - -namespace SharpCompress -{ - internal class LazyReadOnlyCollection : ICollection - { - private readonly List backing = new List(); - private readonly IEnumerator source; - private bool fullyLoaded; - - public LazyReadOnlyCollection(IEnumerable source) - { - this.source = source.GetEnumerator(); - } - - private class LazyLoader : IEnumerator - { - private readonly LazyReadOnlyCollection lazyReadOnlyCollection; - private bool disposed; - private int index = -1; - - internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) - { - this.lazyReadOnlyCollection = lazyReadOnlyCollection; - } - - #region IEnumerator Members - - public T Current - { - get { return lazyReadOnlyCollection.backing[index]; } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!disposed) - { - disposed = true; - } - } - - #endregion - - #region IEnumerator Members - - object System.Collections.IEnumerator.Current - { - get { return Current; } - } - - public bool MoveNext() - { - if (index + 1 < lazyReadOnlyCollection.backing.Count) - { - index++; - return true; - } - if (!lazyReadOnlyCollection.fullyLoaded && lazyReadOnlyCollection.source.MoveNext()) - { - lazyReadOnlyCollection.backing.Add(lazyReadOnlyCollection.source.Current); - index++; - return true; - } - lazyReadOnlyCollection.fullyLoaded = true; - return false; - } - - public void Reset() - { - throw new NotSupportedException(); - } - - #endregion - } - - internal void EnsureFullyLoaded() - { - if (!fullyLoaded) - { - this.ForEach(x => { }); - fullyLoaded = true; - } - } - - internal IEnumerable GetLoaded() - { - return backing; - } - - #region ICollection Members - - public void Add(T item) - { - throw new NotSupportedException(); - } - - public void Clear() - { - throw new NotSupportedException(); - } - - public bool Contains(T item) - { - EnsureFullyLoaded(); - return backing.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - EnsureFullyLoaded(); - backing.CopyTo(array, arrayIndex); - } - - public int Count - { - get - { - EnsureFullyLoaded(); - return backing.Count; - } - } - - public bool IsReadOnly - { - get { return true; } - } - - public bool Remove(T item) - { - throw new NotSupportedException(); - } - - #endregion - - #region IEnumerable Members - - //TODO check for concurrent access - public IEnumerator GetEnumerator() - { - return new LazyLoader(this); - } - - #endregion - - #region IEnumerable Members - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - } +using System; +using System.Collections.Generic; + +namespace SharpCompress +{ + internal class LazyReadOnlyCollection : ICollection + { + private readonly List backing = new List(); + private readonly IEnumerator source; + private bool fullyLoaded; + + public LazyReadOnlyCollection(IEnumerable source) + { + this.source = source.GetEnumerator(); + } + + private class LazyLoader : IEnumerator + { + private readonly LazyReadOnlyCollection lazyReadOnlyCollection; + private bool disposed; + private int index = -1; + + internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) + { + this.lazyReadOnlyCollection = lazyReadOnlyCollection; + } + + #region IEnumerator Members + + public T Current + { + get { return lazyReadOnlyCollection.backing[index]; } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) + { + disposed = true; + } + } + + #endregion + + #region IEnumerator Members + + object System.Collections.IEnumerator.Current + { + get { return Current; } + } + + public bool MoveNext() + { + if (index + 1 < lazyReadOnlyCollection.backing.Count) + { + index++; + return true; + } + if (!lazyReadOnlyCollection.fullyLoaded && lazyReadOnlyCollection.source.MoveNext()) + { + lazyReadOnlyCollection.backing.Add(lazyReadOnlyCollection.source.Current); + index++; + return true; + } + lazyReadOnlyCollection.fullyLoaded = true; + return false; + } + + public void Reset() + { + throw new NotSupportedException(); + } + + #endregion + } + + internal void EnsureFullyLoaded() + { + if (!fullyLoaded) + { + this.ForEach(x => { }); + fullyLoaded = true; + } + } + + internal IEnumerable GetLoaded() + { + return backing; + } + + #region ICollection Members + + public void Add(T item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Contains(T item) + { + EnsureFullyLoaded(); + return backing.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + EnsureFullyLoaded(); + backing.CopyTo(array, arrayIndex); + } + + public int Count + { + get + { + EnsureFullyLoaded(); + return backing.Count; + } + } + + public bool IsReadOnly + { + get { return true; } + } + + public bool Remove(T item) + { + throw new NotSupportedException(); + } + + #endregion + + #region IEnumerable Members + + //TODO check for concurrent access + public IEnumerator GetEnumerator() + { + return new LazyLoader(this); + } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/ReadOnlyCollection.cs b/src/SharpCompress/ReadOnlyCollection.cs similarity index 95% rename from SharpCompress/ReadOnlyCollection.cs rename to src/SharpCompress/ReadOnlyCollection.cs index d291e4a3..37bd9a4c 100644 --- a/SharpCompress/ReadOnlyCollection.cs +++ b/src/SharpCompress/ReadOnlyCollection.cs @@ -1,60 +1,60 @@ -using System; -using System.Collections.Generic; - -namespace SharpCompress -{ - internal class ReadOnlyCollection : ICollection - { - private ICollection collection; - - public ReadOnlyCollection(ICollection collection) - { - this.collection = collection; - } - - public void Add(T item) - { - throw new NotSupportedException(); - } - - public void Clear() - { - throw new NotSupportedException(); - } - - public bool Contains(T item) - { - return collection.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - collection.CopyTo(array, arrayIndex); - } - - public int Count - { - get { return collection.Count; } - } - - public bool IsReadOnly - { - get { return true; } - } - - public bool Remove(T item) - { - throw new NotSupportedException(); - } - - public IEnumerator GetEnumerator() - { - return collection.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - throw new NotSupportedException(); - } - } +using System; +using System.Collections.Generic; + +namespace SharpCompress +{ + internal class ReadOnlyCollection : ICollection + { + private ICollection collection; + + public ReadOnlyCollection(ICollection collection) + { + this.collection = collection; + } + + public void Add(T item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Contains(T item) + { + return collection.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + collection.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return collection.Count; } + } + + public bool IsReadOnly + { + get { return true; } + } + + public bool Remove(T item) + { + throw new NotSupportedException(); + } + + public IEnumerator GetEnumerator() + { + return collection.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + throw new NotSupportedException(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/AbstractReader.cs b/src/SharpCompress/Reader/AbstractReader.cs similarity index 96% rename from SharpCompress/Reader/AbstractReader.cs rename to src/SharpCompress/Reader/AbstractReader.cs index db2b401b..ca7ba6ce 100644 --- a/SharpCompress/Reader/AbstractReader.cs +++ b/src/SharpCompress/Reader/AbstractReader.cs @@ -1,278 +1,278 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Archive.Rar; -using SharpCompress.Common; -using SharpCompress.Reader.Rar; - -namespace SharpCompress.Reader -{ - /// - /// A generic push reader that reads unseekable comrpessed streams. - /// - public abstract class AbstractReader : IReader, IReaderExtractionListener - where TEntry : Entry - where TVolume : Volume - { - private bool completed; - private IEnumerator entriesForCurrentReadStream; - private bool wroteCurrentEntry; - - public event EventHandler> EntryExtractionBegin; - public event EventHandler> EntryExtractionEnd; - - public event EventHandler CompressedBytesRead; - public event EventHandler FilePartExtractionBegin; - - - - internal AbstractReader(Options options, ArchiveType archiveType) - { - ArchiveType = archiveType; - Options = options; - } - - internal Options Options { get; private set; } - - public ArchiveType ArchiveType { get; private set; } - - /// - /// Current volume that the current entry resides in - /// - public abstract TVolume Volume { get; } - - /// - /// Current file entry - /// - public TEntry Entry - { - get { return entriesForCurrentReadStream.Current; } - } - - #region IDisposable Members - - public void Dispose() - { - if (entriesForCurrentReadStream != null) - { - entriesForCurrentReadStream.Dispose(); - } - Volume.Dispose(); - } - - #endregion - - - public bool Cancelled { get; private set; } - - /// - /// Indicates that the remaining entries are not required. - /// On dispose of an EntryStream, the stream will not skip to the end of the entry. - /// An attempt to move to the next entry will throw an exception, as the compressed stream is not positioned at an entry boundary. - /// - public void Cancel() - { - if (!completed) - { - Cancelled = true; - } - } - - public bool MoveToNextEntry() - { - if (completed) - { - return false; - } - if (Cancelled) - { - throw new InvalidOperationException("Reader has been cancelled."); - } - if (entriesForCurrentReadStream == null) - { - return LoadStreamForReading(RequestInitialStream()); - } - if (!wroteCurrentEntry) - { - SkipEntry(); - } - wroteCurrentEntry = false; - if (NextEntryForCurrentStream()) - { - return true; - } - completed = true; - return false; - } - - internal bool LoadStreamForReading(Stream stream) - { - if (entriesForCurrentReadStream != null) - { - entriesForCurrentReadStream.Dispose(); - } - if ((stream == null) || (!stream.CanRead)) - { - throw new MultipartStreamRequiredException("File is split into multiple archives: '" - + Entry.Key + - "'. A new readable stream is required. Use Cancel if it was intended."); - } - entriesForCurrentReadStream = GetEntries(stream).GetEnumerator(); - if (entriesForCurrentReadStream.MoveNext()) - { - return true; - } - return false; - } - - internal virtual Stream RequestInitialStream() - { - return Volume.Stream; - } - - internal virtual bool NextEntryForCurrentStream() - { - return entriesForCurrentReadStream.MoveNext(); - } - - internal abstract IEnumerable GetEntries(Stream stream); - - #region Entry Skip/Write - - private void SkipEntry() - { - if (!Entry.IsDirectory) - { - Skip(); - } - } - - private readonly byte[] skipBuffer = new byte[4096]; - - private void Skip() - { - if (!Entry.IsSolid) - { - var rawStream = Entry.Parts.First().GetRawStream(); - - if (rawStream != null) - { - var bytesToAdvance = Entry.CompressedSize; - for (var i = 0; i < bytesToAdvance / skipBuffer.Length; i++) - { - rawStream.Read(skipBuffer, 0, skipBuffer.Length); - } - rawStream.Read(skipBuffer, 0, (int)(bytesToAdvance % skipBuffer.Length)); - return; - } - } - using (var s = OpenEntryStream()) - { - while (s.Read(skipBuffer, 0, skipBuffer.Length) > 0) - { - } - } - } - - public void WriteEntryTo(Stream writableStream) - { - if (wroteCurrentEntry) - { - throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); - } - if ((writableStream == null) || (!writableStream.CanWrite)) - { - throw new ArgumentNullException( - "A writable Stream was required. Use Cancel if that was intended."); - } - - var streamListener = this as IReaderExtractionListener; - streamListener.FireEntryExtractionBegin(this.Entry); - Write(writableStream); - streamListener.FireEntryExtractionEnd(this.Entry); - wroteCurrentEntry = true; - } - - internal void Write(Stream writeStream) - { - using (Stream s = OpenEntryStream()) - { - s.TransferTo(writeStream); - } - } - - public EntryStream OpenEntryStream() - { - if (wroteCurrentEntry) - { - throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); - } - var stream = GetEntryStream(); - wroteCurrentEntry = true; - return stream; - } - - /// - /// Retains a reference to the entry stream, so we can check whether it completed later. - /// - protected EntryStream CreateEntryStream(Stream decompressed) - { - return new EntryStream(this, decompressed); - } - - protected virtual EntryStream GetEntryStream() - { - return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); - } - - #endregion - - IEntry IReader.Entry - { - get { return Entry; } - } - - void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) - { - if (CompressedBytesRead != null) - { - CompressedBytesRead(this, new CompressedBytesReadEventArgs() - { - CurrentFilePartCompressedBytesRead = currentPartCompressedBytes, - CompressedBytesRead = compressedReadBytes - }); - } - } - - void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) - { - if (FilePartExtractionBegin != null) - { - FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs() - { - CompressedSize = compressedSize, - Size = size, - Name = name, - }); - } - } - - void IReaderExtractionListener.FireEntryExtractionBegin(Entry entry) - { - if (EntryExtractionBegin!=null) - { - EntryExtractionBegin(this, new ReaderExtractionEventArgs(entry)); - } - } - - void IReaderExtractionListener.FireEntryExtractionEnd(Entry entry) - { - if (EntryExtractionEnd!=null) - { - EntryExtractionEnd(this, new ReaderExtractionEventArgs(entry)); - } - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Archive; +using SharpCompress.Archive.Rar; +using SharpCompress.Common; +using SharpCompress.Reader.Rar; + +namespace SharpCompress.Reader +{ + /// + /// A generic push reader that reads unseekable comrpessed streams. + /// + public abstract class AbstractReader : IReader, IReaderExtractionListener + where TEntry : Entry + where TVolume : Volume + { + private bool completed; + private IEnumerator entriesForCurrentReadStream; + private bool wroteCurrentEntry; + + public event EventHandler> EntryExtractionBegin; + public event EventHandler> EntryExtractionEnd; + + public event EventHandler CompressedBytesRead; + public event EventHandler FilePartExtractionBegin; + + + + internal AbstractReader(Options options, ArchiveType archiveType) + { + ArchiveType = archiveType; + Options = options; + } + + internal Options Options { get; private set; } + + public ArchiveType ArchiveType { get; private set; } + + /// + /// Current volume that the current entry resides in + /// + public abstract TVolume Volume { get; } + + /// + /// Current file entry + /// + public TEntry Entry + { + get { return entriesForCurrentReadStream.Current; } + } + + #region IDisposable Members + + public void Dispose() + { + if (entriesForCurrentReadStream != null) + { + entriesForCurrentReadStream.Dispose(); + } + Volume.Dispose(); + } + + #endregion + + + public bool Cancelled { get; private set; } + + /// + /// Indicates that the remaining entries are not required. + /// On dispose of an EntryStream, the stream will not skip to the end of the entry. + /// An attempt to move to the next entry will throw an exception, as the compressed stream is not positioned at an entry boundary. + /// + public void Cancel() + { + if (!completed) + { + Cancelled = true; + } + } + + public bool MoveToNextEntry() + { + if (completed) + { + return false; + } + if (Cancelled) + { + throw new InvalidOperationException("Reader has been cancelled."); + } + if (entriesForCurrentReadStream == null) + { + return LoadStreamForReading(RequestInitialStream()); + } + if (!wroteCurrentEntry) + { + SkipEntry(); + } + wroteCurrentEntry = false; + if (NextEntryForCurrentStream()) + { + return true; + } + completed = true; + return false; + } + + internal bool LoadStreamForReading(Stream stream) + { + if (entriesForCurrentReadStream != null) + { + entriesForCurrentReadStream.Dispose(); + } + if ((stream == null) || (!stream.CanRead)) + { + throw new MultipartStreamRequiredException("File is split into multiple archives: '" + + Entry.Key + + "'. A new readable stream is required. Use Cancel if it was intended."); + } + entriesForCurrentReadStream = GetEntries(stream).GetEnumerator(); + if (entriesForCurrentReadStream.MoveNext()) + { + return true; + } + return false; + } + + internal virtual Stream RequestInitialStream() + { + return Volume.Stream; + } + + internal virtual bool NextEntryForCurrentStream() + { + return entriesForCurrentReadStream.MoveNext(); + } + + internal abstract IEnumerable GetEntries(Stream stream); + + #region Entry Skip/Write + + private void SkipEntry() + { + if (!Entry.IsDirectory) + { + Skip(); + } + } + + private readonly byte[] skipBuffer = new byte[4096]; + + private void Skip() + { + if (!Entry.IsSolid) + { + var rawStream = Entry.Parts.First().GetRawStream(); + + if (rawStream != null) + { + var bytesToAdvance = Entry.CompressedSize; + for (var i = 0; i < bytesToAdvance / skipBuffer.Length; i++) + { + rawStream.Read(skipBuffer, 0, skipBuffer.Length); + } + rawStream.Read(skipBuffer, 0, (int)(bytesToAdvance % skipBuffer.Length)); + return; + } + } + using (var s = OpenEntryStream()) + { + while (s.Read(skipBuffer, 0, skipBuffer.Length) > 0) + { + } + } + } + + public void WriteEntryTo(Stream writableStream) + { + if (wroteCurrentEntry) + { + throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); + } + if ((writableStream == null) || (!writableStream.CanWrite)) + { + throw new ArgumentNullException( + "A writable Stream was required. Use Cancel if that was intended."); + } + + var streamListener = this as IReaderExtractionListener; + streamListener.FireEntryExtractionBegin(this.Entry); + Write(writableStream); + streamListener.FireEntryExtractionEnd(this.Entry); + wroteCurrentEntry = true; + } + + internal void Write(Stream writeStream) + { + using (Stream s = OpenEntryStream()) + { + s.TransferTo(writeStream); + } + } + + public EntryStream OpenEntryStream() + { + if (wroteCurrentEntry) + { + throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); + } + var stream = GetEntryStream(); + wroteCurrentEntry = true; + return stream; + } + + /// + /// Retains a reference to the entry stream, so we can check whether it completed later. + /// + protected EntryStream CreateEntryStream(Stream decompressed) + { + return new EntryStream(this, decompressed); + } + + protected virtual EntryStream GetEntryStream() + { + return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); + } + + #endregion + + IEntry IReader.Entry + { + get { return Entry; } + } + + void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) + { + if (CompressedBytesRead != null) + { + CompressedBytesRead(this, new CompressedBytesReadEventArgs() + { + CurrentFilePartCompressedBytesRead = currentPartCompressedBytes, + CompressedBytesRead = compressedReadBytes + }); + } + } + + void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) + { + if (FilePartExtractionBegin != null) + { + FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs() + { + CompressedSize = compressedSize, + Size = size, + Name = name, + }); + } + } + + void IReaderExtractionListener.FireEntryExtractionBegin(Entry entry) + { + if (EntryExtractionBegin!=null) + { + EntryExtractionBegin(this, new ReaderExtractionEventArgs(entry)); + } + } + + void IReaderExtractionListener.FireEntryExtractionEnd(Entry entry) + { + if (EntryExtractionEnd!=null) + { + EntryExtractionEnd(this, new ReaderExtractionEventArgs(entry)); + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/GZip/GZipReader.cs b/src/SharpCompress/Reader/GZip/GZipReader.cs similarity index 96% rename from SharpCompress/Reader/GZip/GZipReader.cs rename to src/SharpCompress/Reader/GZip/GZipReader.cs index d97bd552..6dee2da3 100644 --- a/SharpCompress/Reader/GZip/GZipReader.cs +++ b/src/SharpCompress/Reader/GZip/GZipReader.cs @@ -1,45 +1,45 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.GZip; - -namespace SharpCompress.Reader.GZip -{ - public class GZipReader : AbstractReader - { - private readonly GZipVolume volume; - - internal GZipReader(Stream stream, Options options) - : base(options, ArchiveType.GZip) - { - volume = new GZipVolume(stream, options); - } - - public override GZipVolume Volume - { - get { return volume; } - } - - #region Open - - /// - /// Opens a GZipReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static GZipReader Open(Stream stream, - Options options = Options.KeepStreamsOpen) - { - stream.CheckNotNull("stream"); - return new GZipReader(stream, options); - } - - #endregion - - internal override IEnumerable GetEntries(Stream stream) - { - return GZipEntry.GetEntries(stream); - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.GZip; + +namespace SharpCompress.Reader.GZip +{ + public class GZipReader : AbstractReader + { + private readonly GZipVolume volume; + + internal GZipReader(Stream stream, Options options) + : base(options, ArchiveType.GZip) + { + volume = new GZipVolume(stream, options); + } + + public override GZipVolume Volume + { + get { return volume; } + } + + #region Open + + /// + /// Opens a GZipReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static GZipReader Open(Stream stream, + Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + return new GZipReader(stream, options); + } + + #endregion + + internal override IEnumerable GetEntries(Stream stream) + { + return GZipEntry.GetEntries(stream); + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/IReader.Extensions.cs b/src/SharpCompress/Reader/IReader.Extensions.cs similarity index 97% rename from SharpCompress/Reader/IReader.Extensions.cs rename to src/SharpCompress/Reader/IReader.Extensions.cs index 075e6c24..f98d115c 100644 --- a/SharpCompress/Reader/IReader.Extensions.cs +++ b/src/SharpCompress/Reader/IReader.Extensions.cs @@ -1,95 +1,95 @@ -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.Reader -{ - public static class IReaderExtensions - { -#if !DOTNET51 - public static void WriteEntryTo(this IReader reader, string filePath) - { - using (Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write)) - { - reader.WriteEntryTo(stream); - } - } - - public static void WriteEntryTo(this IReader reader, FileInfo filePath) - { - using (Stream stream = filePath.Open(FileMode.Create)) - { - reader.WriteEntryTo(stream); - } - } - - /// - /// Extract all remaining unread entries to specific directory, retaining filename - /// - public static void WriteAllToDirectory(this IReader reader, string destinationDirectory, - ExtractOptions options = ExtractOptions.Overwrite) - { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory(destinationDirectory, options); - } - } - - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteEntryToDirectory(this IReader reader, string destinationDirectory, - ExtractOptions options = ExtractOptions.Overwrite) - { - string destinationFileName = string.Empty; - string file = Path.GetFileName(reader.Entry.Key); - - - if (options.HasFlag(ExtractOptions.ExtractFullPath)) - { - string folder = Path.GetDirectoryName(reader.Entry.Key); - string destdir = Path.Combine(destinationDirectory, folder); - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - destinationFileName = Path.Combine(destdir, file); - } - else - { - destinationFileName = Path.Combine(destinationDirectory, file); - } - - if (!reader.Entry.IsDirectory) - { - reader.WriteEntryToFile(destinationFileName, options); - } - else if (options.HasFlag(ExtractOptions.ExtractFullPath) && !Directory.Exists(destinationFileName)) - { - Directory.CreateDirectory(destinationFileName); - } - } - - /// - /// Extract to specific file - /// - public static void WriteEntryToFile(this IReader reader, string destinationFileName, - ExtractOptions options = ExtractOptions.Overwrite) - { - FileMode fm = FileMode.Create; - - if (!options.HasFlag(ExtractOptions.Overwrite)) - { - fm = FileMode.CreateNew; - } - using (FileStream fs = File.Open(destinationFileName, fm)) - { - reader.WriteEntryTo(fs); - //using (Stream s = reader.OpenEntryStream()) - //{ - // s.TransferTo(fs); - //} - } - } -#endif - } +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Reader +{ + public static class IReaderExtensions + { +#if !DOTNET51 + public static void WriteEntryTo(this IReader reader, string filePath) + { + using (Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write)) + { + reader.WriteEntryTo(stream); + } + } + + public static void WriteEntryTo(this IReader reader, FileInfo filePath) + { + using (Stream stream = filePath.Open(FileMode.Create)) + { + reader.WriteEntryTo(stream); + } + } + + /// + /// Extract all remaining unread entries to specific directory, retaining filename + /// + public static void WriteAllToDirectory(this IReader reader, string destinationDirectory, + ExtractOptions options = ExtractOptions.Overwrite) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory(destinationDirectory, options); + } + } + + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteEntryToDirectory(this IReader reader, string destinationDirectory, + ExtractOptions options = ExtractOptions.Overwrite) + { + string destinationFileName = string.Empty; + string file = Path.GetFileName(reader.Entry.Key); + + + if (options.HasFlag(ExtractOptions.ExtractFullPath)) + { + string folder = Path.GetDirectoryName(reader.Entry.Key); + string destdir = Path.Combine(destinationDirectory, folder); + if (!Directory.Exists(destdir)) + { + Directory.CreateDirectory(destdir); + } + destinationFileName = Path.Combine(destdir, file); + } + else + { + destinationFileName = Path.Combine(destinationDirectory, file); + } + + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToFile(destinationFileName, options); + } + else if (options.HasFlag(ExtractOptions.ExtractFullPath) && !Directory.Exists(destinationFileName)) + { + Directory.CreateDirectory(destinationFileName); + } + } + + /// + /// Extract to specific file + /// + public static void WriteEntryToFile(this IReader reader, string destinationFileName, + ExtractOptions options = ExtractOptions.Overwrite) + { + FileMode fm = FileMode.Create; + + if (!options.HasFlag(ExtractOptions.Overwrite)) + { + fm = FileMode.CreateNew; + } + using (FileStream fs = File.Open(destinationFileName, fm)) + { + reader.WriteEntryTo(fs); + //using (Stream s = reader.OpenEntryStream()) + //{ + // s.TransferTo(fs); + //} + } + } +#endif + } } \ No newline at end of file diff --git a/SharpCompress/Reader/IReader.cs b/src/SharpCompress/Reader/IReader.cs similarity index 97% rename from SharpCompress/Reader/IReader.cs rename to src/SharpCompress/Reader/IReader.cs index cf26ea16..bb13b5e5 100644 --- a/SharpCompress/Reader/IReader.cs +++ b/src/SharpCompress/Reader/IReader.cs @@ -1,40 +1,40 @@ -using System; -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.Reader -{ - public interface IReader : IDisposable - { - event EventHandler> EntryExtractionBegin; - event EventHandler> EntryExtractionEnd; - - event EventHandler CompressedBytesRead; - event EventHandler FilePartExtractionBegin; - - ArchiveType ArchiveType { get; } - - IEntry Entry { get; } - - /// - /// Decompresses the current entry to the stream. This cannot be called twice for the current entry. - /// - /// - void WriteEntryTo(Stream writableStream); - - bool Cancelled { get; } - void Cancel(); - - /// - /// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read. - /// - /// - bool MoveToNextEntry(); - - /// - /// Opens the current entry as a stream that will decompress as it is read. - /// Read the entire stream or use SkipEntry on EntryStream. - /// - EntryStream OpenEntryStream(); - } +using System; +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Reader +{ + public interface IReader : IDisposable + { + event EventHandler> EntryExtractionBegin; + event EventHandler> EntryExtractionEnd; + + event EventHandler CompressedBytesRead; + event EventHandler FilePartExtractionBegin; + + ArchiveType ArchiveType { get; } + + IEntry Entry { get; } + + /// + /// Decompresses the current entry to the stream. This cannot be called twice for the current entry. + /// + /// + void WriteEntryTo(Stream writableStream); + + bool Cancelled { get; } + void Cancel(); + + /// + /// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read. + /// + /// + bool MoveToNextEntry(); + + /// + /// Opens the current entry as a stream that will decompress as it is read. + /// Read the entire stream or use SkipEntry on EntryStream. + /// + EntryStream OpenEntryStream(); + } } \ No newline at end of file diff --git a/SharpCompress/Reader/IReaderExtractionListener.cs b/src/SharpCompress/Reader/IReaderExtractionListener.cs similarity index 96% rename from SharpCompress/Reader/IReaderExtractionListener.cs rename to src/SharpCompress/Reader/IReaderExtractionListener.cs index 33ae423c..c4c9b2bb 100644 --- a/SharpCompress/Reader/IReaderExtractionListener.cs +++ b/src/SharpCompress/Reader/IReaderExtractionListener.cs @@ -1,16 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SharpCompress.Archive; -using SharpCompress.Common; - -namespace SharpCompress.Reader -{ - internal interface IReaderExtractionListener:IExtractionListener - { -// void EnsureEntriesLoaded(); - void FireEntryExtractionBegin(Entry entry); - void FireEntryExtractionEnd(Entry entry); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SharpCompress.Archive; +using SharpCompress.Common; + +namespace SharpCompress.Reader +{ + internal interface IReaderExtractionListener:IExtractionListener + { +// void EnsureEntriesLoaded(); + void FireEntryExtractionBegin(Entry entry); + void FireEntryExtractionEnd(Entry entry); + } +} diff --git a/SharpCompress/Reader/Rar/MultiVolumeRarReader.cs b/src/SharpCompress/Reader/Rar/MultiVolumeRarReader.cs similarity index 96% rename from SharpCompress/Reader/Rar/MultiVolumeRarReader.cs rename to src/SharpCompress/Reader/Rar/MultiVolumeRarReader.cs index 68c77779..b84fd4dc 100644 --- a/SharpCompress/Reader/Rar/MultiVolumeRarReader.cs +++ b/src/SharpCompress/Reader/Rar/MultiVolumeRarReader.cs @@ -1,126 +1,126 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Rar; - -namespace SharpCompress.Reader.Rar -{ - internal class MultiVolumeRarReader : RarReader - { - private readonly IEnumerator streams; - private Stream tempStream; - - internal MultiVolumeRarReader(IEnumerable streams, Options options) - : base(options) - { - this.streams = streams.GetEnumerator(); - } - - internal override void ValidateArchive(RarVolume archive) - { - } - - internal override Stream RequestInitialStream() - { - if (streams.MoveNext()) - { - return streams.Current; - } - throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); - } - - internal override bool NextEntryForCurrentStream() - { - if (!base.NextEntryForCurrentStream()) - { - //if we're got another stream to try to process then do so - if (streams.MoveNext() && LoadStreamForReading(streams.Current)) - { - return true; - } - return false; - } - return true; - } - - protected override IEnumerable CreateFilePartEnumerableForCurrentEntry() - { - var enumerator = new MultiVolumeStreamEnumerator(this, streams, tempStream); - tempStream = null; - return enumerator; - } - - private class MultiVolumeStreamEnumerator : IEnumerable, IEnumerator - { - private readonly MultiVolumeRarReader reader; - private readonly IEnumerator nextReadableStreams; - private Stream tempStream; - private bool isFirst = true; - - internal MultiVolumeStreamEnumerator(MultiVolumeRarReader r, IEnumerator nextReadableStreams, - Stream tempStream) - { - reader = r; - this.nextReadableStreams = nextReadableStreams; - this.tempStream = tempStream; - } - - public IEnumerator GetEnumerator() - { - return this; - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return this; - } - - public FilePart Current { get; private set; } - - public void Dispose() - { - } - - object System.Collections.IEnumerator.Current - { - get { return Current; } - } - - public bool MoveNext() - { - if (isFirst) - { - Current = reader.Entry.Parts.First(); - isFirst = false; //first stream already to go - return true; - } - - if (!reader.Entry.IsSplit) - { - return false; - } - if (tempStream != null) - { - reader.LoadStreamForReading(tempStream); - tempStream = null; - } - else if (!nextReadableStreams.MoveNext()) - { - throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); - } - else - { - reader.LoadStreamForReading(nextReadableStreams.Current); - } - - Current = reader.Entry.Parts.First(); - return true; - } - - public void Reset() - { - } - } - } +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Rar; + +namespace SharpCompress.Reader.Rar +{ + internal class MultiVolumeRarReader : RarReader + { + private readonly IEnumerator streams; + private Stream tempStream; + + internal MultiVolumeRarReader(IEnumerable streams, Options options) + : base(options) + { + this.streams = streams.GetEnumerator(); + } + + internal override void ValidateArchive(RarVolume archive) + { + } + + internal override Stream RequestInitialStream() + { + if (streams.MoveNext()) + { + return streams.Current; + } + throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); + } + + internal override bool NextEntryForCurrentStream() + { + if (!base.NextEntryForCurrentStream()) + { + //if we're got another stream to try to process then do so + if (streams.MoveNext() && LoadStreamForReading(streams.Current)) + { + return true; + } + return false; + } + return true; + } + + protected override IEnumerable CreateFilePartEnumerableForCurrentEntry() + { + var enumerator = new MultiVolumeStreamEnumerator(this, streams, tempStream); + tempStream = null; + return enumerator; + } + + private class MultiVolumeStreamEnumerator : IEnumerable, IEnumerator + { + private readonly MultiVolumeRarReader reader; + private readonly IEnumerator nextReadableStreams; + private Stream tempStream; + private bool isFirst = true; + + internal MultiVolumeStreamEnumerator(MultiVolumeRarReader r, IEnumerator nextReadableStreams, + Stream tempStream) + { + reader = r; + this.nextReadableStreams = nextReadableStreams; + this.tempStream = tempStream; + } + + public IEnumerator GetEnumerator() + { + return this; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this; + } + + public FilePart Current { get; private set; } + + public void Dispose() + { + } + + object System.Collections.IEnumerator.Current + { + get { return Current; } + } + + public bool MoveNext() + { + if (isFirst) + { + Current = reader.Entry.Parts.First(); + isFirst = false; //first stream already to go + return true; + } + + if (!reader.Entry.IsSplit) + { + return false; + } + if (tempStream != null) + { + reader.LoadStreamForReading(tempStream); + tempStream = null; + } + else if (!nextReadableStreams.MoveNext()) + { + throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); + } + else + { + reader.LoadStreamForReading(nextReadableStreams.Current); + } + + Current = reader.Entry.Parts.First(); + return true; + } + + public void Reset() + { + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs b/src/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs similarity index 96% rename from SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs rename to src/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs index 3d4d8faa..1cacba4b 100644 --- a/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs +++ b/src/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs @@ -1,24 +1,24 @@ -using System.IO; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Reader.Rar -{ - internal class NonSeekableStreamFilePart : RarFilePart - { - internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh) - : base(mh, fh) - { - } - - internal override Stream GetCompressedStream() - { - return FileHeader.PackedStream; - } - - internal override string FilePartName - { - get { return "Unknown Stream - File Entry: " + FileHeader.FileName; } - } - } +using System.IO; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Reader.Rar +{ + internal class NonSeekableStreamFilePart : RarFilePart + { + internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh) + : base(mh, fh) + { + } + + internal override Stream GetCompressedStream() + { + return FileHeader.PackedStream; + } + + internal override string FilePartName + { + get { return "Unknown Stream - File Entry: " + FileHeader.FileName; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Rar/RarReader.cs b/src/SharpCompress/Reader/Rar/RarReader.cs similarity index 97% rename from SharpCompress/Reader/Rar/RarReader.cs rename to src/SharpCompress/Reader/Rar/RarReader.cs index 58a1be35..bf048beb 100644 --- a/SharpCompress/Reader/Rar/RarReader.cs +++ b/src/SharpCompress/Reader/Rar/RarReader.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Compressor.Rar; - -namespace SharpCompress.Reader.Rar -{ - /// - /// This class faciliates Reading a Rar Archive in a non-seekable forward-only manner - /// - public abstract class RarReader : AbstractReader - { - public string Password { get; set; } - private RarVolume volume; - private readonly Unpack pack = new Unpack(); - - internal RarReader(Options options) - : base(options, ArchiveType.Rar) - { - } - - internal abstract void ValidateArchive(RarVolume archive); - - public override RarVolume Volume - { - get { return volume; } - } - - #region Open - - /// - /// Opens a RarReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static RarReader Open(Stream stream, Options options = Options.KeepStreamsOpen) - { - return Open(stream, null, options); - } - - /// - /// Opens a RarReader for Non-seeking usage with multiple volumes - /// - /// - /// - /// - public static RarReader Open(IEnumerable streams, Options options = Options.KeepStreamsOpen) - { - streams.CheckNotNull("streams"); - return new MultiVolumeRarReader(streams, options); - } - - #endregion - - internal override IEnumerable GetEntries(Stream stream) - { - volume = new RarReaderVolume(stream, Password, Options); - foreach (RarFilePart fp in volume.ReadFileParts()) - { - ValidateArchive(volume); - yield return new RarReaderEntry(volume.IsSolidArchive, fp); - } - } - - protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() - { - return Entry.Parts; - } - - protected override EntryStream GetEntryStream() - { - return CreateEntryStream(new RarStream(pack, Entry.FileHeader, - new MultiVolumeReadOnlyStream( - CreateFilePartEnumerableForCurrentEntry().Cast(), this))); - } - - public static RarReader Open(Stream stream, string password, Options options = Options.KeepStreamsOpen) - { - stream.CheckNotNull("stream"); - return new SingleVolumeRarReader(stream, password, options); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Compressor.Rar; + +namespace SharpCompress.Reader.Rar +{ + /// + /// This class faciliates Reading a Rar Archive in a non-seekable forward-only manner + /// + public abstract class RarReader : AbstractReader + { + public string Password { get; set; } + private RarVolume volume; + private readonly Unpack pack = new Unpack(); + + internal RarReader(Options options) + : base(options, ArchiveType.Rar) + { + } + + internal abstract void ValidateArchive(RarVolume archive); + + public override RarVolume Volume + { + get { return volume; } + } + + #region Open + + /// + /// Opens a RarReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static RarReader Open(Stream stream, Options options = Options.KeepStreamsOpen) + { + return Open(stream, null, options); + } + + /// + /// Opens a RarReader for Non-seeking usage with multiple volumes + /// + /// + /// + /// + public static RarReader Open(IEnumerable streams, Options options = Options.KeepStreamsOpen) + { + streams.CheckNotNull("streams"); + return new MultiVolumeRarReader(streams, options); + } + + #endregion + + internal override IEnumerable GetEntries(Stream stream) + { + volume = new RarReaderVolume(stream, Password, Options); + foreach (RarFilePart fp in volume.ReadFileParts()) + { + ValidateArchive(volume); + yield return new RarReaderEntry(volume.IsSolidArchive, fp); + } + } + + protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() + { + return Entry.Parts; + } + + protected override EntryStream GetEntryStream() + { + return CreateEntryStream(new RarStream(pack, Entry.FileHeader, + new MultiVolumeReadOnlyStream( + CreateFilePartEnumerableForCurrentEntry().Cast(), this))); + } + + public static RarReader Open(Stream stream, string password, Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + return new SingleVolumeRarReader(stream, password, options); + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Rar/RarReaderEntry.cs b/src/SharpCompress/Reader/Rar/RarReaderEntry.cs similarity index 96% rename from SharpCompress/Reader/Rar/RarReaderEntry.cs rename to src/SharpCompress/Reader/Rar/RarReaderEntry.cs index 5e1205ca..4300d15a 100644 --- a/SharpCompress/Reader/Rar/RarReaderEntry.cs +++ b/src/SharpCompress/Reader/Rar/RarReaderEntry.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; - -namespace SharpCompress.Reader.Rar -{ - public class RarReaderEntry : RarEntry - { - internal RarReaderEntry(bool solid, RarFilePart part) - { - Part = part; - IsSolid = solid; - } - - internal RarFilePart Part { get; private set; } - - internal override IEnumerable Parts - { - get { return Part.AsEnumerable(); } - } - - internal override FileHeader FileHeader - { - get { return Part.FileHeader; } - } - - public override CompressionType CompressionType - { - get { return CompressionType.Rar; } - } - - /// - /// The compressed file size - /// - public override long CompressedSize - { - get { return Part.FileHeader.CompressedSize; } - } - - /// - /// The uncompressed file size - /// - public override long Size - { - get { return Part.FileHeader.UncompressedSize; } - } - } +using System.Collections.Generic; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; + +namespace SharpCompress.Reader.Rar +{ + public class RarReaderEntry : RarEntry + { + internal RarReaderEntry(bool solid, RarFilePart part) + { + Part = part; + IsSolid = solid; + } + + internal RarFilePart Part { get; private set; } + + internal override IEnumerable Parts + { + get { return Part.AsEnumerable(); } + } + + internal override FileHeader FileHeader + { + get { return Part.FileHeader; } + } + + public override CompressionType CompressionType + { + get { return CompressionType.Rar; } + } + + /// + /// The compressed file size + /// + public override long CompressedSize + { + get { return Part.FileHeader.CompressedSize; } + } + + /// + /// The uncompressed file size + /// + public override long Size + { + get { return Part.FileHeader.UncompressedSize; } + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Rar/RarReaderVolume.cs b/src/SharpCompress/Reader/Rar/RarReaderVolume.cs similarity index 96% rename from SharpCompress/Reader/Rar/RarReaderVolume.cs rename to src/SharpCompress/Reader/Rar/RarReaderVolume.cs index 2b92e8b3..7042e808 100644 --- a/SharpCompress/Reader/Rar/RarReaderVolume.cs +++ b/src/SharpCompress/Reader/Rar/RarReaderVolume.cs @@ -1,27 +1,27 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.IO; - -namespace SharpCompress.Reader.Rar -{ - public class RarReaderVolume : RarVolume - { - internal RarReaderVolume(Stream stream, string password, Options options) - : base(StreamingMode.Streaming, stream, password, options) - { - } - - internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader) - { - return new NonSeekableStreamFilePart(markHeader, fileHeader); - } - - internal override IEnumerable ReadFileParts() - { - return GetVolumeFileParts(); - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Reader.Rar +{ + public class RarReaderVolume : RarVolume + { + internal RarReaderVolume(Stream stream, string password, Options options) + : base(StreamingMode.Streaming, stream, password, options) + { + } + + internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader) + { + return new NonSeekableStreamFilePart(markHeader, fileHeader); + } + + internal override IEnumerable ReadFileParts() + { + return GetVolumeFileParts(); + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs b/src/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs similarity index 96% rename from SharpCompress/Reader/Rar/SingleVolumeRarReader.cs rename to src/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs index 2fe2b7f0..7375a254 100644 --- a/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs +++ b/src/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar; - -namespace SharpCompress.Reader.Rar -{ - internal class SingleVolumeRarReader : RarReader - { - - private readonly Stream stream; - - internal SingleVolumeRarReader(Stream stream, string password, Options options) - : base(options) - { - Password = password; - this.stream = stream; - } - - internal override void ValidateArchive(RarVolume archive) - { - if (archive.IsMultiVolume) - { - throw new MultiVolumeExtractionException( - "Streamed archive is a Multi-volume archive. Use different RarReader method to extract."); - } - } - - internal override Stream RequestInitialStream() - { - return stream; - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar; + +namespace SharpCompress.Reader.Rar +{ + internal class SingleVolumeRarReader : RarReader + { + + private readonly Stream stream; + + internal SingleVolumeRarReader(Stream stream, string password, Options options) + : base(options) + { + Password = password; + this.stream = stream; + } + + internal override void ValidateArchive(RarVolume archive) + { + if (archive.IsMultiVolume) + { + throw new MultiVolumeExtractionException( + "Streamed archive is a Multi-volume archive. Use different RarReader method to extract."); + } + } + + internal override Stream RequestInitialStream() + { + return stream; + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/ReaderFactory.cs b/src/SharpCompress/Reader/ReaderFactory.cs similarity index 97% rename from SharpCompress/Reader/ReaderFactory.cs rename to src/SharpCompress/Reader/ReaderFactory.cs index e336f2cb..cd1fc02b 100644 --- a/SharpCompress/Reader/ReaderFactory.cs +++ b/src/SharpCompress/Reader/ReaderFactory.cs @@ -1,80 +1,80 @@ -using System; -using System.IO; -using SharpCompress.Archive.GZip; -using SharpCompress.Archive.Rar; -using SharpCompress.Archive.Tar; -using SharpCompress.Archive.Zip; -using SharpCompress.Common; -using SharpCompress.Compressor; -using SharpCompress.Compressor.BZip2; -using SharpCompress.IO; -using SharpCompress.Reader.GZip; -using SharpCompress.Reader.Rar; -using SharpCompress.Reader.Tar; -using SharpCompress.Reader.Zip; -using GZipStream = SharpCompress.Compressor.Deflate.GZipStream; - -namespace SharpCompress.Reader -{ - public static class ReaderFactory - { - /// - /// Opens a Reader for Non-seeking usage - /// - /// - /// - /// - public static IReader Open(Stream stream, Options options = Options.KeepStreamsOpen) - { - stream.CheckNotNull("stream"); - - RewindableStream rewindableStream = new RewindableStream(stream); - rewindableStream.StartRecording(); - if (ZipArchive.IsZipFile(rewindableStream, null)) - { - rewindableStream.Rewind(true); - return ZipReader.Open(rewindableStream, null, options); - } - rewindableStream.Rewind(false); - if (GZipArchive.IsGZipFile(rewindableStream)) - { - rewindableStream.Rewind(false); - GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, CompressionType.GZip, options); - } - rewindableStream.Rewind(true); - return GZipReader.Open(rewindableStream, options); - } - - rewindableStream.Rewind(false); - if (BZip2Stream.IsBZip2(rewindableStream)) - { - rewindableStream.Rewind(false); - BZip2Stream testStream = new BZip2Stream(rewindableStream, CompressionMode.Decompress, false); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, CompressionType.BZip2, options); - } - } - - rewindableStream.Rewind(false); - if (TarArchive.IsTarFile(rewindableStream)) - { - rewindableStream.Rewind(true); - return TarReader.Open(rewindableStream, options); - } - rewindableStream.Rewind(false); - if (RarArchive.IsRarFile(rewindableStream, options)) - { - rewindableStream.Rewind(true); - return RarReader.Open(rewindableStream, options); - } - - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar"); - } - } +using System; +using System.IO; +using SharpCompress.Archive.GZip; +using SharpCompress.Archive.Rar; +using SharpCompress.Archive.Tar; +using SharpCompress.Archive.Zip; +using SharpCompress.Common; +using SharpCompress.Compressor; +using SharpCompress.Compressor.BZip2; +using SharpCompress.IO; +using SharpCompress.Reader.GZip; +using SharpCompress.Reader.Rar; +using SharpCompress.Reader.Tar; +using SharpCompress.Reader.Zip; +using GZipStream = SharpCompress.Compressor.Deflate.GZipStream; + +namespace SharpCompress.Reader +{ + public static class ReaderFactory + { + /// + /// Opens a Reader for Non-seeking usage + /// + /// + /// + /// + public static IReader Open(Stream stream, Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + + RewindableStream rewindableStream = new RewindableStream(stream); + rewindableStream.StartRecording(); + if (ZipArchive.IsZipFile(rewindableStream, null)) + { + rewindableStream.Rewind(true); + return ZipReader.Open(rewindableStream, null, options); + } + rewindableStream.Rewind(false); + if (GZipArchive.IsGZipFile(rewindableStream)) + { + rewindableStream.Rewind(false); + GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, CompressionType.GZip, options); + } + rewindableStream.Rewind(true); + return GZipReader.Open(rewindableStream, options); + } + + rewindableStream.Rewind(false); + if (BZip2Stream.IsBZip2(rewindableStream)) + { + rewindableStream.Rewind(false); + BZip2Stream testStream = new BZip2Stream(rewindableStream, CompressionMode.Decompress, false); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, CompressionType.BZip2, options); + } + } + + rewindableStream.Rewind(false); + if (TarArchive.IsTarFile(rewindableStream)) + { + rewindableStream.Rewind(true); + return TarReader.Open(rewindableStream, options); + } + rewindableStream.Rewind(false); + if (RarArchive.IsRarFile(rewindableStream, options)) + { + rewindableStream.Rewind(true); + return RarReader.Open(rewindableStream, options); + } + + throw new InvalidOperationException("Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar"); + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Tar/TarReader.cs b/src/SharpCompress/Reader/Tar/TarReader.cs similarity index 97% rename from SharpCompress/Reader/Tar/TarReader.cs rename to src/SharpCompress/Reader/Tar/TarReader.cs index 80ff407e..36c1b0cf 100644 --- a/SharpCompress/Reader/Tar/TarReader.cs +++ b/src/SharpCompress/Reader/Tar/TarReader.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using System.IO; -using SharpCompress.Archive.GZip; -using SharpCompress.Archive.Tar; -using SharpCompress.Common; -using SharpCompress.Common.Tar; -using SharpCompress.Compressor; -using SharpCompress.Compressor.BZip2; -using SharpCompress.Compressor.Deflate; -using SharpCompress.IO; - -namespace SharpCompress.Reader.Tar -{ - public class TarReader : AbstractReader - { - private readonly TarVolume volume; - private readonly CompressionType compressionType; - - internal TarReader(Stream stream, CompressionType compressionType, - Options options) - : base(options, ArchiveType.Tar) - { - this.compressionType = compressionType; - volume = new TarVolume(stream, options); - } - - public override TarVolume Volume - { - get { return volume; } - } - - internal override Stream RequestInitialStream() - { - var stream = base.RequestInitialStream(); - switch (compressionType) - { - case CompressionType.BZip2: - { - return new BZip2Stream(stream, CompressionMode.Decompress, false); - } - case CompressionType.GZip: - { - return new GZipStream(stream, CompressionMode.Decompress); - } - case CompressionType.None: - { - return stream; - } - default: - { - throw new NotSupportedException("Invalid compression type: " + compressionType); - } - } - } - - #region Open - - /// - /// Opens a TarReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static TarReader Open(Stream stream, Options options = Options.KeepStreamsOpen) - { - stream.CheckNotNull("stream"); - - RewindableStream rewindableStream = new RewindableStream(stream); - rewindableStream.StartRecording(); - if (GZipArchive.IsGZipFile(rewindableStream)) - { - rewindableStream.Rewind(false); - GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, CompressionType.GZip, options); - } - throw new InvalidFormatException("Not a tar file."); - } - - rewindableStream.Rewind(false); - if (BZip2Stream.IsBZip2(rewindableStream)) - { - rewindableStream.Rewind(false); - BZip2Stream testStream = new BZip2Stream(rewindableStream, CompressionMode.Decompress, false); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, CompressionType.BZip2, options); - } - throw new InvalidFormatException("Not a tar file."); - } - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, CompressionType.None, options); - } - - #endregion - - internal override IEnumerable GetEntries(Stream stream) - { - return TarEntry.GetEntries(StreamingMode.Streaming, stream, compressionType); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using SharpCompress.Archive.GZip; +using SharpCompress.Archive.Tar; +using SharpCompress.Common; +using SharpCompress.Common.Tar; +using SharpCompress.Compressor; +using SharpCompress.Compressor.BZip2; +using SharpCompress.Compressor.Deflate; +using SharpCompress.IO; + +namespace SharpCompress.Reader.Tar +{ + public class TarReader : AbstractReader + { + private readonly TarVolume volume; + private readonly CompressionType compressionType; + + internal TarReader(Stream stream, CompressionType compressionType, + Options options) + : base(options, ArchiveType.Tar) + { + this.compressionType = compressionType; + volume = new TarVolume(stream, options); + } + + public override TarVolume Volume + { + get { return volume; } + } + + internal override Stream RequestInitialStream() + { + var stream = base.RequestInitialStream(); + switch (compressionType) + { + case CompressionType.BZip2: + { + return new BZip2Stream(stream, CompressionMode.Decompress, false); + } + case CompressionType.GZip: + { + return new GZipStream(stream, CompressionMode.Decompress); + } + case CompressionType.None: + { + return stream; + } + default: + { + throw new NotSupportedException("Invalid compression type: " + compressionType); + } + } + } + + #region Open + + /// + /// Opens a TarReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static TarReader Open(Stream stream, Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + + RewindableStream rewindableStream = new RewindableStream(stream); + rewindableStream.StartRecording(); + if (GZipArchive.IsGZipFile(rewindableStream)) + { + rewindableStream.Rewind(false); + GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, CompressionType.GZip, options); + } + throw new InvalidFormatException("Not a tar file."); + } + + rewindableStream.Rewind(false); + if (BZip2Stream.IsBZip2(rewindableStream)) + { + rewindableStream.Rewind(false); + BZip2Stream testStream = new BZip2Stream(rewindableStream, CompressionMode.Decompress, false); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, CompressionType.BZip2, options); + } + throw new InvalidFormatException("Not a tar file."); + } + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, CompressionType.None, options); + } + + #endregion + + internal override IEnumerable GetEntries(Stream stream) + { + return TarEntry.GetEntries(StreamingMode.Streaming, stream, compressionType); + } + } } \ No newline at end of file diff --git a/SharpCompress/Reader/Zip/ZipReader.cs b/src/SharpCompress/Reader/Zip/ZipReader.cs similarity index 97% rename from SharpCompress/Reader/Zip/ZipReader.cs rename to src/SharpCompress/Reader/Zip/ZipReader.cs index 8bbc16b0..bb2c9956 100644 --- a/SharpCompress/Reader/Zip/ZipReader.cs +++ b/src/SharpCompress/Reader/Zip/ZipReader.cs @@ -1,67 +1,67 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Zip; -using SharpCompress.Common.Zip.Headers; - -namespace SharpCompress.Reader.Zip -{ - public class ZipReader : AbstractReader - { - private readonly StreamingZipHeaderFactory headerFactory; - private readonly ZipVolume volume; - - internal ZipReader(Stream stream, Options options, string password) - : base(options, ArchiveType.Zip) - { - volume = new ZipVolume(stream, options); - headerFactory = new StreamingZipHeaderFactory(password); - } - - public override ZipVolume Volume - { - get { return volume; } - } - - #region Open - - /// - /// Opens a ZipReader for Non-seeking usage with a single volume - /// - /// - /// - /// - /// - public static ZipReader Open(Stream stream, string password = null, - Options options = Options.KeepStreamsOpen) - { - stream.CheckNotNull("stream"); - return new ZipReader(stream, options, password); - } - - #endregion - - internal override IEnumerable GetEntries(Stream stream) - { - foreach (ZipHeader h in headerFactory.ReadStreamHeader(stream)) - { - if (h != null) - { - switch (h.ZipHeaderType) - { - case ZipHeaderType.LocalEntry: - { - yield return new ZipEntry(new StreamingZipFilePart(h as LocalEntryHeader, - stream)); - } - break; - case ZipHeaderType.DirectoryEnd: - { - yield break; - } - } - } - } - } - } +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Zip; +using SharpCompress.Common.Zip.Headers; + +namespace SharpCompress.Reader.Zip +{ + public class ZipReader : AbstractReader + { + private readonly StreamingZipHeaderFactory headerFactory; + private readonly ZipVolume volume; + + internal ZipReader(Stream stream, Options options, string password) + : base(options, ArchiveType.Zip) + { + volume = new ZipVolume(stream, options); + headerFactory = new StreamingZipHeaderFactory(password); + } + + public override ZipVolume Volume + { + get { return volume; } + } + + #region Open + + /// + /// Opens a ZipReader for Non-seeking usage with a single volume + /// + /// + /// + /// + /// + public static ZipReader Open(Stream stream, string password = null, + Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + return new ZipReader(stream, options, password); + } + + #endregion + + internal override IEnumerable GetEntries(Stream stream) + { + foreach (ZipHeader h in headerFactory.ReadStreamHeader(stream)) + { + if (h != null) + { + switch (h.ZipHeaderType) + { + case ZipHeaderType.LocalEntry: + { + yield return new ZipEntry(new StreamingZipFilePart(h as LocalEntryHeader, + stream)); + } + break; + case ZipHeaderType.DirectoryEnd: + { + yield break; + } + } + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/SharpCompress.pfx b/src/SharpCompress/SharpCompress.pfx similarity index 100% rename from SharpCompress/SharpCompress.pfx rename to src/SharpCompress/SharpCompress.pfx diff --git a/SharpCompress/SharpCompress.xproj b/src/SharpCompress/SharpCompress.xproj similarity index 100% rename from SharpCompress/SharpCompress.xproj rename to src/SharpCompress/SharpCompress.xproj diff --git a/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs similarity index 97% rename from SharpCompress/Utility.cs rename to src/SharpCompress/Utility.cs index a8fb4f62..1d07901c 100644 --- a/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -1,480 +1,480 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Common; -using SharpCompress.IO; - -namespace SharpCompress -{ - internal static class Utility - { - public static ReadOnlyCollection ToReadOnly(this IEnumerable items) - { - return new ReadOnlyCollection(items.ToList()); - } - - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static int URShift(int number, int bits) - { - if (number >= 0) - return number >> bits; - else - return (number >> bits) + (2 << ~bits); - } - - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static int URShift(int number, long bits) - { - return URShift(number, (int)bits); - } - - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static long URShift(long number, int bits) - { - if (number >= 0) - return number >> bits; - else - return (number >> bits) + (2L << ~bits); - } - - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static long URShift(long number, long bits) - { - return URShift(number, (int)bits); - } - - /// - /// Fills the array with an specific value from an specific index to an specific index. - /// - /// The array to be filled. - /// The first index to be filled. - /// The last index to be filled. - /// The value to fill the array with. - public static void Fill(T[] array, int fromindex, int toindex, T val) where T : struct - { - if (array.Length == 0) - { - throw new NullReferenceException(); - } - if (fromindex > toindex) - { - throw new ArgumentException(); - } - if ((fromindex < 0) || ((System.Array)array).Length < toindex) - { - throw new IndexOutOfRangeException(); - } - for (int index = (fromindex > 0) ? fromindex-- : fromindex; index < toindex; index++) - { - array[index] = val; - } - } - - /// - /// Fills the array with an specific value. - /// - /// The array to be filled. - /// The value to fill the array with. - public static void Fill(T[] array, T val) where T : struct - { - Fill(array, 0, array.Length, val); - } - - public static void SetSize(this List list, int count) - { - if (count > list.Count) - { - for (int i = list.Count; i < count; i++) - { - list.Add(0x0); - } - } - else - { - byte[] temp = new byte[count]; - list.CopyTo(temp, 0); - list.Clear(); - list.AddRange(temp); - } - } - - /// Read a int value from the byte array at the given position (Big Endian) - /// - /// - /// the array to read from - /// - /// the offset - /// - /// the value - /// - public static int readIntBigEndian(byte[] array, int pos) - { - int temp = 0; - temp |= array[pos] & 0xff; - temp <<= 8; - temp |= array[pos + 1] & 0xff; - temp <<= 8; - temp |= array[pos + 2] & 0xff; - temp <<= 8; - temp |= array[pos + 3] & 0xff; - return temp; - } - - /// Read a short value from the byte array at the given position (little - /// Endian) - /// - /// - /// the array to read from - /// - /// the offset - /// - /// the value - /// - public static short readShortLittleEndian(byte[] array, int pos) - { - return BitConverter.ToInt16(array, pos); - } - - /// Read an int value from the byte array at the given position (little - /// Endian) - /// - /// - /// the array to read from - /// - /// the offset - /// - /// the value - /// - public static int readIntLittleEndian(byte[] array, int pos) - { - return BitConverter.ToInt32(array, pos); - } - - /// Write an int value into the byte array at the given position (Big endian) - /// - /// - /// the array - /// - /// the offset - /// - /// the value to write - /// - public static void writeIntBigEndian(byte[] array, int pos, int value) - { - array[pos] = (byte)((Utility.URShift(value, 24)) & 0xff); - array[pos + 1] = (byte)((Utility.URShift(value, 16)) & 0xff); - array[pos + 2] = (byte)((Utility.URShift(value, 8)) & 0xff); - array[pos + 3] = (byte)((value) & 0xff); - } - - /// Write a short value into the byte array at the given position (little - /// endian) - /// - /// - /// the array - /// - /// the offset - /// - /// the value to write - /// - public static void WriteLittleEndian(byte[] array, int pos, short value) - { - byte[] newBytes = BitConverter.GetBytes(value); - - if (!BitConverter.IsLittleEndian) - Array.Reverse(newBytes); - - Array.Copy(newBytes, 0, array, pos, newBytes.Length); - } - - /// Increment a short value at the specified position by the specified amount - /// (little endian). - /// - public static void incShortLittleEndian(byte[] array, int pos, short incrementValue) - { - short existingValue = BitConverter.ToInt16(array, pos); - existingValue += incrementValue; - WriteLittleEndian(array, pos, existingValue); - //int c = Utility.URShift(((array[pos] & 0xff) + (dv & 0xff)), 8); - //array[pos] = (byte)(array[pos] + (dv & 0xff)); - //if ((c > 0) || ((dv & 0xff00) != 0)) - //{ - // array[pos + 1] = (byte)(array[pos + 1] + ((Utility.URShift(dv, 8)) & 0xff) + c); - //} - } - - /// Write an int value into the byte array at the given position (little - /// endian) - /// - /// - /// the array - /// - /// the offset - /// - /// the value to write - /// - public static void WriteLittleEndian(byte[] array, int pos, int value) - { - byte[] newBytes = BitConverter.GetBytes(value); - - if (!BitConverter.IsLittleEndian) - Array.Reverse(newBytes); - - Array.Copy(newBytes, 0, array, pos, newBytes.Length); - } - - public static void Initialize(this T[] array, Func func) - { - for (int i = 0; i < array.Length; i++) - { - array[i] = func(); - } - } - - public static void AddRange(this ICollection destination, IEnumerable source) - { - foreach (T item in source) - { - destination.Add(item); - } - } - - public static void ForEach(this IEnumerable items, Action action) - { - foreach (T item in items) - { - action(item); - } - } - - public static IEnumerable AsEnumerable(this T item) - { - yield return item; - } - - public static void CheckNotNull(this object obj, string name) - { - if (obj == null) - { - throw new ArgumentNullException(name); - } - } - - public static void CheckNotNullOrEmpty(this string obj, string name) - { - obj.CheckNotNull(name); - if (obj.Length == 0) - { - throw new ArgumentException("String is empty."); - } - } - - public static void Skip(this Stream source, long advanceAmount) - { - byte[] buffer = new byte[32 * 1024]; - int read = 0; - int readCount = 0; - do - { - readCount = buffer.Length; - if (readCount > advanceAmount) - { - readCount = (int)advanceAmount; - } - read = source.Read(buffer, 0, readCount); - if (read < 0) - { - break; - } - advanceAmount -= read; - if (advanceAmount == 0) - { - break; - } - } while (true); - } - - public static void SkipAll(this Stream source) - { - byte[] buffer = new byte[32 * 1024]; - do - { - } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); - } - - - public static byte[] UInt32ToBigEndianBytes(uint x) - { - return new byte[] - { - (byte) ((x >> 24) & 0xff), - (byte) ((x >> 16) & 0xff), - (byte) ((x >> 8) & 0xff), - (byte) (x & 0xff) - }; - } - - public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime) - { - int year = iDate / 512 + 1980; - int month = iDate % 512 / 32; - int day = iDate % 512 % 32; - int hour = iTime / 2048; - int minute = iTime % 2048 / 32; - int second = iTime % 2048 % 32 * 2; - - if (iDate == UInt16.MaxValue || month == 0 || day == 0) - { - year = 1980; - month = 1; - day = 1; - } - - if (iTime == UInt16.MaxValue) - { - hour = minute = second = 0; - } - - DateTime dt; - try - { - dt = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local); - } - catch - { - dt = new DateTime(); - } - return dt; - } - - public static uint DateTimeToDosTime(this DateTime? dateTime) - { - if (dateTime == null) - { - return 0; - } - - var localDateTime = dateTime.Value.ToLocalTime(); - - return (uint)( - (localDateTime.Second / 2) | (localDateTime.Minute << 5) | (localDateTime.Hour << 11) | - (localDateTime.Day << 16) | (localDateTime.Month << 21) | - ((localDateTime.Year - 1980) << 25)); - } - - - public static DateTime DosDateToDateTime(UInt32 iTime) - { - return DosDateToDateTime((UInt16)(iTime / 65536), - (UInt16)(iTime % 65536)); - } - - public static DateTime DosDateToDateTime(Int32 iTime) - { - return DosDateToDateTime((UInt32)iTime); - } - - public static long TransferTo(this Stream source, Stream destination) - { - byte[] array = new byte[81920]; - int count; - long total = 0; - while ((count = source.Read(array, 0, array.Length)) != 0) - { - total += count; - destination.Write(array, 0, count); - } - return total; - } - - public static bool ReadFully(this Stream stream, byte[] buffer) - { - int total = 0; - int read; - while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0) - { - total += read; - if (total >= buffer.Length) - { - return true; - } - } - return (total >= buffer.Length); - } - - public static string TrimNulls(this string source) - { - return source.Replace('\0', ' ').Trim(); - } - - public static bool BinaryEquals(this byte[] source, byte[] target) - { - if (source.Length != target.Length) - { - return false; - } - for (int i = 0; i < source.Length; ++i) - { - if (source[i] != target[i]) - { - return false; - } - } - return true; - } - - public static void CopyTo(this byte[] array, byte[] destination, int index) - { - Array.Copy(array, 0, destination, index, array.Length); - } - - public static long HostToNetworkOrder(long host) - { - return (int)((long)HostToNetworkOrder((int)host) - & unchecked((long)(unchecked((ulong)-1))) << 32 - | ((long)HostToNetworkOrder((int)((int)host >> 32)) & unchecked((long)(unchecked((ulong)-1))))); - } - public static int HostToNetworkOrder(int host) - { - return (int)((int)(HostToNetworkOrder((short)host) & -1) << 16 | (HostToNetworkOrder((short)(host >> 16)) & -1)); - } - public static short HostToNetworkOrder(short host) - { - return (short)((int)(host & 255) << 8 | ((int)host >> 8 & 255)); - } - public static long NetworkToHostOrder(long network) - { - return HostToNetworkOrder(network); - } - public static int NetworkToHostOrder(int network) - { - return HostToNetworkOrder(network); - } - public static short NetworkToHostOrder(short network) - { - return HostToNetworkOrder(network); - } - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Archive; +using SharpCompress.Common; +using SharpCompress.IO; + +namespace SharpCompress +{ + internal static class Utility + { + public static ReadOnlyCollection ToReadOnly(this IEnumerable items) + { + return new ReadOnlyCollection(items.ToList()); + } + + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static int URShift(int number, int bits) + { + if (number >= 0) + return number >> bits; + else + return (number >> bits) + (2 << ~bits); + } + + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static int URShift(int number, long bits) + { + return URShift(number, (int)bits); + } + + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static long URShift(long number, int bits) + { + if (number >= 0) + return number >> bits; + else + return (number >> bits) + (2L << ~bits); + } + + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static long URShift(long number, long bits) + { + return URShift(number, (int)bits); + } + + /// + /// Fills the array with an specific value from an specific index to an specific index. + /// + /// The array to be filled. + /// The first index to be filled. + /// The last index to be filled. + /// The value to fill the array with. + public static void Fill(T[] array, int fromindex, int toindex, T val) where T : struct + { + if (array.Length == 0) + { + throw new NullReferenceException(); + } + if (fromindex > toindex) + { + throw new ArgumentException(); + } + if ((fromindex < 0) || ((System.Array)array).Length < toindex) + { + throw new IndexOutOfRangeException(); + } + for (int index = (fromindex > 0) ? fromindex-- : fromindex; index < toindex; index++) + { + array[index] = val; + } + } + + /// + /// Fills the array with an specific value. + /// + /// The array to be filled. + /// The value to fill the array with. + public static void Fill(T[] array, T val) where T : struct + { + Fill(array, 0, array.Length, val); + } + + public static void SetSize(this List list, int count) + { + if (count > list.Count) + { + for (int i = list.Count; i < count; i++) + { + list.Add(0x0); + } + } + else + { + byte[] temp = new byte[count]; + list.CopyTo(temp, 0); + list.Clear(); + list.AddRange(temp); + } + } + + /// Read a int value from the byte array at the given position (Big Endian) + /// + /// + /// the array to read from + /// + /// the offset + /// + /// the value + /// + public static int readIntBigEndian(byte[] array, int pos) + { + int temp = 0; + temp |= array[pos] & 0xff; + temp <<= 8; + temp |= array[pos + 1] & 0xff; + temp <<= 8; + temp |= array[pos + 2] & 0xff; + temp <<= 8; + temp |= array[pos + 3] & 0xff; + return temp; + } + + /// Read a short value from the byte array at the given position (little + /// Endian) + /// + /// + /// the array to read from + /// + /// the offset + /// + /// the value + /// + public static short readShortLittleEndian(byte[] array, int pos) + { + return BitConverter.ToInt16(array, pos); + } + + /// Read an int value from the byte array at the given position (little + /// Endian) + /// + /// + /// the array to read from + /// + /// the offset + /// + /// the value + /// + public static int readIntLittleEndian(byte[] array, int pos) + { + return BitConverter.ToInt32(array, pos); + } + + /// Write an int value into the byte array at the given position (Big endian) + /// + /// + /// the array + /// + /// the offset + /// + /// the value to write + /// + public static void writeIntBigEndian(byte[] array, int pos, int value) + { + array[pos] = (byte)((Utility.URShift(value, 24)) & 0xff); + array[pos + 1] = (byte)((Utility.URShift(value, 16)) & 0xff); + array[pos + 2] = (byte)((Utility.URShift(value, 8)) & 0xff); + array[pos + 3] = (byte)((value) & 0xff); + } + + /// Write a short value into the byte array at the given position (little + /// endian) + /// + /// + /// the array + /// + /// the offset + /// + /// the value to write + /// + public static void WriteLittleEndian(byte[] array, int pos, short value) + { + byte[] newBytes = BitConverter.GetBytes(value); + + if (!BitConverter.IsLittleEndian) + Array.Reverse(newBytes); + + Array.Copy(newBytes, 0, array, pos, newBytes.Length); + } + + /// Increment a short value at the specified position by the specified amount + /// (little endian). + /// + public static void incShortLittleEndian(byte[] array, int pos, short incrementValue) + { + short existingValue = BitConverter.ToInt16(array, pos); + existingValue += incrementValue; + WriteLittleEndian(array, pos, existingValue); + //int c = Utility.URShift(((array[pos] & 0xff) + (dv & 0xff)), 8); + //array[pos] = (byte)(array[pos] + (dv & 0xff)); + //if ((c > 0) || ((dv & 0xff00) != 0)) + //{ + // array[pos + 1] = (byte)(array[pos + 1] + ((Utility.URShift(dv, 8)) & 0xff) + c); + //} + } + + /// Write an int value into the byte array at the given position (little + /// endian) + /// + /// + /// the array + /// + /// the offset + /// + /// the value to write + /// + public static void WriteLittleEndian(byte[] array, int pos, int value) + { + byte[] newBytes = BitConverter.GetBytes(value); + + if (!BitConverter.IsLittleEndian) + Array.Reverse(newBytes); + + Array.Copy(newBytes, 0, array, pos, newBytes.Length); + } + + public static void Initialize(this T[] array, Func func) + { + for (int i = 0; i < array.Length; i++) + { + array[i] = func(); + } + } + + public static void AddRange(this ICollection destination, IEnumerable source) + { + foreach (T item in source) + { + destination.Add(item); + } + } + + public static void ForEach(this IEnumerable items, Action action) + { + foreach (T item in items) + { + action(item); + } + } + + public static IEnumerable AsEnumerable(this T item) + { + yield return item; + } + + public static void CheckNotNull(this object obj, string name) + { + if (obj == null) + { + throw new ArgumentNullException(name); + } + } + + public static void CheckNotNullOrEmpty(this string obj, string name) + { + obj.CheckNotNull(name); + if (obj.Length == 0) + { + throw new ArgumentException("String is empty."); + } + } + + public static void Skip(this Stream source, long advanceAmount) + { + byte[] buffer = new byte[32 * 1024]; + int read = 0; + int readCount = 0; + do + { + readCount = buffer.Length; + if (readCount > advanceAmount) + { + readCount = (int)advanceAmount; + } + read = source.Read(buffer, 0, readCount); + if (read < 0) + { + break; + } + advanceAmount -= read; + if (advanceAmount == 0) + { + break; + } + } while (true); + } + + public static void SkipAll(this Stream source) + { + byte[] buffer = new byte[32 * 1024]; + do + { + } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); + } + + + public static byte[] UInt32ToBigEndianBytes(uint x) + { + return new byte[] + { + (byte) ((x >> 24) & 0xff), + (byte) ((x >> 16) & 0xff), + (byte) ((x >> 8) & 0xff), + (byte) (x & 0xff) + }; + } + + public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime) + { + int year = iDate / 512 + 1980; + int month = iDate % 512 / 32; + int day = iDate % 512 % 32; + int hour = iTime / 2048; + int minute = iTime % 2048 / 32; + int second = iTime % 2048 % 32 * 2; + + if (iDate == UInt16.MaxValue || month == 0 || day == 0) + { + year = 1980; + month = 1; + day = 1; + } + + if (iTime == UInt16.MaxValue) + { + hour = minute = second = 0; + } + + DateTime dt; + try + { + dt = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local); + } + catch + { + dt = new DateTime(); + } + return dt; + } + + public static uint DateTimeToDosTime(this DateTime? dateTime) + { + if (dateTime == null) + { + return 0; + } + + var localDateTime = dateTime.Value.ToLocalTime(); + + return (uint)( + (localDateTime.Second / 2) | (localDateTime.Minute << 5) | (localDateTime.Hour << 11) | + (localDateTime.Day << 16) | (localDateTime.Month << 21) | + ((localDateTime.Year - 1980) << 25)); + } + + + public static DateTime DosDateToDateTime(UInt32 iTime) + { + return DosDateToDateTime((UInt16)(iTime / 65536), + (UInt16)(iTime % 65536)); + } + + public static DateTime DosDateToDateTime(Int32 iTime) + { + return DosDateToDateTime((UInt32)iTime); + } + + public static long TransferTo(this Stream source, Stream destination) + { + byte[] array = new byte[81920]; + int count; + long total = 0; + while ((count = source.Read(array, 0, array.Length)) != 0) + { + total += count; + destination.Write(array, 0, count); + } + return total; + } + + public static bool ReadFully(this Stream stream, byte[] buffer) + { + int total = 0; + int read; + while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0) + { + total += read; + if (total >= buffer.Length) + { + return true; + } + } + return (total >= buffer.Length); + } + + public static string TrimNulls(this string source) + { + return source.Replace('\0', ' ').Trim(); + } + + public static bool BinaryEquals(this byte[] source, byte[] target) + { + if (source.Length != target.Length) + { + return false; + } + for (int i = 0; i < source.Length; ++i) + { + if (source[i] != target[i]) + { + return false; + } + } + return true; + } + + public static void CopyTo(this byte[] array, byte[] destination, int index) + { + Array.Copy(array, 0, destination, index, array.Length); + } + + public static long HostToNetworkOrder(long host) + { + return (int)((long)HostToNetworkOrder((int)host) + & unchecked((long)(unchecked((ulong)-1))) << 32 + | ((long)HostToNetworkOrder((int)((int)host >> 32)) & unchecked((long)(unchecked((ulong)-1))))); + } + public static int HostToNetworkOrder(int host) + { + return (int)((int)(HostToNetworkOrder((short)host) & -1) << 16 | (HostToNetworkOrder((short)(host >> 16)) & -1)); + } + public static short HostToNetworkOrder(short host) + { + return (short)((int)(host & 255) << 8 | ((int)host >> 8 & 255)); + } + public static long NetworkToHostOrder(long network) + { + return HostToNetworkOrder(network); + } + public static int NetworkToHostOrder(int network) + { + return HostToNetworkOrder(network); + } + public static short NetworkToHostOrder(short network) + { + return HostToNetworkOrder(network); + } + } } \ No newline at end of file diff --git a/SharpCompress/Writer/AbstractWriter.cs b/src/SharpCompress/Writer/AbstractWriter.cs similarity index 95% rename from SharpCompress/Writer/AbstractWriter.cs rename to src/SharpCompress/Writer/AbstractWriter.cs index 8ace64b3..2c45827f 100644 --- a/SharpCompress/Writer/AbstractWriter.cs +++ b/src/SharpCompress/Writer/AbstractWriter.cs @@ -1,56 +1,56 @@ -using System; -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.Writer -{ - public abstract class AbstractWriter : IWriter - { - private bool closeStream; - private bool isDisposed; - - protected AbstractWriter(ArchiveType type) - { - this.WriterType = type; - } - - protected void InitalizeStream(Stream stream, bool closeStream) - { - this.OutputStream = stream; - this.closeStream = closeStream; - } - - protected Stream OutputStream { get; private set; } - - public ArchiveType WriterType { get; private set; } - - public abstract void Write(string filename, System.IO.Stream source, DateTime? modificationTime); - - protected virtual void Dispose(bool isDisposing) - { - if (isDisposing && closeStream) - { - OutputStream.Dispose(); - } - } - - public void Dispose() - { - if (!isDisposed) - { - GC.SuppressFinalize(this); - Dispose(true); - isDisposed = true; - } - } - - ~AbstractWriter() - { - if (!isDisposed) - { - Dispose(false); - isDisposed = true; - } - } - } +using System; +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Writer +{ + public abstract class AbstractWriter : IWriter + { + private bool closeStream; + private bool isDisposed; + + protected AbstractWriter(ArchiveType type) + { + this.WriterType = type; + } + + protected void InitalizeStream(Stream stream, bool closeStream) + { + this.OutputStream = stream; + this.closeStream = closeStream; + } + + protected Stream OutputStream { get; private set; } + + public ArchiveType WriterType { get; private set; } + + public abstract void Write(string filename, System.IO.Stream source, DateTime? modificationTime); + + protected virtual void Dispose(bool isDisposing) + { + if (isDisposing && closeStream) + { + OutputStream.Dispose(); + } + } + + public void Dispose() + { + if (!isDisposed) + { + GC.SuppressFinalize(this); + Dispose(true); + isDisposed = true; + } + } + + ~AbstractWriter() + { + if (!isDisposed) + { + Dispose(false); + isDisposed = true; + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Writer/GZip/GZipWriter.cs b/src/SharpCompress/Writer/GZip/GZipWriter.cs similarity index 96% rename from SharpCompress/Writer/GZip/GZipWriter.cs rename to src/SharpCompress/Writer/GZip/GZipWriter.cs index a718aad1..ae10cf65 100644 --- a/SharpCompress/Writer/GZip/GZipWriter.cs +++ b/src/SharpCompress/Writer/GZip/GZipWriter.cs @@ -1,43 +1,43 @@ -using System; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.Compressor; -using SharpCompress.Compressor.Deflate; - -namespace SharpCompress.Writer.GZip -{ - public class GZipWriter : AbstractWriter - { - private bool wroteToStream; - - public GZipWriter(Stream destination) - : base(ArchiveType.GZip) - { - InitalizeStream(new GZipStream(destination, CompressionMode.Compress, true), true); - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - //dispose here to finish the GZip, GZip won't close the underlying stream - OutputStream.Dispose(); - } - base.Dispose(isDisposing); - } - - public override void Write(string filename, Stream source, DateTime? modificationTime) - { - if (wroteToStream) - { - throw new ArgumentException("Can only write a single stream to a GZip file."); - } - GZipStream stream = OutputStream as GZipStream; - stream.FileName = filename; - stream.LastModified = modificationTime; - source.TransferTo(stream); - wroteToStream = true; - } - } +using System; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.Compressor; +using SharpCompress.Compressor.Deflate; + +namespace SharpCompress.Writer.GZip +{ + public class GZipWriter : AbstractWriter + { + private bool wroteToStream; + + public GZipWriter(Stream destination) + : base(ArchiveType.GZip) + { + InitalizeStream(new GZipStream(destination, CompressionMode.Compress, true), true); + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + //dispose here to finish the GZip, GZip won't close the underlying stream + OutputStream.Dispose(); + } + base.Dispose(isDisposing); + } + + public override void Write(string filename, Stream source, DateTime? modificationTime) + { + if (wroteToStream) + { + throw new ArgumentException("Can only write a single stream to a GZip file."); + } + GZipStream stream = OutputStream as GZipStream; + stream.FileName = filename; + stream.LastModified = modificationTime; + source.TransferTo(stream); + wroteToStream = true; + } + } } \ No newline at end of file diff --git a/SharpCompress/Writer/IWriter.Extensions.cs b/src/SharpCompress/Writer/IWriter.Extensions.cs similarity index 97% rename from SharpCompress/Writer/IWriter.Extensions.cs rename to src/SharpCompress/Writer/IWriter.Extensions.cs index 857da856..aa14e791 100644 --- a/SharpCompress/Writer/IWriter.Extensions.cs +++ b/src/SharpCompress/Writer/IWriter.Extensions.cs @@ -1,49 +1,49 @@ -using System; -using System.IO; - -namespace SharpCompress.Writer -{ - public static class IWriterExtensions - { - public static void Write(this IWriter writer, string entryPath, Stream source) - { - writer.Write(entryPath, source, null); - } - -#if !DOTNET51 - public static void Write(this IWriter writer, string entryPath, FileInfo source) - { - if (!source.Exists) - { - throw new ArgumentException("Source does not exist: " + source.FullName); - } - using (var stream = source.OpenRead()) - { - writer.Write(entryPath, stream, source.LastWriteTime); - } - } - - public static void Write(this IWriter writer, string entryPath, string source) - { - writer.Write(entryPath, new FileInfo(source)); - } - - public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", - SearchOption option = SearchOption.TopDirectoryOnly) - { - if (!Directory.Exists(directory)) - { - throw new ArgumentException("Directory does not exist: " + directory); - } -#if NET35 - foreach (var file in Directory.GetDirectories(directory, searchPattern, option)) -#else - foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option)) -#endif - { - writer.Write(file.Substring(directory.Length), file); - } - } -#endif - } +using System; +using System.IO; + +namespace SharpCompress.Writer +{ + public static class IWriterExtensions + { + public static void Write(this IWriter writer, string entryPath, Stream source) + { + writer.Write(entryPath, source, null); + } + +#if !DOTNET51 + public static void Write(this IWriter writer, string entryPath, FileInfo source) + { + if (!source.Exists) + { + throw new ArgumentException("Source does not exist: " + source.FullName); + } + using (var stream = source.OpenRead()) + { + writer.Write(entryPath, stream, source.LastWriteTime); + } + } + + public static void Write(this IWriter writer, string entryPath, string source) + { + writer.Write(entryPath, new FileInfo(source)); + } + + public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", + SearchOption option = SearchOption.TopDirectoryOnly) + { + if (!Directory.Exists(directory)) + { + throw new ArgumentException("Directory does not exist: " + directory); + } +#if NET35 + foreach (var file in Directory.GetDirectories(directory, searchPattern, option)) +#else + foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option)) +#endif + { + writer.Write(file.Substring(directory.Length), file); + } + } +#endif + } } \ No newline at end of file diff --git a/SharpCompress/Writer/IWriter.cs b/src/SharpCompress/Writer/IWriter.cs similarity index 96% rename from SharpCompress/Writer/IWriter.cs rename to src/SharpCompress/Writer/IWriter.cs index 2a94ceba..c413400b 100644 --- a/SharpCompress/Writer/IWriter.cs +++ b/src/SharpCompress/Writer/IWriter.cs @@ -1,12 +1,12 @@ -using System; -using System.IO; -using SharpCompress.Common; - -namespace SharpCompress.Writer -{ - public interface IWriter : IDisposable - { - ArchiveType WriterType { get; } - void Write(string filename, Stream source, DateTime? modificationTime); - } +using System; +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Writer +{ + public interface IWriter : IDisposable + { + ArchiveType WriterType { get; } + void Write(string filename, Stream source, DateTime? modificationTime); + } } \ No newline at end of file diff --git a/SharpCompress/Writer/Tar/TarWriter.cs b/src/SharpCompress/Writer/Tar/TarWriter.cs similarity index 97% rename from SharpCompress/Writer/Tar/TarWriter.cs rename to src/SharpCompress/Writer/Tar/TarWriter.cs index 5c947cc9..64da6e82 100644 --- a/SharpCompress/Writer/Tar/TarWriter.cs +++ b/src/SharpCompress/Writer/Tar/TarWriter.cs @@ -1,99 +1,99 @@ -using System; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.Compressor; -using SharpCompress.Compressor.BZip2; -using SharpCompress.Compressor.Deflate; - -namespace SharpCompress.Writer.Tar -{ - public class TarWriter : AbstractWriter - { - public TarWriter(Stream destination, CompressionInfo compressionInfo) - : base(ArchiveType.Tar) - { - if (!destination.CanWrite) - { - throw new ArgumentException("Tars require writable streams."); - } - switch (compressionInfo.Type) - { - case CompressionType.None: - break; - case CompressionType.BZip2: - { - destination = new BZip2Stream(destination, CompressionMode.Compress, false); - } - break; - case CompressionType.GZip: - { - destination = new GZipStream(destination, CompressionMode.Compress, false); - } - break; - default: - { - throw new InvalidFormatException("Tar does not support compression: " + compressionInfo.Type); - } - } - InitalizeStream(destination, false); - } - - public override void Write(string filename, Stream source, DateTime? modificationTime) - { - Write(filename, source, modificationTime, null); - } - - private string NormalizeFilename(string filename) - { - filename = filename.Replace('\\', '/'); - - int pos = filename.IndexOf(':'); - if (pos >= 0) - filename = filename.Remove(0, pos + 1); - - return filename.Trim('/'); - } - - public void Write(string filename, Stream source, DateTime? modificationTime, long? size) - { - if (!source.CanSeek && size == null) - { - throw new ArgumentException("Seekable stream is required if no size is given."); - } - - long realSize = size ?? source.Length; - - - TarHeader header = new TarHeader(); - header.LastModifiedTime = modificationTime ?? TarHeader.Epoch; - header.Name = NormalizeFilename(filename); - header.Size = realSize; - header.Write(OutputStream); - size = source.TransferTo(OutputStream); - PadTo512(size.Value, false); - } - - private void PadTo512(long size, bool forceZeros) - { - int zeros = (int) size%512; - if (zeros == 0 && !forceZeros) - { - return; - } - zeros = 512 - zeros; - OutputStream.Write(new byte[zeros], 0, zeros); - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - PadTo512(0, true); - PadTo512(0, true); - OutputStream.Dispose(); // required when bzip2 compression is used - } - base.Dispose(isDisposing); - } - } +using System; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Tar.Headers; +using SharpCompress.Compressor; +using SharpCompress.Compressor.BZip2; +using SharpCompress.Compressor.Deflate; + +namespace SharpCompress.Writer.Tar +{ + public class TarWriter : AbstractWriter + { + public TarWriter(Stream destination, CompressionInfo compressionInfo) + : base(ArchiveType.Tar) + { + if (!destination.CanWrite) + { + throw new ArgumentException("Tars require writable streams."); + } + switch (compressionInfo.Type) + { + case CompressionType.None: + break; + case CompressionType.BZip2: + { + destination = new BZip2Stream(destination, CompressionMode.Compress, false); + } + break; + case CompressionType.GZip: + { + destination = new GZipStream(destination, CompressionMode.Compress, false); + } + break; + default: + { + throw new InvalidFormatException("Tar does not support compression: " + compressionInfo.Type); + } + } + InitalizeStream(destination, false); + } + + public override void Write(string filename, Stream source, DateTime? modificationTime) + { + Write(filename, source, modificationTime, null); + } + + private string NormalizeFilename(string filename) + { + filename = filename.Replace('\\', '/'); + + int pos = filename.IndexOf(':'); + if (pos >= 0) + filename = filename.Remove(0, pos + 1); + + return filename.Trim('/'); + } + + public void Write(string filename, Stream source, DateTime? modificationTime, long? size) + { + if (!source.CanSeek && size == null) + { + throw new ArgumentException("Seekable stream is required if no size is given."); + } + + long realSize = size ?? source.Length; + + + TarHeader header = new TarHeader(); + header.LastModifiedTime = modificationTime ?? TarHeader.Epoch; + header.Name = NormalizeFilename(filename); + header.Size = realSize; + header.Write(OutputStream); + size = source.TransferTo(OutputStream); + PadTo512(size.Value, false); + } + + private void PadTo512(long size, bool forceZeros) + { + int zeros = (int) size%512; + if (zeros == 0 && !forceZeros) + { + return; + } + zeros = 512 - zeros; + OutputStream.Write(new byte[zeros], 0, zeros); + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + PadTo512(0, true); + PadTo512(0, true); + OutputStream.Dispose(); // required when bzip2 compression is used + } + base.Dispose(isDisposing); + } + } } \ No newline at end of file diff --git a/SharpCompress/Writer/WriterFactory.cs b/src/SharpCompress/Writer/WriterFactory.cs similarity index 97% rename from SharpCompress/Writer/WriterFactory.cs rename to src/SharpCompress/Writer/WriterFactory.cs index 7a17ec1c..c6100138 100644 --- a/SharpCompress/Writer/WriterFactory.cs +++ b/src/SharpCompress/Writer/WriterFactory.cs @@ -1,47 +1,47 @@ -using System; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Writer.GZip; -using SharpCompress.Writer.Tar; -using SharpCompress.Writer.Zip; - -namespace SharpCompress.Writer -{ - public static class WriterFactory - { - public static IWriter Open(Stream stream, ArchiveType archiveType, CompressionType compressionType) - { - return Open(stream, archiveType, new CompressionInfo - { - Type = compressionType - }); - } - - public static IWriter Open(Stream stream, ArchiveType archiveType, CompressionInfo compressionInfo) - { - switch (archiveType) - { - case ArchiveType.GZip: - { - if (compressionInfo.Type != CompressionType.GZip) - { - throw new InvalidFormatException("GZip archives only support GZip compression type."); - } - return new GZipWriter(stream); - } - case ArchiveType.Zip: - { - return new ZipWriter(stream, compressionInfo, null); - } - case ArchiveType.Tar: - { - return new TarWriter(stream, compressionInfo); - } - default: - { - throw new NotSupportedException("Archive Type does not have a Writer: " + archiveType); - } - } - } - } +using System; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Writer.GZip; +using SharpCompress.Writer.Tar; +using SharpCompress.Writer.Zip; + +namespace SharpCompress.Writer +{ + public static class WriterFactory + { + public static IWriter Open(Stream stream, ArchiveType archiveType, CompressionType compressionType) + { + return Open(stream, archiveType, new CompressionInfo + { + Type = compressionType + }); + } + + public static IWriter Open(Stream stream, ArchiveType archiveType, CompressionInfo compressionInfo) + { + switch (archiveType) + { + case ArchiveType.GZip: + { + if (compressionInfo.Type != CompressionType.GZip) + { + throw new InvalidFormatException("GZip archives only support GZip compression type."); + } + return new GZipWriter(stream); + } + case ArchiveType.Zip: + { + return new ZipWriter(stream, compressionInfo, null); + } + case ArchiveType.Tar: + { + return new TarWriter(stream, compressionInfo); + } + default: + { + throw new NotSupportedException("Archive Type does not have a Writer: " + archiveType); + } + } + } + } } \ No newline at end of file diff --git a/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs b/src/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs similarity index 98% rename from SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs rename to src/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs index c1a4c1e8..da5d94f4 100644 --- a/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs +++ b/src/SharpCompress/Writer/Zip/ZipCentralDirectoryEntry.cs @@ -1,60 +1,60 @@ -using System; -using System.IO; -using System.Text; -using SharpCompress.Common.Zip; -using SharpCompress.Common.Zip.Headers; - -namespace SharpCompress.Writer.Zip -{ - internal class ZipCentralDirectoryEntry - { - internal string FileName { get; set; } - internal DateTime? ModificationTime { get; set; } - internal string Comment { get; set; } - internal uint Crc { get; set; } - internal uint HeaderOffset { get; set; } - internal uint Compressed { get; set; } - internal uint Decompressed { get; set; } - - - internal uint Write(Stream outputStream, ZipCompressionMethod compression) - { - byte[] encodedFilename = Encoding.UTF8.GetBytes(FileName); - byte[] encodedComment = Encoding.UTF8.GetBytes(Comment); - - outputStream.Write(new byte[] {80, 75, 1, 2, 0x3F, 0, 0x0A, 0}, 0, 8); - HeaderFlags flags = HeaderFlags.UTF8; - if (!outputStream.CanSeek) - { - flags |= HeaderFlags.UsePostDataDescriptor; - if (compression == ZipCompressionMethod.LZMA) - { - flags |= HeaderFlags.Bit1; // eos marker - } - } - outputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); - outputStream.Write(BitConverter.GetBytes((ushort) compression), 0, 2); // zipping method - outputStream.Write(BitConverter.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); - // zipping date and time - outputStream.Write(BitConverter.GetBytes(Crc), 0, 4); // file CRC - outputStream.Write(BitConverter.GetBytes(Compressed), 0, 4); // compressed file size - outputStream.Write(BitConverter.GetBytes(Decompressed), 0, 4); // uncompressed file size - outputStream.Write(BitConverter.GetBytes((ushort) encodedFilename.Length), 0, 2); // Filename in zip - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // extra length - outputStream.Write(BitConverter.GetBytes((ushort) encodedComment.Length), 0, 2); - - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // disk=0 - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // file type: binary - outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // Internal file attributes - outputStream.Write(BitConverter.GetBytes((ushort) 0x8100), 0, 2); - // External file attributes (normal/readable) - outputStream.Write(BitConverter.GetBytes(HeaderOffset), 0, 4); // Offset of header - - outputStream.Write(encodedFilename, 0, encodedFilename.Length); - outputStream.Write(encodedComment, 0, encodedComment.Length); - - return (uint) (8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2 - + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + encodedComment.Length); - } - } +using System; +using System.IO; +using System.Text; +using SharpCompress.Common.Zip; +using SharpCompress.Common.Zip.Headers; + +namespace SharpCompress.Writer.Zip +{ + internal class ZipCentralDirectoryEntry + { + internal string FileName { get; set; } + internal DateTime? ModificationTime { get; set; } + internal string Comment { get; set; } + internal uint Crc { get; set; } + internal uint HeaderOffset { get; set; } + internal uint Compressed { get; set; } + internal uint Decompressed { get; set; } + + + internal uint Write(Stream outputStream, ZipCompressionMethod compression) + { + byte[] encodedFilename = Encoding.UTF8.GetBytes(FileName); + byte[] encodedComment = Encoding.UTF8.GetBytes(Comment); + + outputStream.Write(new byte[] {80, 75, 1, 2, 0x3F, 0, 0x0A, 0}, 0, 8); + HeaderFlags flags = HeaderFlags.UTF8; + if (!outputStream.CanSeek) + { + flags |= HeaderFlags.UsePostDataDescriptor; + if (compression == ZipCompressionMethod.LZMA) + { + flags |= HeaderFlags.Bit1; // eos marker + } + } + outputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); + outputStream.Write(BitConverter.GetBytes((ushort) compression), 0, 2); // zipping method + outputStream.Write(BitConverter.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); + // zipping date and time + outputStream.Write(BitConverter.GetBytes(Crc), 0, 4); // file CRC + outputStream.Write(BitConverter.GetBytes(Compressed), 0, 4); // compressed file size + outputStream.Write(BitConverter.GetBytes(Decompressed), 0, 4); // uncompressed file size + outputStream.Write(BitConverter.GetBytes((ushort) encodedFilename.Length), 0, 2); // Filename in zip + outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // extra length + outputStream.Write(BitConverter.GetBytes((ushort) encodedComment.Length), 0, 2); + + outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // disk=0 + outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // file type: binary + outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // Internal file attributes + outputStream.Write(BitConverter.GetBytes((ushort) 0x8100), 0, 2); + // External file attributes (normal/readable) + outputStream.Write(BitConverter.GetBytes(HeaderOffset), 0, 4); // Offset of header + + outputStream.Write(encodedFilename, 0, encodedFilename.Length); + outputStream.Write(encodedComment, 0, encodedComment.Length); + + return (uint) (8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2 + + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + encodedComment.Length); + } + } } \ No newline at end of file diff --git a/SharpCompress/Writer/Zip/ZipCompressionInfo.cs b/src/SharpCompress/Writer/Zip/ZipCompressionInfo.cs similarity index 100% rename from SharpCompress/Writer/Zip/ZipCompressionInfo.cs rename to src/SharpCompress/Writer/Zip/ZipCompressionInfo.cs diff --git a/SharpCompress/Writer/Zip/ZipWriter.cs b/src/SharpCompress/Writer/Zip/ZipWriter.cs similarity index 97% rename from SharpCompress/Writer/Zip/ZipWriter.cs rename to src/SharpCompress/Writer/Zip/ZipWriter.cs index 4f44fe5d..9bb2bf35 100644 --- a/SharpCompress/Writer/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writer/Zip/ZipWriter.cs @@ -1,295 +1,295 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using SharpCompress.Common; -using SharpCompress.Common.Zip; -using SharpCompress.Common.Zip.Headers; -using SharpCompress.Compressor; -using SharpCompress.Compressor.BZip2; -using SharpCompress.Compressor.Deflate; -using SharpCompress.Compressor.LZMA; -using SharpCompress.Compressor.PPMd; -using SharpCompress.IO; -using DeflateStream = SharpCompress.Compressor.Deflate.DeflateStream; - -namespace SharpCompress.Writer.Zip -{ - public class ZipWriter : AbstractWriter - { - private readonly ZipCompressionInfo zipCompressionInfo; - private readonly PpmdProperties ppmdProperties = new PpmdProperties(); // Caching properties to speed up PPMd - private readonly List entries = new List(); - private readonly string zipComment; - private long streamPosition; - - public ZipWriter(Stream destination, CompressionInfo compressionInfo, string zipComment) - : base(ArchiveType.Zip) - { - this.zipComment = zipComment ?? string.Empty; - - this.zipCompressionInfo = new ZipCompressionInfo(compressionInfo); - InitalizeStream(destination, false); - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - uint size = 0; - foreach (ZipCentralDirectoryEntry entry in entries) - { - size += entry.Write(OutputStream, zipCompressionInfo.Compression); - } - WriteEndRecord(size); - } - base.Dispose(isDisposing); - } - - public override void Write(string entryPath, Stream source, DateTime? modificationTime) - { - Write(entryPath, source, modificationTime, null); - } - - public void Write(string entryPath, Stream source, DateTime? modificationTime, string comment, CompressionInfo compressionInfo = null) - { - using (Stream output = WriteToStream(entryPath, modificationTime, comment, compressionInfo)) - { - source.TransferTo(output); - } - } - - public Stream WriteToStream(string entryPath, DateTime? modificationTime, string comment, CompressionInfo compressionInfo = null) - { - entryPath = NormalizeFilename(entryPath); - modificationTime = modificationTime ?? DateTime.Now; - comment = comment ?? ""; - var entry = new ZipCentralDirectoryEntry - { - Comment = comment, - FileName = entryPath, - ModificationTime = modificationTime, - HeaderOffset = (uint) streamPosition, - }; - - var headersize = (uint)WriteHeader(entryPath, modificationTime, compressionInfo); - streamPosition += headersize; - return new ZipWritingStream(this, OutputStream, entry); - } - - private string NormalizeFilename(string filename) - { - filename = filename.Replace('\\', '/'); - - int pos = filename.IndexOf(':'); - if (pos >= 0) - filename = filename.Remove(0, pos + 1); - - return filename.Trim('/'); - } - - private int WriteHeader(string filename, DateTime? modificationTime, CompressionInfo compressionInfo = null) - { - var explicitZipCompressionInfo = compressionInfo != null ? new ZipCompressionInfo(compressionInfo) : this.zipCompressionInfo; - byte[] encodedFilename = ArchiveEncoding.Default.GetBytes(filename); - - OutputStream.Write(BitConverter.GetBytes(ZipHeaderFactory.ENTRY_HEADER_BYTES), 0, 4); - if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.Deflate) - { - OutputStream.Write(new byte[] {20, 0}, 0, 2); //older version which is more compatible - } - else - { - OutputStream.Write(new byte[] {63, 0}, 0, 2); //version says we used PPMd or LZMA - } - HeaderFlags flags = ArchiveEncoding.Default == Encoding.UTF8 ? HeaderFlags.UTF8 : (HeaderFlags)0; - if (!OutputStream.CanSeek) - { - flags |= HeaderFlags.UsePostDataDescriptor; - if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.LZMA) - { - flags |= HeaderFlags.Bit1; // eos marker - } - } - OutputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); - OutputStream.Write(BitConverter.GetBytes((ushort)explicitZipCompressionInfo.Compression), 0, 2); // zipping method - OutputStream.Write(BitConverter.GetBytes(modificationTime.DateTimeToDosTime()), 0, 4); - // zipping date and time - OutputStream.Write(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 12); - // unused CRC, un/compressed size, updated later - OutputStream.Write(BitConverter.GetBytes((ushort) encodedFilename.Length), 0, 2); // filename length - OutputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // extra length - OutputStream.Write(encodedFilename, 0, encodedFilename.Length); - - return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length; - } - - private void WriteFooter(uint crc, uint compressed, uint uncompressed) - { - OutputStream.Write(BitConverter.GetBytes(crc), 0, 4); - OutputStream.Write(BitConverter.GetBytes(compressed), 0, 4); - OutputStream.Write(BitConverter.GetBytes(uncompressed), 0, 4); - } - - private void WriteEndRecord(uint size) - { - byte[] encodedComment = ArchiveEncoding.Default.GetBytes(zipComment); - - OutputStream.Write(new byte[] {80, 75, 5, 6, 0, 0, 0, 0}, 0, 8); - OutputStream.Write(BitConverter.GetBytes((ushort) entries.Count), 0, 2); - OutputStream.Write(BitConverter.GetBytes((ushort) entries.Count), 0, 2); - OutputStream.Write(BitConverter.GetBytes(size), 0, 4); - OutputStream.Write(BitConverter.GetBytes((uint) streamPosition), 0, 4); - OutputStream.Write(BitConverter.GetBytes((ushort) encodedComment.Length), 0, 2); - OutputStream.Write(encodedComment, 0, encodedComment.Length); - } - - #region Nested type: ZipWritingStream - - internal class ZipWritingStream : Stream - { - private readonly CRC32 crc = new CRC32(); - private readonly ZipCentralDirectoryEntry entry; - private readonly Stream originalStream; - private readonly Stream writeStream; - private readonly ZipWriter writer; - private CountingWritableSubStream counting; - private uint decompressed; - - internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry) - { - this.writer = writer; - this.originalStream = originalStream; - writeStream = GetWriteStream(originalStream); - this.writer = writer; - this.entry = entry; - } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - private Stream GetWriteStream(Stream writeStream) - { - counting = new CountingWritableSubStream(writeStream); - Stream output = counting; - switch (writer.zipCompressionInfo.Compression) - { - case ZipCompressionMethod.None: - { - return output; - } - case ZipCompressionMethod.Deflate: - { - return new DeflateStream(counting, CompressionMode.Compress, writer.zipCompressionInfo.DeflateCompressionLevel, - true); - } - case ZipCompressionMethod.BZip2: - { - return new BZip2Stream(counting, CompressionMode.Compress, true); - } - case ZipCompressionMethod.LZMA: - { - counting.WriteByte(9); - counting.WriteByte(20); - counting.WriteByte(5); - counting.WriteByte(0); - - LzmaStream lzmaStream = new LzmaStream(new LzmaEncoderProperties(!originalStream.CanSeek), - false, counting); - counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); - return lzmaStream; - } - case ZipCompressionMethod.PPMd: - { - counting.Write(writer.ppmdProperties.Properties, 0, 2); - return new PpmdStream(writer.ppmdProperties, counting, true); - } - default: - { - throw new NotSupportedException("CompressionMethod: " + writer.zipCompressionInfo.Compression); - } - } - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - writeStream.Dispose(); - entry.Crc = (uint) crc.Crc32Result; - entry.Compressed = counting.Count; - entry.Decompressed = decompressed; - if (originalStream.CanSeek) - { - originalStream.Position = entry.HeaderOffset + 6; - originalStream.WriteByte(0); - originalStream.Position = entry.HeaderOffset + 14; - writer.WriteFooter(entry.Crc, counting.Count, decompressed); - originalStream.Position = writer.streamPosition + entry.Compressed; - writer.streamPosition += entry.Compressed; - } - else - { - originalStream.Write(BitConverter.GetBytes(ZipHeaderFactory.POST_DATA_DESCRIPTOR), 0, 4); - writer.WriteFooter(entry.Crc, counting.Count, decompressed); - writer.streamPosition += entry.Compressed + 16; - } - writer.entries.Add(entry); - } - } - - public override void Flush() - { - writeStream.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - decompressed += (uint) count; - crc.SlurpBlock(buffer, offset, count); - writeStream.Write(buffer, offset, count); - } - } - - #endregion - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using SharpCompress.Common; +using SharpCompress.Common.Zip; +using SharpCompress.Common.Zip.Headers; +using SharpCompress.Compressor; +using SharpCompress.Compressor.BZip2; +using SharpCompress.Compressor.Deflate; +using SharpCompress.Compressor.LZMA; +using SharpCompress.Compressor.PPMd; +using SharpCompress.IO; +using DeflateStream = SharpCompress.Compressor.Deflate.DeflateStream; + +namespace SharpCompress.Writer.Zip +{ + public class ZipWriter : AbstractWriter + { + private readonly ZipCompressionInfo zipCompressionInfo; + private readonly PpmdProperties ppmdProperties = new PpmdProperties(); // Caching properties to speed up PPMd + private readonly List entries = new List(); + private readonly string zipComment; + private long streamPosition; + + public ZipWriter(Stream destination, CompressionInfo compressionInfo, string zipComment) + : base(ArchiveType.Zip) + { + this.zipComment = zipComment ?? string.Empty; + + this.zipCompressionInfo = new ZipCompressionInfo(compressionInfo); + InitalizeStream(destination, false); + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + uint size = 0; + foreach (ZipCentralDirectoryEntry entry in entries) + { + size += entry.Write(OutputStream, zipCompressionInfo.Compression); + } + WriteEndRecord(size); + } + base.Dispose(isDisposing); + } + + public override void Write(string entryPath, Stream source, DateTime? modificationTime) + { + Write(entryPath, source, modificationTime, null); + } + + public void Write(string entryPath, Stream source, DateTime? modificationTime, string comment, CompressionInfo compressionInfo = null) + { + using (Stream output = WriteToStream(entryPath, modificationTime, comment, compressionInfo)) + { + source.TransferTo(output); + } + } + + public Stream WriteToStream(string entryPath, DateTime? modificationTime, string comment, CompressionInfo compressionInfo = null) + { + entryPath = NormalizeFilename(entryPath); + modificationTime = modificationTime ?? DateTime.Now; + comment = comment ?? ""; + var entry = new ZipCentralDirectoryEntry + { + Comment = comment, + FileName = entryPath, + ModificationTime = modificationTime, + HeaderOffset = (uint) streamPosition, + }; + + var headersize = (uint)WriteHeader(entryPath, modificationTime, compressionInfo); + streamPosition += headersize; + return new ZipWritingStream(this, OutputStream, entry); + } + + private string NormalizeFilename(string filename) + { + filename = filename.Replace('\\', '/'); + + int pos = filename.IndexOf(':'); + if (pos >= 0) + filename = filename.Remove(0, pos + 1); + + return filename.Trim('/'); + } + + private int WriteHeader(string filename, DateTime? modificationTime, CompressionInfo compressionInfo = null) + { + var explicitZipCompressionInfo = compressionInfo != null ? new ZipCompressionInfo(compressionInfo) : this.zipCompressionInfo; + byte[] encodedFilename = ArchiveEncoding.Default.GetBytes(filename); + + OutputStream.Write(BitConverter.GetBytes(ZipHeaderFactory.ENTRY_HEADER_BYTES), 0, 4); + if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.Deflate) + { + OutputStream.Write(new byte[] {20, 0}, 0, 2); //older version which is more compatible + } + else + { + OutputStream.Write(new byte[] {63, 0}, 0, 2); //version says we used PPMd or LZMA + } + HeaderFlags flags = ArchiveEncoding.Default == Encoding.UTF8 ? HeaderFlags.UTF8 : (HeaderFlags)0; + if (!OutputStream.CanSeek) + { + flags |= HeaderFlags.UsePostDataDescriptor; + if (explicitZipCompressionInfo.Compression == ZipCompressionMethod.LZMA) + { + flags |= HeaderFlags.Bit1; // eos marker + } + } + OutputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); + OutputStream.Write(BitConverter.GetBytes((ushort)explicitZipCompressionInfo.Compression), 0, 2); // zipping method + OutputStream.Write(BitConverter.GetBytes(modificationTime.DateTimeToDosTime()), 0, 4); + // zipping date and time + OutputStream.Write(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 12); + // unused CRC, un/compressed size, updated later + OutputStream.Write(BitConverter.GetBytes((ushort) encodedFilename.Length), 0, 2); // filename length + OutputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); // extra length + OutputStream.Write(encodedFilename, 0, encodedFilename.Length); + + return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length; + } + + private void WriteFooter(uint crc, uint compressed, uint uncompressed) + { + OutputStream.Write(BitConverter.GetBytes(crc), 0, 4); + OutputStream.Write(BitConverter.GetBytes(compressed), 0, 4); + OutputStream.Write(BitConverter.GetBytes(uncompressed), 0, 4); + } + + private void WriteEndRecord(uint size) + { + byte[] encodedComment = ArchiveEncoding.Default.GetBytes(zipComment); + + OutputStream.Write(new byte[] {80, 75, 5, 6, 0, 0, 0, 0}, 0, 8); + OutputStream.Write(BitConverter.GetBytes((ushort) entries.Count), 0, 2); + OutputStream.Write(BitConverter.GetBytes((ushort) entries.Count), 0, 2); + OutputStream.Write(BitConverter.GetBytes(size), 0, 4); + OutputStream.Write(BitConverter.GetBytes((uint) streamPosition), 0, 4); + OutputStream.Write(BitConverter.GetBytes((ushort) encodedComment.Length), 0, 2); + OutputStream.Write(encodedComment, 0, encodedComment.Length); + } + + #region Nested type: ZipWritingStream + + internal class ZipWritingStream : Stream + { + private readonly CRC32 crc = new CRC32(); + private readonly ZipCentralDirectoryEntry entry; + private readonly Stream originalStream; + private readonly Stream writeStream; + private readonly ZipWriter writer; + private CountingWritableSubStream counting; + private uint decompressed; + + internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry) + { + this.writer = writer; + this.originalStream = originalStream; + writeStream = GetWriteStream(originalStream); + this.writer = writer; + this.entry = entry; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + private Stream GetWriteStream(Stream writeStream) + { + counting = new CountingWritableSubStream(writeStream); + Stream output = counting; + switch (writer.zipCompressionInfo.Compression) + { + case ZipCompressionMethod.None: + { + return output; + } + case ZipCompressionMethod.Deflate: + { + return new DeflateStream(counting, CompressionMode.Compress, writer.zipCompressionInfo.DeflateCompressionLevel, + true); + } + case ZipCompressionMethod.BZip2: + { + return new BZip2Stream(counting, CompressionMode.Compress, true); + } + case ZipCompressionMethod.LZMA: + { + counting.WriteByte(9); + counting.WriteByte(20); + counting.WriteByte(5); + counting.WriteByte(0); + + LzmaStream lzmaStream = new LzmaStream(new LzmaEncoderProperties(!originalStream.CanSeek), + false, counting); + counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); + return lzmaStream; + } + case ZipCompressionMethod.PPMd: + { + counting.Write(writer.ppmdProperties.Properties, 0, 2); + return new PpmdStream(writer.ppmdProperties, counting, true); + } + default: + { + throw new NotSupportedException("CompressionMethod: " + writer.zipCompressionInfo.Compression); + } + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + writeStream.Dispose(); + entry.Crc = (uint) crc.Crc32Result; + entry.Compressed = counting.Count; + entry.Decompressed = decompressed; + if (originalStream.CanSeek) + { + originalStream.Position = entry.HeaderOffset + 6; + originalStream.WriteByte(0); + originalStream.Position = entry.HeaderOffset + 14; + writer.WriteFooter(entry.Crc, counting.Count, decompressed); + originalStream.Position = writer.streamPosition + entry.Compressed; + writer.streamPosition += entry.Compressed; + } + else + { + originalStream.Write(BitConverter.GetBytes(ZipHeaderFactory.POST_DATA_DESCRIPTOR), 0, 4); + writer.WriteFooter(entry.Crc, counting.Count, decompressed); + writer.streamPosition += entry.Compressed + 16; + } + writer.entries.Add(entry); + } + } + + public override void Flush() + { + writeStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + decompressed += (uint) count; + crc.SlurpBlock(buffer, offset, count); + writeStream.Write(buffer, offset, count); + } + } + + #endregion + } } \ No newline at end of file diff --git a/SharpCompress/project.json b/src/SharpCompress/project.json similarity index 98% rename from SharpCompress/project.json rename to src/SharpCompress/project.json index 9dcf2492..0d9b3df7 100644 --- a/SharpCompress/project.json +++ b/src/SharpCompress/project.json @@ -1,5 +1,5 @@ { - "version": "0.11.3", + "version": "0.11.4", "description": "SharpCompress Class Library", "authors": [ "Adam Hathcock" ], "tags": [ "" ], diff --git a/SharpCompress.Test/ArchiveTests.cs b/test/SharpCompress.Test/ArchiveTests.cs similarity index 97% rename from SharpCompress.Test/ArchiveTests.cs rename to test/SharpCompress.Test/ArchiveTests.cs index db9071a1..5ff6d6ce 100644 --- a/SharpCompress.Test/ArchiveTests.cs +++ b/test/SharpCompress.Test/ArchiveTests.cs @@ -1,183 +1,183 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Common; -using Xunit; - -namespace SharpCompress.Test -{ - public class ArchiveTests : TestBase - { - protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamReadExtractAll(testArchive.AsEnumerable(), compression); - } - - - protected void ArchiveStreamReadExtractAll(IEnumerable testArchives, CompressionType compression) - { - foreach (var path in testArchives) - { - ResetScratch(); - using (Stream stream = File.OpenRead(path)) - using (var archive = ArchiveFactory.Open(stream)) - { - Assert.True(archive.IsSolid); - using (var reader = archive.ExtractAllEntries()) - { - ReaderTests.UseReader(this, reader, compression); - } - VerifyFiles(); - - if (archive.Entries.First().CompressionType == CompressionType.Rar) - { - return; - } - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - } - - protected void ArchiveStreamRead(string testArchive) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamRead(testArchive.AsEnumerable()); - } - - protected void ArchiveStreamRead(params string[] testArchives) - { - ArchiveStreamRead(testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); - } - - protected void ArchiveStreamRead(IEnumerable testArchives) - { - foreach (var path in testArchives) - { - ResetScratch(); - using (Stream stream = File.OpenRead(path)) - using (var archive = ArchiveFactory.Open(stream)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - } - - protected void ArchiveFileRead(string testArchive) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveFileRead(testArchive.AsEnumerable()); - } - protected void ArchiveFileRead(IEnumerable testArchives) - { - foreach (var path in testArchives) - { - ResetScratch(); - using (var archive = ArchiveFactory.Open(path)) - { - archive.EntryExtractionBegin += archive_EntryExtractionBegin; - archive.FilePartExtractionBegin += archive_FilePartExtractionBegin; - archive.CompressedBytesRead += archive_CompressedBytesRead; - - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - } - - void archive_CompressedBytesRead(object sender, CompressedBytesReadEventArgs e) - { - Console.WriteLine("Read Compressed File Part Bytes: {0} Percentage: {1}%", - e.CurrentFilePartCompressedBytesRead, CreatePercentage(e.CurrentFilePartCompressedBytesRead, partTotal)); - - string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead, - entryTotal.Value).ToString() : "Unknown"; - Console.WriteLine("Read Compressed File Entry Bytes: {0} Percentage: {1}%", - e.CompressedBytesRead, percentage); - } - - void archive_FilePartExtractionBegin(object sender, FilePartExtractionBeginEventArgs e) - { - this.partTotal = e.Size; - Console.WriteLine("Initializing File Part Extraction: " + e.Name); - } - - void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs e) - { - this.entryTotal = e.Item.Size; - Console.WriteLine("Initializing File Entry Extraction: " + e.Item.Key); - } - - private long? entryTotal; - private long partTotal; - private long totalSize; - - protected void ArchiveFileReadEx(string testArchive) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveFileReadEx(testArchive.AsEnumerable()); - } - - /// - /// Demonstrate the TotalUncompressSize property, and the ExtractOptions.PreserveFileTime and ExtractOptions.PreserveAttributes extract options - /// - protected void ArchiveFileReadEx(IEnumerable testArchives) - { - foreach (var path in testArchives) - { - ResetScratch(); - using (var archive = ArchiveFactory.Open(path)) - { - this.totalSize = archive.TotalUncompressSize; - archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx; - archive.EntryExtractionEnd += Archive_EntryExtractionEndEx; - archive.CompressedBytesRead += Archive_CompressedBytesReadEx; - - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite | ExtractOptions.PreserveFileTime | ExtractOptions.PreserveAttributes); - } - } - VerifyFilesEx(); - } - } - - private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs e) - { - this.partTotal += e.Item.Size; - } - - private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e) - { - string percentage = this.entryTotal.HasValue ? this.CreatePercentage(e.CompressedBytesRead, this.entryTotal.Value).ToString() : "-"; - string tortalPercentage = this.CreatePercentage(this.partTotal + e.CompressedBytesRead, this.totalSize).ToString(); - Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage); - } - - private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs e) - { - this.entryTotal = e.Item.Size; - } - - private int CreatePercentage(long n, long d) - { - return (int)(((double)n / (double)d) * 100); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SharpCompress.Archive; +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test +{ + public class ArchiveTests : TestBase + { + protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + ArchiveStreamReadExtractAll(testArchive.AsEnumerable(), compression); + } + + + protected void ArchiveStreamReadExtractAll(IEnumerable testArchives, CompressionType compression) + { + foreach (var path in testArchives) + { + ResetScratch(); + using (Stream stream = File.OpenRead(path)) + using (var archive = ArchiveFactory.Open(stream)) + { + Assert.True(archive.IsSolid); + using (var reader = archive.ExtractAllEntries()) + { + ReaderTests.UseReader(this, reader, compression); + } + VerifyFiles(); + + if (archive.Entries.First().CompressionType == CompressionType.Rar) + { + return; + } + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + } + + protected void ArchiveStreamRead(string testArchive) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + ArchiveStreamRead(testArchive.AsEnumerable()); + } + + protected void ArchiveStreamRead(params string[] testArchives) + { + ArchiveStreamRead(testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); + } + + protected void ArchiveStreamRead(IEnumerable testArchives) + { + foreach (var path in testArchives) + { + ResetScratch(); + using (Stream stream = File.OpenRead(path)) + using (var archive = ArchiveFactory.Open(stream)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + } + + protected void ArchiveFileRead(string testArchive) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + ArchiveFileRead(testArchive.AsEnumerable()); + } + protected void ArchiveFileRead(IEnumerable testArchives) + { + foreach (var path in testArchives) + { + ResetScratch(); + using (var archive = ArchiveFactory.Open(path)) + { + archive.EntryExtractionBegin += archive_EntryExtractionBegin; + archive.FilePartExtractionBegin += archive_FilePartExtractionBegin; + archive.CompressedBytesRead += archive_CompressedBytesRead; + + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + } + + void archive_CompressedBytesRead(object sender, CompressedBytesReadEventArgs e) + { + Console.WriteLine("Read Compressed File Part Bytes: {0} Percentage: {1}%", + e.CurrentFilePartCompressedBytesRead, CreatePercentage(e.CurrentFilePartCompressedBytesRead, partTotal)); + + string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead, + entryTotal.Value).ToString() : "Unknown"; + Console.WriteLine("Read Compressed File Entry Bytes: {0} Percentage: {1}%", + e.CompressedBytesRead, percentage); + } + + void archive_FilePartExtractionBegin(object sender, FilePartExtractionBeginEventArgs e) + { + this.partTotal = e.Size; + Console.WriteLine("Initializing File Part Extraction: " + e.Name); + } + + void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs e) + { + this.entryTotal = e.Item.Size; + Console.WriteLine("Initializing File Entry Extraction: " + e.Item.Key); + } + + private long? entryTotal; + private long partTotal; + private long totalSize; + + protected void ArchiveFileReadEx(string testArchive) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + ArchiveFileReadEx(testArchive.AsEnumerable()); + } + + /// + /// Demonstrate the TotalUncompressSize property, and the ExtractOptions.PreserveFileTime and ExtractOptions.PreserveAttributes extract options + /// + protected void ArchiveFileReadEx(IEnumerable testArchives) + { + foreach (var path in testArchives) + { + ResetScratch(); + using (var archive = ArchiveFactory.Open(path)) + { + this.totalSize = archive.TotalUncompressSize; + archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx; + archive.EntryExtractionEnd += Archive_EntryExtractionEndEx; + archive.CompressedBytesRead += Archive_CompressedBytesReadEx; + + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite | ExtractOptions.PreserveFileTime | ExtractOptions.PreserveAttributes); + } + } + VerifyFilesEx(); + } + } + + private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs e) + { + this.partTotal += e.Item.Size; + } + + private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e) + { + string percentage = this.entryTotal.HasValue ? this.CreatePercentage(e.CompressedBytesRead, this.entryTotal.Value).ToString() : "-"; + string tortalPercentage = this.CreatePercentage(this.partTotal + e.CompressedBytesRead, this.totalSize).ToString(); + Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage); + } + + private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs e) + { + this.entryTotal = e.Item.Size; + } + + private int CreatePercentage(long n, long d) + { + return (int)(((double)n / (double)d) * 100); + } + } +} diff --git a/SharpCompress.Test/GZip/GZipArchiveTests.cs b/test/SharpCompress.Test/GZip/GZipArchiveTests.cs similarity index 97% rename from SharpCompress.Test/GZip/GZipArchiveTests.cs rename to test/SharpCompress.Test/GZip/GZipArchiveTests.cs index 043502f6..533c3ddb 100644 --- a/SharpCompress.Test/GZip/GZipArchiveTests.cs +++ b/test/SharpCompress.Test/GZip/GZipArchiveTests.cs @@ -1,59 +1,59 @@ -using System; -using System.IO; -using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Archive.GZip; -using Xunit; - -namespace SharpCompress.Test -{ - public class GZipArchiveTests : ArchiveTests - { - public GZipArchiveTests() - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void GZip_Archive_Generic() - { - ResetScratch(); - using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open)) - using (var archive = ArchiveFactory.Open(stream)) - { - var entry = archive.Entries.First(); - entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); - } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - - [Fact] - public void GZip_Archive() - { - ResetScratch(); - using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open)) - using (var archive = GZipArchive.Open(stream)) - { - var entry = archive.Entries.First(); - entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); - } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - - - [Fact] - public void GZip_Archive_NoAdd() - { - string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg"); - ResetScratch(); - using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open)) - using (var archive = GZipArchive.Open(stream)) - { - Assert.Throws(() => archive.AddEntry("jpg\\test.jpg", jpg)); - archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); - } - } - } -} +using System; +using System.IO; +using System.Linq; +using SharpCompress.Archive; +using SharpCompress.Archive.GZip; +using Xunit; + +namespace SharpCompress.Test +{ + public class GZipArchiveTests : ArchiveTests + { + public GZipArchiveTests() + { + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void GZip_Archive_Generic() + { + ResetScratch(); + using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open)) + using (var archive = ArchiveFactory.Open(stream)) + { + var entry = archive.Entries.First(); + entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); + } + CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + } + + [Fact] + public void GZip_Archive() + { + ResetScratch(); + using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open)) + using (var archive = GZipArchive.Open(stream)) + { + var entry = archive.Entries.First(); + entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); + } + CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + } + + + [Fact] + public void GZip_Archive_NoAdd() + { + string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg"); + ResetScratch(); + using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open)) + using (var archive = GZipArchive.Open(stream)) + { + Assert.Throws(() => archive.AddEntry("jpg\\test.jpg", jpg)); + archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); + } + } + } +} diff --git a/SharpCompress.Test/GZip/GZipWriterTests.cs b/test/SharpCompress.Test/GZip/GZipWriterTests.cs similarity index 97% rename from SharpCompress.Test/GZip/GZipWriterTests.cs rename to test/SharpCompress.Test/GZip/GZipWriterTests.cs index 25ff271a..775e7b06 100644 --- a/SharpCompress.Test/GZip/GZipWriterTests.cs +++ b/test/SharpCompress.Test/GZip/GZipWriterTests.cs @@ -1,60 +1,60 @@ -using System.IO; -using SharpCompress.Common; -using SharpCompress.Writer; -using SharpCompress.Writer.GZip; -using Xunit; - -namespace SharpCompress.Test -{ - public class GZipWriterTests : WriterTests - { - public GZipWriterTests() - : base(ArchiveType.GZip) - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void GZip_Writer_Generic() - { - ResetScratch(); - using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) - using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip)) - { - writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); - } - - [Fact] - public void GZip_Writer() - { - ResetScratch(); - using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) - using (var writer = new GZipWriter(stream)) - { - writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); - } - - [Fact] - public void GZip_Writer_Generic_Bad_Compression() - { - Assert.Throws(() => - { - ResetScratch(); - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"))) - using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2)) - { - writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); - - }); - } - } -} +using System.IO; +using SharpCompress.Common; +using SharpCompress.Writer; +using SharpCompress.Writer.GZip; +using Xunit; + +namespace SharpCompress.Test +{ + public class GZipWriterTests : WriterTests + { + public GZipWriterTests() + : base(ArchiveType.GZip) + { + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void GZip_Writer_Generic() + { + ResetScratch(); + using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) + using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip)) + { + writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + } + CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + } + + [Fact] + public void GZip_Writer() + { + ResetScratch(); + using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) + using (var writer = new GZipWriter(stream)) + { + writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + } + CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + } + + [Fact] + public void GZip_Writer_Generic_Bad_Compression() + { + Assert.Throws(() => + { + ResetScratch(); + using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"))) + using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2)) + { + writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + } + CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + + }); + } + } +} diff --git a/SharpCompress.Test/Rar/RarArchiveTests.cs b/test/SharpCompress.Test/Rar/RarArchiveTests.cs similarity index 97% rename from SharpCompress.Test/Rar/RarArchiveTests.cs rename to test/SharpCompress.Test/Rar/RarArchiveTests.cs index f7afea04..f451e2aa 100644 --- a/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/test/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -1,242 +1,242 @@ -using System.IO; -using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Archive.Rar; -using SharpCompress.Common; -using Xunit; - -namespace SharpCompress.Test -{ - public class RarArchiveTests : ArchiveTests - { - [Fact] - public void Rar_EncryptedFileAndHeader_Archive() - { - ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test"); - - } - - [Fact] - public void Rar_EncryptedFileOnly_Archive() - { - ReadRarPassword("Rar.encrypted_filesOnly.rar", "test"); - - } - - [Fact] - public void Rar_Encrypted_Archive() - { - ReadRarPassword("Encrypted.rar", "test"); - } - - private void ReadRarPassword(string testArchive, string password) - { - ResetScratch(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) - using (var archive = RarArchive.Open(stream, Options.KeepStreamsOpen, password)) - { - foreach (var entry in archive.Entries) - { - if (!entry.IsDirectory) - { - Assert.Equal(entry.CompressionType, CompressionType.Rar); - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Multi_Archive_Encrypted() - { - Assert.Throws(() => ArchiveFileReadPassword("EncryptedParts.part01.rar", "test")); - } - - protected void ArchiveFileReadPassword(string archiveName, string password) - { - ResetScratch(); - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, archiveName), Options.None, password)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_None_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.none.rar"); - } - - [Fact] - public void Rar_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.rar"); - } - - [Fact] - public void Rar_test_invalid_exttime_ArchiveStreamRead() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_invalid_exttime.rar"))) - { - using (var archive = ArchiveFactory.Open(stream)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - } - - [Fact] - public void Rar_Jpg_ArchiveStreamRead() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"))) - { - using (var archive = RarArchive.Open(stream, Options.LookForHeader)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - } - - [Fact] - public void Rar_IsSolidArchiveCheck() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) - { - using (var archive = RarArchive.Open(stream)) - { - Assert.False(archive.IsSolid); - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Solid_ArchiveStreamRead() - { - Assert.Throws(() => ArchiveStreamRead("Rar.solid.rar")); - } - - [Fact] - public void Rar_Solid_StreamRead_Extract_All() - { - ArchiveStreamReadExtractAll("Rar.solid.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_Multi_ArchiveStreamRead() - { - var testArchives = new string[] { "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar"}; - - - ResetScratch(); - using (var archive = RarArchive.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)))) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - [Fact] - public void RarNoneArchiveFileRead() - { - ArchiveFileRead("Rar.none.rar"); - } - - [Fact] - public void Rar_ArchiveFileRead() - { - ArchiveFileRead("Rar.rar"); - } - - [Fact] - public void Rar_ArchiveFileRead_HasDirectories() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) - { - using (var archive = RarArchive.Open(stream)) - { - Assert.False(archive.IsSolid); - Assert.True(archive.Entries.Any(entry => entry.IsDirectory)); - } - } - } - - [Fact] - public void Rar_Jpg_ArchiveFileRead() - { - ResetScratch(); - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"), Options.LookForHeader)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Solid_ArchiveFileRead() - { - Assert.Throws(() => ArchiveFileRead("Rar.solid.rar")); - } - - [Fact] - public void Rar_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar.multi.part01.rar"); - } - - [Fact] - public void Rar_IsFirstVolume_True() - { - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part01.rar"))) - { - Assert.True(archive.IsMultipartVolume()); - Assert.True(archive.IsFirstVolume()); - } - } - - [Fact] - public void Rar_IsFirstVolume_False() - { - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part03.rar"))) - { - Assert.True(archive.IsMultipartVolume()); - Assert.False(archive.IsFirstVolume()); - } - } - } -} +using System.IO; +using System.Linq; +using SharpCompress.Archive; +using SharpCompress.Archive.Rar; +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test +{ + public class RarArchiveTests : ArchiveTests + { + [Fact] + public void Rar_EncryptedFileAndHeader_Archive() + { + ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test"); + + } + + [Fact] + public void Rar_EncryptedFileOnly_Archive() + { + ReadRarPassword("Rar.encrypted_filesOnly.rar", "test"); + + } + + [Fact] + public void Rar_Encrypted_Archive() + { + ReadRarPassword("Encrypted.rar", "test"); + } + + private void ReadRarPassword(string testArchive, string password) + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) + using (var archive = RarArchive.Open(stream, Options.KeepStreamsOpen, password)) + { + foreach (var entry in archive.Entries) + { + if (!entry.IsDirectory) + { + Assert.Equal(entry.CompressionType, CompressionType.Rar); + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Multi_Archive_Encrypted() + { + Assert.Throws(() => ArchiveFileReadPassword("EncryptedParts.part01.rar", "test")); + } + + protected void ArchiveFileReadPassword(string archiveName, string password) + { + ResetScratch(); + using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, archiveName), Options.None, password)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_None_ArchiveStreamRead() + { + ArchiveStreamRead("Rar.none.rar"); + } + + [Fact] + public void Rar_ArchiveStreamRead() + { + ArchiveStreamRead("Rar.rar"); + } + + [Fact] + public void Rar_test_invalid_exttime_ArchiveStreamRead() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_invalid_exttime.rar"))) + { + using (var archive = ArchiveFactory.Open(stream)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + } + + [Fact] + public void Rar_Jpg_ArchiveStreamRead() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"))) + { + using (var archive = RarArchive.Open(stream, Options.LookForHeader)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + } + + [Fact] + public void Rar_IsSolidArchiveCheck() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) + { + using (var archive = RarArchive.Open(stream)) + { + Assert.False(archive.IsSolid); + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Solid_ArchiveStreamRead() + { + Assert.Throws(() => ArchiveStreamRead("Rar.solid.rar")); + } + + [Fact] + public void Rar_Solid_StreamRead_Extract_All() + { + ArchiveStreamReadExtractAll("Rar.solid.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_Multi_ArchiveStreamRead() + { + var testArchives = new string[] { "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar"}; + + + ResetScratch(); + using (var archive = RarArchive.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) + .Select(p => File.OpenRead(p)))) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + [Fact] + public void RarNoneArchiveFileRead() + { + ArchiveFileRead("Rar.none.rar"); + } + + [Fact] + public void Rar_ArchiveFileRead() + { + ArchiveFileRead("Rar.rar"); + } + + [Fact] + public void Rar_ArchiveFileRead_HasDirectories() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) + { + using (var archive = RarArchive.Open(stream)) + { + Assert.False(archive.IsSolid); + Assert.True(archive.Entries.Any(entry => entry.IsDirectory)); + } + } + } + + [Fact] + public void Rar_Jpg_ArchiveFileRead() + { + ResetScratch(); + using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"), Options.LookForHeader)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Solid_ArchiveFileRead() + { + Assert.Throws(() => ArchiveFileRead("Rar.solid.rar")); + } + + [Fact] + public void Rar_Multi_ArchiveFileRead() + { + ArchiveFileRead("Rar.multi.part01.rar"); + } + + [Fact] + public void Rar_IsFirstVolume_True() + { + using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part01.rar"))) + { + Assert.True(archive.IsMultipartVolume()); + Assert.True(archive.IsFirstVolume()); + } + } + + [Fact] + public void Rar_IsFirstVolume_False() + { + using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part03.rar"))) + { + Assert.True(archive.IsMultipartVolume()); + Assert.False(archive.IsFirstVolume()); + } + } + } +} diff --git a/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs b/test/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs similarity index 96% rename from SharpCompress.Test/Rar/RarHeaderFactoryTest.cs rename to test/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs index 530d5df4..be8239f4 100644 --- a/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs +++ b/test/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs @@ -1,58 +1,58 @@ -using System.IO; -using SharpCompress.Common; -using SharpCompress.Common.Rar.Headers; -using SharpCompress.IO; -using Xunit; - -namespace SharpCompress.Test.Rar -{ - /// - /// Summary description for RarFactoryReaderTest - /// - public class RarHeaderFactoryTest : TestBase - { - private RarHeaderFactory rarHeaderFactory; - - public RarHeaderFactoryTest() - { - ResetScratch(); - rarHeaderFactory = new RarHeaderFactory(StreamingMode.Seekable, Options.KeepStreamsOpen); - } - - - [Fact] - public void ReadHeaders_RecognizeEncryptedFlag() - { - - ReadEncryptedFlag("Rar.Encrypted_filesAndHeader.rar", true); - - - - } - - private void ReadEncryptedFlag(string testArchive, bool isEncrypted) - { - using (var stream = GetReaderStream(testArchive)) - foreach (var header in rarHeaderFactory.ReadHeaders(stream)) - { - if (header.HeaderType == HeaderType.ArchiveHeader) - { - Assert.Equal(isEncrypted, rarHeaderFactory.IsEncrypted); - break; - } - } - } - - [Fact] - public void ReadHeaders_RecognizeNoEncryptedFlag() - { - ReadEncryptedFlag("Rar.rar", false); - } - - private FileStream GetReaderStream(string testArchive) - { - return new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), - FileMode.Open); - } - } -} +using System.IO; +using SharpCompress.Common; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; +using Xunit; + +namespace SharpCompress.Test.Rar +{ + /// + /// Summary description for RarFactoryReaderTest + /// + public class RarHeaderFactoryTest : TestBase + { + private RarHeaderFactory rarHeaderFactory; + + public RarHeaderFactoryTest() + { + ResetScratch(); + rarHeaderFactory = new RarHeaderFactory(StreamingMode.Seekable, Options.KeepStreamsOpen); + } + + + [Fact] + public void ReadHeaders_RecognizeEncryptedFlag() + { + + ReadEncryptedFlag("Rar.Encrypted_filesAndHeader.rar", true); + + + + } + + private void ReadEncryptedFlag(string testArchive, bool isEncrypted) + { + using (var stream = GetReaderStream(testArchive)) + foreach (var header in rarHeaderFactory.ReadHeaders(stream)) + { + if (header.HeaderType == HeaderType.ArchiveHeader) + { + Assert.Equal(isEncrypted, rarHeaderFactory.IsEncrypted); + break; + } + } + } + + [Fact] + public void ReadHeaders_RecognizeNoEncryptedFlag() + { + ReadEncryptedFlag("Rar.rar", false); + } + + private FileStream GetReaderStream(string testArchive) + { + return new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), + FileMode.Open); + } + } +} diff --git a/SharpCompress.Test/Rar/RarReaderTests.cs b/test/SharpCompress.Test/Rar/RarReaderTests.cs similarity index 97% rename from SharpCompress.Test/Rar/RarReaderTests.cs rename to test/SharpCompress.Test/Rar/RarReaderTests.cs index 17bf0544..a114835b 100644 --- a/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/test/SharpCompress.Test/Rar/RarReaderTests.cs @@ -1,254 +1,254 @@ -using System.IO; -using System.Linq; -using SharpCompress.Common; -using SharpCompress.Reader; -using SharpCompress.Reader.Rar; -using Xunit; - -namespace SharpCompress.Test -{ - public class RarReaderTests : ReaderTests - { - [Fact] - public void Rar_Multi_Reader() - { - var testArchives = new string[] { "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar"}; - - - ResetScratch(); - using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)))) - { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - //[Fact] - public void Rar_Multi_Reader_Encrypted() - { - var testArchives = new string[] { "EncryptedParts.part01.rar", - "EncryptedParts.part02.rar", - "EncryptedParts.part03.rar", - "EncryptedParts.part04.rar", - "EncryptedParts.part05.rar", - "EncryptedParts.part06.rar"}; - - - ResetScratch(); - using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)))) - { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Multi_Reader_Delete_Files() - { - var testArchives = new string[] { "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar"}; - - - ResetScratch(); - - foreach (var file in testArchives) - { - File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file)); - } - var streams = testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)).Select(File.OpenRead).ToList(); - using (var reader = RarReader.Open(streams)) - { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - foreach (var stream in streams) - { - stream.Dispose(); - } - VerifyFiles(); - - foreach (var file in testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))) - { - File.Delete(file); - } - } - - [Fact] - public void Rar_None_Reader() - { - Read("Rar.none.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_Reader() - { - Read("Rar.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_EncryptedFileAndHeader_Reader() - { - ReadRar("Rar.encrypted_filesAndHeader.rar", "test"); - - } - - [Fact] - public void Rar_EncryptedFileOnly_Reader() - { - ReadRar("Rar.encrypted_filesOnly.rar", "test"); - - } - - [Fact] - public void Rar_Encrypted_Reader() - { - ReadRar("Encrypted.rar", "test"); - } - - private void ReadRar(string testArchive, string password) - { - ResetScratch(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) - using (var reader = RarReader.Open(stream, password)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Entry_Stream() - { - ResetScratch(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) - using (var reader = RarReader.Open(stream)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); - using (var entryStream = reader.OpenEntryStream()) - { - string file = Path.GetFileName(reader.Entry.Key); - string folder = Path.GetDirectoryName(reader.Entry.Key); - string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - string destinationFileName = Path.Combine(destdir, file); - - using (FileStream fs = File.OpenWrite(destinationFileName)) - { - entryStream.TransferTo(fs); - } - } - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Reader_Audio_program() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Audio_program.rar"))) - using (var reader = RarReader.Open(stream, Options.LookForHeader)) - { - while (reader.MoveToNextEntry()) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - CompareFilesByPath(Path.Combine(SCRATCH_FILES_PATH, "test.dat"), - Path.Combine(MISC_TEST_FILES_PATH, "test.dat")); - } - - [Fact] - public void Rar_Jpg_Reader() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"))) - using (var reader = RarReader.Open(stream, Options.LookForHeader)) - { - while (reader.MoveToNextEntry()) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Solid_Reader() - { - Read("Rar.solid.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_Solid_Skip_Reader() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.solid.rar"))) - using (var reader = RarReader.Open(stream, Options.LookForHeader)) - { - while (reader.MoveToNextEntry()) - { - if (reader.Entry.Key.Contains("jpg")) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - } - - [Fact] - public void Rar_Reader_Skip() - { - ResetScratch(); - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) - using (var reader = RarReader.Open(stream, Options.LookForHeader)) - { - while (reader.MoveToNextEntry()) - { - if (reader.Entry.Key.Contains("jpg")) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - } - } -} +using System.IO; +using System.Linq; +using SharpCompress.Common; +using SharpCompress.Reader; +using SharpCompress.Reader.Rar; +using Xunit; + +namespace SharpCompress.Test +{ + public class RarReaderTests : ReaderTests + { + [Fact] + public void Rar_Multi_Reader() + { + var testArchives = new string[] { "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar"}; + + + ResetScratch(); + using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) + .Select(p => File.OpenRead(p)))) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + //[Fact] + public void Rar_Multi_Reader_Encrypted() + { + var testArchives = new string[] { "EncryptedParts.part01.rar", + "EncryptedParts.part02.rar", + "EncryptedParts.part03.rar", + "EncryptedParts.part04.rar", + "EncryptedParts.part05.rar", + "EncryptedParts.part06.rar"}; + + + ResetScratch(); + using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) + .Select(p => File.OpenRead(p)))) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Multi_Reader_Delete_Files() + { + var testArchives = new string[] { "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar"}; + + + ResetScratch(); + + foreach (var file in testArchives) + { + File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file)); + } + var streams = testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)).Select(File.OpenRead).ToList(); + using (var reader = RarReader.Open(streams)) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + foreach (var stream in streams) + { + stream.Dispose(); + } + VerifyFiles(); + + foreach (var file in testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))) + { + File.Delete(file); + } + } + + [Fact] + public void Rar_None_Reader() + { + Read("Rar.none.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_Reader() + { + Read("Rar.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_EncryptedFileAndHeader_Reader() + { + ReadRar("Rar.encrypted_filesAndHeader.rar", "test"); + + } + + [Fact] + public void Rar_EncryptedFileOnly_Reader() + { + ReadRar("Rar.encrypted_filesOnly.rar", "test"); + + } + + [Fact] + public void Rar_Encrypted_Reader() + { + ReadRar("Encrypted.rar", "test"); + } + + private void ReadRar(string testArchive, string password) + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) + using (var reader = RarReader.Open(stream, password)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Entry_Stream() + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) + using (var reader = RarReader.Open(stream)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); + using (var entryStream = reader.OpenEntryStream()) + { + string file = Path.GetFileName(reader.Entry.Key); + string folder = Path.GetDirectoryName(reader.Entry.Key); + string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); + if (!Directory.Exists(destdir)) + { + Directory.CreateDirectory(destdir); + } + string destinationFileName = Path.Combine(destdir, file); + + using (FileStream fs = File.OpenWrite(destinationFileName)) + { + entryStream.TransferTo(fs); + } + } + } + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Reader_Audio_program() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Audio_program.rar"))) + using (var reader = RarReader.Open(stream, Options.LookForHeader)) + { + while (reader.MoveToNextEntry()) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + CompareFilesByPath(Path.Combine(SCRATCH_FILES_PATH, "test.dat"), + Path.Combine(MISC_TEST_FILES_PATH, "test.dat")); + } + + [Fact] + public void Rar_Jpg_Reader() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"))) + using (var reader = RarReader.Open(stream, Options.LookForHeader)) + { + while (reader.MoveToNextEntry()) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Solid_Reader() + { + Read("Rar.solid.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_Solid_Skip_Reader() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.solid.rar"))) + using (var reader = RarReader.Open(stream, Options.LookForHeader)) + { + while (reader.MoveToNextEntry()) + { + if (reader.Entry.Key.Contains("jpg")) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + } + + [Fact] + public void Rar_Reader_Skip() + { + ResetScratch(); + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"))) + using (var reader = RarReader.Open(stream, Options.LookForHeader)) + { + while (reader.MoveToNextEntry()) + { + if (reader.Entry.Key.Contains("jpg")) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Rar); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + } + } +} diff --git a/SharpCompress.Test/ReaderTests.cs b/test/SharpCompress.Test/ReaderTests.cs similarity index 88% rename from SharpCompress.Test/ReaderTests.cs rename to test/SharpCompress.Test/ReaderTests.cs index a6939110..205c3cbf 100644 --- a/SharpCompress.Test/ReaderTests.cs +++ b/test/SharpCompress.Test/ReaderTests.cs @@ -1,43 +1,43 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Reader; -using Xunit; - -namespace SharpCompress.Test -{ - public class ReaderTests : TestBase - { - protected void Read(string testArchive, CompressionType expectedCompression) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - Read(testArchive.AsEnumerable(), expectedCompression); - } - - protected void Read(IEnumerable testArchives, CompressionType expectedCompression) - { - foreach (var path in testArchives) - { - using (Stream stream = File.OpenRead(path)) - using (IReader reader = ReaderFactory.Open(stream)) - { - UseReader(this, reader, expectedCompression); - } - } - } - - public static void UseReader(TestBase test, IReader reader, CompressionType expectedCompression) - { - test.ResetScratch(); - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, expectedCompression); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - test.VerifyFiles(); - } - } -} +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Reader; +using Xunit; + +namespace SharpCompress.Test +{ + public class ReaderTests : TestBase + { + protected void Read(string testArchive, CompressionType expectedCompression) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + Read(testArchive.AsEnumerable(), expectedCompression); + } + + protected void Read(IEnumerable testArchives, CompressionType expectedCompression) + { + foreach (var path in testArchives) + { + using (Stream stream = File.OpenRead(path)) + using (IReader reader = ReaderFactory.Open(stream)) + { + UseReader(this, reader, expectedCompression); + } + } + } + + public static void UseReader(TestBase test, IReader reader, CompressionType expectedCompression) + { + test.ResetScratch(); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, expectedCompression); + reader.WriteEntryToDirectory(test.SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + test.VerifyFiles(); + } + } +} diff --git a/SharpCompress.Test/RewindableStreamTest.cs b/test/SharpCompress.Test/RewindableStreamTest.cs similarity index 97% rename from SharpCompress.Test/RewindableStreamTest.cs rename to test/SharpCompress.Test/RewindableStreamTest.cs index 4a92f607..991b1acf 100644 --- a/SharpCompress.Test/RewindableStreamTest.cs +++ b/test/SharpCompress.Test/RewindableStreamTest.cs @@ -1,83 +1,83 @@ -using System.IO; -using SharpCompress.IO; -using Xunit; - -namespace SharpCompress.Test -{ - public class RewindableStreamTest - { - [Fact] - public void TestRewind() - { - MemoryStream ms = new MemoryStream(); - BinaryWriter bw = new BinaryWriter(ms); - bw.Write(1); - bw.Write(2); - bw.Write(3); - bw.Write(4); - bw.Write(5); - bw.Write(6); - bw.Write(7); - bw.Flush(); - ms.Position = 0; - RewindableStream stream = new RewindableStream(ms); - stream.StartRecording(); - BinaryReader br = new BinaryReader(stream); - Assert.Equal(br.ReadInt32(), 1); - Assert.Equal(br.ReadInt32(), 2); - Assert.Equal(br.ReadInt32(), 3); - Assert.Equal(br.ReadInt32(), 4); - stream.Rewind(true); - stream.StartRecording(); - Assert.Equal(br.ReadInt32(), 1); - Assert.Equal(br.ReadInt32(), 2); - Assert.Equal(br.ReadInt32(), 3); - Assert.Equal(br.ReadInt32(), 4); - Assert.Equal(br.ReadInt32(), 5); - Assert.Equal(br.ReadInt32(), 6); - Assert.Equal(br.ReadInt32(), 7); - stream.Rewind(true); - stream.StartRecording(); - Assert.Equal(br.ReadInt32(), 1); - Assert.Equal(br.ReadInt32(), 2); - Assert.Equal(br.ReadInt32(), 3); - Assert.Equal(br.ReadInt32(), 4); - } - - [Fact] - public void TestIncompleteRewind() - { - MemoryStream ms = new MemoryStream(); - BinaryWriter bw = new BinaryWriter(ms); - bw.Write(1); - bw.Write(2); - bw.Write(3); - bw.Write(4); - bw.Write(5); - bw.Write(6); - bw.Write(7); - bw.Flush(); - ms.Position = 0; - RewindableStream stream = new RewindableStream(ms); - stream.StartRecording(); - BinaryReader br = new BinaryReader(stream); - Assert.Equal(br.ReadInt32(), 1); - Assert.Equal(br.ReadInt32(), 2); - Assert.Equal(br.ReadInt32(), 3); - Assert.Equal(br.ReadInt32(), 4); - stream.Rewind(true); - Assert.Equal(br.ReadInt32(), 1); - Assert.Equal(br.ReadInt32(), 2); - stream.StartRecording(); - Assert.Equal(br.ReadInt32(), 3); - Assert.Equal(br.ReadInt32(), 4); - Assert.Equal(br.ReadInt32(), 5); - stream.Rewind(true); - Assert.Equal(br.ReadInt32(), 3); - Assert.Equal(br.ReadInt32(), 4); - Assert.Equal(br.ReadInt32(), 5); - Assert.Equal(br.ReadInt32(), 6); - Assert.Equal(br.ReadInt32(), 7); - } - } -} +using System.IO; +using SharpCompress.IO; +using Xunit; + +namespace SharpCompress.Test +{ + public class RewindableStreamTest + { + [Fact] + public void TestRewind() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + bw.Write(1); + bw.Write(2); + bw.Write(3); + bw.Write(4); + bw.Write(5); + bw.Write(6); + bw.Write(7); + bw.Flush(); + ms.Position = 0; + RewindableStream stream = new RewindableStream(ms); + stream.StartRecording(); + BinaryReader br = new BinaryReader(stream); + Assert.Equal(br.ReadInt32(), 1); + Assert.Equal(br.ReadInt32(), 2); + Assert.Equal(br.ReadInt32(), 3); + Assert.Equal(br.ReadInt32(), 4); + stream.Rewind(true); + stream.StartRecording(); + Assert.Equal(br.ReadInt32(), 1); + Assert.Equal(br.ReadInt32(), 2); + Assert.Equal(br.ReadInt32(), 3); + Assert.Equal(br.ReadInt32(), 4); + Assert.Equal(br.ReadInt32(), 5); + Assert.Equal(br.ReadInt32(), 6); + Assert.Equal(br.ReadInt32(), 7); + stream.Rewind(true); + stream.StartRecording(); + Assert.Equal(br.ReadInt32(), 1); + Assert.Equal(br.ReadInt32(), 2); + Assert.Equal(br.ReadInt32(), 3); + Assert.Equal(br.ReadInt32(), 4); + } + + [Fact] + public void TestIncompleteRewind() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + bw.Write(1); + bw.Write(2); + bw.Write(3); + bw.Write(4); + bw.Write(5); + bw.Write(6); + bw.Write(7); + bw.Flush(); + ms.Position = 0; + RewindableStream stream = new RewindableStream(ms); + stream.StartRecording(); + BinaryReader br = new BinaryReader(stream); + Assert.Equal(br.ReadInt32(), 1); + Assert.Equal(br.ReadInt32(), 2); + Assert.Equal(br.ReadInt32(), 3); + Assert.Equal(br.ReadInt32(), 4); + stream.Rewind(true); + Assert.Equal(br.ReadInt32(), 1); + Assert.Equal(br.ReadInt32(), 2); + stream.StartRecording(); + Assert.Equal(br.ReadInt32(), 3); + Assert.Equal(br.ReadInt32(), 4); + Assert.Equal(br.ReadInt32(), 5); + stream.Rewind(true); + Assert.Equal(br.ReadInt32(), 3); + Assert.Equal(br.ReadInt32(), 4); + Assert.Equal(br.ReadInt32(), 5); + Assert.Equal(br.ReadInt32(), 6); + Assert.Equal(br.ReadInt32(), 7); + } + } +} diff --git a/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/test/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs similarity index 96% rename from SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs rename to test/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index 18df658c..59a8340d 100644 --- a/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/test/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -1,76 +1,76 @@ - -using System; -using SharpCompress.Common; -using Xunit; - -namespace SharpCompress.Test -{ - public class SevenZipArchiveTests : ArchiveTests - { - [Fact] - public void SevenZipArchive_LZMA_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA.7z"); - } - - [Fact] - public void SevenZipArchive_LZMA_PathRead() - { - ArchiveFileRead("7Zip.LZMA.7z"); - } - - [Fact] - public void SevenZipArchive_PPMd_StreamRead() - { - ArchiveStreamRead("7Zip.PPMd.7z"); - } - - [Fact] - public void SevenZipArchive_PPMd_StreamRead_Extract_All() - { - ArchiveStreamReadExtractAll("7Zip.PPMd.7z", CompressionType.PPMd); - } - - [Fact] - public void SevenZipArchive_PPMd_PathRead() - { - ArchiveFileRead("7Zip.PPMd.7z"); - } - [Fact] - public void SevenZipArchive_LZMA2_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA2.7z"); - } - - [Fact] - public void SevenZipArchive_LZMA2_PathRead() - { - ArchiveFileRead("7Zip.LZMA2.7z"); - } - [Fact] - public void SevenZipArchive_BZip2_StreamRead() - { - ArchiveStreamRead("7Zip.BZip2.7z"); - } - - [Fact] - public void SevenZipArchive_BZip2_PathRead() - { - ArchiveFileRead("7Zip.BZip2.7z"); - } - - [Fact] - public void SevenZipArchive_LZMA_Time_Attributes_PathRead() - { - ArchiveFileReadEx("7Zip.LZMA.7z"); - } - - [Fact] - public void SevenZipArchive_BZip2_Split() - { - Assert.Throws(() => ArchiveStreamRead("Original.7z.001", "Original.7z.002", - "Original.7z.003", "Original.7z.004", "Original.7z.005", - "Original.7z.006", "Original.7z.007")); - } - } -} + +using System; +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test +{ + public class SevenZipArchiveTests : ArchiveTests + { + [Fact] + public void SevenZipArchive_LZMA_StreamRead() + { + ArchiveStreamRead("7Zip.LZMA.7z"); + } + + [Fact] + public void SevenZipArchive_LZMA_PathRead() + { + ArchiveFileRead("7Zip.LZMA.7z"); + } + + [Fact] + public void SevenZipArchive_PPMd_StreamRead() + { + ArchiveStreamRead("7Zip.PPMd.7z"); + } + + [Fact] + public void SevenZipArchive_PPMd_StreamRead_Extract_All() + { + ArchiveStreamReadExtractAll("7Zip.PPMd.7z", CompressionType.PPMd); + } + + [Fact] + public void SevenZipArchive_PPMd_PathRead() + { + ArchiveFileRead("7Zip.PPMd.7z"); + } + [Fact] + public void SevenZipArchive_LZMA2_StreamRead() + { + ArchiveStreamRead("7Zip.LZMA2.7z"); + } + + [Fact] + public void SevenZipArchive_LZMA2_PathRead() + { + ArchiveFileRead("7Zip.LZMA2.7z"); + } + [Fact] + public void SevenZipArchive_BZip2_StreamRead() + { + ArchiveStreamRead("7Zip.BZip2.7z"); + } + + [Fact] + public void SevenZipArchive_BZip2_PathRead() + { + ArchiveFileRead("7Zip.BZip2.7z"); + } + + [Fact] + public void SevenZipArchive_LZMA_Time_Attributes_PathRead() + { + ArchiveFileReadEx("7Zip.LZMA.7z"); + } + + [Fact] + public void SevenZipArchive_BZip2_Split() + { + Assert.Throws(() => ArchiveStreamRead("Original.7z.001", "Original.7z.002", + "Original.7z.003", "Original.7z.004", "Original.7z.005", + "Original.7z.006", "Original.7z.007")); + } + } +} diff --git a/SharpCompress.Test/SharpCompress.Test.xproj b/test/SharpCompress.Test/SharpCompress.Test.xproj similarity index 100% rename from SharpCompress.Test/SharpCompress.Test.xproj rename to test/SharpCompress.Test/SharpCompress.Test.xproj diff --git a/SharpCompress.Test/Streams/StreamTests.cs b/test/SharpCompress.Test/Streams/StreamTests.cs similarity index 96% rename from SharpCompress.Test/Streams/StreamTests.cs rename to test/SharpCompress.Test/Streams/StreamTests.cs index ea10984c..d49cb5b3 100644 --- a/SharpCompress.Test/Streams/StreamTests.cs +++ b/test/SharpCompress.Test/Streams/StreamTests.cs @@ -1,20 +1,20 @@ -using System.IO; -using SharpCompress.Compressor.LZMA; -using Xunit; - -namespace SharpCompress.Test.Streams -{ - public class StreamTests - { - [Fact] - public void TestLzma2Decompress1Byte() - { - byte[] properties = new byte[] { 0x01 }; - byte[] compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 }; - MemoryStream lzma2Stream = new MemoryStream(compressedData); - - LzmaStream decompressor = new LzmaStream(properties, lzma2Stream, 5, 1); - Assert.Equal('X', decompressor.ReadByte()); - } - } +using System.IO; +using SharpCompress.Compressor.LZMA; +using Xunit; + +namespace SharpCompress.Test.Streams +{ + public class StreamTests + { + [Fact] + public void TestLzma2Decompress1Byte() + { + byte[] properties = new byte[] { 0x01 }; + byte[] compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 }; + MemoryStream lzma2Stream = new MemoryStream(compressedData); + + LzmaStream decompressor = new LzmaStream(properties, lzma2Stream, 5, 1); + Assert.Equal('X', decompressor.ReadByte()); + } + } } \ No newline at end of file diff --git a/SharpCompress.Test/Tar/TarArchiveTests.cs b/test/SharpCompress.Test/Tar/TarArchiveTests.cs similarity index 97% rename from SharpCompress.Test/Tar/TarArchiveTests.cs rename to test/SharpCompress.Test/Tar/TarArchiveTests.cs index 1528c2e1..1cb5ebd0 100644 --- a/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/test/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -1,149 +1,149 @@ - -using System.IO; -using System.Linq; -using SharpCompress.Archive; -using SharpCompress.Archive.Tar; -using SharpCompress.Common; -using SharpCompress.Writer; -using Xunit; - -namespace SharpCompress.Test -{ - public class TarArchiveTests : ArchiveTests - { - public TarArchiveTests() - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void TarArchiveStreamRead() - { - ArchiveStreamRead("Tar.tar"); - } - - [Fact] - public void TarArchivePathRead() - { - ArchiveFileRead("Tar.tar"); - } - - - [Fact] - public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne() - { - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar"); - using (var archive = TarArchive.Open(unmodified)) - { - Assert.Equal(5, archive.Entries.Count); - Assert.True(archive.Entries.Any(entry => entry.Key == "very long filename/")); - Assert.True(archive.Entries.Any(entry => entry.Key == "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg")); - Assert.True(archive.Entries.Any(entry => entry.Key == "z_file 1.txt")); - Assert.True(archive.Entries.Any(entry => entry.Key == "z_file 2.txt")); - Assert.True(archive.Entries.Any(entry => entry.Key == "z_file 3.txt")); - } - } - - [Fact] - public void Tar_VeryLongFilepathReadback() - { - string archive = "Tar_VeryLongFilepathReadback.tar"; - - ResetScratch(); - - // create a very long filename - string longFilename = ""; - for (int i = 0; i < 600; i = longFilename.Length) - longFilename += i.ToString("D10") + "-"; - longFilename += ".txt"; - - // Step 1: create a tar file containing a file with a long name - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) - using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None)) - using (Stream inputStream = new MemoryStream()) - { - StreamWriter sw = new StreamWriter(inputStream); - sw.Write("dummy filecontent"); - sw.Flush(); - - inputStream.Position = 0; - writer.Write(longFilename, inputStream, null); - } - - // Step 2: check if the written tar file can be read correctly - string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); - using (var archive2 = TarArchive.Open(unmodified)) - { - Assert.Equal(1, archive2.Entries.Count); - Assert.True(archive2.Entries.Any(entry => entry.Key == longFilename)); - - foreach (var entry in archive2.Entries) - Assert.Equal("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine()); - } - } - - [Fact] - public void Tar_UstarArchivePathReadLongName() - { - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar"); - using(var archive = TarArchive.Open(unmodified)) - { - Assert.Equal(6, archive.Entries.Count); - Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/")); - Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Some file with veeeeeeeeeery loooooooooong name")); - Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/")); - Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name")); - Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/")); - Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name")); - } - } - - [Fact] - public void Tar_Create_New() - { - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); - - base.ResetScratch(); - using (var archive = TarArchive.Create()) - { - archive.AddAllFromDirectory(ORIGINAL_FILES_PATH); - archive.SaveTo(scratchPath, CompressionType.None); - } - CompareArchivesByPath(unmodified, scratchPath); - } - [Fact] - public void Tar_Random_Write_Add() - { - string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg"); - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); - - base.ResetScratch(); - using (var archive = TarArchive.Open(unmodified)) - { - archive.AddEntry("jpg\\test.jpg", jpg); - archive.SaveTo(scratchPath, CompressionType.None); - } - CompareArchivesByPath(modified, scratchPath); - } - - [Fact] - public void Tar_Random_Write_Remove() - { - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); - - base.ResetScratch(); - using (var archive = TarArchive.Open(unmodified)) - { - var entry = archive.Entries.Where(x => x.Key.EndsWith("jpg")).Single(); - archive.RemoveEntry(entry); - archive.SaveTo(scratchPath, CompressionType.None); - } - CompareArchivesByPath(modified, scratchPath); - } - } -} + +using System.IO; +using System.Linq; +using SharpCompress.Archive; +using SharpCompress.Archive.Tar; +using SharpCompress.Common; +using SharpCompress.Writer; +using Xunit; + +namespace SharpCompress.Test +{ + public class TarArchiveTests : ArchiveTests + { + public TarArchiveTests() + { + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void TarArchiveStreamRead() + { + ArchiveStreamRead("Tar.tar"); + } + + [Fact] + public void TarArchivePathRead() + { + ArchiveFileRead("Tar.tar"); + } + + + [Fact] + public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne() + { + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar"); + using (var archive = TarArchive.Open(unmodified)) + { + Assert.Equal(5, archive.Entries.Count); + Assert.True(archive.Entries.Any(entry => entry.Key == "very long filename/")); + Assert.True(archive.Entries.Any(entry => entry.Key == "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg")); + Assert.True(archive.Entries.Any(entry => entry.Key == "z_file 1.txt")); + Assert.True(archive.Entries.Any(entry => entry.Key == "z_file 2.txt")); + Assert.True(archive.Entries.Any(entry => entry.Key == "z_file 3.txt")); + } + } + + [Fact] + public void Tar_VeryLongFilepathReadback() + { + string archive = "Tar_VeryLongFilepathReadback.tar"; + + ResetScratch(); + + // create a very long filename + string longFilename = ""; + for (int i = 0; i < 600; i = longFilename.Length) + longFilename += i.ToString("D10") + "-"; + longFilename += ".txt"; + + // Step 1: create a tar file containing a file with a long name + using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) + using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None)) + using (Stream inputStream = new MemoryStream()) + { + StreamWriter sw = new StreamWriter(inputStream); + sw.Write("dummy filecontent"); + sw.Flush(); + + inputStream.Position = 0; + writer.Write(longFilename, inputStream, null); + } + + // Step 2: check if the written tar file can be read correctly + string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); + using (var archive2 = TarArchive.Open(unmodified)) + { + Assert.Equal(1, archive2.Entries.Count); + Assert.True(archive2.Entries.Any(entry => entry.Key == longFilename)); + + foreach (var entry in archive2.Entries) + Assert.Equal("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine()); + } + } + + [Fact] + public void Tar_UstarArchivePathReadLongName() + { + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar"); + using(var archive = TarArchive.Open(unmodified)) + { + Assert.Equal(6, archive.Entries.Count); + Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/")); + Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Some file with veeeeeeeeeery loooooooooong name")); + Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/")); + Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name")); + Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/")); + Assert.True(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name")); + } + } + + [Fact] + public void Tar_Create_New() + { + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); + + base.ResetScratch(); + using (var archive = TarArchive.Create()) + { + archive.AddAllFromDirectory(ORIGINAL_FILES_PATH); + archive.SaveTo(scratchPath, CompressionType.None); + } + CompareArchivesByPath(unmodified, scratchPath); + } + [Fact] + public void Tar_Random_Write_Add() + { + string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg"); + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); + + base.ResetScratch(); + using (var archive = TarArchive.Open(unmodified)) + { + archive.AddEntry("jpg\\test.jpg", jpg); + archive.SaveTo(scratchPath, CompressionType.None); + } + CompareArchivesByPath(modified, scratchPath); + } + + [Fact] + public void Tar_Random_Write_Remove() + { + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); + + base.ResetScratch(); + using (var archive = TarArchive.Open(unmodified)) + { + var entry = archive.Entries.Where(x => x.Key.EndsWith("jpg")).Single(); + archive.RemoveEntry(entry); + archive.SaveTo(scratchPath, CompressionType.None); + } + CompareArchivesByPath(modified, scratchPath); + } + } +} diff --git a/SharpCompress.Test/Tar/TarReaderTests.cs b/test/SharpCompress.Test/Tar/TarReaderTests.cs similarity index 97% rename from SharpCompress.Test/Tar/TarReaderTests.cs rename to test/SharpCompress.Test/Tar/TarReaderTests.cs index 4c9150f9..b2c4a092 100644 --- a/SharpCompress.Test/Tar/TarReaderTests.cs +++ b/test/SharpCompress.Test/Tar/TarReaderTests.cs @@ -1,91 +1,91 @@ -using System.Collections.Generic; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Reader.Tar; -using Xunit; - -namespace SharpCompress.Test -{ - public class TarReaderTests : ReaderTests - { - public TarReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void Tar_Reader() - { - Read("Tar.tar", CompressionType.None); - } - - [Fact] - public void Tar_BZip2_Reader() - { - Read("Tar.tar.bz2", CompressionType.BZip2); - } - - [Fact] - public void Tar_GZip_Reader() - { - Read("Tar.tar.gz", CompressionType.GZip); - } - - [Fact] - public void Tar_BZip2_Entry_Stream() - { - ResetScratch(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) - using (var reader = TarReader.Open(stream)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.BZip2); - using (var entryStream = reader.OpenEntryStream()) - { - string file = Path.GetFileName(reader.Entry.Key); - string folder = Path.GetDirectoryName(reader.Entry.Key); - string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - string destinationFileName = Path.Combine(destdir, file); - - using (FileStream fs = File.OpenWrite(destinationFileName)) - { - entryStream.TransferTo(fs); - } - } - } - } - } - VerifyFiles(); - } - - [Fact] - public void Tar_BZip2_Skip_Entry_Stream() - { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) - using (var reader = TarReader.Open(stream)) - { - List names = new List(); - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.BZip2); - using (var entryStream = reader.OpenEntryStream()) - { - entryStream.SkipEntry(); - names.Add(reader.Entry.Key); - } - } - } - Assert.Equal(names.Count, 3); - } - } - } -} +using System.Collections.Generic; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Reader.Tar; +using Xunit; + +namespace SharpCompress.Test +{ + public class TarReaderTests : ReaderTests + { + public TarReaderTests() + { + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void Tar_Reader() + { + Read("Tar.tar", CompressionType.None); + } + + [Fact] + public void Tar_BZip2_Reader() + { + Read("Tar.tar.bz2", CompressionType.BZip2); + } + + [Fact] + public void Tar_GZip_Reader() + { + Read("Tar.tar.gz", CompressionType.GZip); + } + + [Fact] + public void Tar_BZip2_Entry_Stream() + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) + using (var reader = TarReader.Open(stream)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.BZip2); + using (var entryStream = reader.OpenEntryStream()) + { + string file = Path.GetFileName(reader.Entry.Key); + string folder = Path.GetDirectoryName(reader.Entry.Key); + string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); + if (!Directory.Exists(destdir)) + { + Directory.CreateDirectory(destdir); + } + string destinationFileName = Path.Combine(destdir, file); + + using (FileStream fs = File.OpenWrite(destinationFileName)) + { + entryStream.TransferTo(fs); + } + } + } + } + } + VerifyFiles(); + } + + [Fact] + public void Tar_BZip2_Skip_Entry_Stream() + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) + using (var reader = TarReader.Open(stream)) + { + List names = new List(); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.BZip2); + using (var entryStream = reader.OpenEntryStream()) + { + entryStream.SkipEntry(); + names.Add(reader.Entry.Key); + } + } + } + Assert.Equal(names.Count, 3); + } + } + } +} diff --git a/SharpCompress.Test/Tar/TarWriterTests.cs b/test/SharpCompress.Test/Tar/TarWriterTests.cs similarity index 96% rename from SharpCompress.Test/Tar/TarWriterTests.cs rename to test/SharpCompress.Test/Tar/TarWriterTests.cs index 12fd736f..c4f783bd 100644 --- a/SharpCompress.Test/Tar/TarWriterTests.cs +++ b/test/SharpCompress.Test/Tar/TarWriterTests.cs @@ -1,32 +1,32 @@ -using SharpCompress.Common; -using Xunit; - -namespace SharpCompress.Test -{ - public class TarWriterTests : WriterTests - { - public TarWriterTests() - : base(ArchiveType.Tar) - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void Tar_Writer() - { - Write(CompressionType.None, "Tar.noEmptyDirs.tar", "Tar.noEmptyDirs.tar"); - } - - [Fact] - public void Tar_BZip2_Writer() - { - Write(CompressionType.BZip2, "Tar.noEmptyDirs.tar.bz2", "Tar.noEmptyDirs.tar.bz2"); - } - - [Fact] - public void Tar_Rar_Write() - { - Assert.Throws(() => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")); - } - } -} +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test +{ + public class TarWriterTests : WriterTests + { + public TarWriterTests() + : base(ArchiveType.Tar) + { + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void Tar_Writer() + { + Write(CompressionType.None, "Tar.noEmptyDirs.tar", "Tar.noEmptyDirs.tar"); + } + + [Fact] + public void Tar_BZip2_Writer() + { + Write(CompressionType.BZip2, "Tar.noEmptyDirs.tar.bz2", "Tar.noEmptyDirs.tar.bz2"); + } + + [Fact] + public void Tar_Rar_Write() + { + Assert.Throws(() => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")); + } + } +} diff --git a/SharpCompress.Test/TestBase.cs b/test/SharpCompress.Test/TestBase.cs similarity index 97% rename from SharpCompress.Test/TestBase.cs rename to test/SharpCompress.Test/TestBase.cs index e1dc9324..af337f90 100644 --- a/SharpCompress.Test/TestBase.cs +++ b/test/SharpCompress.Test/TestBase.cs @@ -1,233 +1,233 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Extensions.PlatformAbstractions; -using SharpCompress.Common; -using SharpCompress.Reader; -using Xunit; - -namespace SharpCompress.Test -{ - public class TestBase - { - protected string SOLUTION_BASE_PATH=null; - protected string TEST_ARCHIVES_PATH; - protected string ORIGINAL_FILES_PATH; - protected string MISC_TEST_FILES_PATH; - protected string SCRATCH_FILES_PATH; - protected string SCRATCH2_FILES_PATH; - protected IEnumerable GetRarArchives() - { - yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.none.rar"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.solid.rar"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part01.rar"); - } - protected IEnumerable GetZipArchives() - { - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.dd.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd-.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.dd.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.ppmd.dd.zip"); - yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.ppmd.zip"); - } - protected IEnumerable GetTarArchives() - { - yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"); - } - protected IEnumerable GetTarBz2Archives() - { - yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"); - } - protected IEnumerable GetTarGzArchives() - { - yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"); - } - - public void ResetScratch() - { - if (Directory.Exists(SCRATCH_FILES_PATH)) - { - Directory.Delete(SCRATCH_FILES_PATH, true); - } - Directory.CreateDirectory(SCRATCH_FILES_PATH); - if (Directory.Exists(SCRATCH2_FILES_PATH)) - { - Directory.Delete(SCRATCH2_FILES_PATH, true); - } - Directory.CreateDirectory(SCRATCH2_FILES_PATH); - - } - - public void VerifyFiles() - { - if (UseExtensionInsteadOfNameToVerify) - { - VerifyFilesByExtension(); - } - else - { - VerifyFilesByName(); - } - } - - /// - /// Verifies the files also check modified time and attributes. - /// - public void VerifyFilesEx() - { - if (UseExtensionInsteadOfNameToVerify) - { - VerifyFilesByExtensionEx(); - } - else - { - VerifyFilesByNameEx(); - } - } - - protected void VerifyFilesByName() - { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - } - } - - /// - /// Verifies the files by name also check modified time and attributes. - /// - protected void VerifyFilesByNameEx() - { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); - } - } - - /// - /// Verifies the files by extension also check modified time and attributes. - /// - protected void VerifyFilesByExtensionEx() - { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); - } - } - - protected bool UseExtensionInsteadOfNameToVerify { get; set; } - - protected void VerifyFilesByExtension() - { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - } - } - - protected void CompareFilesByPath(string file1, string file2) - { - using (var file1Stream = File.OpenRead(file1)) - using (var file2Stream = File.OpenRead(file2)) - { - Assert.Equal(file1Stream.Length, file2Stream.Length); - int byte1 = 0; - int byte2 = 0; - for (int counter = 0; byte1 != -1; counter++) - { - byte1 = file1Stream.ReadByte(); - byte2 = file2Stream.ReadByte(); - if (byte1 != byte2) - { - //string.Format("Byte {0} differ between {1} and {2}", counter, file1, file2) - Assert.Equal(byte1, byte2); - } - } - } - } - - protected void CompareFilesByTimeAndAttribut(string file1, string file2) - { - FileInfo fi1 = new FileInfo(file1); - FileInfo fi2 = new FileInfo(file2); - Assert.NotEqual(fi1.LastWriteTime, fi2.LastWriteTime); - Assert.Equal(fi1.Attributes, fi2.Attributes); - } - - protected void CompareArchivesByPath(string file1, string file2) - { - using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), Options.None)) - using (var archive2 = ReaderFactory.Open(File.OpenRead(file2), Options.None)) - { - while (archive1.MoveToNextEntry()) - { - Assert.True(archive2.MoveToNextEntry()); - Assert.Equal(archive1.Entry.Key, archive2.Entry.Key); - } - Assert.False(archive2.MoveToNextEntry()); - } - } - - public TestBase() - { - SOLUTION_BASE_PATH = Path.GetDirectoryName(PlatformServices.Default.Application.ApplicationBasePath); - TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives"); - ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original"); - MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest"); - SCRATCH_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch"); - SCRATCH2_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch2"); - } - } -} +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Extensions.PlatformAbstractions; +using SharpCompress.Common; +using SharpCompress.Reader; +using Xunit; + +namespace SharpCompress.Test +{ + public class TestBase + { + protected string SOLUTION_BASE_PATH=null; + protected string TEST_ARCHIVES_PATH; + protected string ORIGINAL_FILES_PATH; + protected string MISC_TEST_FILES_PATH; + public string SCRATCH_FILES_PATH; + protected string SCRATCH2_FILES_PATH; + protected IEnumerable GetRarArchives() + { + yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.none.rar"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.solid.rar"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part01.rar"); + } + protected IEnumerable GetZipArchives() + { + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.dd.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd-.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.dd.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.ppmd.dd.zip"); + yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.ppmd.zip"); + } + protected IEnumerable GetTarArchives() + { + yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"); + } + protected IEnumerable GetTarBz2Archives() + { + yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"); + } + protected IEnumerable GetTarGzArchives() + { + yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"); + } + + public void ResetScratch() + { + if (Directory.Exists(SCRATCH_FILES_PATH)) + { + Directory.Delete(SCRATCH_FILES_PATH, true); + } + Directory.CreateDirectory(SCRATCH_FILES_PATH); + if (Directory.Exists(SCRATCH2_FILES_PATH)) + { + Directory.Delete(SCRATCH2_FILES_PATH, true); + } + Directory.CreateDirectory(SCRATCH2_FILES_PATH); + + } + + public void VerifyFiles() + { + if (UseExtensionInsteadOfNameToVerify) + { + VerifyFilesByExtension(); + } + else + { + VerifyFilesByName(); + } + } + + /// + /// Verifies the files also check modified time and attributes. + /// + public void VerifyFilesEx() + { + if (UseExtensionInsteadOfNameToVerify) + { + VerifyFilesByExtensionEx(); + } + else + { + VerifyFilesByNameEx(); + } + } + + protected void VerifyFilesByName() + { + var extracted = + Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); + var original = + Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + } + } + + /// + /// Verifies the files by name also check modified time and attributes. + /// + protected void VerifyFilesByNameEx() + { + var extracted = + Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); + var original = + Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); + } + } + + /// + /// Verifies the files by extension also check modified time and attributes. + /// + protected void VerifyFilesByExtensionEx() + { + var extracted = + Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + var original = + Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); + } + } + + protected bool UseExtensionInsteadOfNameToVerify { get; set; } + + protected void VerifyFilesByExtension() + { + var extracted = + Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + var original = + Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + } + } + + protected void CompareFilesByPath(string file1, string file2) + { + using (var file1Stream = File.OpenRead(file1)) + using (var file2Stream = File.OpenRead(file2)) + { + Assert.Equal(file1Stream.Length, file2Stream.Length); + int byte1 = 0; + int byte2 = 0; + for (int counter = 0; byte1 != -1; counter++) + { + byte1 = file1Stream.ReadByte(); + byte2 = file2Stream.ReadByte(); + if (byte1 != byte2) + { + //string.Format("Byte {0} differ between {1} and {2}", counter, file1, file2) + Assert.Equal(byte1, byte2); + } + } + } + } + + protected void CompareFilesByTimeAndAttribut(string file1, string file2) + { + FileInfo fi1 = new FileInfo(file1); + FileInfo fi2 = new FileInfo(file2); + Assert.NotEqual(fi1.LastWriteTime, fi2.LastWriteTime); + Assert.Equal(fi1.Attributes, fi2.Attributes); + } + + protected void CompareArchivesByPath(string file1, string file2) + { + using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), Options.None)) + using (var archive2 = ReaderFactory.Open(File.OpenRead(file2), Options.None)) + { + while (archive1.MoveToNextEntry()) + { + Assert.True(archive2.MoveToNextEntry()); + Assert.Equal(archive1.Entry.Key, archive2.Entry.Key); + } + Assert.False(archive2.MoveToNextEntry()); + } + } + + public TestBase() + { + SOLUTION_BASE_PATH = Path.GetDirectoryName(PlatformServices.Default.Application.ApplicationBasePath); + TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives"); + ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original"); + MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest"); + SCRATCH_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch"); + SCRATCH2_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch2"); + } + } +} diff --git a/SharpCompress.Test/TestStream.cs b/test/SharpCompress.Test/TestStream.cs similarity index 95% rename from SharpCompress.Test/TestStream.cs rename to test/SharpCompress.Test/TestStream.cs index 912899b1..b6c1abf5 100644 --- a/SharpCompress.Test/TestStream.cs +++ b/test/SharpCompress.Test/TestStream.cs @@ -1,85 +1,85 @@ -using System.IO; - -namespace SharpCompress.Test -{ - public class TestStream : Stream - { - private Stream stream; - private bool read; - private bool write; - private bool seek; - - public TestStream(Stream stream) - : this(stream, true, true, true) - { - } - - public bool IsDisposed { get; private set; } - - public TestStream(Stream stream, bool read, bool write, bool seek) - { - this.stream = stream; - this.read = read; - this.write = write; - this.seek = seek; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - stream.Dispose(); - IsDisposed = true; - } - - public override bool CanRead - { - get { return read; } - } - - public override bool CanSeek - { - get { return seek; } - } - - public override bool CanWrite - { - get { return write; } - } - - public override void Flush() - { - stream.Flush(); - } - - public override long Length - { - get { return stream.Length; } - } - - public override long Position - { - get { return stream.Position; } - set { stream.Position = value; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - stream.Write(buffer, offset, count); - } - } -} +using System.IO; + +namespace SharpCompress.Test +{ + public class TestStream : Stream + { + private Stream stream; + private bool read; + private bool write; + private bool seek; + + public TestStream(Stream stream) + : this(stream, true, true, true) + { + } + + public bool IsDisposed { get; private set; } + + public TestStream(Stream stream, bool read, bool write, bool seek) + { + this.stream = stream; + this.read = read; + this.write = write; + this.seek = seek; + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + stream.Dispose(); + IsDisposed = true; + } + + public override bool CanRead + { + get { return read; } + } + + public override bool CanSeek + { + get { return seek; } + } + + public override bool CanWrite + { + get { return write; } + } + + public override void Flush() + { + stream.Flush(); + } + + public override long Length + { + get { return stream.Length; } + } + + public override long Position + { + get { return stream.Position; } + set { stream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return stream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + stream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + stream.Write(buffer, offset, count); + } + } +} diff --git a/SharpCompress.Test/WriterTests.cs b/test/SharpCompress.Test/WriterTests.cs similarity index 97% rename from SharpCompress.Test/WriterTests.cs rename to test/SharpCompress.Test/WriterTests.cs index 5efd9dc4..7c0f8f9f 100644 --- a/SharpCompress.Test/WriterTests.cs +++ b/test/SharpCompress.Test/WriterTests.cs @@ -1,36 +1,36 @@ -using System.IO; -using SharpCompress.Common; -using SharpCompress.Reader; -using SharpCompress.Writer; - -namespace SharpCompress.Test -{ - public class WriterTests : TestBase - { - private ArchiveType type; - - protected WriterTests(ArchiveType type) - { - this.type = type; - } - - protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst) - { - ResetScratch(); - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) - using (var writer = WriterFactory.Open(stream, type, compressionType)) - { - writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories); - } - CompareArchivesByPath(Path.Combine(SCRATCH2_FILES_PATH, archive), - Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst)); - - using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive))) - using (var reader = ReaderFactory.Open(stream)) - { - reader.WriteAllToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath); - } - VerifyFiles(); - } - } -} +using System.IO; +using SharpCompress.Common; +using SharpCompress.Reader; +using SharpCompress.Writer; + +namespace SharpCompress.Test +{ + public class WriterTests : TestBase + { + private ArchiveType type; + + protected WriterTests(ArchiveType type) + { + this.type = type; + } + + protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst) + { + ResetScratch(); + using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) + using (var writer = WriterFactory.Open(stream, type, compressionType)) + { + writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories); + } + CompareArchivesByPath(Path.Combine(SCRATCH2_FILES_PATH, archive), + Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst)); + + using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive))) + using (var reader = ReaderFactory.Open(stream)) + { + reader.WriteAllToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath); + } + VerifyFiles(); + } + } +} diff --git a/SharpCompress.Test/Zip/ZipArchiveTests.cs b/test/SharpCompress.Test/Zip/ZipArchiveTests.cs similarity index 97% rename from SharpCompress.Test/Zip/ZipArchiveTests.cs rename to test/SharpCompress.Test/Zip/ZipArchiveTests.cs index d6845f1a..5aa55c78 100644 --- a/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/test/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -1,405 +1,405 @@ - -using System; -using System.IO; -using System.Linq; -using System.Text; -using SharpCompress.Archive; -using SharpCompress.Archive.Zip; -using SharpCompress.Common; -using SharpCompress.Writer; -using Xunit; - -namespace SharpCompress.Test -{ - public class ZipArchiveTests : ArchiveTests - { - public ZipArchiveTests() - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void Zip_ZipX_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.zipx"); - } - - - [Fact] - public void Zip_BZip2_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.bzip2.dd.zip"); - } - [Fact] - public void Zip_BZip2_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.bzip2.zip"); - } - [Fact] - public void Zip_Deflate_Streamed2_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate.dd-.zip"); - } - [Fact] - public void Zip_Deflate_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate.dd.zip"); - } - [Fact] - public void Zip_Deflate_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate.zip"); - } - - [Fact] - public void Zip_LZMA_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.lzma.dd.zip"); - } - [Fact] - public void Zip_LZMA_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.lzma.zip"); - } - [Fact] - public void Zip_PPMd_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.ppmd.dd.zip"); - } - [Fact] - public void Zip_PPMd_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.ppmd.zip"); - } - [Fact] - public void Zip_None_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.none.zip"); - } - - [Fact] - public void Zip_BZip2_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.bzip2.dd.zip"); - } - [Fact] - public void Zip_BZip2_ArchiveFileRead() - { - ArchiveFileRead("Zip.bzip2.zip"); - } - [Fact] - public void Zip_Deflate_Streamed2_ArchiveFileRead() - { - ArchiveFileRead("Zip.deflate.dd-.zip"); - } - [Fact] - public void Zip_Deflate_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.deflate.dd.zip"); - } - [Fact] - public void Zip_Deflate_ArchiveFileRead() - { - ArchiveFileRead("Zip.deflate.zip"); - } - - [Fact] - public void Zip_LZMA_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.lzma.dd.zip"); - } - [Fact] - public void Zip_LZMA_ArchiveFileRead() - { - ArchiveFileRead("Zip.lzma.zip"); - } - [Fact] - public void Zip_PPMd_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.ppmd.dd.zip"); - } - [Fact] - public void Zip_PPMd_ArchiveFileRead() - { - ArchiveFileRead("Zip.ppmd.zip"); - } - [Fact] - public void Zip_None_ArchiveFileRead() - { - ArchiveFileRead("Zip.none.zip"); - } - - [Fact] - public void Zip_Random_Write_Remove() - { - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); - - base.ResetScratch(); - using (var archive = ZipArchive.Open(unmodified)) - { - var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg")); - archive.RemoveEntry(entry); - archive.SaveTo(scratchPath, CompressionType.Deflate); - } - CompareArchivesByPath(modified, scratchPath); - } - - [Fact] - public void Zip_Random_Write_Add() - { - string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg"); - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod2.zip"); - - base.ResetScratch(); - using (var archive = ZipArchive.Open(unmodified)) - { - archive.AddEntry("jpg\\test.jpg", jpg); - archive.SaveTo(scratchPath, CompressionType.Deflate); - } - CompareArchivesByPath(modified, scratchPath); - } - - [Fact] - public void Zip_Save_Twice() - { - string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); - string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); - - ResetScratch(); - using (var arc = ZipArchive.Create()) - { - string str = "test.txt"; - var source = new MemoryStream(Encoding.UTF8.GetBytes(str)); - arc.AddEntry("test.txt", source, true, source.Length); - arc.SaveTo(scratchPath1, CompressionType.Deflate); - arc.SaveTo(scratchPath2, CompressionType.Deflate); - } - - Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); - } - - [Fact] - public void Zip_Removal_Poly() - { - ResetScratch(); - - string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - - - using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath)) - { - var e = vfs.Entries.First(v => v.Key.EndsWith("jpg")); - vfs.RemoveEntry(e); - Assert.Null(vfs.Entries.FirstOrDefault(v => v.Key.EndsWith("jpg"))); - Assert.Null(((IArchive)vfs).Entries.FirstOrDefault(v => v.Key.EndsWith("jpg"))); - } - } - - [Fact] - public void Zip_Create_NoDups() - { - using (var arc = ZipArchive.Create()) - { - arc.AddEntry("1.txt", new MemoryStream()); - Assert.Throws(() => arc.AddEntry("\\1.txt", new MemoryStream())); - } - } - - [Fact] - public void Zip_Create_Same_Stream() - { - string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); - string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); - - using (var arc = ZipArchive.Create()) - { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("qwert"))) - { - arc.AddEntry("1.txt", stream, false, stream.Length); - arc.AddEntry("2.txt", stream, false, stream.Length); - arc.SaveTo(scratchPath1, CompressionType.Deflate); - arc.SaveTo(scratchPath2, CompressionType.Deflate); - } - } - - Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); - } - - [Fact] - public void Zip_Create_New() - { - base.ResetScratch(); - foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)) - { - var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); - if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString())) - { - newFileName = newFileName.Substring(1); - } - newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = Path.GetDirectoryName(newFileName); - if (!Directory.Exists(newDir)) - { - Directory.CreateDirectory(newDir); - } - File.Copy(file, newFileName); - } - string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - using (var archive = ZipArchive.Create()) - { - archive.AddAllFromDirectory(SCRATCH_FILES_PATH); - archive.SaveTo(scratchPath, CompressionType.Deflate); - } - CompareArchivesByPath(unmodified, scratchPath); - Directory.Delete(SCRATCH_FILES_PATH, true); - } - - [Fact] - public void Zip_Create_New_Add_Remove() - { - base.ResetScratch(); - foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)) - { - var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); - if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString())) - { - newFileName = newFileName.Substring(1); - } - newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = Path.GetDirectoryName(newFileName); - if (!Directory.Exists(newDir)) - { - Directory.CreateDirectory(newDir); - } - File.Copy(file, newFileName); - } - string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - using (var archive = ZipArchive.Create()) - { - archive.AddAllFromDirectory(SCRATCH_FILES_PATH); - archive.RemoveEntry(archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))); - Assert.False(archive.Entries.Any(x => x.Key.EndsWith("jpg"))); - } - Directory.Delete(SCRATCH_FILES_PATH, true); - } - - [Fact] - public void Zip_Deflate_WinzipAES_Read() - { - ResetScratch(); - using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), "test")) - { - foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - - [Fact] - public void Zip_BZip2_Pkware_Read() - { - ResetScratch(); - using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), "test")) - { - foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - VerifyFiles(); - } - - [Fact] - public void Zip_Random_Entry_Access() - { - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - base.ResetScratch(); - ZipArchive a = ZipArchive.Open(unmodified); - int count = 0; - foreach (var e in a.Entries) - count++; - - //Prints 3 - Assert.Equal(count, 3); - a.Dispose(); - - a = ZipArchive.Open(unmodified); - int count2 = 0; - - foreach (var e in a.Entries) - { - count2++; - - //Stop at last file - if (count2 == count) - { - var s = e.OpenEntryStream(); - s.ReadByte(); //Actually access stream - s.Dispose(); - break; - } - } - - int count3 = 0; - foreach (var e in a.Entries) - count3++; - - Assert.Equal(count3, 3); - } - - - class NonSeekableMemoryStream : MemoryStream - { - public override bool CanSeek - { - get - { - return false; - } - } - } - - [Fact] - public void TestSharpCompressWithEmptyStream() - { - MemoryStream stream = new NonSeekableMemoryStream(); - - using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) - { - zipWriter.Write("foo.txt", new MemoryStream(new byte[0])); - zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); - } - - stream = new MemoryStream(stream.ToArray()); - File.WriteAllBytes("foo.zip", stream.ToArray()); - - using (var zipArchive = ZipArchive.Open(stream)) - { - foreach (var entry in zipArchive.Entries) - { - using (var entryStream = entry.OpenEntryStream()) - { - MemoryStream tempStream = new MemoryStream(); - const int bufSize = 0x1000; - byte[] buf = new byte[bufSize]; - int bytesRead = 0; - while ((bytesRead = entryStream.Read(buf, 0, bufSize)) > 0) - tempStream.Write(buf, 0, bytesRead); - } - } - } - } - } -} + +using System; +using System.IO; +using System.Linq; +using System.Text; +using SharpCompress.Archive; +using SharpCompress.Archive.Zip; +using SharpCompress.Common; +using SharpCompress.Writer; +using Xunit; + +namespace SharpCompress.Test +{ + public class ZipArchiveTests : ArchiveTests + { + public ZipArchiveTests() + { + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void Zip_ZipX_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.zipx"); + } + + + [Fact] + public void Zip_BZip2_Streamed_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.bzip2.dd.zip"); + } + [Fact] + public void Zip_BZip2_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.bzip2.zip"); + } + [Fact] + public void Zip_Deflate_Streamed2_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.deflate.dd-.zip"); + } + [Fact] + public void Zip_Deflate_Streamed_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.deflate.dd.zip"); + } + [Fact] + public void Zip_Deflate_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.deflate.zip"); + } + + [Fact] + public void Zip_LZMA_Streamed_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.lzma.dd.zip"); + } + [Fact] + public void Zip_LZMA_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.lzma.zip"); + } + [Fact] + public void Zip_PPMd_Streamed_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.ppmd.dd.zip"); + } + [Fact] + public void Zip_PPMd_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.ppmd.zip"); + } + [Fact] + public void Zip_None_ArchiveStreamRead() + { + ArchiveStreamRead("Zip.none.zip"); + } + + [Fact] + public void Zip_BZip2_Streamed_ArchiveFileRead() + { + ArchiveFileRead("Zip.bzip2.dd.zip"); + } + [Fact] + public void Zip_BZip2_ArchiveFileRead() + { + ArchiveFileRead("Zip.bzip2.zip"); + } + [Fact] + public void Zip_Deflate_Streamed2_ArchiveFileRead() + { + ArchiveFileRead("Zip.deflate.dd-.zip"); + } + [Fact] + public void Zip_Deflate_Streamed_ArchiveFileRead() + { + ArchiveFileRead("Zip.deflate.dd.zip"); + } + [Fact] + public void Zip_Deflate_ArchiveFileRead() + { + ArchiveFileRead("Zip.deflate.zip"); + } + + [Fact] + public void Zip_LZMA_Streamed_ArchiveFileRead() + { + ArchiveFileRead("Zip.lzma.dd.zip"); + } + [Fact] + public void Zip_LZMA_ArchiveFileRead() + { + ArchiveFileRead("Zip.lzma.zip"); + } + [Fact] + public void Zip_PPMd_Streamed_ArchiveFileRead() + { + ArchiveFileRead("Zip.ppmd.dd.zip"); + } + [Fact] + public void Zip_PPMd_ArchiveFileRead() + { + ArchiveFileRead("Zip.ppmd.zip"); + } + [Fact] + public void Zip_None_ArchiveFileRead() + { + ArchiveFileRead("Zip.none.zip"); + } + + [Fact] + public void Zip_Random_Write_Remove() + { + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); + + base.ResetScratch(); + using (var archive = ZipArchive.Open(unmodified)) + { + var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg")); + archive.RemoveEntry(entry); + archive.SaveTo(scratchPath, CompressionType.Deflate); + } + CompareArchivesByPath(modified, scratchPath); + } + + [Fact] + public void Zip_Random_Write_Add() + { + string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg"); + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod2.zip"); + + base.ResetScratch(); + using (var archive = ZipArchive.Open(unmodified)) + { + archive.AddEntry("jpg\\test.jpg", jpg); + archive.SaveTo(scratchPath, CompressionType.Deflate); + } + CompareArchivesByPath(modified, scratchPath); + } + + [Fact] + public void Zip_Save_Twice() + { + string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); + string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); + + ResetScratch(); + using (var arc = ZipArchive.Create()) + { + string str = "test.txt"; + var source = new MemoryStream(Encoding.UTF8.GetBytes(str)); + arc.AddEntry("test.txt", source, true, source.Length); + arc.SaveTo(scratchPath1, CompressionType.Deflate); + arc.SaveTo(scratchPath2, CompressionType.Deflate); + } + + Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); + } + + [Fact] + public void Zip_Removal_Poly() + { + ResetScratch(); + + string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + + + using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath)) + { + var e = vfs.Entries.First(v => v.Key.EndsWith("jpg")); + vfs.RemoveEntry(e); + Assert.Null(vfs.Entries.FirstOrDefault(v => v.Key.EndsWith("jpg"))); + Assert.Null(((IArchive)vfs).Entries.FirstOrDefault(v => v.Key.EndsWith("jpg"))); + } + } + + [Fact] + public void Zip_Create_NoDups() + { + using (var arc = ZipArchive.Create()) + { + arc.AddEntry("1.txt", new MemoryStream()); + Assert.Throws(() => arc.AddEntry("\\1.txt", new MemoryStream())); + } + } + + [Fact] + public void Zip_Create_Same_Stream() + { + string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); + string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); + + using (var arc = ZipArchive.Create()) + { + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("qwert"))) + { + arc.AddEntry("1.txt", stream, false, stream.Length); + arc.AddEntry("2.txt", stream, false, stream.Length); + arc.SaveTo(scratchPath1, CompressionType.Deflate); + arc.SaveTo(scratchPath2, CompressionType.Deflate); + } + } + + Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); + } + + [Fact] + public void Zip_Create_New() + { + base.ResetScratch(); + foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)) + { + var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); + if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString())) + { + newFileName = newFileName.Substring(1); + } + newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); + var newDir = Path.GetDirectoryName(newFileName); + if (!Directory.Exists(newDir)) + { + Directory.CreateDirectory(newDir); + } + File.Copy(file, newFileName); + } + string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (var archive = ZipArchive.Create()) + { + archive.AddAllFromDirectory(SCRATCH_FILES_PATH); + archive.SaveTo(scratchPath, CompressionType.Deflate); + } + CompareArchivesByPath(unmodified, scratchPath); + Directory.Delete(SCRATCH_FILES_PATH, true); + } + + [Fact] + public void Zip_Create_New_Add_Remove() + { + base.ResetScratch(); + foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)) + { + var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); + if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString())) + { + newFileName = newFileName.Substring(1); + } + newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); + var newDir = Path.GetDirectoryName(newFileName); + if (!Directory.Exists(newDir)) + { + Directory.CreateDirectory(newDir); + } + File.Copy(file, newFileName); + } + string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (var archive = ZipArchive.Create()) + { + archive.AddAllFromDirectory(SCRATCH_FILES_PATH); + archive.RemoveEntry(archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))); + Assert.False(archive.Entries.Any(x => x.Key.EndsWith("jpg"))); + } + Directory.Delete(SCRATCH_FILES_PATH, true); + } + + [Fact] + public void Zip_Deflate_WinzipAES_Read() + { + ResetScratch(); + using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), "test")) + { + foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + + [Fact] + public void Zip_BZip2_Pkware_Read() + { + ResetScratch(); + using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), "test")) + { + foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + VerifyFiles(); + } + + [Fact] + public void Zip_Random_Entry_Access() + { + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + base.ResetScratch(); + ZipArchive a = ZipArchive.Open(unmodified); + int count = 0; + foreach (var e in a.Entries) + count++; + + //Prints 3 + Assert.Equal(count, 3); + a.Dispose(); + + a = ZipArchive.Open(unmodified); + int count2 = 0; + + foreach (var e in a.Entries) + { + count2++; + + //Stop at last file + if (count2 == count) + { + var s = e.OpenEntryStream(); + s.ReadByte(); //Actually access stream + s.Dispose(); + break; + } + } + + int count3 = 0; + foreach (var e in a.Entries) + count3++; + + Assert.Equal(count3, 3); + } + + + class NonSeekableMemoryStream : MemoryStream + { + public override bool CanSeek + { + get + { + return false; + } + } + } + + [Fact] + public void TestSharpCompressWithEmptyStream() + { + MemoryStream stream = new NonSeekableMemoryStream(); + + using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) + { + zipWriter.Write("foo.txt", new MemoryStream(new byte[0])); + zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); + } + + stream = new MemoryStream(stream.ToArray()); + File.WriteAllBytes("foo.zip", stream.ToArray()); + + using (var zipArchive = ZipArchive.Open(stream)) + { + foreach (var entry in zipArchive.Entries) + { + using (var entryStream = entry.OpenEntryStream()) + { + MemoryStream tempStream = new MemoryStream(); + const int bufSize = 0x1000; + byte[] buf = new byte[bufSize]; + int bytesRead = 0; + while ((bytesRead = entryStream.Read(buf, 0, bufSize)) > 0) + tempStream.Write(buf, 0, bytesRead); + } + } + } + } + } +} diff --git a/SharpCompress.Test/Zip/ZipReaderTests.cs b/test/SharpCompress.Test/Zip/ZipReaderTests.cs similarity index 97% rename from SharpCompress.Test/Zip/ZipReaderTests.cs rename to test/SharpCompress.Test/Zip/ZipReaderTests.cs index a939f1b3..fcef177a 100644 --- a/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/test/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -1,231 +1,231 @@ -using System; -using System.IO; -using SharpCompress.Common; -using SharpCompress.Reader; -using SharpCompress.Reader.Zip; -using SharpCompress.Writer; -using Xunit; - -namespace SharpCompress.Test -{ - public class ZipReaderTests : ReaderTests - { - public ZipReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } - [Fact] - public void Zip_ZipX_Streamed_Read() - { - Read("Zip.Zipx", CompressionType.LZMA); - } - - [Fact] - public void Zip_BZip2_Streamed_Read() - { - Read("Zip.bzip2.dd.zip", CompressionType.BZip2); - } - [Fact] - public void Zip_BZip2_Read() - { - Read("Zip.bzip2.zip", CompressionType.BZip2); - } - [Fact] - public void Zip_Deflate_Streamed2_Read() - { - Read("Zip.deflate.dd-.zip", CompressionType.Deflate); - } - [Fact] - public void Zip_Deflate_Streamed_Read() - { - Read("Zip.deflate.dd.zip", CompressionType.Deflate); - } - [Fact] - public void Zip_Deflate_Read() - { - Read("Zip.deflate.zip", CompressionType.Deflate); - } - - [Fact] - public void Zip_LZMA_Streamed_Read() - { - Read("Zip.lzma.dd.zip", CompressionType.LZMA); - } - [Fact] - public void Zip_LZMA_Read() - { - Read("Zip.lzma.zip", CompressionType.LZMA); - } - [Fact] - public void Zip_PPMd_Streamed_Read() - { - Read("Zip.ppmd.dd.zip", CompressionType.PPMd); - } - [Fact] - public void Zip_PPMd_Read() - { - Read("Zip.ppmd.zip", CompressionType.PPMd); - } - - [Fact] - public void Zip_None_Read() - { - Read("Zip.none.zip", CompressionType.None); - } - - [Fact] - public void Zip_Deflate_NoEmptyDirs_Read() - { - Read("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate); - } - - [Fact] - public void Zip_BZip2_PkwareEncryption_Read() - { - ResetScratch(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"))) - using (var reader = ZipReader.Open(stream, "test")) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.BZip2); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Zip_Reader_Disposal_Test() - { - ResetScratch(); - using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) - { - using (var reader = ReaderFactory.Open(stream, Options.None)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - Assert.True(stream.IsDisposed); - } - } - - [Fact] - public void Zip_Reader_Disposal_Test2() - { - ResetScratch(); - using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) - { - var reader = ReaderFactory.Open(stream, Options.None); - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - Assert.False(stream.IsDisposed); - } - } - - [Fact] - public void Zip_LZMA_WinzipAES_Read() - { - Assert.Throws(() => - { - ResetScratch(); - using ( - Stream stream = - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, - "Zip.lzma.winzipaes.zip"))) - using (var reader = ZipReader.Open(stream, "test")) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, - CompressionType.Unknown); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath - | ExtractOptions.Overwrite); - } - } - } - VerifyFiles(); - }); - } - - [Fact] - public void Zip_Deflate_WinzipAES_Read() - { - ResetScratch(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"))) - using (var reader = ZipReader.Open(stream, "test")) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(reader.Entry.CompressionType, CompressionType.Unknown); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); - } - } - } - VerifyFiles(); - } - - class NonSeekableMemoryStream : MemoryStream - { - public override bool CanSeek - { - get - { - return false; - } - } - } - - [Fact] - public void TestSharpCompressWithEmptyStream() - { - MemoryStream stream = new NonSeekableMemoryStream(); - - using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) - { - zipWriter.Write("foo.txt", new MemoryStream(new byte[0])); - zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); - } - - stream = new MemoryStream(stream.ToArray()); - File.WriteAllBytes("foo.zip", stream.ToArray()); - - using (IReader zipReader = ZipReader.Open(stream)) - { - while (zipReader.MoveToNextEntry()) - { - using (EntryStream entry = zipReader.OpenEntryStream()) - { - MemoryStream tempStream = new MemoryStream(); - const int bufSize = 0x1000; - byte[] buf = new byte[bufSize]; - int bytesRead = 0; - while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0) - tempStream.Write(buf, 0, bytesRead); - } - } - } - } - } -} +using System; +using System.IO; +using SharpCompress.Common; +using SharpCompress.Reader; +using SharpCompress.Reader.Zip; +using SharpCompress.Writer; +using Xunit; + +namespace SharpCompress.Test +{ + public class ZipReaderTests : ReaderTests + { + public ZipReaderTests() + { + UseExtensionInsteadOfNameToVerify = true; + } + [Fact] + public void Zip_ZipX_Streamed_Read() + { + Read("Zip.Zipx", CompressionType.LZMA); + } + + [Fact] + public void Zip_BZip2_Streamed_Read() + { + Read("Zip.bzip2.dd.zip", CompressionType.BZip2); + } + [Fact] + public void Zip_BZip2_Read() + { + Read("Zip.bzip2.zip", CompressionType.BZip2); + } + [Fact] + public void Zip_Deflate_Streamed2_Read() + { + Read("Zip.deflate.dd-.zip", CompressionType.Deflate); + } + [Fact] + public void Zip_Deflate_Streamed_Read() + { + Read("Zip.deflate.dd.zip", CompressionType.Deflate); + } + [Fact] + public void Zip_Deflate_Read() + { + Read("Zip.deflate.zip", CompressionType.Deflate); + } + + [Fact] + public void Zip_LZMA_Streamed_Read() + { + Read("Zip.lzma.dd.zip", CompressionType.LZMA); + } + [Fact] + public void Zip_LZMA_Read() + { + Read("Zip.lzma.zip", CompressionType.LZMA); + } + [Fact] + public void Zip_PPMd_Streamed_Read() + { + Read("Zip.ppmd.dd.zip", CompressionType.PPMd); + } + [Fact] + public void Zip_PPMd_Read() + { + Read("Zip.ppmd.zip", CompressionType.PPMd); + } + + [Fact] + public void Zip_None_Read() + { + Read("Zip.none.zip", CompressionType.None); + } + + [Fact] + public void Zip_Deflate_NoEmptyDirs_Read() + { + Read("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate); + } + + [Fact] + public void Zip_BZip2_PkwareEncryption_Read() + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"))) + using (var reader = ZipReader.Open(stream, "test")) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.BZip2); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + } + + [Fact] + public void Zip_Reader_Disposal_Test() + { + ResetScratch(); + using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) + { + using (var reader = ReaderFactory.Open(stream, Options.None)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + Assert.True(stream.IsDisposed); + } + } + + [Fact] + public void Zip_Reader_Disposal_Test2() + { + ResetScratch(); + using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) + { + var reader = ReaderFactory.Open(stream, Options.None); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + Assert.False(stream.IsDisposed); + } + } + + [Fact] + public void Zip_LZMA_WinzipAES_Read() + { + Assert.Throws(() => + { + ResetScratch(); + using ( + Stream stream = + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, + "Zip.lzma.winzipaes.zip"))) + using (var reader = ZipReader.Open(stream, "test")) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, + CompressionType.Unknown); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath + | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + }); + } + + [Fact] + public void Zip_Deflate_WinzipAES_Read() + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"))) + using (var reader = ZipReader.Open(stream, "test")) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(reader.Entry.CompressionType, CompressionType.Unknown); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, + ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + } + + class NonSeekableMemoryStream : MemoryStream + { + public override bool CanSeek + { + get + { + return false; + } + } + } + + [Fact] + public void TestSharpCompressWithEmptyStream() + { + MemoryStream stream = new NonSeekableMemoryStream(); + + using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) + { + zipWriter.Write("foo.txt", new MemoryStream(new byte[0])); + zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); + } + + stream = new MemoryStream(stream.ToArray()); + File.WriteAllBytes("foo.zip", stream.ToArray()); + + using (IReader zipReader = ZipReader.Open(stream)) + { + while (zipReader.MoveToNextEntry()) + { + using (EntryStream entry = zipReader.OpenEntryStream()) + { + MemoryStream tempStream = new MemoryStream(); + const int bufSize = 0x1000; + byte[] buf = new byte[bufSize]; + int bytesRead = 0; + while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0) + tempStream.Write(buf, 0, bytesRead); + } + } + } + } + } +} diff --git a/SharpCompress.Test/Zip/ZipWriterTests.cs b/test/SharpCompress.Test/Zip/ZipWriterTests.cs similarity index 96% rename from SharpCompress.Test/Zip/ZipWriterTests.cs rename to test/SharpCompress.Test/Zip/ZipWriterTests.cs index d1e800fe..413365a2 100644 --- a/SharpCompress.Test/Zip/ZipWriterTests.cs +++ b/test/SharpCompress.Test/Zip/ZipWriterTests.cs @@ -1,52 +1,52 @@ -using SharpCompress.Common; -using Xunit; - -namespace SharpCompress.Test -{ - public class ZipWriterTests : WriterTests - { - public ZipWriterTests() - : base(ArchiveType.Zip) - { - } - - [Fact] - public void Zip_Deflate_Write() - { - Write(CompressionType.Deflate, "Zip.deflate.noEmptyDirs.zip", "Zip.deflate.noEmptyDirs.zip"); - } - - - [Fact] - public void Zip_BZip2_Write() - { - Write(CompressionType.BZip2, "Zip.bzip2.noEmptyDirs.zip", "Zip.bzip2.noEmptyDirs.zip"); - } - - - [Fact] - public void Zip_None_Write() - { - Write(CompressionType.None, "Zip.none.noEmptyDirs.zip", "Zip.none.noEmptyDirs.zip"); - } - - - [Fact] - public void Zip_LZMA_Write() - { - Write(CompressionType.LZMA, "Zip.lzma.noEmptyDirs.zip", "Zip.lzma.noEmptyDirs.zip"); - } - - [Fact] - public void Zip_PPMd_Write() - { - Write(CompressionType.PPMd, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip"); - } - - [Fact] - public void Zip_Rar_Write() - { - Assert.Throws(() => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")); - } - } -} +using SharpCompress.Common; +using Xunit; + +namespace SharpCompress.Test +{ + public class ZipWriterTests : WriterTests + { + public ZipWriterTests() + : base(ArchiveType.Zip) + { + } + + [Fact] + public void Zip_Deflate_Write() + { + Write(CompressionType.Deflate, "Zip.deflate.noEmptyDirs.zip", "Zip.deflate.noEmptyDirs.zip"); + } + + + [Fact] + public void Zip_BZip2_Write() + { + Write(CompressionType.BZip2, "Zip.bzip2.noEmptyDirs.zip", "Zip.bzip2.noEmptyDirs.zip"); + } + + + [Fact] + public void Zip_None_Write() + { + Write(CompressionType.None, "Zip.none.noEmptyDirs.zip", "Zip.none.noEmptyDirs.zip"); + } + + + [Fact] + public void Zip_LZMA_Write() + { + Write(CompressionType.LZMA, "Zip.lzma.noEmptyDirs.zip", "Zip.lzma.noEmptyDirs.zip"); + } + + [Fact] + public void Zip_PPMd_Write() + { + Write(CompressionType.PPMd, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip"); + } + + [Fact] + public void Zip_Rar_Write() + { + Assert.Throws(() => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")); + } + } +} diff --git a/SharpCompress.Test/project.json b/test/SharpCompress.Test/project.json similarity index 96% rename from SharpCompress.Test/project.json rename to test/SharpCompress.Test/project.json index 3fcaf126..b27d797e 100644 --- a/SharpCompress.Test/project.json +++ b/test/SharpCompress.Test/project.json @@ -22,7 +22,7 @@ } }, "dependencies": { - "SharpCompress": "0.11.3", + "SharpCompress": "0.11.4", "xunit": "2.1.0", "xunit.runner.dnx": "2.1.0-rc1-build204" }