Exemple #1
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;
        }
Exemple #2
0
    /// <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();
      }
    }
Exemple #3
0
 // 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);
   }
 }
Exemple #4
0
    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);
        }
      }
    }
Exemple #5
0
    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;
      }
    }
Exemple #6
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;
    }