17 using System.Collections.Generic;
18 using System.Diagnostics;
32 private const float SmoothingFactor = 0.005F;
41 private byte[] centralDirImage;
46 private Stream zipFileStream;
50 #region Constructors and Destructors
63 : this(new FileStream(filename,
FileMode.Open, FileAccess.Read))
65 this.FileName = filename;
82 throw new InvalidOperationException(
"Stream cannot seek");
85 this.zipFileStream = stream;
87 if (!this.ReadFileInfo())
92 this.FileName = string.Empty;
97 #region Public Properties
102 public int EntryCount {
get;
private set; }
107 public string FileName {
get;
private set; }
111 #region Public Methods and Operators
132 return (uint)((dateTime.Second / 2) |
133 (dateTime.Minute << 5) |
134 (dateTime.Hour << 11) |
135 (dateTime.Day << 16) |
136 (dateTime.Month << 21) |
137 ((dateTime.Year - 1980) << 25));
151 var buf =
new byte[1024 * 256];
158 long totalCompressedLength = entries.Sum(entry => entry.CompressedSize);
159 float averageVerifySpeed = 0;
160 long totalBytesRemaining = totalCompressedLength;
161 validationHandler.TotalBytes = totalCompressedLength;
167 if (entry.
Crc32 != -1)
169 DateTime startTime = DateTime.UtcNow;
171 var crc =
new Crc32();
173 uint offset = entry.FileOffset;
176 Stream raf = zip.zipFileStream;
177 raf.Seek(offset, SeekOrigin.Begin);
181 int seek = length > buf.Length ? buf.Length : length;
182 raf.Read(buf, 0, seek);
183 crc.Update(buf, 0, seek);
186 DateTime currentTime = DateTime.UtcNow;
187 var timePassed = (float)(currentTime - startTime).TotalMilliseconds;
190 float currentSpeedSample = seek / timePassed;
191 if (averageVerifySpeed <= 0)
193 averageVerifySpeed = (SmoothingFactor * currentSpeedSample)
194 + ((1 - SmoothingFactor) * averageVerifySpeed);
198 averageVerifySpeed = currentSpeedSample;
201 totalBytesRemaining -= seek;
202 var timeRemaining = (long)(totalBytesRemaining / averageVerifySpeed);
204 validationHandler.AverageSpeed = averageVerifySpeed;
205 validationHandler.CurrentBytes = totalCompressedLength - totalBytesRemaining;
206 validationHandler.TimeRemaining = timeRemaining;
208 validationHandler.UpdateUi(validationHandler);
211 startTime = currentTime;
218 if (crc.Value != entry.
Crc32)
220 Debug.WriteLine(
"CRC does not match for entry: " + entry.FilenameInZip);
221 Debug.WriteLine(
"In file: " + entry.ZipFileName);
228 catch (IOException e)
230 Console.WriteLine(e.ToString());
231 Console.Write(e.StackTrace);
246 if (this.zipFileStream != null)
248 this.zipFileStream.Flush();
249 this.zipFileStream.Dispose();
250 this.zipFileStream = null;
280 string path = Path.GetDirectoryName(filename);
282 if (!
string.IsNullOrWhiteSpace(path) && !Directory.Exists(path))
284 Directory.CreateDirectory(path);
288 if (Directory.Exists(filename))
293 Stream output =
new FileStream(filename,
FileMode.Create, FileAccess.Write);
294 bool result = this.ExtractFile(zfe, output);
300 File.SetCreationTime(filename, zfe.ModifyTime);
301 File.SetLastWriteTime(filename, zfe.ModifyTime);
323 if (!stream.CanWrite)
325 throw new InvalidOperationException(
"Stream cannot be written");
329 var signature =
new byte[4];
330 this.zipFileStream.Seek(zfe.HeaderOffset, SeekOrigin.Begin);
331 this.zipFileStream.Read(signature, 0, 4);
332 if (BitConverter.ToUInt32(signature, 0) != 0x04034b50)
338 Stream inStream = this.GetZipStream(zfe);
339 if (inStream == null)
345 var buffer =
new byte[16384];
346 this.zipFileStream.Seek(zfe.FileOffset, SeekOrigin.Begin);
347 uint bytesPending = zfe.FileSize;
348 while (bytesPending > 0)
350 int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length));
351 stream.Write(buffer, 0, bytesRead);
352 bytesPending -= (uint)bytesRead;
383 var signature =
new byte[4];
384 zipFileStream.Seek(zfe.HeaderOffset, SeekOrigin.Begin);
385 zipFileStream.Read(signature, 0, 4);
386 if (BitConverter.ToUInt32(signature, 0) != 0x04034b50)
390 Stream inStream = GetZipStream(zfe);
391 if (inStream == null)
397 zipFileStream.Seek(zfe.FileOffset, SeekOrigin.Begin);
398 inStream.Read(buffer, 0, buffer.Length);
414 if (this.centralDirImage == null)
416 throw new InvalidOperationException(
"Central directory currently does not exist");
419 var result =
new List<ZipFileEntry>();
422 while (pointer < this.centralDirImage.Length)
424 uint signature = BitConverter.ToUInt32(this.centralDirImage, pointer);
425 if (signature != 0x02014b50)
430 result.Add(this.GetEntry(ref pointer));
433 return result.ToArray();
451 var signature =
new byte[4];
452 this.zipFileStream.Seek(zfe.HeaderOffset, SeekOrigin.Begin);
453 this.zipFileStream.Read(signature, 0, 4);
454 if (BitConverter.ToUInt32(signature, 0) != 0x04034b50)
456 throw new InvalidOperationException(
"Not a valid zip entry.");
463 case Compression.Store:
464 inStream = this.zipFileStream;
466 case Compression.Deflate:
467 inStream =
new DeflateStream(this.zipFileStream, CompressionMode.Decompress,
true);
470 throw new InvalidOperationException(
"Not a valid zip entry.");
473 this.zipFileStream.Seek(zfe.FileOffset, SeekOrigin.Begin);
499 private static DateTime DosTimeToDateTime(uint dosDateTime)
502 (
int)(dosDateTime >> 25) + 1980,
503 (
int)(dosDateTime >> 21) & 15,
504 (
int)(dosDateTime >> 16) & 31,
505 (
int)(dosDateTime >> 11) & 31,
506 (
int)(dosDateTime >> 5) & 63,
507 (
int)(dosDateTime & 31) * 2);
519 private ZipFileEntry GetEntry(ref
int pointer)
521 bool encodeUtf8 = (BitConverter.ToUInt16(this.centralDirImage, pointer + 8) & 0x0800) != 0;
522 ushort method = BitConverter.ToUInt16(this.centralDirImage, pointer + 10);
523 uint modifyTime = BitConverter.ToUInt32(this.centralDirImage, pointer + 12);
524 uint crc32 = BitConverter.ToUInt32(this.centralDirImage, pointer + 16);
525 uint comprSize = BitConverter.ToUInt32(this.centralDirImage, pointer + 20);
526 uint fileSize = BitConverter.ToUInt32(this.centralDirImage, pointer + 24);
527 ushort filenameSize = BitConverter.ToUInt16(this.centralDirImage, pointer + 28);
528 ushort extraSize = BitConverter.ToUInt16(this.centralDirImage, pointer + 30);
529 ushort commentSize = BitConverter.ToUInt16(this.centralDirImage, pointer + 32);
530 uint headerOffset = BitConverter.ToUInt32(this.centralDirImage, pointer + 42);
531 int commentsStart = 46 + filenameSize + extraSize;
532 int headerSize = commentsStart + commentSize;
533 Encoding encoder = encodeUtf8 ? Encoding.UTF8 : Encoding.Default;
534 string comment = null;
537 comment = encoder.GetString(this.centralDirImage, pointer + commentsStart, commentSize);
540 var zfe =
new ZipFileEntry
543 FilenameInZip = encoder.GetString(
this.centralDirImage, pointer + 46, filenameSize),
544 FileOffset = this.GetFileOffset(headerOffset),
546 CompressedSize = comprSize,
547 HeaderOffset = headerOffset,
548 HeaderSize = (uint)headerSize,
550 ModifyTime = DosTimeToDateTime(modifyTime),
551 Comment = comment ??
string.Empty,
552 ZipFileName = this.FileName
554 pointer += headerSize;
567 private uint GetFileOffset(uint headerOffset)
569 var buffer =
new byte[2];
571 this.zipFileStream.Seek(headerOffset + 26, SeekOrigin.Begin);
572 this.zipFileStream.Read(buffer, 0, 2);
573 ushort filenameSize = BitConverter.ToUInt16(buffer, 0);
574 this.zipFileStream.Read(buffer, 0, 2);
575 ushort extraSize = BitConverter.ToUInt16(buffer, 0);
577 long offset = 30 + filenameSize + extraSize + headerOffset;
591 private Stream GetZipStream(ZipFileEntry zfe)
595 case Compression.Store:
596 return this.zipFileStream;
597 case Compression.Deflate:
598 return new DeflateStream(this.zipFileStream, CompressionMode.Decompress,
true);
610 private bool ReadFileInfo()
612 if (this.zipFileStream.Length < 22)
619 this.zipFileStream.Seek(-17, SeekOrigin.End);
620 var br =
new BinaryReader(this.zipFileStream);
623 this.zipFileStream.Seek(-5, SeekOrigin.Current);
624 uint sig = br.ReadUInt32();
625 if (sig == 0x06054b50)
627 this.zipFileStream.Seek(6, SeekOrigin.Current);
629 this.EntryCount = br.ReadUInt16();
630 int centralSize = br.ReadInt32();
631 uint centralDirOffset = br.ReadUInt32();
632 ushort commentSize = br.ReadUInt16();
635 if (this.zipFileStream.Position + commentSize !=
this.zipFileStream.Length)
641 this.centralDirImage =
new byte[centralSize];
642 this.zipFileStream.Seek(centralDirOffset, SeekOrigin.Begin);
643 this.zipFileStream.Read(this.centralDirImage, 0, centralSize);
646 this.zipFileStream.Seek(centralDirOffset, SeekOrigin.Begin);
650 while (this.zipFileStream.Position > 0);
654 Debug.WriteLine(ex.Message);
Represents an entry in Zip file directory
Unique class for compression/decompression file. Represents a Zip file.
uint CompressedSize
Gets the compressed file size.
The zip file validation handler.
System.Text.Encoding Encoding
System.IO.FileMode FileMode
ZipFile(Stream stream)
Initializes a new instance of the ZipFile class. Method to open an existing storage from stream ...
ZipFile(string filename)
Initializes a new instance of the ZipFile class. Method to open an existing storage file ...
ZipFileEntry[] GetAllEntries()
Read all the file records in the central directory
bool ExtractFile(ZipFileEntry zfe, Stream stream)
Copy the contents of a stored file into an opened stream
bool ExtractFile(ZipFileEntry zfe, byte[] buffer)
Copy the contents of a stored file into an opened stream
bool ShouldCancel
Gets or sets a value indicating whether ShouldCancel.
uint Crc32
Gets the 32-bit checksum of entire file.
void Close()
Updates central directory (if pertinent) and close the Zip storage
bool ExtractFile(ZipFileEntry zfe, string filename)
Copy the contents of a stored file into a physical file
static uint DateTimeToDosTime(DateTime dateTime)
DOS Date and time are packed values with the following format: MS-DOS date bits description: 0-4 Day ...
void Dispose()
Closes the Zip file stream
Compression
Compression method enumeration
string Filename
Gets Filename.
Stream ReadFile(ZipFileEntry zfe)
Copy the contents of a stored file into an opened stream
Compression Method
Gets the compression method.
static bool Validate(ZipFileValidationHandler validationHandler)
Ensures that the zip file is valid.