Files
sharpcompress/src/SharpCompress/Common/Zip/ZipFilePart.cs

180 lines
6.8 KiB
C#
Raw Normal View History

2015-12-30 11:19:42 +00:00
using System;
using System.IO;
using System.Linq;
using SharpCompress.Common.Zip.Headers;
2016-09-26 11:49:49 +01:00
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.PPMd;
using SharpCompress.Converters;
2015-12-30 11:19:42 +00:00
using SharpCompress.IO;
namespace SharpCompress.Common.Zip
{
internal abstract class ZipFilePart : FilePart
{
internal ZipFilePart(ZipFileEntry header, Stream stream)
{
Header = header;
header.Part = this;
BaseStream = stream;
2015-12-30 11:19:42 +00:00
}
internal Stream BaseStream { get; private set; }
internal ZipFileEntry Header { get; set; }
internal override string FilePartName { get { return Header.Name; } }
2015-12-30 11:19:42 +00:00
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); } }
2015-12-30 11:19:42 +00:00
protected Stream CreateDecompressionStream(Stream stream)
{
switch (Header.CompressionMethod)
{
case ZipCompressionMethod.None:
{
return stream;
}
2015-12-30 11:19:42 +00:00
case ZipCompressionMethod.Deflate:
{
return new DeflateStream(stream, CompressionMode.Decompress);
}
2015-12-30 11:19:42 +00:00
case ZipCompressionMethod.BZip2:
{
return new BZip2Stream(stream, CompressionMode.Decompress);
}
2015-12-30 11:19:42 +00:00
case ZipCompressionMethod.LZMA:
{
if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted))
2015-12-30 11:19:42 +00:00
{
throw new NotSupportedException("LZMA with pkware encryption.");
2015-12-30 11:19:42 +00:00
}
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);
}
2015-12-30 11:19:42 +00:00
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)
2015-12-30 11:19:42 +00:00
{
throw new InvalidFormatException("No Winzip AES extra data found.");
2015-12-30 11:19:42 +00:00
}
if (data.Length != 7)
2015-12-30 11:19:42 +00:00
{
throw new InvalidFormatException("Winzip data length is not 7.");
}
ushort method = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 0);
2015-12-30 11:19:42 +00:00
if (method != 0x01 && method != 0x02)
{
throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata");
2015-12-30 11:19:42 +00:00
}
ushort vendorId = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 2);
if (vendorId != 0x4541)
2015-12-30 11:19:42 +00:00
{
throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata");
2015-12-30 11:19:42 +00:00
}
Header.CompressionMethod = (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(data.DataBytes, 5);
return CreateDecompressionStream(stream);
}
default:
{
throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod);
}
2015-12-30 11:19:42 +00:00
}
}
2016-11-24 17:11:43 +03:00
protected Stream GetCryptoStream(Stream plainStream)
{
2016-11-24 18:01:49 +03:00
if (Header.CompressedSize == 0)
2016-11-24 17:11:43 +03:00
{
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 (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted))
{
switch (Header.CompressionMethod)
{
case ZipCompressionMethod.None:
case ZipCompressionMethod.Deflate:
case ZipCompressionMethod.Deflate64:
case ZipCompressionMethod.BZip2:
case ZipCompressionMethod.LZMA:
case ZipCompressionMethod.PPMd:
2016-11-24 18:01:49 +03:00
{
2016-11-24 17:11:43 +03:00
return new PkwareTraditionalCryptoStream(plainStream, Header.ComposeEncryptionData(plainStream), CryptoMode.Decrypt);
2016-11-24 18:01:49 +03:00
}
2016-11-24 17:11:43 +03:00
case ZipCompressionMethod.WinzipAes:
2016-11-24 18:01:49 +03:00
{
2016-01-02 15:02:45 +00:00
#if !NO_FILE
2016-11-24 17:11:43 +03:00
if (Header.WinzipAesEncryptionData != null)
{
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
}
2015-12-30 11:19:42 +00:00
#endif
2016-11-24 17:11:43 +03:00
return plainStream;
2016-11-24 18:01:49 +03:00
}
2016-11-24 17:11:43 +03:00
default:
2016-11-24 18:01:49 +03:00
{
2016-11-24 17:11:43 +03:00
throw new ArgumentOutOfRangeException();
2016-11-24 18:01:49 +03:00
}
2016-11-24 17:11:43 +03:00
}
}
2016-11-24 17:11:43 +03:00
return plainStream;
}
}
2013-04-07 10:58:58 +01:00
}