/// <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(); } long numEntries = entries.Count; long sizeEntries = 0; foreach (ZipEntry entry in entries) { WriteLeInt(ZipConstants.CentralHeaderSignature); WriteLeShort(ZipConstants.VersionMadeBy); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((short)entry.CompressionMethod); WriteLeInt((int)entry.DosTime); WriteLeInt((int)entry.Crc); if (entry.IsZip64Forced() || (entry.CompressedSize >= uint.MaxValue)) { WriteLeInt(-1); } else { WriteLeInt((int)entry.CompressedSize); } if (entry.IsZip64Forced() || (entry.Size >= uint.MaxValue)) { WriteLeInt(-1); } else { WriteLeInt((int)entry.Size); } var name = ZipConstants.ConvertToArray(entry.Flags, entry.Name); if (name.Length > 0xffff) { throw new ZipException("Name too long."); } var ed = new ZipExtraData(entry.ExtraData); if (entry.CentralHeaderRequiresZip64) { ed.StartNewEntry(); if (entry.IsZip64Forced() || (entry.Size >= 0xffffffff)) { ed.AddLeLong(entry.Size); } if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffff)) { ed.AddLeLong(entry.CompressedSize); } if (entry.Offset >= 0xffffffff) { ed.AddLeLong(entry.Offset); } ed.AddNewEntry(1); } else { ed.Delete(1); } var extra = ed.GetEntryData(); var entryComment = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Flags, 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 attributes // external file attributes if (entry.ExternalFileAttributes != -1) { WriteLeInt(entry.ExternalFileAttributes); } else { WriteLeInt(entry.IsDirectory ? 16 : 0); } if (entry.Offset >= uint.MaxValue) { WriteLeInt(-1); } else { WriteLeInt((int)entry.Offset); } if (name.Length > 0) { baseOutputStream_.Write(name, 0, name.Length); } if (extra.Length > 0) { baseOutputStream_.Write(extra, 0, extra.Length); } if (entryComment.Length > 0) { baseOutputStream_.Write(entryComment, 0, entryComment.Length); } sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length; } using (var zhs = new ZipHelperStream(baseOutputStream_)) { zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment); } entries = null; }
/// <summary> /// Commit current updates, updating this archive. /// </summary> /// <seealso cref="BeginUpdate()"></seealso> /// <seealso cref="AbortUpdate"></seealso> /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception> public void CommitUpdate() { if (isDisposed_) { throw new ObjectDisposedException("ZipFile"); } CheckUpdating(); try { updateIndex_.Clear(); updateIndex_ = null; if (contentsEdited_) { RunUpdates(); } else { // Create an empty archive if none existed originally. if (entries_.Length == 0) { var theComment = ZipConstants.ConvertToArray(comment_); using (var zhs = new ZipHelperStream(baseStream_)) { zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment); } } } } finally { PostUpdateCleanup(); } }
// NOTE this returns the offset of the first byte after the signature. private long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData) { using (var les = new ZipHelperStream(baseStream_)) { return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData); } }
private void RunUpdates() { long sizeEntries = 0; long endOfStream = 0; var allOk = true; var directUpdate = false; long destinationPosition = 0; // NOT SFX friendly ZipFile workFile; if (IsNewArchive) { workFile = this; workFile.baseStream_.Position = 0; directUpdate = true; } else if (archiveStorage_.UpdateMode == FileUpdateMode.Direct) { workFile = this; workFile.baseStream_.Position = 0; directUpdate = true; // Sort the updates by offset within copies/modifies, then adds. // This ensures that data required by copies will not be overwritten. updates_.Sort(new UpdateComparer()); } else { workFile = Create(archiveStorage_.GetTemporaryOutput()); workFile.UseZip64 = UseZip64; if (key != null) { workFile.key = (byte[]) key.Clone(); } } try { foreach (ZipUpdate update in updates_) { if (update != null) { switch (update.Command) { case UpdateCommand.Copy: if (directUpdate) { CopyEntryDirect(workFile, update, ref destinationPosition); } else { CopyEntry(workFile, update); } break; case UpdateCommand.Modify: // TODO: Direct modifying of an entry will take some legwork. ModifyEntry(workFile, update); break; case UpdateCommand.Add: if (!IsNewArchive && directUpdate) { workFile.baseStream_.Position = destinationPosition; } AddEntry(workFile, update); if (directUpdate) { destinationPosition = workFile.baseStream_.Position; } break; } } } if (!IsNewArchive && directUpdate) { workFile.baseStream_.Position = destinationPosition; } var centralDirOffset = workFile.baseStream_.Position; foreach (ZipUpdate update in updates_) { if (update != null) { sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry); } } var theComment = ZipConstants.ConvertToArray(comment_); using (var zhs = new ZipHelperStream(workFile.baseStream_)) { zhs.WriteEndOfCentralDirectory(updateCount_, sizeEntries, centralDirOffset, theComment); } endOfStream = workFile.baseStream_.Position; // And now patch entries... foreach (ZipUpdate update in updates_) { if (update != null) { // If the size of the entry is zero leave the crc as 0 as well. // The calculated crc will be all bits on... if ((update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0)) { workFile.baseStream_.Position = update.CrcPatchOffset; workFile.WriteLEInt((int) update.OutEntry.Crc); } if (update.SizePatchOffset > 0) { workFile.baseStream_.Position = update.SizePatchOffset; if (update.OutEntry.LocalHeaderRequiresZip64) { workFile.WriteLeLong(update.OutEntry.Size); workFile.WriteLeLong(update.OutEntry.CompressedSize); } else { workFile.WriteLEInt((int) update.OutEntry.CompressedSize); workFile.WriteLEInt((int) update.OutEntry.Size); } } } } } catch (Exception) { allOk = false; } finally { if (directUpdate) { if (allOk) { workFile.baseStream_.Flush(); workFile.baseStream_.SetLength(endOfStream); } } else { workFile.Close(); } } if (allOk) { if (directUpdate) { IsNewArchive = false; workFile.baseStream_.Flush(); ReadEntries(); } else { baseStream_.Close(); Reopen(archiveStorage_.ConvertTemporaryToFinal()); } } else { workFile.Close(); if (!directUpdate && (workFile.Name != null)) { File.Delete(workFile.Name); } } }
private void AddEntry(ZipFile workFile, ZipUpdate update) { Stream source = null; if (update.Entry.IsFile) { source = update.GetSource(); if (source == null) { source = updateDataSource_.GetSource(update.Entry, null); } } if (source != null) { using (source) { var sourceStreamLength = source.Length; if (update.OutEntry.Size < 0) { update.OutEntry.Size = sourceStreamLength; } else { // Check for errant entries. if (update.OutEntry.Size != sourceStreamLength) { throw new ZipException("Entry size/stream size mismatch"); } } workFile.WriteLocalEntryHeader(update); var dataStart = workFile.baseStream_.Position; using (var output = workFile.GetOutputStream(update.OutEntry)) { CopyBytes(update, output, source, sourceStreamLength, true); } var dataEnd = workFile.baseStream_.Position; update.OutEntry.CompressedSize = dataEnd - dataStart; if ((update.OutEntry.Flags & (int) GeneralBitFlags.Descriptor) == (int) GeneralBitFlags.Descriptor) { var helper = new ZipHelperStream(workFile.baseStream_); helper.WriteDataDescriptor(update.OutEntry); } } } else { workFile.WriteLocalEntryHeader(update); update.OutEntry.CompressedSize = 0; } }
/// <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(); } long numEntries = entries.Count; long sizeEntries = 0; foreach (ZipEntry entry in entries) { WriteLeInt(ZipConstants.CentralHeaderSignature); WriteLeShort(ZipConstants.VersionMadeBy); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((short) entry.CompressionMethod); WriteLeInt((int) entry.DosTime); WriteLeInt((int) entry.Crc); if (entry.IsZip64Forced() || (entry.CompressedSize >= uint.MaxValue)) { WriteLeInt(-1); } else { WriteLeInt((int) entry.CompressedSize); } if (entry.IsZip64Forced() || (entry.Size >= uint.MaxValue)) { WriteLeInt(-1); } else { WriteLeInt((int) entry.Size); } var name = ZipConstants.ConvertToArray(entry.Flags, entry.Name); if (name.Length > 0xffff) { throw new ZipException("Name too long."); } var ed = new ZipExtraData(entry.ExtraData); if (entry.CentralHeaderRequiresZip64) { ed.StartNewEntry(); if (entry.IsZip64Forced() || (entry.Size >= 0xffffffff)) { ed.AddLeLong(entry.Size); } if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffff)) { ed.AddLeLong(entry.CompressedSize); } if (entry.Offset >= 0xffffffff) { ed.AddLeLong(entry.Offset); } ed.AddNewEntry(1); } else { ed.Delete(1); } var extra = ed.GetEntryData(); var entryComment = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Flags, 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 attributes // external file attributes if (entry.ExternalFileAttributes != -1) { WriteLeInt(entry.ExternalFileAttributes); } else { WriteLeInt(entry.IsDirectory ? 16 : 0); } if (entry.Offset >= uint.MaxValue) { WriteLeInt(-1); } else { WriteLeInt((int) entry.Offset); } if (name.Length > 0) { baseOutputStream_.Write(name, 0, name.Length); } if (extra.Length > 0) { baseOutputStream_.Write(extra, 0, extra.Length); } if (entryComment.Length > 0) { baseOutputStream_.Write(entryComment, 0, entryComment.Length); } sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length; } using (var zhs = new ZipHelperStream(baseOutputStream_)) { zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment); } entries = null; }