📄 zipoutputstream.cs
字号:
}
}
entry.Offset = (int)offset;
entry.CompressionMethod = (CompressionMethod)method;
curMethod = method;
// Write the local file header
WriteLeInt(ZipConstants.LOCSIG);
WriteLeShort(entry.Version);
WriteLeShort(entry.Flags);
WriteLeShort((byte)method);
WriteLeInt((int)entry.DosTime);
if (headerInfoAvailable == true) {
WriteLeInt((int)entry.Crc);
WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CRYPTO_HEADER_SIZE : (int)entry.CompressedSize);
WriteLeInt((int)entry.Size);
} else {
if (patchEntryHeader == true) {
headerPatchPos = baseOutputStream.Position;
}
WriteLeInt(0); // Crc
WriteLeInt(0); // Compressed size
WriteLeInt(0); // Uncompressed size
}
byte[] name = ZipConstants.ConvertToArray(entry.Name);
if (name.Length > 0xFFFF) {
throw new ZipException("Entry name too long.");
}
byte[] extra = entry.ExtraData;
if (extra == null) {
extra = new byte[0];
}
if (extra.Length > 0xFFFF) {
throw new ZipException("Extra data too long.");
}
WriteLeShort(name.Length);
WriteLeShort(extra.Length);
baseOutputStream.Write(name, 0, name.Length);
baseOutputStream.Write(extra, 0, extra.Length);
offset += ZipConstants.LOCHDR + name.Length + extra.Length;
// Activate the entry.
curEntry = entry;
crc.Reset();
if (method == CompressionMethod.Deflated) {
def.Reset();
def.SetLevel(compressionLevel);
}
size = 0;
if (entry.IsCrypted == true) {
if (entry.Crc < 0) { // so testing Zip will says its ok
WriteEncryptionHeader(entry.DosTime << 16);
} else {
WriteEncryptionHeader(entry.Crc);
}
}
}
/// <summary>
/// Closes the current entry, updating header and footer information as required
/// </summary>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// No entry is active.
/// </exception>
public void CloseEntry()
{
if (curEntry == null) {
throw new InvalidOperationException("No open entry");
}
// First finish the deflater, if appropriate
if (curMethod == CompressionMethod.Deflated) {
base.Finish();
}
long csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size;
if (curEntry.Size < 0) {
curEntry.Size = size;
} else if (curEntry.Size != size) {
throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
}
if (curEntry.CompressedSize < 0) {
curEntry.CompressedSize = csize;
} else if (curEntry.CompressedSize != csize) {
throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
}
if (curEntry.Crc < 0) {
curEntry.Crc = crc.Value;
} else if (curEntry.Crc != crc.Value) {
throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc);
}
offset += csize;
if (offset > 0xffffffff) {
throw new ZipException("Maximum Zip file size exceeded");
}
if (curEntry.IsCrypted == true) {
curEntry.CompressedSize += ZipConstants.CRYPTO_HEADER_SIZE;
}
// Patch the header if possible
if (patchEntryHeader == true) {
long curPos = baseOutputStream.Position;
baseOutputStream.Seek(headerPatchPos, SeekOrigin.Begin);
WriteLeInt((int)curEntry.Crc);
WriteLeInt((int)curEntry.CompressedSize);
WriteLeInt((int)curEntry.Size);
baseOutputStream.Seek(curPos, SeekOrigin.Begin);
patchEntryHeader = false;
}
// Add data descriptor if flagged as required
if ((curEntry.Flags & 8) != 0) {
WriteLeInt(ZipConstants.EXTSIG);
WriteLeInt((int)curEntry.Crc);
WriteLeInt((int)curEntry.CompressedSize);
WriteLeInt((int)curEntry.Size);
offset += ZipConstants.EXTHDR;
}
entries.Add(curEntry);
curEntry = null;
}
void WriteEncryptionHeader(long crcValue)
{
offset += ZipConstants.CRYPTO_HEADER_SIZE;
InitializePassword(Password);
byte[] cryptBuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
Random rnd = new Random();
rnd.NextBytes(cryptBuffer);
cryptBuffer[11] = (byte)(crcValue >> 24);
EncryptBlock(cryptBuffer, 0, cryptBuffer.Length);
baseOutputStream.Write(cryptBuffer, 0, cryptBuffer.Length);
}
/// <summary>
/// Writes the given buffer to the current entry.
/// </summary>
/// <exception cref="ZipException">
/// Archive size is invalid
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// No entry is active.
/// </exception>
public override void Write(byte[] b, int off, int len)
{
if (curEntry == null) {
throw new InvalidOperationException("No open entry.");
}
if (len <= 0)
return;
crc.Update(b, off, len);
size += len;
if (size > 0xffffffff || size < 0) {
throw new ZipException("Maximum entry size exceeded");
}
switch (curMethod) {
case CompressionMethod.Deflated:
base.Write(b, off, len);
break;
case CompressionMethod.Stored:
if (Password != null) {
byte[] buf = new byte[len];
Array.Copy(b, off, buf, 0, len);
EncryptBlock(buf, 0, len);
baseOutputStream.Write(buf, off, len);
} else {
baseOutputStream.Write(b, off, len);
}
break;
}
}
/// <summary>
/// Finishes the stream. This will write the central directory at the
/// end of the zip file and flush the stream.
/// </summary>
/// <remarks>
/// This is automatically called when the stream is closed.
/// </remarks>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="ZipException">
/// Comment exceeds the maximum length<br/>
/// Entry name exceeds the maximum length
/// </exception>
public override void Finish()
{
if (entries == null) {
return;
}
if (curEntry != null) {
CloseEntry();
}
int numEntries = 0;
int sizeEntries = 0;
foreach (ZipEntry entry in entries) {
CompressionMethod method = entry.CompressionMethod;
WriteLeInt(ZipConstants.CENSIG);
WriteLeShort(ZipConstants.VERSION_MADE_BY);
WriteLeShort(entry.Version);
WriteLeShort(entry.Flags);
WriteLeShort((short)method);
WriteLeInt((int)entry.DosTime);
WriteLeInt((int)entry.Crc);
WriteLeInt((int)entry.CompressedSize);
WriteLeInt((int)entry.Size);
byte[] name = ZipConstants.ConvertToArray(entry.Name);
if (name.Length > 0xffff) {
throw new ZipException("Name too long.");
}
byte[] extra = entry.ExtraData;
if (extra == null) {
extra = new byte[0];
}
byte[] entryComment = entry.Comment != null ? ZipConstants.ConvertToArray(entry.Comment) : new byte[0];
if (entryComment.Length > 0xffff) {
throw new ZipException("Comment too long.");
}
WriteLeShort(name.Length);
WriteLeShort(extra.Length);
WriteLeShort(entryComment.Length);
WriteLeShort(0); // disk number
WriteLeShort(0); // internal file attr
// external file attribute
if (entry.ExternalFileAttributes != -1) {
WriteLeInt(entry.ExternalFileAttributes);
} else {
if (entry.IsDirectory) { // mark entry as directory (from nikolam.AT.perfectinfo.com)
WriteLeInt(16);
} else {
WriteLeInt(0);
}
}
WriteLeInt(entry.Offset);
baseOutputStream.Write(name, 0, name.Length);
baseOutputStream.Write(extra, 0, extra.Length);
baseOutputStream.Write(entryComment, 0, entryComment.Length);
++numEntries;
sizeEntries += ZipConstants.CENHDR + name.Length + extra.Length + entryComment.Length;
}
WriteLeInt(ZipConstants.ENDSIG);
WriteLeShort(0); // number of this disk
WriteLeShort(0); // no of disk with start of central dir
WriteLeShort(numEntries); // entries in central dir for this disk
WriteLeShort(numEntries); // total entries in central directory
WriteLeInt(sizeEntries); // size of the central directory
WriteLeInt((int)offset); // offset of start of central dir
WriteLeShort(zipComment.Length);
baseOutputStream.Write(zipComment, 0, zipComment.Length);
baseOutputStream.Flush();
entries = null;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -