Example #1
0
		/// <summary>
		/// Commit current updates, updating this archive.
		/// </summary>
		/// <seealso cref="BeginUpdate()"></seealso>
		/// <seealso cref="AbortUpdate"></seealso>
		public void CommitUpdate()
		{
			CheckUpdating();

			try
			{
				updateIndex_.Clear();
				updateIndex_ = null;

				if (contentsEdited_)
				{
					RunUpdates();
				}
				else if (commentEdited_)
				{
					UpdateCommentOnly();
				}
				else
				{
					// Create an empty archive if none existed originally.
					if ((entries_ != null) && (entries_.Length == 0))
					{
						byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
						using (ZipHelperStream zhs = new ZipHelperStream(baseStream_))
						{
							zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
						}
					}
				}
			}
			finally
			{
				PostUpdateCleanup();
			}
		}
Example #2
0
		private void RunUpdates()
		{
			long sizeEntries = 0;
			long endOfStream = 0;
			bool allOk = true;
			bool 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;
				}

				long centralDirOffset = workFile.baseStream_.Position;

				foreach (ZipUpdate update in updates_)
				{
					if (update != null)
					{
						sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
					}
				}

				byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
				using (ZipHelperStream 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);
				}
			}
		}
		/// <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);
				}

				byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);

				if (name.Length > 0xffff)
				{
					throw new ZipException("Name too long.");
				}

				ZipExtraData 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);
				}

				byte[] extra = ed.GetEntryData();

				byte[] 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
				{
					if (entry.IsDirectory)
					{
						// mark entry as directory (from nikolam.AT.perfectinfo.com)
						WriteLeInt(16);
					}
					else
					{
						WriteLeInt(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 (ZipHelperStream zhs = new ZipHelperStream(baseOutputStream_))
			{
				zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
			}

			entries = null;
		}