初始化上传
This commit is contained in:
629
常用工具集/Utility/ICSharpCode.SharpZipLib/Zip/ZipHelperStream.cs
Normal file
629
常用工具集/Utility/ICSharpCode.SharpZipLib/Zip/ZipHelperStream.cs
Normal file
@@ -0,0 +1,629 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ICSharpCode.SharpZipLib.Zip
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds data pertinent to a data descriptor.
|
||||
/// </summary>
|
||||
public class DescriptorData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get /set the compressed size of data.
|
||||
/// </summary>
|
||||
public long CompressedSize
|
||||
{
|
||||
get { return compressedSize; }
|
||||
set { compressedSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get / set the uncompressed size of data
|
||||
/// </summary>
|
||||
public long Size
|
||||
{
|
||||
get { return size; }
|
||||
set { size = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get /set the crc value.
|
||||
/// </summary>
|
||||
public long Crc
|
||||
{
|
||||
get { return crc; }
|
||||
set { crc = (value & 0xffffffff); }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
|
||||
private long size;
|
||||
private long compressedSize;
|
||||
private long crc;
|
||||
|
||||
#endregion Instance Fields
|
||||
}
|
||||
|
||||
internal class EntryPatchData
|
||||
{
|
||||
public long SizePatchOffset
|
||||
{
|
||||
get { return sizePatchOffset_; }
|
||||
set { sizePatchOffset_ = value; }
|
||||
}
|
||||
|
||||
public long CrcPatchOffset
|
||||
{
|
||||
get { return crcPatchOffset_; }
|
||||
set { crcPatchOffset_ = value; }
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
|
||||
private long sizePatchOffset_;
|
||||
private long crcPatchOffset_;
|
||||
|
||||
#endregion Instance Fields
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class assists with writing/reading from Zip files.
|
||||
/// </summary>
|
||||
internal class ZipHelperStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initialise an instance of this class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the file to open.</param>
|
||||
public ZipHelperStream(string name)
|
||||
{
|
||||
stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
|
||||
isOwner_ = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="ZipHelperStream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to use.</param>
|
||||
public ZipHelperStream(Stream stream)
|
||||
{
|
||||
stream_ = stream;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Get / set a value indicating whether the underlying stream is owned or not.
|
||||
/// </summary>
|
||||
/// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isOwner_; }
|
||||
set { isOwner_ = value; }
|
||||
}
|
||||
|
||||
#region Base Stream Methods
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return stream_.CanRead; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return stream_.CanSeek; }
|
||||
}
|
||||
|
||||
public override bool CanTimeout
|
||||
{
|
||||
get { return stream_.CanTimeout; }
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return stream_.Length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return stream_.Position; }
|
||||
set { stream_.Position = value; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return stream_.CanWrite; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream_.Flush();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream_.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream_.SetLength(value);
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream_.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream_.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
|
||||
/// </remarks>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Stream toClose = stream_;
|
||||
stream_ = null;
|
||||
if (isOwner_ && (toClose != null))
|
||||
{
|
||||
isOwner_ = false;
|
||||
toClose.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Base Stream Methods
|
||||
|
||||
// Write the local file header
|
||||
// TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
|
||||
private void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
|
||||
{
|
||||
CompressionMethod method = entry.CompressionMethod;
|
||||
bool headerInfoAvailable = true; // How to get this?
|
||||
bool patchEntryHeader = false;
|
||||
|
||||
WriteLEInt(ZipConstants.LocalHeaderSignature);
|
||||
|
||||
WriteLEShort(entry.Version);
|
||||
WriteLEShort(entry.Flags);
|
||||
WriteLEShort((byte)method);
|
||||
WriteLEInt((int)entry.DosTime);
|
||||
|
||||
if (headerInfoAvailable == true)
|
||||
{
|
||||
WriteLEInt((int)entry.Crc);
|
||||
if (entry.LocalHeaderRequiresZip64)
|
||||
{
|
||||
WriteLEInt(-1);
|
||||
WriteLEInt(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
|
||||
WriteLEInt((int)entry.Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (patchData != null)
|
||||
{
|
||||
patchData.CrcPatchOffset = stream_.Position;
|
||||
}
|
||||
WriteLEInt(0); // Crc
|
||||
|
||||
if (patchData != null)
|
||||
{
|
||||
patchData.SizePatchOffset = stream_.Position;
|
||||
}
|
||||
|
||||
// For local header both sizes appear in Zip64 Extended Information
|
||||
if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
|
||||
{
|
||||
WriteLEInt(-1);
|
||||
WriteLEInt(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEInt(0); // Compressed size
|
||||
WriteLEInt(0); // Uncompressed size
|
||||
}
|
||||
}
|
||||
|
||||
byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);
|
||||
|
||||
if (name.Length > 0xFFFF)
|
||||
{
|
||||
throw new ZipException("Entry name too long.");
|
||||
}
|
||||
|
||||
var ed = new ZipExtraData(entry.ExtraData);
|
||||
|
||||
if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader))
|
||||
{
|
||||
ed.StartNewEntry();
|
||||
if (headerInfoAvailable)
|
||||
{
|
||||
ed.AddLeLong(entry.Size);
|
||||
ed.AddLeLong(entry.CompressedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
ed.AddLeLong(-1);
|
||||
ed.AddLeLong(-1);
|
||||
}
|
||||
ed.AddNewEntry(1);
|
||||
|
||||
if (!ed.Find(1))
|
||||
{
|
||||
throw new ZipException("Internal error cant find extra data");
|
||||
}
|
||||
|
||||
if (patchData != null)
|
||||
{
|
||||
patchData.SizePatchOffset = ed.CurrentReadIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ed.Delete(1);
|
||||
}
|
||||
|
||||
byte[] extra = ed.GetEntryData();
|
||||
|
||||
WriteLEShort(name.Length);
|
||||
WriteLEShort(extra.Length);
|
||||
|
||||
if (name.Length > 0)
|
||||
{
|
||||
stream_.Write(name, 0, name.Length);
|
||||
}
|
||||
|
||||
if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
|
||||
{
|
||||
patchData.SizePatchOffset += stream_.Position;
|
||||
}
|
||||
|
||||
if (extra.Length > 0)
|
||||
{
|
||||
stream_.Write(extra, 0, extra.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locates a block with the desired <paramref name="signature"/>.
|
||||
/// </summary>
|
||||
/// <param name="signature">The signature to find.</param>
|
||||
/// <param name="endLocation">Location, marking the end of block.</param>
|
||||
/// <param name="minimumBlockSize">Minimum size of the block.</param>
|
||||
/// <param name="maximumVariableData">The maximum variable data.</param>
|
||||
/// <returns>Returns the offset of the first byte after the signature; -1 if not found</returns>
|
||||
public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
|
||||
{
|
||||
long pos = endLocation - minimumBlockSize;
|
||||
if (pos < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
|
||||
|
||||
// TODO: This loop could be optimised for speed.
|
||||
do
|
||||
{
|
||||
if (pos < giveUpMarker)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
Seek(pos--, SeekOrigin.Begin);
|
||||
} while (ReadLEInt() != signature);
|
||||
|
||||
return Position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write Zip64 end of central directory records (File header and locator).
|
||||
/// </summary>
|
||||
/// <param name="noOfEntries">The number of entries in the central directory.</param>
|
||||
/// <param name="sizeEntries">The size of entries in the central directory.</param>
|
||||
/// <param name="centralDirOffset">The offset of the central directory.</param>
|
||||
public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
|
||||
{
|
||||
long centralSignatureOffset = centralDirOffset + sizeEntries;
|
||||
WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
|
||||
WriteLELong(44); // Size of this record (total size of remaining fields in header or full size - 12)
|
||||
WriteLEShort(ZipConstants.VersionMadeBy); // Version made by
|
||||
WriteLEShort(ZipConstants.VersionZip64); // Version to extract
|
||||
WriteLEInt(0); // Number of this disk
|
||||
WriteLEInt(0); // number of the disk with the start of the central directory
|
||||
WriteLELong(noOfEntries); // No of entries on this disk
|
||||
WriteLELong(noOfEntries); // Total No of entries in central directory
|
||||
WriteLELong(sizeEntries); // Size of the central directory
|
||||
WriteLELong(centralDirOffset); // offset of start of central directory
|
||||
// zip64 extensible data sector not catered for here (variable size)
|
||||
|
||||
// Write the Zip64 end of central directory locator
|
||||
WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
|
||||
|
||||
// no of the disk with the start of the zip64 end of central directory
|
||||
WriteLEInt(0);
|
||||
|
||||
// relative offset of the zip64 end of central directory record
|
||||
WriteLELong(centralSignatureOffset);
|
||||
|
||||
// total number of disks
|
||||
WriteLEInt(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the required records to end the central directory.
|
||||
/// </summary>
|
||||
/// <param name="noOfEntries">The number of entries in the directory.</param>
|
||||
/// <param name="sizeEntries">The size of the entries in the directory.</param>
|
||||
/// <param name="startOfCentralDirectory">The start of the central directory.</param>
|
||||
/// <param name="comment">The archive comment. (This can be null).</param>
|
||||
public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
|
||||
long startOfCentralDirectory, byte[] comment)
|
||||
{
|
||||
if ((noOfEntries >= 0xffff) ||
|
||||
(startOfCentralDirectory >= 0xffffffff) ||
|
||||
(sizeEntries >= 0xffffffff))
|
||||
{
|
||||
WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
|
||||
}
|
||||
|
||||
WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
|
||||
|
||||
// TODO: ZipFile Multi disk handling not done
|
||||
WriteLEShort(0); // number of this disk
|
||||
WriteLEShort(0); // no of disk with start of central dir
|
||||
|
||||
// Number of entries
|
||||
if (noOfEntries >= 0xffff)
|
||||
{
|
||||
WriteLEUshort(0xffff); // Zip64 marker
|
||||
WriteLEUshort(0xffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEShort((short)noOfEntries); // entries in central dir for this disk
|
||||
WriteLEShort((short)noOfEntries); // total entries in central directory
|
||||
}
|
||||
|
||||
// Size of the central directory
|
||||
if (sizeEntries >= 0xffffffff)
|
||||
{
|
||||
WriteLEUint(0xffffffff); // Zip64 marker
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEInt((int)sizeEntries);
|
||||
}
|
||||
|
||||
// offset of start of central directory
|
||||
if (startOfCentralDirectory >= 0xffffffff)
|
||||
{
|
||||
WriteLEUint(0xffffffff); // Zip64 marker
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEInt((int)startOfCentralDirectory);
|
||||
}
|
||||
|
||||
int commentLength = (comment != null) ? comment.Length : 0;
|
||||
|
||||
if (commentLength > 0xffff)
|
||||
{
|
||||
throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
|
||||
}
|
||||
|
||||
WriteLEShort(commentLength);
|
||||
|
||||
if (commentLength > 0)
|
||||
{
|
||||
Write(comment, 0, comment.Length);
|
||||
}
|
||||
}
|
||||
|
||||
#region LE value reading/writing
|
||||
|
||||
/// <summary>
|
||||
/// Read an unsigned short in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>Returns the value read.</returns>
|
||||
/// <exception cref="IOException">
|
||||
/// An i/o error occurs.
|
||||
/// </exception>
|
||||
/// <exception cref="EndOfStreamException">
|
||||
/// The file ends prematurely
|
||||
/// </exception>
|
||||
public int ReadLEShort()
|
||||
{
|
||||
int byteValue1 = stream_.ReadByte();
|
||||
|
||||
if (byteValue1 < 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
int byteValue2 = stream_.ReadByte();
|
||||
if (byteValue2 < 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
return byteValue1 | (byteValue2 << 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an int in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>Returns the value read.</returns>
|
||||
/// <exception cref="IOException">
|
||||
/// An i/o error occurs.
|
||||
/// </exception>
|
||||
/// <exception cref="System.IO.EndOfStreamException">
|
||||
/// The file ends prematurely
|
||||
/// </exception>
|
||||
public int ReadLEInt()
|
||||
{
|
||||
return ReadLEShort() | (ReadLEShort() << 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a long in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The value read.</returns>
|
||||
public long ReadLELong()
|
||||
{
|
||||
return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an unsigned short in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEShort(int value)
|
||||
{
|
||||
stream_.WriteByte((byte)(value & 0xff));
|
||||
stream_.WriteByte((byte)((value >> 8) & 0xff));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ushort in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEUshort(ushort value)
|
||||
{
|
||||
stream_.WriteByte((byte)(value & 0xff));
|
||||
stream_.WriteByte((byte)(value >> 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an int in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEInt(int value)
|
||||
{
|
||||
WriteLEShort(value);
|
||||
WriteLEShort(value >> 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a uint in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEUint(uint value)
|
||||
{
|
||||
WriteLEUshort((ushort)(value & 0xffff));
|
||||
WriteLEUshort((ushort)(value >> 16));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a long in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLELong(long value)
|
||||
{
|
||||
WriteLEInt((int)value);
|
||||
WriteLEInt((int)(value >> 32));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ulong in little endian byte order.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public void WriteLEUlong(ulong value)
|
||||
{
|
||||
WriteLEUint((uint)(value & 0xffffffff));
|
||||
WriteLEUint((uint)(value >> 32));
|
||||
}
|
||||
|
||||
#endregion LE value reading/writing
|
||||
|
||||
/// <summary>
|
||||
/// Write a data descriptor.
|
||||
/// </summary>
|
||||
/// <param name="entry">The entry to write a descriptor for.</param>
|
||||
/// <returns>Returns the number of descriptor bytes written.</returns>
|
||||
public int WriteDataDescriptor(ZipEntry entry)
|
||||
{
|
||||
if (entry == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(entry));
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
|
||||
// Add data descriptor if flagged as required
|
||||
if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)
|
||||
{
|
||||
// The signature is not PKZIP originally but is now described as optional
|
||||
// in the PKZIP Appnote documenting the format.
|
||||
WriteLEInt(ZipConstants.DataDescriptorSignature);
|
||||
WriteLEInt(unchecked((int)(entry.Crc)));
|
||||
|
||||
result += 8;
|
||||
|
||||
if (entry.LocalHeaderRequiresZip64)
|
||||
{
|
||||
WriteLELong(entry.CompressedSize);
|
||||
WriteLELong(entry.Size);
|
||||
result += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLEInt((int)entry.CompressedSize);
|
||||
WriteLEInt((int)entry.Size);
|
||||
result += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data descriptor at the end of compressed data.
|
||||
/// </summary>
|
||||
/// <param name="zip64">if set to <c>true</c> [zip64].</param>
|
||||
/// <param name="data">The data to fill in.</param>
|
||||
/// <returns>Returns the number of bytes read in the descriptor.</returns>
|
||||
public void ReadDataDescriptor(bool zip64, DescriptorData data)
|
||||
{
|
||||
int intValue = ReadLEInt();
|
||||
|
||||
// In theory this may not be a descriptor according to PKZIP appnote.
|
||||
// In practice its always there.
|
||||
if (intValue != ZipConstants.DataDescriptorSignature)
|
||||
{
|
||||
throw new ZipException("Data descriptor signature not found");
|
||||
}
|
||||
|
||||
data.Crc = ReadLEInt();
|
||||
|
||||
if (zip64)
|
||||
{
|
||||
data.CompressedSize = ReadLELong();
|
||||
data.Size = ReadLELong();
|
||||
}
|
||||
else
|
||||
{
|
||||
data.CompressedSize = ReadLEInt();
|
||||
data.Size = ReadLEInt();
|
||||
}
|
||||
}
|
||||
|
||||
#region Instance Fields
|
||||
|
||||
private bool isOwner_;
|
||||
private Stream stream_;
|
||||
|
||||
#endregion Instance Fields
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user