Beispiel #1
0
        /// <summary>
        /// Gets the offset of an archive that is positioned 0 or more bytes
        /// from the start of the Stream.
        /// </summary>
        /// <param name="stream">A stream for reading the archive.</param>
        /// <returns>The offset in bytes of the archive,
        /// or -1 if no archive is found in the Stream.</returns>
        /// <remarks>The archive must begin on a 4-byte boundary.</remarks>
        public override long FindArchiveOffset(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            long offset = base.FindArchiveOffset(stream);

            if (offset > 0)
            {
                // Some self-extract packages include the exe stub in file offset calculations.
                // Check the first header directory offset to decide whether the entire
                // archive needs to be offset or not.

                ZipEndOfCentralDirectory eocd = this.GetEOCD(null, stream);
                if (eocd != null && eocd.totalEntries > 0)
                {
                    stream.Seek(eocd.dirOffset, SeekOrigin.Begin);

                    ZipFileHeader header = new ZipFileHeader();
                    if (header.Read(stream, true) && header.localHeaderOffset < stream.Length)
                    {
                        stream.Seek(header.localHeaderOffset, SeekOrigin.Begin);
                        if (header.Read(stream, false))
                        {
                            return(0);
                        }
                    }
                }
            }

            return(offset);
        }
Beispiel #2
0
        /// <summary>
        /// Reads all the file headers from the central directory in the main archive.
        /// </summary>
        private IList <ZipFileHeader> GetCentralDirectory(IUnpackStreamContext streamContext)
        {
            Stream archiveStream = null;

            this.currentArchiveNumber = 0;
            try
            {
                List <ZipFileHeader> headers = new List <ZipFileHeader>();
                archiveStream = this.OpenArchive(streamContext, 0);

                ZipEndOfCentralDirectory eocd = this.GetEOCD(streamContext, archiveStream);
                if (eocd == null)
                {
                    return(null);
                }
                else if (eocd.totalEntries == 0)
                {
                    return(headers);
                }

                headers.Capacity = (int)eocd.totalEntries;

                if (eocd.dirOffset > archiveStream.Length - ZipFileHeader.CFH_FIXEDSIZE)
                {
                    streamContext.CloseArchiveReadStream(
                        this.currentArchiveNumber, String.Empty, archiveStream);
                    archiveStream = null;
                }
                else
                {
                    archiveStream.Seek(eocd.dirOffset, SeekOrigin.Begin);
                    uint sig = new BinaryReader(archiveStream).ReadUInt32();
                    if (sig != ZipFileHeader.CFHSIG)
                    {
                        streamContext.CloseArchiveReadStream(
                            this.currentArchiveNumber, String.Empty, archiveStream);
                        archiveStream = null;
                    }
                }

                if (archiveStream == null)
                {
                    this.currentArchiveNumber = (short)(eocd.dirStartDiskNumber + 1);
                    archiveStream             = streamContext.OpenArchiveReadStream(
                        this.currentArchiveNumber, String.Empty, this);

                    if (archiveStream == null)
                    {
                        return(null);
                    }
                }

                archiveStream.Seek(eocd.dirOffset, SeekOrigin.Begin);

                while (headers.Count < eocd.totalEntries)
                {
                    ZipFileHeader header = new ZipFileHeader();
                    if (!header.Read(archiveStream, true))
                    {
                        throw new ZipException(
                                  "Missing or invalid central directory file header");
                    }

                    headers.Add(header);

                    if (headers.Count < eocd.totalEntries &&
                        archiveStream.Position == archiveStream.Length)
                    {
                        streamContext.CloseArchiveReadStream(
                            this.currentArchiveNumber, String.Empty, archiveStream);
                        this.currentArchiveNumber++;
                        archiveStream = streamContext.OpenArchiveReadStream(
                            this.currentArchiveNumber, String.Empty, this);
                        if (archiveStream == null)
                        {
                            this.currentArchiveNumber = 0;
                            archiveStream             = streamContext.OpenArchiveReadStream(
                                this.currentArchiveNumber, String.Empty, this);
                        }
                    }
                }

                return(headers);
            }
            finally
            {
                if (archiveStream != null)
                {
                    streamContext.CloseArchiveReadStream(
                        this.currentArchiveNumber, String.Empty, archiveStream);
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Unpacks a single file from an archive or archive chain.
        /// </summary>
        private void UnpackOneFile(
            IUnpackStreamContext streamContext,
            ZipFileHeader header,
            ref Stream archiveStream)
        {
            ZipFileInfo fileInfo   = null;
            Stream      fileStream = null;

            try
            {
                Converter <Stream, Stream> compressionStreamCreator;
                if (!ZipEngine.decompressionStreamCreators.TryGetValue(
                        header.compressionMethod, out compressionStreamCreator))
                {
                    // Silently skip files of an unsupported compression method.
                    return;
                }

                long compressedSize;
                long uncompressedSize;
                long localHeaderOffset;
                int  archiveNumber;
                uint crc;
                header.GetZip64Fields(
                    out compressedSize,
                    out uncompressedSize,
                    out localHeaderOffset,
                    out archiveNumber,
                    out crc);

                if (this.currentArchiveNumber != archiveNumber + 1)
                {
                    if (archiveStream != null)
                    {
                        streamContext.CloseArchiveReadStream(
                            this.currentArchiveNumber,
                            String.Empty,
                            archiveStream);
                        archiveStream = null;

                        this.OnProgress(ArchiveProgressType.FinishArchive);
                        this.currentArchiveName = null;
                    }

                    this.currentArchiveNumber         = (short)(archiveNumber + 1);
                    this.currentArchiveBytesProcessed = 0;
                    this.currentArchiveTotalBytes     = 0;

                    archiveStream = this.OpenArchive(
                        streamContext, this.currentArchiveNumber);

                    FileStream archiveFileStream = archiveStream as FileStream;
                    this.currentArchiveName = (archiveFileStream != null ?
                                               Path.GetFileName(archiveFileStream.Name) : null);

                    this.currentArchiveTotalBytes = archiveStream.Length;
                    this.currentArchiveNumber--;
                    this.OnProgress(ArchiveProgressType.StartArchive);
                    this.currentArchiveNumber++;
                }

                archiveStream.Seek(localHeaderOffset, SeekOrigin.Begin);

                ZipFileHeader localHeader = new ZipFileHeader();
                if (!localHeader.Read(archiveStream, false) ||
                    !ZipEngine.AreFilePathsEqual(localHeader.fileName, header.fileName))
                {
                    string msg = "Could not read file: " + header.fileName;
                    throw new ZipException(msg);
                }

                fileInfo = header.ToZipFileInfo();

                fileStream = streamContext.OpenFileWriteStream(
                    fileInfo.FullName,
                    fileInfo.Length,
                    fileInfo.LastWriteTime);

                if (fileStream != null)
                {
                    this.currentFileName           = header.fileName;
                    this.currentFileBytesProcessed = 0;
                    this.currentFileTotalBytes     = fileInfo.Length;
                    this.currentArchiveNumber--;
                    this.OnProgress(ArchiveProgressType.StartFile);
                    this.currentArchiveNumber++;

                    this.UnpackFileBytes(
                        streamContext,
                        fileInfo.FullName,
                        fileInfo.CompressedLength,
                        fileInfo.Length,
                        header.crc32,
                        fileStream,
                        compressionStreamCreator,
                        ref archiveStream);
                }
            }
            finally
            {
                if (fileStream != null)
                {
                    streamContext.CloseFileWriteStream(
                        fileInfo.FullName,
                        fileStream,
                        fileInfo.Attributes,
                        fileInfo.LastWriteTime);

                    this.currentArchiveNumber--;
                    this.OnProgress(ArchiveProgressType.FinishFile);
                    this.currentArchiveNumber++;
                }
            }
        }