From f811835f022b2cb92a345e08ac5a96b6bdd45d4c Mon Sep 17 00:00:00 2001 From: coderb Date: Mon, 18 Dec 2017 09:20:20 -0500 Subject: [PATCH] rar5: rename Entry.IsSplit -> IsSplitAfter, misc wip --- .../Archives/GZip/GZipWritableArchiveEntry.cs | 2 +- .../Archives/Rar/RarArchiveEntry.cs | 4 +- .../Archives/Rar/RarArchiveEntryFactory.cs | 2 +- .../Archives/Tar/TarWritableArchiveEntry.cs | 2 +- .../Archives/Zip/ZipWritableArchiveEntry.cs | 2 +- src/SharpCompress/Common/Entry.cs | 2 +- src/SharpCompress/Common/GZip/GZipEntry.cs | 2 +- src/SharpCompress/Common/IEntry.cs | 2 +- .../Common/Rar/Headers/FileHeader.cs | 16 +++-- src/SharpCompress/Common/Rar/Headers/Flags.cs | 8 +-- .../Common/Rar/Headers/RarHeader.cs | 7 +-- src/SharpCompress/Common/Rar/RarEntry.cs | 2 +- .../Common/SevenZip/SevenZipEntry.cs | 2 +- src/SharpCompress/Common/Tar/TarEntry.cs | 2 +- src/SharpCompress/Common/Zip/ZipEntry.cs | 2 +- .../Rar/MultiVolumeReadOnlyStream.cs | 2 +- .../Rar/UnpackV2017/BitInput.getbits_hpp.cs | 21 +++---- .../Compressors/Rar/UnpackV2017/Unpack.cs | 58 ++++++++++++++----- .../Readers/Rar/MultiVolumeRarReader.cs | 2 +- 19 files changed, 84 insertions(+), 56 deletions(-) diff --git a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs index 852b15da..8bf96f39 100644 --- a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs @@ -42,7 +42,7 @@ namespace SharpCompress.Archives.GZip public override bool IsDirectory => false; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; internal override IEnumerable Parts => throw new NotImplementedException(); diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs index 8043784d..064dcf7a 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs @@ -33,7 +33,7 @@ namespace SharpCompress.Archives.Rar get { CheckIncomplete(); - return parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplit).FileCrc; + return parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc; } } @@ -68,7 +68,7 @@ namespace SharpCompress.Archives.Rar { get { - return parts.Select(fp => fp.FileHeader).Any(fh => !fh.IsSplit); + return parts.Select(fp => fp.FileHeader).Any(fh => !fh.IsSplitAfter); } } diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs index 91305cfd..e41c024d 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs @@ -23,7 +23,7 @@ namespace SharpCompress.Archives.Rar { groupedParts.Add(fp); - if (!fp.FileHeader.IsSplit) + if (!fp.FileHeader.IsSplitAfter) { yield return groupedParts; groupedParts = new List(); diff --git a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs index 33c2e766..8e693d52 100644 --- a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs @@ -42,7 +42,7 @@ namespace SharpCompress.Archives.Tar public override bool IsDirectory => false; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; internal override IEnumerable Parts => throw new NotImplementedException(); Stream IWritableArchiveEntry.Stream => stream; diff --git a/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs index 4b4bbf36..4cd1fe61 100644 --- a/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs @@ -43,7 +43,7 @@ namespace SharpCompress.Archives.Zip public override bool IsDirectory => false; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; internal override IEnumerable Parts => throw new NotImplementedException(); diff --git a/src/SharpCompress/Common/Entry.cs b/src/SharpCompress/Common/Entry.cs index 5f07af2f..cd659d31 100644 --- a/src/SharpCompress/Common/Entry.cs +++ b/src/SharpCompress/Common/Entry.cs @@ -63,7 +63,7 @@ namespace SharpCompress.Common /// /// Entry is split among multiple volumes /// - public abstract bool IsSplit { get; } + public abstract bool IsSplitAfter { get; } internal abstract IEnumerable Parts { get; } internal bool IsSolid { get; set; } diff --git a/src/SharpCompress/Common/GZip/GZipEntry.cs b/src/SharpCompress/Common/GZip/GZipEntry.cs index 6c80ddff..849d4741 100644 --- a/src/SharpCompress/Common/GZip/GZipEntry.cs +++ b/src/SharpCompress/Common/GZip/GZipEntry.cs @@ -36,7 +36,7 @@ namespace SharpCompress.Common.GZip public override bool IsDirectory => false; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; internal override IEnumerable Parts => filePart.AsEnumerable(); diff --git a/src/SharpCompress/Common/IEntry.cs b/src/SharpCompress/Common/IEntry.cs index ac15828c..e8f13a30 100644 --- a/src/SharpCompress/Common/IEntry.cs +++ b/src/SharpCompress/Common/IEntry.cs @@ -12,7 +12,7 @@ namespace SharpCompress.Common string Key { get; } bool IsDirectory { get; } bool IsEncrypted { get; } - bool IsSplit { get; } + bool IsSplitAfter { get; } DateTime? LastAccessedTime { get; } DateTime? LastModifiedTime { get; } long Size { get; } diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index b6181c5b..0d5524c8 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -31,7 +31,8 @@ namespace SharpCompress.Common.Rar.Headers Flags = reader.ReadRarVIntUInt16(); var lvalue = checked((long)reader.ReadRarVInt()); -//!!! rar5 TODO: this may cause problems with user code, Unpack20 seems to use this field to decompress + + // long.MaxValue causes the unpack code to finish when the input stream is exhausted UncompressedSize = HasFlag(FileFlagsV5.UnpackedSizeUnknown) ? long.MaxValue : lvalue; FileAttributes = reader.ReadRarVIntUInt32(); @@ -56,6 +57,7 @@ namespace SharpCompress.Common.Rar.Headers // 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files. // It can be set only for file headers and is never set for service headers. IsSolid = (us & 0x40) == 0x40; + if (IsSolid != HasHeaderFlag(HeaderFlagsV5.Solid_TESTME)) throw new InvalidFormatException("rar solid flag base header != file header"); // Bits 8 - 10 (0x0380 mask) define the compression method. Currently only values 0 - 5 are used. 0 means no compression. CompressionMethod = (byte)((us >> 7) & 0x7); @@ -63,6 +65,7 @@ namespace SharpCompress.Common.Rar.Headers // Bits 11 - 14 (0x3c00) define the minimum size of dictionary size required to extract data. Value 0 means 128 KB, 1 - 256 KB, ..., 14 - 2048 MB, 15 - 4096 MB. // 2 ^ (17 + x) R5DictSize_2_17plusX = (byte)((us >> 10) & 0xf); + //WindowSize = hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5) HostOs = reader.ReadRarVIntByte(); @@ -393,8 +396,14 @@ namespace SharpCompress.Common.Rar.Headers // 5 - best compression internal byte CompressionMethod { get; private set; } - // see unpack.cs + // eg (see DoUnpack()) + //case 15: // rar 1.5 compression + //case 20: // rar 2.x compression + //case 26: // files larger than 2GB + //case 29: // rar 3.x compression + //case 50: // RAR 5.0 compression algorithm. internal byte CompressionAlgorithm { get; private set; } + public bool IsSolid { get; private set; } internal byte[] R4Salt { get; private set; } @@ -410,8 +419,7 @@ namespace SharpCompress.Common.Rar.Headers internal long DataStartPosition { get; set; } public Stream PackedStream { get; set; } -//!!! TODO rar5 - public bool IsSplit => HasFlag(FileFlagsV4.SplitAfter); + public bool IsSplitAfter => IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SplitAfter) : HasFlag(FileFlagsV4.SplitAfter); public bool IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.Directory : FileFlagsV4.Directory); diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs index a3811740..746b9018 100644 --- a/src/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -45,10 +45,10 @@ namespace SharpCompress.Common.Rar.Headers public const ushort HasExtra = 0x0001; public const ushort HasData = 0x0002; public const ushort Keep = 0x0004; // block must be kept during an update - public const ushort VolumeContinuation = 0x0008; - public const ushort VolumeIncomplete = 0x0010; - public const ushort Solid = 0x0020; // ??? - public const ushort PreserveChild = 0x0040; + public const ushort SplitBefore = 0x0008; + public const ushort SplitAfter = 0x0010; + public const ushort Solid_TESTME = 0x0020; // ??? Block depends on preceding file block. + public const ushort PreserveChild = 0x0040; // ???? Preserve a child block if host block is modified } internal static class ArchiveFlagsV4 diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs index 8abf8670..d4bead44 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs @@ -35,11 +35,6 @@ namespace SharpCompress.Common.Rar.Headers HeaderCode = reader.ReadRarVIntByte(); HeaderFlags = reader.ReadRarVIntUInt16(2); -// if (HasHeaderFlag(HeaderFlagsV5.VolumeContinuation)) throw new NotImplementedException(); -// if (HasHeaderFlag(HeaderFlagsV5.VolumeIncomplete)) throw new NotImplementedException(); -// if (HasHeaderFlag(HeaderFlagsV5.Solid)) throw new NotImplementedException(); -// if (HasHeaderFlag(HeaderFlagsV5.PreserveChild)) throw new NotImplementedException(); - if (HasHeaderFlag(HeaderFlagsV5.HasExtra)) { ExtraSize = reader.ReadRarVIntUInt32(); @@ -111,7 +106,7 @@ namespace SharpCompress.Common.Rar.Headers protected ushort HeaderFlags { get; } - private bool HasHeaderFlag(ushort flag) + protected bool HasHeaderFlag(ushort flag) { return (HeaderFlags & flag) == flag; } diff --git a/src/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs index 105a306a..cec1eb44 100644 --- a/src/SharpCompress/Common/Rar/RarEntry.cs +++ b/src/SharpCompress/Common/Rar/RarEntry.cs @@ -47,7 +47,7 @@ namespace SharpCompress.Common.Rar /// public override bool IsDirectory => FileHeader.IsDirectory; - public override bool IsSplit => FileHeader.IsSplit; + public override bool IsSplitAfter => FileHeader.IsSplitAfter; public override string ToString() { diff --git a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs index dd23d629..584bfb95 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs @@ -34,7 +34,7 @@ namespace SharpCompress.Common.SevenZip public override bool IsDirectory => FilePart.Header.IsDir; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; public override int? Attrib => (int)FilePart.Header.Attrib; diff --git a/src/SharpCompress/Common/Tar/TarEntry.cs b/src/SharpCompress/Common/Tar/TarEntry.cs index 5208bce1..6ff6e19f 100644 --- a/src/SharpCompress/Common/Tar/TarEntry.cs +++ b/src/SharpCompress/Common/Tar/TarEntry.cs @@ -39,7 +39,7 @@ namespace SharpCompress.Common.Tar public override bool IsDirectory => filePart.Header.EntryType == EntryType.Directory; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; internal override IEnumerable Parts => filePart.AsEnumerable(); diff --git a/src/SharpCompress/Common/Zip/ZipEntry.cs b/src/SharpCompress/Common/Zip/ZipEntry.cs index 8b8c7337..b721d57f 100644 --- a/src/SharpCompress/Common/Zip/ZipEntry.cs +++ b/src/SharpCompress/Common/Zip/ZipEntry.cs @@ -72,7 +72,7 @@ namespace SharpCompress.Common.Zip public override bool IsDirectory => filePart.Header.IsDirectory; - public override bool IsSplit => false; + public override bool IsSplitAfter => false; internal override IEnumerable Parts => filePart.AsEnumerable(); } diff --git a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs index 69e7734d..57e9fd6f 100644 --- a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs @@ -89,7 +89,7 @@ namespace SharpCompress.Compressors.Rar currentCount -= read; totalRead += read; if (((maxPosition - currentPosition) == 0) - && filePartEnumerator.Current.FileHeader.IsSplit) + && filePartEnumerator.Current.FileHeader.IsSplitAfter) { if (filePartEnumerator.Current.FileHeader.R4Salt != null) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs index 0fd6bd48..0eb0b64a 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs @@ -5,19 +5,15 @@ internal partial class BitInput { public const int MAX_SIZE=0x8000; // Size of input buffer. - public - int InAddr; // Curent byte position in the buffer. - public - int InBit; // Current bit position in the current byte. + public int InAddr; // Curent byte position in the buffer. + public int InBit; // Current bit position in the current byte. - public - bool ExternalBuffer; + public bool ExternalBuffer; //BitInput(bool AllocBuffer); //~BitInput(); - public - byte[] InBuf; // Dynamically allocated input buffer. + public byte[] InBuf; // Dynamically allocated input buffer. public void InitBitInput() @@ -26,8 +22,7 @@ internal partial class BitInput } // Move forward by 'Bits' bits. - public - void addbits(uint _Bits) + public void addbits(uint _Bits) { var Bits = checked((int)_Bits); Bits+=InBit; @@ -37,8 +32,7 @@ internal partial class BitInput // Return 16 bits from current position in the buffer. // Bit at (InAddr,InBit) has the highest position in returning data. - public - uint getbits() + public uint getbits() { uint BitField=(uint)InBuf[InAddr] << 16; BitField|=(uint)InBuf[InAddr+1] << 8; @@ -49,8 +43,7 @@ internal partial class BitInput // Return 32 bits from current position in the buffer. // Bit at (InAddr,InBit) has the highest position in returning data. - public - uint getbits32() + public uint getbits32() { uint BitField=(uint)InBuf[InAddr] << 24; BitField|=(uint)InBuf[InAddr+1] << 16; diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs index 65ec8690..f7c8f536 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs @@ -13,15 +13,17 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) { + // may be long.MaxValue which could indicate unknown size (not present in header) DestUnpSize = fileHeader.UncompressedSize; this.fileHeader = fileHeader; this.readStream = readStream; this.writeStream = writeStream; - if (!fileHeader.IsSolid) - { - Init(null); - Init(size_t WinSize,bool Solid) - } +// if (!fileHeader.IsSolid) +// { +// Init(null); +// } +fileHeader. + Init(size_t WinSize, fileHeader.IsSolid) Suspended = false; DoUnpack(); } @@ -31,23 +33,53 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 if (this.fileHeader.CompressionMethod == 0) { UnstoreFile(); - return; + } else { + DoUnpack(uint Method,bool Solid); } - DoUnpack(uint Method,bool Solid); } + private void UnstoreFile() + { + var b = new byte[0x10000]; + while (true) + { + int n = this.readStream.Read(b, 0, (int)Math.Min(b.Length, DestUnpSize)); + if (n == 0) + { + break; + } + + n = n < DestUnpSize ? n : (int)DestUnpSize; + this.writeStream.Write(b, 0, n); + if (DestUnpSize >= 0) + { + DestUnpSize -= n; + } + if (Suspended) + { + return; + } + } + } + public bool Suspended { get; set; } public long DestSize { get => DestUnpSize; } - public int Char { - get { throw new NotImplementedException(); } + public int Char + { + get + { + // TODO: coderb: not sure where the "MAXSIZE-30" comes from, ported from V1 code + if (InAddr > MAX_SIZE - 30) + { + UnpReadBuf(); + } + return InBuf[InAddr++]; + } } - public int PpmEscChar { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } + public int PpmEscChar { get => this.PPMEscChar; set => this.PPMEscChar = value; } } } #endif \ No newline at end of file diff --git a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs index 068d7572..cfbdc5c0 100644 --- a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs @@ -89,7 +89,7 @@ namespace SharpCompress.Readers.Rar return true; } - if (!reader.Entry.IsSplit) + if (!reader.Entry.IsSplitAfter) { return false; }