📄 zipfile.cs
字号:
while (len > 0) {
int count = s.Read(outBuf, off, len);
if (count <= 0) {
throw new ZipException("Unexpected EOF");
}
off += count;
len -= count;
}
}
void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
{
byte[] cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
ReadFully(classicCryptoStream, cryptbuffer);
if ((entry.Flags & (int)GeneralBitFlags.Descriptor) == 0) {
if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(entry.Crc >> 24)) {
throw new ZipException("Invalid password");
}
}
else {
if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((entry.DosTime >> 8) & 0xff)) {
throw new ZipException("Invalid password");
}
}
}
Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
{
CryptoStream result = null;
if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION
|| (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
PkzipClassicManaged classicManaged = new PkzipClassicManaged();
OnKeysRequired(entry.Name);
if (HaveKeys == false) {
throw new ZipException("No password available for encrypted stream");
}
result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, iv), CryptoStreamMode.Read);
CheckClassicPassword(result, entry);
}
else {
throw new ZipException("Decryption method not supported");
}
return result;
}
void WriteEncryptionHeader(Stream stream, long crcValue)
{
byte[] cryptBuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
Random rnd = new Random();
rnd.NextBytes(cryptBuffer);
cryptBuffer[11] = (byte)(crcValue >> 24);
stream.Write(cryptBuffer, 0, cryptBuffer.Length);
}
Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
{
CryptoStream result = null;
if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION
|| (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
PkzipClassicManaged classicManaged = new PkzipClassicManaged();
OnKeysRequired(entry.Name);
if (HaveKeys == false) {
throw new ZipException("No password available for encrypted stream");
}
result = new CryptoStream(baseStream, classicManaged.CreateEncryptor(key, iv), CryptoStreamMode.Write);
if (entry.Crc < 0 || (entry.Flags & 8) != 0) {
WriteEncryptionHeader(result, entry.DosTime << 16);
}
else {
WriteEncryptionHeader(result, entry.Crc);
}
}
return result;
}
/// <summary>
/// Gets an output stream for the specified <see cref="ZipEntry"/>
/// </summary>
/// <param name="entry">The entry to get an outputstream for.</param>
/// <param name="fileName"></param>
/// <returns>The output stream obtained for the entry.</returns>
Stream GetOutputStream(ZipEntry entry, string fileName)
{
baseStream.Seek(0, SeekOrigin.End);
Stream result = File.OpenWrite(fileName);
if (entry.IsCrypted == true)
{
result = CreateAndInitEncryptionStream(result, entry);
}
switch (entry.CompressionMethod)
{
case CompressionMethod.Stored:
break;
case CompressionMethod.Deflated:
result = new DeflaterOutputStream(result);
break;
default:
throw new ZipException("Unknown compression method " + entry.CompressionMethod);
}
return result;
}
/// <summary>
/// Creates an input stream reading the given zip entry as
/// uncompressed data. Normally zip entry should be an entry
/// returned by GetEntry().
/// </summary>
/// <returns>
/// the input stream.
/// </returns>
/// <exception cref="InvalidOperationException">
/// The ZipFile has already been closed
/// </exception>
/// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
/// The compression method for the entry is unknown
/// </exception>
/// <exception cref="IndexOutOfRangeException">
/// The entry is not found in the ZipFile
/// </exception>
public Stream GetInputStream(ZipEntry entry)
{
if (entries == null) {
throw new InvalidOperationException("ZipFile has closed");
}
int index = entry.ZipFileIndex;
if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {
index = FindEntry(entry.Name, true);
if (index < 0) {
throw new IndexOutOfRangeException();
}
}
return GetInputStream(index);
}
/// <summary>
/// Creates an input stream reading a zip entry
/// </summary>
/// <param name="entryIndex">The index of the entry to obtain an input stream for.</param>
/// <returns>
/// An input stream.
/// </returns>
/// <exception cref="InvalidOperationException">
/// The ZipFile has already been closed
/// </exception>
/// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
/// The compression method for the entry is unknown
/// </exception>
/// <exception cref="IndexOutOfRangeException">
/// The entry is not found in the ZipFile
/// </exception>
public Stream GetInputStream(int entryIndex)
{
if (entries == null) {
throw new InvalidOperationException("ZipFile has closed");
}
long start = CheckLocalHeader(entries[entryIndex]);
CompressionMethod method = entries[entryIndex].CompressionMethod;
Stream istr = new PartialInputStream(baseStream, start, entries[entryIndex].CompressedSize);
if (entries[entryIndex].IsCrypted == true) {
istr = CreateAndInitDecryptionStream(istr, entries[entryIndex]);
if (istr == null) {
throw new ZipException("Unable to decrypt this entry");
}
}
switch (method) {
case CompressionMethod.Stored:
return istr;
case CompressionMethod.Deflated:
return new InflaterInputStream(istr, new Inflater(true));
default:
throw new ZipException("Unsupported compression method " + method);
}
}
/// <summary>
/// Gets the comment for the zip file.
/// </summary>
public string ZipFileComment {
get {
return comment;
}
}
/// <summary>
/// Gets the name of this zip file.
/// </summary>
public string Name {
get {
return name;
}
}
/// <summary>
/// Gets the number of entries in this zip file.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The Zip file has been closed.
/// </exception>
public int Size {
get {
if (entries != null) {
return entries.Length;
} else {
throw new InvalidOperationException("ZipFile is closed");
}
}
}
class ZipEntryEnumeration : IEnumerator
{
ZipEntry[] array;
int ptr = -1;
public ZipEntryEnumeration(ZipEntry[] arr)
{
array = arr;
}
public object Current {
get {
return array[ptr];
}
}
public void Reset()
{
ptr = -1;
}
public bool MoveNext()
{
return (++ptr < array.Length);
}
}
class PartialInputStream : InflaterInputStream
{
Stream baseStream;
long filepos, end;
public PartialInputStream(Stream baseStream, long start, long len) : base(baseStream)
{
this.baseStream = baseStream;
filepos = start;
end = start + len;
}
public override int Available
{
get {
long amount = end - filepos;
if (amount > Int32.MaxValue) {
return Int32.MaxValue;
}
return (int) amount;
}
}
/// <summary>
/// Read a byte from this stream.
/// </summary>
/// <returns>Returns the byte read or -1 on end of stream.</returns>
public override int ReadByte()
{
if (filepos == end) {
return -1; //ok
}
lock(baseStream) {
baseStream.Seek(filepos++, SeekOrigin.Begin);
return baseStream.ReadByte();
}
}
/// <summary>
/// Close this partial input stream.
/// </summary>
/// <remarks>
/// The underlying stream is not closed. Close the parent ZipFile class to do that.
/// </remarks>
public override void Close()
{
// Do nothing at all!
}
public override int Read(byte[] b, int off, int len)
{
if (len > end - filepos) {
len = (int) (end - filepos);
if (len == 0) {
return 0;
}
}
lock(baseStream) {
baseStream.Seek(filepos, SeekOrigin.Begin);
int count = baseStream.Read(b, off, len);
if (count > 0) {
filepos += len;
}
return count;
}
}
public long SkipBytes(long amount)
{
if (amount < 0) {
throw new ArgumentOutOfRangeException();
}
if (amount > end - filepos) {
amount = end - filepos;
}
filepos += amount;
return amount;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -