public void Pack(IPackStreamContext streamContext, IEnumerable <string> files)
 {
     if (files == null)
     {
         throw new ArgumentNullException("files");
     }
     Pack(streamContext, files, 0L);
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Creates a cabinet or chain of cabinets.
 /// </summary>
 /// <param name="streamContext">A context interface to handle opening
 /// and closing of cabinet and file streams.</param>
 /// <param name="files">The paths of the files in the archive (not
 /// external file paths).</param>
 /// <param name="maxArchiveSize">The maximum number of bytes for one
 /// cabinet before the contents are chained to the next cabinet, or zero
 /// for unlimited cabinet size.</param>
 /// <exception cref="ArchiveException">The cabinet could not be
 /// created.</exception>
 /// <remarks>
 /// The stream context implementation may provide a mapping from the
 /// file paths within the cabinet to the external file paths.
 /// <para>Smaller folder sizes can make it more efficient to extract
 /// individual files out of large cabinet packages.</para>
 /// </remarks>
 internal override void Pack(
     IPackStreamContext streamContext,
     IEnumerable <string> files,
     long maxArchiveSize)
 {
     this.Packer.CompressionLevel = this.CompressionLevel;
     this.Packer.UseTempFiles     = this.UseTempFiles;
     this.Packer.Pack(streamContext, files, maxArchiveSize);
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Creates a cabinet or chain of cabinets.
 /// </summary>
 /// <param name="streamContext">A context interface to handle opening
 /// and closing of cabinet and file streams.</param>
 /// <param name="files">The paths of the files in the archive (not
 /// external file paths).</param>
 /// <param name="maxArchiveSize">The maximum number of bytes for one
 /// cabinet before the contents are chained to the next cabinet, or zero
 /// for unlimited cabinet size.</param>
 /// <exception cref="ArchiveException">The cabinet could not be
 /// created.</exception>
 /// <remarks>
 /// The stream context implementation may provide a mapping from the
 /// file paths within the cabinet to the external file paths.
 /// <para>Smaller folder sizes can make it more efficient to extract
 /// individual files out of large cabinet packages.</para>
 /// </remarks>
 public override void Pack(
     IPackStreamContext streamContext,
     IEnumerable <string> files,
     long maxArchiveSize)
 {
     Packer.CompressionLevel = CompressionLevel;
     Packer.UseTempFiles     = UseTempFiles;
     Packer.Pack(streamContext, files, maxArchiveSize);
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates an archive.
        /// </summary>
        /// <param name="streamContext">A context interface to handle opening
        /// and closing of archive and file streams.</param>
        /// <param name="files">The paths of the files in the archive
        /// (not external file paths).</param>
        /// <exception cref="ArchiveException">The archive could not be
        /// created.</exception>
        /// <remarks>
        /// The stream context implementation may provide a mapping from the
        /// file paths within the archive to the external file paths.
        /// </remarks>
        internal void Pack(IPackStreamContext streamContext, IEnumerable <string> files)
        {
            if (files == null)
            {
                throw new ArgumentNullException("files");
            }

            this.Pack(streamContext, files, 0);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Moves to the next archive in the sequence if necessary.
        /// </summary>
        private void CheckArchiveWriteStream(
            IPackStreamContext streamContext,
            long maxArchiveSize,
            long requiredSize,
            ref Stream archiveStream)
        {
            if (archiveStream != null &&
                archiveStream.Length > 0 && maxArchiveSize > 0)
            {
                long sizeRemaining = maxArchiveSize - archiveStream.Length;
                if (sizeRemaining < requiredSize)
                {
                    string nextArchiveName = streamContext.GetArchiveName(
                        this.currentArchiveNumber + 1);

                    if (string.IsNullOrWhiteSpace(nextArchiveName))
                    {
                        throw new FileNotFoundException("No name provided for archive #" +
                                                        this.currentArchiveNumber + 1);
                    }

                    this.currentArchiveTotalBytes     = archiveStream.Position;
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;

                    streamContext.CloseArchiveWriteStream(
                        this.currentArchiveNumber,
                        nextArchiveName,
                        archiveStream);
                    archiveStream = null;

                    this.OnProgress(ArchiveProgressType.FinishArchive);

                    this.currentArchiveNumber++;
                    this.totalArchives++;
                    this.currentArchiveBytesProcessed = 0;
                    this.currentArchiveTotalBytes     = 0;
                }
            }

            if (archiveStream == null)
            {
                if (this.currentArchiveNumber > 0)
                {
                    this.OnProgress(ArchiveProgressType.StartArchive);
                }

                archiveStream = streamContext.OpenArchiveWriteStream(
                    this.currentArchiveNumber, this.mainArchiveName, true, this);

                if (archiveStream == null)
                {
                    throw new FileNotFoundException("Stream not provided for archive #" +
                                                    this.currentArchiveNumber);
                }
            }
        }
Ejemplo n.º 6
0
        public static void Pack(this ArchiveInfo o, string sourceDirectory, bool includeSubdirectories, CompressionLevel compLevel, EventHandler <ArchiveProgressEventArgs> progressHandler, IPackStreamContext ipackstreamcontext)
        {
            IList <string> relativeFilePathsInDirectoryTree = GetRelativeFilePathsInDirectoryTree(sourceDirectory, includeSubdirectories);

            o.PackFiles(sourceDirectory, relativeFilePathsInDirectoryTree, relativeFilePathsInDirectoryTree, compLevel, progressHandler);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Creates a zip archive or chain of zip archives.
        /// </summary>
        /// <param name="streamContext">A context interface to handle opening
        /// and closing of archive and file streams.</param>
        /// <param name="files">An array of file lists.  Each list is
        /// compressed into one stream in the archive.</param>
        /// <param name="maxArchiveSize">The maximum number of bytes for one archive
        /// before the contents are chained to the next archive, or zero for unlimited
        /// archive size.</param>
        /// <exception cref="ArchiveException">The archive could not be
        /// created.</exception>
        /// <remarks>
        /// The stream context implementation may provide a mapping from the file
        /// paths within the archive to the external file paths.
        /// </remarks>
        public override void Pack(
            IPackStreamContext streamContext,
            IEnumerable<string> files,
            long maxArchiveSize)
        {
            if (streamContext == null)
            {
                throw new ArgumentNullException("streamContext");
            }

            if (files == null)
            {
                throw new ArgumentNullException("files");
            }

            lock (this)
            {
                Stream archiveStream = null;
                try
                {
                    this.ResetProgressData();
                    this.totalArchives = 1;

                    object forceZip64Value = streamContext.GetOption("forceZip64", null);
                    bool forceZip64 = Convert.ToBoolean(
                        forceZip64Value, CultureInfo.InvariantCulture);

                    // Count the total number of files and bytes to be compressed.
                    foreach (string file in files)
                    {
                        FileAttributes attributes;
                        DateTime lastWriteTime;
                        Stream fileStream = streamContext.OpenFileReadStream(
                            file,
                            out attributes,
                            out lastWriteTime);
                        if (fileStream != null)
                        {
                            this.totalFileBytes += fileStream.Length;
                            this.totalFiles++;
                            streamContext.CloseFileReadStream(file, fileStream);
                        }
                    }

                    List<ZipFileHeader> fileHeaders = new List<ZipFileHeader>();
                    this.currentFileNumber = -1;

                    if (this.currentArchiveName == null)
                    {
                        this.mainArchiveName = streamContext.GetArchiveName(0);
                        this.currentArchiveName = this.mainArchiveName;

                        if (string.IsNullOrWhiteSpace(this.currentArchiveName))
                        {
                            throw new FileNotFoundException("No name provided for archive.");
                        }
                    }

                    this.OnProgress(ArchiveProgressType.StartArchive);

                    // Compress files one by one, saving header info for each.
                    foreach (string file in files)
                    {
                        ZipFileHeader fileHeader = this.PackOneFile(
                                streamContext,
                                file,
                                maxArchiveSize,
                                forceZip64,
                                ref archiveStream);

                        if (fileHeader != null)
                        {
                            fileHeaders.Add(fileHeader);
                        }

                        this.currentArchiveTotalBytes = (archiveStream != null ?
                            archiveStream.Position : 0);
                        this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
                    }

                    bool zip64 = forceZip64 || this.totalFiles > UInt16.MaxValue;

                    // Write the central directory composed of all the file headers.
                    uint centralDirStartArchiveNumber = 0;
                    long centralDirStartPosition = 0;
                    long centralDirSize = 0;
                    for (int i = 0; i < fileHeaders.Count; i++)
                    {
                        ZipFileHeader fileHeader = fileHeaders[i];

                        int headerSize = fileHeader.GetSize(true);
                        centralDirSize += headerSize;

                        this.CheckArchiveWriteStream(
                            streamContext,
                            maxArchiveSize,
                            headerSize,
                            ref archiveStream);

                        if (i == 0)
                        {
                            centralDirStartArchiveNumber = (uint) this.currentArchiveNumber;
                            centralDirStartPosition = archiveStream.Position;
                        }

                        fileHeader.Write(archiveStream, true);
                        if (fileHeader.zip64)
                        {
                            zip64 = true;
                        }
                    }

                    this.currentArchiveTotalBytes =
                        (archiveStream != null ? archiveStream.Position : 0);
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;

                    ZipEndOfCentralDirectory eocd = new ZipEndOfCentralDirectory();
                    eocd.dirStartDiskNumber = centralDirStartArchiveNumber;
                    eocd.entriesOnDisk = fileHeaders.Count;
                    eocd.totalEntries = fileHeaders.Count;
                    eocd.dirSize = centralDirSize;
                    eocd.dirOffset = centralDirStartPosition;
                    eocd.comment = this.comment;

                    Zip64EndOfCentralDirectoryLocator eocdl =
                        new Zip64EndOfCentralDirectoryLocator();

                    int maxFooterSize = eocd.GetSize(false);
                    if (archiveStream != null && (zip64 || archiveStream.Position >
                        ((long) UInt32.MaxValue) - eocd.GetSize(false)))
                    {
                        maxFooterSize += eocd.GetSize(true) + (int)
                            Zip64EndOfCentralDirectoryLocator.EOCDL64_SIZE;
                        zip64 = true;
                    }

                    this.CheckArchiveWriteStream(
                        streamContext,
                        maxArchiveSize,
                        maxFooterSize,
                        ref archiveStream);
                    eocd.diskNumber = (uint) this.currentArchiveNumber;

                    if (zip64)
                    {
                        eocd.versionMadeBy = 45;
                        eocd.versionNeeded = 45;
                        eocd.zip64 = true;
                        eocdl.dirOffset = archiveStream.Position;
                        eocdl.dirStartDiskNumber = (uint) this.currentArchiveNumber;
                        eocdl.totalDisks = (uint) this.currentArchiveNumber + 1;
                        eocd.Write(archiveStream);
                        eocdl.Write(archiveStream);

                        eocd.dirOffset = UInt32.MaxValue;
                        eocd.dirStartDiskNumber = UInt16.MaxValue;
                    }

                    eocd.zip64 = false;
                    eocd.Write(archiveStream);

                    this.currentArchiveTotalBytes = archiveStream.Position;
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
                }
                finally
                {
                    if (archiveStream != null)
                    {
                        streamContext.CloseArchiveWriteStream(
                            this.currentArchiveNumber, this.mainArchiveName, archiveStream);
                        this.OnProgress(ArchiveProgressType.FinishArchive);
                    }
                }
            }
        }
Ejemplo n.º 8
0
 public static void Pack(this ArchiveInfo o, string sourceDirectory, IPackStreamContext ipackstreamcontext)
 {
     o.Pack(sourceDirectory, false, CompressionLevel.Max, null);
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Writes compressed bytes of one file to the archive,
        /// keeping track of the CRC and number of bytes written.
        /// </summary>
        private long PackFileBytes(
            IPackStreamContext streamContext,
            Stream fileStream,
            long maxArchiveSize,
            Converter<Stream, Stream> compressionStreamCreator,
            ref Stream archiveStream,
            out uint crc)
        {
            long writeStartPosition = archiveStream.Position;
            long bytesWritten = 0;
            CrcStream fileCrcStream = new CrcStream(fileStream);

            ConcatStream concatStream = new ConcatStream(
                delegate(ConcatStream s)
                {
                    Stream sourceStream = s.Source;
                    bytesWritten += sourceStream.Position - writeStartPosition;

                    this.CheckArchiveWriteStream(
                        streamContext,
                        maxArchiveSize,
                        1,
                        ref sourceStream);

                    writeStartPosition = sourceStream.Position;
                    s.Source = sourceStream;
                });

            concatStream.Source = archiveStream;

            if (maxArchiveSize > 0)
            {
                concatStream.SetLength(maxArchiveSize);
            }

            Stream compressionStream = compressionStreamCreator(concatStream);

            try
            {
                byte[] buf = new byte[4096];
                long bytesRemaining = fileStream.Length;
                int counter = 0;
                while (bytesRemaining > 0)
                {
                    int count = (int) Math.Min(
                        bytesRemaining, (long) buf.Length);

                    count = fileCrcStream.Read(buf, 0, count);
                    if (count <= 0)
                    {
                        throw new ZipException(
                            "Failed to read file: " + this.currentFileName);
                    }

                    compressionStream.Write(buf, 0, count);
                    bytesRemaining -= count;

                    this.fileBytesProcessed += count;
                    this.currentFileBytesProcessed += count;
                    this.currentArchiveTotalBytes = concatStream.Source.Position;
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;

                    if (++counter % 16 == 0) // Report every 64K
                    {
                        this.OnProgress(ArchiveProgressType.PartialFile);
                    }
                }

                if (compressionStream is DeflateStream)
                {
                    compressionStream.Close();
                }
                else
                {
                    compressionStream.Flush();
                }
            }
            finally
            {
                archiveStream = concatStream.Source;
            }

            bytesWritten += archiveStream.Position - writeStartPosition;

            crc = fileCrcStream.Crc;

            return bytesWritten;
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Adds one file to a zip archive in the process of being created.
        /// </summary>
        private ZipFileHeader PackOneFile(
            IPackStreamContext streamContext,
            string file,
            long maxArchiveSize,
            bool forceZip64,
            ref Stream archiveStream)
        {
            Stream fileStream = null;
            int headerArchiveNumber = 0;
            try
            {
                // TODO: call GetOption to get compression method for the specific file
                ZipCompressionMethod compressionMethod = ZipCompressionMethod.Deflate;
                if (this.CompressionLevel == CompressionLevel.None)
                {
                    compressionMethod = ZipCompressionMethod.Store;
                }

                Converter<Stream, Stream> compressionStreamCreator;
                if (!ZipEngine.compressionStreamCreators.TryGetValue(
                    compressionMethod, out compressionStreamCreator))
                {
                    return null;
                }

                FileAttributes attributes;
                DateTime lastWriteTime;
                fileStream = streamContext.OpenFileReadStream(
                    file, out attributes, out lastWriteTime);
                if (fileStream == null)
                {
                    return null;
                }

                this.currentFileName = file;
                this.currentFileNumber++;

                this.currentFileTotalBytes = fileStream.Length;
                this.currentFileBytesProcessed = 0;
                this.OnProgress(ArchiveProgressType.StartFile);

                ZipFileInfo fileInfo = new ZipFileInfo(
                    file,
                    this.currentArchiveNumber,
                    attributes,
                    lastWriteTime,
                    fileStream.Length,
                    0,
                    compressionMethod);

                bool zip64 = forceZip64 || fileStream.Length >= (long) UInt32.MaxValue;
                ZipFileHeader fileHeader = new ZipFileHeader(fileInfo, zip64);

                this.CheckArchiveWriteStream(
                    streamContext,
                    maxArchiveSize,
                    fileHeader.GetSize(false),
                    ref archiveStream);

                long headerPosition = archiveStream.Position;
                fileHeader.Write(archiveStream, false);
                headerArchiveNumber = this.currentArchiveNumber;

                uint crc;
                long bytesWritten = this.PackFileBytes(
                    streamContext,
                    fileStream,
                    maxArchiveSize,
                    compressionStreamCreator,
                    ref archiveStream,
                    out crc);

                fileHeader.Update(
                    bytesWritten,
                    fileStream.Length,
                    crc,
                    headerPosition,
                    headerArchiveNumber);

                streamContext.CloseFileReadStream(file, fileStream);
                fileStream = null;

                // Go back and rewrite the updated file header.
                if (this.currentArchiveNumber == headerArchiveNumber)
                {
                    long fileEndPosition = archiveStream.Position;
                    archiveStream.Seek(headerPosition, SeekOrigin.Begin);
                    fileHeader.Write(archiveStream, false);
                    archiveStream.Seek(fileEndPosition, SeekOrigin.Begin);
                }
                else
                {
                    // The file spanned archives, so temporarily reopen
                    // the archive where it started.
                    string headerArchiveName = streamContext.GetArchiveName(
                        headerArchiveNumber + 1);
                    Stream headerStream = null;
                    try
                    {
                        headerStream = streamContext.OpenArchiveWriteStream(
                            headerArchiveNumber, headerArchiveName, false, this);
                        headerStream.Seek(headerPosition, SeekOrigin.Begin);
                        fileHeader.Write(headerStream, false);
                    }
                    finally
                    {
                        if (headerStream != null)
                        {
                            streamContext.CloseArchiveWriteStream(
                                headerArchiveNumber, headerArchiveName, headerStream);
                        }
                    }
                }

                this.OnProgress(ArchiveProgressType.FinishFile);

                return fileHeader;
            }
            finally
            {
                if (fileStream != null)
                {
                    streamContext.CloseFileReadStream(
                        this.currentFileName, fileStream);
                }
            }
        }
Ejemplo n.º 11
0
        public void Pack(
            IPackStreamContext streamContext,
            IEnumerable<string> files,
            long maxArchiveSize)
        {
            if (streamContext == null)
            {
                throw new ArgumentNullException("streamContext");
            }

            if (files == null)
            {
                throw new ArgumentNullException("files");
            }

            lock (this)
            {
                try
                {
                    this.context = streamContext;

                    this.ResetProgressData();

                    this.CreateFci(maxArchiveSize);

                    foreach (string file in files)
                    {
                        FileAttributes attributes;
                        DateTime lastWriteTime;
                        Stream fileStream = this.context.OpenFileReadStream(
                            file,
                            out attributes,
                            out lastWriteTime);
                        if (fileStream != null)
                        {
                            this.totalFileBytes += fileStream.Length;
                            this.totalFiles++;
                            this.context.CloseFileReadStream(file, fileStream);
                        }
                    }

                    long uncompressedBytesInFolder = 0;
                    this.currentFileNumber = -1;

                    foreach (string file in files)
                    {
                        FileAttributes attributes;
                        DateTime lastWriteTime;
                        Stream fileStream = this.context.OpenFileReadStream(
                            file, out attributes, out lastWriteTime);
                        if (fileStream == null)
                        {
                            continue;
                        }

                        if (fileStream.Length >= (long) NativeMethods.FCI.MAX_FOLDER)
                        {
                            throw new NotSupportedException(String.Format(
                                CultureInfo.InvariantCulture,
                                "File {0} exceeds maximum file size " +
                                "for cabinet format.",
                                file));
                        }

                        if (uncompressedBytesInFolder > 0)
                        {
                            // Automatically create a new folder if this file
                            // won't fit in the current folder.
                            bool nextFolder = uncompressedBytesInFolder
                                + fileStream.Length >= (long) NativeMethods.FCI.MAX_FOLDER;

                            // Otherwise ask the client if it wants to
                            // move to the next folder.
                            if (!nextFolder)
                            {
                                object nextFolderOption = streamContext.GetOption(
                                    "nextFolder",
                                    new object[] { file, this.currentFolderNumber });
                                nextFolder = Convert.ToBoolean(
                                    nextFolderOption, CultureInfo.InvariantCulture);
                            }

                            if (nextFolder)
                            {
                                this.FlushFolder();
                                uncompressedBytesInFolder = 0;
                            }
                        }

                        if (this.currentFolderTotalBytes > 0)
                        {
                            this.currentFolderTotalBytes = 0;
                            this.currentFolderNumber++;
                            uncompressedBytesInFolder = 0;
                        }

                        this.currentFileName = file;
                        this.currentFileNumber++;

                        this.currentFileTotalBytes = fileStream.Length;
                        this.currentFileBytesProcessed = 0;
                        this.OnProgress(ArchiveProgressType.StartFile);

                        uncompressedBytesInFolder += fileStream.Length;

                        this.AddFile(
                            file,
                            fileStream,
                            attributes,
                            lastWriteTime,
                            false,
                            this.CompressionLevel);
                    }

                    this.FlushFolder();
                    this.FlushCabinet();
                }
                finally
                {
                    if (this.CabStream != null)
                    {
                        this.context.CloseArchiveWriteStream(
                            this.currentArchiveNumber,
                            this.currentArchiveName,
                            this.CabStream);
                        this.CabStream = null;
                    }

                    if (this.FileStream != null)
                    {
                        this.context.CloseFileReadStream(
                            this.currentFileName, this.FileStream);
                        this.FileStream = null;
                    }
                    this.context = null;

                    if (this.fciHandle != null)
                    {
                        this.fciHandle.Dispose();
                        this.fciHandle = null;
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Moves to the next archive in the sequence if necessary.
        /// </summary>
        private void CheckArchiveWriteStream(
            IPackStreamContext streamContext,
            long maxArchiveSize,
            long requiredSize,
            ref Stream archiveStream)
        {
            if (archiveStream != null &&
                archiveStream.Length > 0 && maxArchiveSize > 0)
            {
                long sizeRemaining = maxArchiveSize - archiveStream.Length;
                if (sizeRemaining < requiredSize)
                {
                    string nextArchiveName = streamContext.GetArchiveName(
                        this.currentArchiveNumber + 1);

                    if (string.IsNullOrWhiteSpace(nextArchiveName))
                    {
                        throw new FileNotFoundException("No name provided for archive #" +
                            this.currentArchiveNumber + 1);
                    }

                    this.currentArchiveTotalBytes = archiveStream.Position;
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;

                    streamContext.CloseArchiveWriteStream(
                        this.currentArchiveNumber,
                        nextArchiveName,
                        archiveStream);
                    archiveStream = null;

                    this.OnProgress(ArchiveProgressType.FinishArchive);

                    this.currentArchiveNumber++;
                    this.totalArchives++;
                    this.currentArchiveBytesProcessed = 0;
                    this.currentArchiveTotalBytes = 0;
                }
            }

            if (archiveStream == null)
            {
                if (this.currentArchiveNumber > 0)
                {
                    this.OnProgress(ArchiveProgressType.StartArchive);
                }

                archiveStream = streamContext.OpenArchiveWriteStream(
                    this.currentArchiveNumber, this.mainArchiveName, true, this);

                if (archiveStream == null)
                {
                    throw new FileNotFoundException("Stream not provided for archive #" +
                        this.currentArchiveNumber);
                }
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Creates a zip archive or chain of zip archives.
        /// </summary>
        /// <param name="streamContext">A context interface to handle opening
        /// and closing of archive and file streams.</param>
        /// <param name="files">An array of file lists.  Each list is
        /// compressed into one stream in the archive.</param>
        /// <param name="maxArchiveSize">The maximum number of bytes for one archive
        /// before the contents are chained to the next archive, or zero for unlimited
        /// archive size.</param>
        /// <exception cref="ArchiveException">The archive could not be
        /// created.</exception>
        /// <remarks>
        /// The stream context implementation may provide a mapping from the file
        /// paths within the archive to the external file paths.
        /// </remarks>
        public override void Pack(
            IPackStreamContext streamContext,
            IEnumerable <string> files,
            long maxArchiveSize)
        {
            if (streamContext == null)
            {
                throw new ArgumentNullException("streamContext");
            }

            if (files == null)
            {
                throw new ArgumentNullException("files");
            }

            lock (this)
            {
                Stream archiveStream = null;
                try
                {
                    this.ResetProgressData();
                    this.totalArchives = 1;

                    object forceZip64Value = streamContext.GetOption("forceZip64", null);
                    bool   forceZip64      = Convert.ToBoolean(
                        forceZip64Value, CultureInfo.InvariantCulture);

                    // Count the total number of files and bytes to be compressed.
                    foreach (string file in files)
                    {
                        FileAttributes attributes;
                        DateTime       lastWriteTime;
                        Stream         fileStream = streamContext.OpenFileReadStream(
                            file,
                            out attributes,
                            out lastWriteTime);
                        if (fileStream != null)
                        {
                            this.totalFileBytes += fileStream.Length;
                            this.totalFiles++;
                            streamContext.CloseFileReadStream(file, fileStream);
                        }
                    }

                    List <ZipFileHeader> fileHeaders = new List <ZipFileHeader>();
                    this.currentFileNumber = -1;

                    if (this.currentArchiveName == null)
                    {
                        this.mainArchiveName    = streamContext.GetArchiveName(0);
                        this.currentArchiveName = this.mainArchiveName;

                        if (string.IsNullOrWhiteSpace(this.currentArchiveName))
                        {
                            throw new FileNotFoundException("No name provided for archive.");
                        }
                    }

                    this.OnProgress(ArchiveProgressType.StartArchive);

                    // Compress files one by one, saving header info for each.
                    foreach (string file in files)
                    {
                        ZipFileHeader fileHeader = this.PackOneFile(
                            streamContext,
                            file,
                            maxArchiveSize,
                            forceZip64,
                            ref archiveStream);

                        if (fileHeader != null)
                        {
                            fileHeaders.Add(fileHeader);
                        }

                        this.currentArchiveTotalBytes = (archiveStream != null ?
                                                         archiveStream.Position : 0);
                        this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
                    }

                    bool zip64 = forceZip64 || this.totalFiles > UInt16.MaxValue;

                    // Write the central directory composed of all the file headers.
                    uint centralDirStartArchiveNumber = 0;
                    long centralDirStartPosition      = 0;
                    long centralDirSize = 0;
                    for (int i = 0; i < fileHeaders.Count; i++)
                    {
                        ZipFileHeader fileHeader = fileHeaders[i];

                        int headerSize = fileHeader.GetSize(true);
                        centralDirSize += headerSize;

                        this.CheckArchiveWriteStream(
                            streamContext,
                            maxArchiveSize,
                            headerSize,
                            ref archiveStream);

                        if (i == 0)
                        {
                            centralDirStartArchiveNumber = (uint)this.currentArchiveNumber;
                            centralDirStartPosition      = archiveStream.Position;
                        }

                        fileHeader.Write(archiveStream, true);
                        if (fileHeader.zip64)
                        {
                            zip64 = true;
                        }
                    }

                    this.currentArchiveTotalBytes =
                        (archiveStream != null ? archiveStream.Position : 0);
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;

                    ZipEndOfCentralDirectory eocd = new ZipEndOfCentralDirectory();
                    eocd.dirStartDiskNumber = centralDirStartArchiveNumber;
                    eocd.entriesOnDisk      = fileHeaders.Count;
                    eocd.totalEntries       = fileHeaders.Count;
                    eocd.dirSize            = centralDirSize;
                    eocd.dirOffset          = centralDirStartPosition;
                    eocd.comment            = this.comment;

                    Zip64EndOfCentralDirectoryLocator eocdl =
                        new Zip64EndOfCentralDirectoryLocator();

                    int maxFooterSize = eocd.GetSize(false);
                    if (archiveStream != null && (zip64 || archiveStream.Position >
                                                  ((long)UInt32.MaxValue) - eocd.GetSize(false)))
                    {
                        maxFooterSize += eocd.GetSize(true) + (int)
                                         Zip64EndOfCentralDirectoryLocator.EOCDL64_SIZE;
                        zip64 = true;
                    }

                    this.CheckArchiveWriteStream(
                        streamContext,
                        maxArchiveSize,
                        maxFooterSize,
                        ref archiveStream);
                    eocd.diskNumber = (uint)this.currentArchiveNumber;

                    if (zip64)
                    {
                        eocd.versionMadeBy       = 45;
                        eocd.versionNeeded       = 45;
                        eocd.zip64               = true;
                        eocdl.dirOffset          = archiveStream.Position;
                        eocdl.dirStartDiskNumber = (uint)this.currentArchiveNumber;
                        eocdl.totalDisks         = (uint)this.currentArchiveNumber + 1;
                        eocd.Write(archiveStream);
                        eocdl.Write(archiveStream);

                        eocd.dirOffset          = UInt32.MaxValue;
                        eocd.dirStartDiskNumber = UInt16.MaxValue;
                    }

                    eocd.zip64 = false;
                    eocd.Write(archiveStream);

                    this.currentArchiveTotalBytes     = archiveStream.Position;
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
                }
                finally
                {
                    if (archiveStream != null)
                    {
                        streamContext.CloseArchiveWriteStream(
                            this.currentArchiveNumber, this.mainArchiveName, archiveStream);
                        this.OnProgress(ArchiveProgressType.FinishArchive);
                    }
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Writes compressed bytes of one file to the archive,
        /// keeping track of the CRC and number of bytes written.
        /// </summary>
        private long PackFileBytes(
            IPackStreamContext streamContext,
            Stream fileStream,
            long maxArchiveSize,
            Func <Stream, Stream> compressionStreamCreator,
            ref Stream archiveStream,
            out uint crc)
        {
            long      writeStartPosition = archiveStream.Position;
            long      bytesWritten       = 0;
            CrcStream fileCrcStream      = new CrcStream(fileStream);

            ConcatStream concatStream = new ConcatStream(
                delegate(ConcatStream s)
            {
                Stream sourceStream = s.Source;
                bytesWritten       += sourceStream.Position - writeStartPosition;

                this.CheckArchiveWriteStream(
                    streamContext,
                    maxArchiveSize,
                    1,
                    ref sourceStream);

                writeStartPosition = sourceStream.Position;
                s.Source           = sourceStream;
            });

            concatStream.Source = archiveStream;

            if (maxArchiveSize > 0)
            {
                concatStream.SetLength(maxArchiveSize);
            }

            Stream compressionStream = compressionStreamCreator(concatStream);

            try
            {
                byte[] buf            = new byte[4096];
                long   bytesRemaining = fileStream.Length;
                int    counter        = 0;
                while (bytesRemaining > 0)
                {
                    int count = (int)Math.Min(
                        bytesRemaining, (long)buf.Length);

                    count = fileCrcStream.Read(buf, 0, count);
                    if (count <= 0)
                    {
                        throw new ZipException(
                                  "Failed to read file: " + this.currentFileName);
                    }

                    compressionStream.Write(buf, 0, count);
                    bytesRemaining -= count;

                    this.fileBytesProcessed          += count;
                    this.currentFileBytesProcessed   += count;
                    this.currentArchiveTotalBytes     = concatStream.Source.Position;
                    this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;

                    if (++counter % 16 == 0) // Report every 64K
                    {
                        this.OnProgress(ArchiveProgressType.PartialFile);
                    }
                }

                if (compressionStream is DeflateStream)
                {
#if CORECLR
                    compressionStream.Dispose();
#else
                    compressionStream.Close();
#endif
                }
                else
                {
                    compressionStream.Flush();
                }
            }
            finally
            {
                archiveStream = concatStream.Source;
            }

            bytesWritten += archiveStream.Position - writeStartPosition;

            crc = fileCrcStream.Crc;

            return(bytesWritten);
        }
Ejemplo n.º 15
0
 public static void Pack(this ArchiveInfo o, string sourceDirectory, IList <string> sourceFileNames, IList <string> fileNames, IPackStreamContext ipackstreamcontext)
 {
     o.PackFiles(sourceDirectory, sourceFileNames, fileNames, CompressionLevel.Max, null);
 }
Ejemplo n.º 16
0
 public void Pack(IPackStreamContext streamContext, IEnumerable <string> files, long maxArchiveSize)
 {
     if (streamContext == null)
     {
         throw new ArgumentNullException("streamContext");
     }
     if (files == null)
     {
         throw new ArgumentNullException("files");
     }
     checked
     {
         lock (this)
         {
             try
             {
                 context = streamContext;
                 ResetProgressData();
                 CreateFci(maxArchiveSize);
                 foreach (string file in files)
                 {
                     FileAttributes attributes;
                     DateTime       lastWriteTime;
                     Stream         stream = context.OpenFileReadStream(file, out attributes, out lastWriteTime);
                     if (stream != null)
                     {
                         totalFileBytes += stream.Length;
                         totalFiles++;
                         context.CloseFileReadStream(file, stream);
                     }
                 }
                 long num = 0L;
                 currentFileNumber = -1;
                 foreach (string file2 in files)
                 {
                     FileAttributes attributes2;
                     DateTime       lastWriteTime2;
                     Stream         stream2 = context.OpenFileReadStream(file2, out attributes2, out lastWriteTime2);
                     if (stream2 == null)
                     {
                         continue;
                     }
                     if (stream2.Length >= 2147450880)
                     {
                         throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "File {0} exceeds maximum file size for cabinet format.", file2));
                     }
                     if (num > 0)
                     {
                         bool flag = num + stream2.Length >= 2147450880;
                         if (!flag)
                         {
                             flag = Convert.ToBoolean(streamContext.GetOption("nextFolder", new object[2]
                             {
                                 file2,
                                 currentFolderNumber
                             }), CultureInfo.InvariantCulture);
                         }
                         if (flag)
                         {
                             FlushFolder();
                             num = 0L;
                         }
                     }
                     if (currentFolderTotalBytes > 0)
                     {
                         currentFolderTotalBytes = 0L;
                         currentFolderNumber++;
                         num = 0L;
                     }
                     currentFileName = file2;
                     currentFileNumber++;
                     currentFileTotalBytes     = stream2.Length;
                     currentFileBytesProcessed = 0L;
                     OnProgress(ArchiveProgressType.StartFile);
                     num += stream2.Length;
                     AddFile(file2, stream2, attributes2, lastWriteTime2, execute: false, CompressionLevel);
                 }
                 FlushFolder();
                 FlushCabinet();
             }
             finally
             {
                 if (base.CabStream != null)
                 {
                     context.CloseArchiveWriteStream(currentArchiveNumber, currentArchiveName, base.CabStream);
                     base.CabStream = null;
                 }
                 if (base.FileStream != null)
                 {
                     context.CloseFileReadStream(currentFileName, base.FileStream);
                     base.FileStream = null;
                 }
                 context = null;
                 if (fciHandle != null)
                 {
                     fciHandle.Dispose();
                     fciHandle = null;
                 }
             }
         }
     }
 }
Ejemplo n.º 17
0
 /// <summary>
 /// Creates an archive or chain of archives.
 /// </summary>
 /// <param name="streamContext">A context interface to handle opening
 /// and closing of archive and file streams.</param>
 /// <param name="files">The paths of the files in the archive (not
 /// external file paths).</param>
 /// <param name="maxArchiveSize">The maximum number of bytes for one
 /// archive before the contents are chained to the next archive, or zero
 /// for unlimited archive size.</param>
 /// <exception cref="ArchiveException">The archive could not be
 /// created.</exception>
 /// <remarks>
 /// The stream context implementation may provide a mapping from the file
 /// paths within the archive to the external file paths.
 /// </remarks>
 public abstract void Pack(
     IPackStreamContext streamContext,
     IEnumerable<string> files,
     long maxArchiveSize);
Ejemplo n.º 18
0
        /// <summary>
        /// Creates an archive.
        /// </summary>
        /// <param name="streamContext">A context interface to handle opening
        /// and closing of archive and file streams.</param>
        /// <param name="files">The paths of the files in the archive
        /// (not external file paths).</param>
        /// <exception cref="ArchiveException">The archive could not be
        /// created.</exception>
        /// <remarks>
        /// The stream context implementation may provide a mapping from the
        /// file paths within the archive to the external file paths.
        /// </remarks>
        public void Pack(IPackStreamContext streamContext, IEnumerable<string> files)
        {
            if (files == null)
            {
                throw new ArgumentNullException("files");
            }

            this.Pack(streamContext, files, 0);
        }
Ejemplo n.º 19
0
 /// <summary>
 /// Creates a cabinet or chain of cabinets.
 /// </summary>
 /// <param name="streamContext">A context interface to handle opening
 /// and closing of cabinet and file streams.</param>
 /// <param name="files">The paths of the files in the archive (not
 /// external file paths).</param>
 /// <param name="maxArchiveSize">The maximum number of bytes for one
 /// cabinet before the contents are chained to the next cabinet, or zero
 /// for unlimited cabinet size.</param>
 /// <exception cref="ArchiveException">The cabinet could not be
 /// created.</exception>
 /// <remarks>
 /// The stream context implementation may provide a mapping from the
 /// file paths within the cabinet to the external file paths.
 /// <para>Smaller folder sizes can make it more efficient to extract
 /// individual files out of large cabinet packages.</para>
 /// </remarks>
 public override void Pack(
     IPackStreamContext streamContext,
     IEnumerable<string> files,
     long maxArchiveSize)
 {
     this.Packer.CompressionLevel = this.CompressionLevel;
     this.Packer.UseTempFiles = this.UseTempFiles;
     this.Packer.Pack(streamContext, files, maxArchiveSize);
 }
Ejemplo n.º 20
0
 /// <summary>
 /// Creates an archive or chain of archives.
 /// </summary>
 /// <param name="streamContext">A context interface to handle opening
 /// and closing of archive and file streams.</param>
 /// <param name="files">The paths of the files in the archive (not
 /// external file paths).</param>
 /// <param name="maxArchiveSize">The maximum number of bytes for one
 /// archive before the contents are chained to the next archive, or zero
 /// for unlimited archive size.</param>
 /// <exception cref="ArchiveException">The archive could not be
 /// created.</exception>
 /// <remarks>
 /// The stream context implementation may provide a mapping from the file
 /// paths within the archive to the external file paths.
 /// </remarks>
 public abstract void Pack(
     IPackStreamContext streamContext,
     IEnumerable <string> files,
     long maxArchiveSize);
Ejemplo n.º 21
0
        public void Pack(
            IPackStreamContext streamContext,
            IEnumerable <string> files,
            long maxArchiveSize)
        {
            if (streamContext == null)
            {
                throw new ArgumentNullException("streamContext");
            }

            if (files == null)
            {
                throw new ArgumentNullException("files");
            }

            lock (this)
            {
                try
                {
                    this.context = streamContext;

                    this.ResetProgressData();

                    this.CreateFci(maxArchiveSize);

                    foreach (string file in files)
                    {
                        FileAttributes attributes;
                        DateTime       lastWriteTime;
                        Stream         fileStream = this.context.OpenFileReadStream(
                            file,
                            out attributes,
                            out lastWriteTime);
                        if (fileStream != null)
                        {
                            this.totalFileBytes += fileStream.Length;
                            this.totalFiles++;
                            this.context.CloseFileReadStream(file, fileStream);
                        }
                    }

                    long uncompressedBytesInFolder = 0;
                    this.currentFileNumber = -1;

                    foreach (string file in files)
                    {
                        FileAttributes attributes;
                        DateTime       lastWriteTime;
                        Stream         fileStream = this.context.OpenFileReadStream(
                            file, out attributes, out lastWriteTime);
                        if (fileStream == null)
                        {
                            continue;
                        }

                        if (fileStream.Length >= (long)NativeMethods.FCI.MAX_FOLDER)
                        {
                            throw new NotSupportedException(String.Format(
                                                                CultureInfo.InvariantCulture,
                                                                "File {0} exceeds maximum file size " +
                                                                "for cabinet format.",
                                                                file));
                        }

                        if (uncompressedBytesInFolder > 0)
                        {
                            // Automatically create a new folder if this file
                            // won't fit in the current folder.
                            bool nextFolder = uncompressedBytesInFolder
                                              + fileStream.Length >= (long)NativeMethods.FCI.MAX_FOLDER;

                            // Otherwise ask the client if it wants to
                            // move to the next folder.
                            if (!nextFolder)
                            {
                                object nextFolderOption = streamContext.GetOption(
                                    "nextFolder",
                                    new object[] { file, this.currentFolderNumber });
                                nextFolder = Convert.ToBoolean(
                                    nextFolderOption, CultureInfo.InvariantCulture);
                            }

                            if (nextFolder)
                            {
                                this.FlushFolder();
                                uncompressedBytesInFolder = 0;
                            }
                        }

                        if (this.currentFolderTotalBytes > 0)
                        {
                            this.currentFolderTotalBytes = 0;
                            this.currentFolderNumber++;
                            uncompressedBytesInFolder = 0;
                        }

                        this.currentFileName = file;
                        this.currentFileNumber++;

                        this.currentFileTotalBytes     = fileStream.Length;
                        this.currentFileBytesProcessed = 0;
                        this.OnProgress(ArchiveProgressType.StartFile);

                        uncompressedBytesInFolder += fileStream.Length;

                        this.AddFile(
                            file,
                            fileStream,
                            attributes,
                            lastWriteTime,
                            false,
                            this.CompressionLevel);
                    }

                    this.FlushFolder();
                    this.FlushCabinet();
                }
                finally
                {
                    if (this.CabStream != null)
                    {
                        this.context.CloseArchiveWriteStream(
                            this.currentArchiveNumber,
                            this.currentArchiveName,
                            this.CabStream);
                        this.CabStream = null;
                    }

                    if (this.FileStream != null)
                    {
                        this.context.CloseFileReadStream(
                            this.currentFileName, this.FileStream);
                        this.FileStream = null;
                    }
                    this.context = null;

                    if (this.fciHandle != null)
                    {
                        this.fciHandle.Dispose();
                        this.fciHandle = null;
                    }
                }
            }
        }
Ejemplo n.º 22
0
 public static void Pack(this ArchiveInfo o, string sourceDirectory, IList <string> sourceFileNames, IList <string> fileNames, CompressionLevel compLevel, EventHandler <ArchiveProgressEventArgs> progressHandler, IPackStreamContext ipackstreamcontext)
 {
     if (sourceFileNames == null)
     {
         throw new ArgumentNullException("sourceFileNames");
     }
     checked
     {
         if (fileNames == null)
         {
             string[] array = new string[sourceFileNames.Count];
             for (int i = 0; i < sourceFileNames.Count; i++)
             {
                 array[i] = Path.GetFileName(sourceFileNames[i]);
             }
             fileNames = array;
         }
         else if (fileNames.Count != sourceFileNames.Count)
         {
             throw new ArgumentOutOfRangeException("fileNames");
         }
         using (CompressionEngine compressionEngine = new CabEngine())
         {
             compressionEngine.Progress += progressHandler;
             IDictionary <string, string> files = CreateStringDictionary(fileNames, sourceFileNames);
             ArchiveFileStreamContext     archiveFileStreamContext = new ArchiveFileStreamContext(o.FullName, sourceDirectory, files);
             archiveFileStreamContext.EnableOffsetOpen = true;
             compressionEngine.CompressionLevel        = compLevel;
             compressionEngine.Pack(archiveFileStreamContext, fileNames);
         }
     }
 }
Ejemplo n.º 23
0
        /// <summary>
        /// Adds one file to a zip archive in the process of being created.
        /// </summary>
        private ZipFileHeader PackOneFile(
            IPackStreamContext streamContext,
            string file,
            long maxArchiveSize,
            bool forceZip64,
            ref Stream archiveStream)
        {
            Stream fileStream          = null;
            int    headerArchiveNumber = 0;

            try
            {
                // TODO: call GetOption to get compression method for the specific file
                ZipCompressionMethod compressionMethod = ZipCompressionMethod.Deflate;
                if (this.CompressionLevel == CompressionLevel.None)
                {
                    compressionMethod = ZipCompressionMethod.Store;
                }

                Func <Stream, Stream> compressionStreamCreator;
                if (!ZipEngine.compressionStreamCreators.TryGetValue(
                        compressionMethod, out compressionStreamCreator))
                {
                    return(null);
                }

                FileAttributes attributes;
                DateTime       lastWriteTime;
                fileStream = streamContext.OpenFileReadStream(
                    file, out attributes, out lastWriteTime);
                if (fileStream == null)
                {
                    return(null);
                }

                this.currentFileName = file;
                this.currentFileNumber++;

                this.currentFileTotalBytes     = fileStream.Length;
                this.currentFileBytesProcessed = 0;
                this.OnProgress(ArchiveProgressType.StartFile);

                ZipFileInfo fileInfo = new ZipFileInfo(
                    file,
                    this.currentArchiveNumber,
                    attributes,
                    lastWriteTime,
                    fileStream.Length,
                    0,
                    compressionMethod);

                bool          zip64      = forceZip64 || fileStream.Length >= (long)UInt32.MaxValue;
                ZipFileHeader fileHeader = new ZipFileHeader(fileInfo, zip64);

                this.CheckArchiveWriteStream(
                    streamContext,
                    maxArchiveSize,
                    fileHeader.GetSize(false),
                    ref archiveStream);

                long headerPosition = archiveStream.Position;
                fileHeader.Write(archiveStream, false);
                headerArchiveNumber = this.currentArchiveNumber;

                uint crc;
                long bytesWritten = this.PackFileBytes(
                    streamContext,
                    fileStream,
                    maxArchiveSize,
                    compressionStreamCreator,
                    ref archiveStream,
                    out crc);

                fileHeader.Update(
                    bytesWritten,
                    fileStream.Length,
                    crc,
                    headerPosition,
                    headerArchiveNumber);

                streamContext.CloseFileReadStream(file, fileStream);
                fileStream = null;

                // Go back and rewrite the updated file header.
                if (this.currentArchiveNumber == headerArchiveNumber)
                {
                    long fileEndPosition = archiveStream.Position;
                    archiveStream.Seek(headerPosition, SeekOrigin.Begin);
                    fileHeader.Write(archiveStream, false);
                    archiveStream.Seek(fileEndPosition, SeekOrigin.Begin);
                }
                else
                {
                    // The file spanned archives, so temporarily reopen
                    // the archive where it started.
                    string headerArchiveName = streamContext.GetArchiveName(
                        headerArchiveNumber + 1);
                    Stream headerStream = null;
                    try
                    {
                        headerStream = streamContext.OpenArchiveWriteStream(
                            headerArchiveNumber, headerArchiveName, false, this);
                        headerStream.Seek(headerPosition, SeekOrigin.Begin);
                        fileHeader.Write(headerStream, false);
                    }
                    finally
                    {
                        if (headerStream != null)
                        {
                            streamContext.CloseArchiveWriteStream(
                                headerArchiveNumber, headerArchiveName, headerStream);
                        }
                    }
                }

                this.OnProgress(ArchiveProgressType.FinishFile);

                return(fileHeader);
            }
            finally
            {
                if (fileStream != null)
                {
                    streamContext.CloseFileReadStream(
                        this.currentFileName, fileStream);
                }
            }
        }