From 5f121c5da475b719ea42b27406647acbc08a19e7 Mon Sep 17 00:00:00 2001 From: coderb Date: Sun, 17 Dec 2017 07:39:02 -0500 Subject: [PATCH] rar5 wip --- .../Common/Rar/Headers/FileHeader.cs | 4 +- src/SharpCompress/Common/Rar/Headers/Flags.cs | 4 +- .../Common/Rar/Headers/RarHeaderFactory.cs | 48 +++++----- src/SharpCompress/Compressors/Rar/Unpack.cs | 10 +-- src/SharpCompress/IO/MarkingBinaryReader.cs | 90 +++++++++---------- 5 files changed, 76 insertions(+), 80 deletions(-) diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index dd789c6b..27fffe3b 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -9,8 +9,8 @@ namespace SharpCompress.Common.Rar.Headers { private uint fileCrc; - public FileHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.File) { + public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) + : base(header, reader, headerType) { } protected override void ReadFromReader(MarkingBinaryReader reader) diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs index dba0d245..0bbe87aa 100644 --- a/src/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -8,9 +8,11 @@ namespace SharpCompress.Common.Rar.Headers Mark, Archive, File, + NewSub, + Service, // Comment, +// Sub // Av, -// Sub, // Protect, // Sign, // NewSub, diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 005e03ac..9db50d8e 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -100,35 +100,23 @@ namespace SharpCompress.Common.Rar.Headers } case HeaderCodeV.Rar5ServiceHeader: + { + var fh = new FileHeader(header, reader, HeaderType.Service); + SkipData(fh, reader); + return fh; + } + case HeaderCodeV.NewSubHeader: { - var fh = new FileHeader(header, 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"); - } - } + var fh = new FileHeader(header, reader, HeaderType.NewSub); + SkipData(fh, reader); return fh; } case HeaderCodeV.Rar5FileHeader: case HeaderCodeV.FileHeader: { - var fh = new FileHeader(header, reader); + var fh = new FileHeader(header, reader, HeaderType.File); switch (StreamingMode) { case StreamingMode.Seekable: @@ -172,5 +160,23 @@ namespace SharpCompress.Common.Rar.Headers } } } + + private void SkipData(FileHeader fh, RarCrcBinaryReader 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"); + } + } + } } } \ No newline at end of file diff --git a/src/SharpCompress/Compressors/Rar/Unpack.cs b/src/SharpCompress/Compressors/Rar/Unpack.cs index 81c053b0..78450eeb 100644 --- a/src/SharpCompress/Compressors/Rar/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/Unpack.cs @@ -154,19 +154,17 @@ namespace SharpCompress.Compressors.Rar unpack15(solid); break; - case 20: - - // rar 2.x compression + case 20: // rar 2.x compression case 26: // files larger than 2GB unpack20(solid); break; - case 29: - - // rar 3.x compression + case 29: // rar 3.x compression case 36: // alternative hash unpack29(solid); break; + + default: throw new InvalidFormatException("unknown rar compression version " + this.fileHeader.R4RarVersion); } } diff --git a/src/SharpCompress/IO/MarkingBinaryReader.cs b/src/SharpCompress/IO/MarkingBinaryReader.cs index 1df9e7df..e1037995 100644 --- a/src/SharpCompress/IO/MarkingBinaryReader.cs +++ b/src/SharpCompress/IO/MarkingBinaryReader.cs @@ -133,82 +133,72 @@ namespace SharpCompress.IO // RAR5 style variable length encoded value // maximum value of 0xffffffffffffffff (64 bits) - // implies max 10 bytes consumed + // technote: "implies max 10 bytes consumed" -- but not really because we could extend indefinitely using 0x80 0x80 ... 0x80 00 // // Variable length integer. Can include one or more bytes, where lower 7 bits of every byte contain integer data // and highest bit in every byte is the continuation flag. If highest bit is 0, this is the last byte in sequence. // So first byte contains 7 least significant bits of integer and continuation flag. Second byte, if present, // contains next 7 bits and so on. - public ulong ReadRarVInt() { + public ulong ReadRarVInt(int maxBytes = 10) { + // hopefully this gets inlined + return DoReadRarVInt((maxBytes - 1) * 7); + } + + private ulong DoReadRarVInt(int maxShift) { int shift = 0; ulong result = 0; do { byte b0 = ReadByte(); - var b1 = b0 & 0x7f; - ulong n = (ulong)b1; - result |= n << shift; + uint b1 = ((uint)b0) & 0x7f; + ulong n = b1; + ulong shifted = n << shift; + if (n != shifted >> shift) { + // overflow + break; + } + result |= shifted; if (b0 == b1) { return result; } - // note: we're actually only allowing a max high bit of 2^56 - // to avoid an extra complex check for shift overflow due to the - // 10th byte having high bits set shift += 7; - } while (shift < 63); + } while (shift <= maxShift); throw new FormatException("malformed vint"); } public uint ReadRarVIntUInt32(int maxBytes = 5) { + // hopefully this gets inlined + return DoReadRarVIntUInt32((maxBytes - 1) * 7); + } + + public ushort ReadRarVIntUInt16(int maxBytes = 3) { + // hopefully this gets inlined + return checked((ushort)DoReadRarVIntUInt32((maxBytes - 1) * 7)); + } + + public byte ReadRarVIntByte(int maxBytes = 2) { + // hopefully this gets inlined + return checked((byte)DoReadRarVIntUInt32((maxBytes - 1) * 7)); + } + + private uint DoReadRarVIntUInt32(int maxShift) { int shift = 0; uint result = 0; do { byte b0 = ReadByte(); - var b1 = b0 & 0x7f; - uint n = (uint)b1; - result |= n << shift; + uint b1 = ((uint)b0) & 0x7f; + uint n = b1; + uint shifted = n << shift; + if (n != shifted >> shift) { + // overflow + break; + } + result |= shifted; if (b0 == b1) { return result; } shift += 7; - // NOTE: we are too strict here but handling the full range adds complexity and we don't need it - } while (shift < 28 && --maxBytes > 0); - - throw new FormatException("malformed vint"); - } - - public ushort ReadRarVIntUInt16(int maxBytes = 3) { - int shift = 0; - uint result = 0; - do { - byte b0 = ReadByte(); - var b1 = b0 & 0x7f; - uint n = (uint)b1; - result |= n << shift; - if (b0 == b1) { - return checked((ushort)result); - } - shift += 7; - // NOTE: we are too strict here but handling the full range adds complexity and we don't need it - } while (shift < 14 && --maxBytes > 0); - - throw new FormatException("malformed vint"); - } - - public byte ReadRarVIntByte(int maxBytes = 1) { - int shift = 0; - uint result = 0; - do { - byte b0 = ReadByte(); - var b1 = b0 & 0x7f; - uint n = (uint)b1; - result |= n << shift; - if (b0 == b1) { - return checked((byte)result); - } - shift += 7; - // NOTE: we are too strict here but handling the full range adds complexity and we don't need it - } while (shift < 7 && --maxBytes > 0); + } while (shift <= maxShift); throw new FormatException("malformed vint"); }