1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
using System;
using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
#if !PORTABLE
using System.Linq;
#endif
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 PORTABLE || NETFX_CORE
throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7.");
#else
var data = entryHeader.Extra.Where(x => x.Type == ExtraDataType.WinZipAes).SingleOrDefault();
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");
}
}
//}
}
}
}
|