/// <summary>
        /// Creates a central file header from the information in a local file header.
        /// </summary>
        /// <param name="localFileHeader">Local file header to </param>
        public ZipFileHeader(ZipFileHeader localFileHeader)
        {
            if (localFileHeader.central)
            {
                throw new ArgumentException();
            }

            this.central           = true;
            this.compressionMethod = localFileHeader.compressionMethod;
            this.fileName          = localFileHeader.fileName;
            this.fileComment       = localFileHeader.fileComment;
            this.flags             = localFileHeader.flags;
            this.externalFileAttrs = localFileHeader.externalFileAttrs;
            this.internalFileAttrs = localFileHeader.internalFileAttrs;
            this.lastModDate       = localFileHeader.lastModDate;
            this.lastModTime       = localFileHeader.lastModTime;
            this.crc32             = localFileHeader.crc32;

            if (this.zip64)
            {
                this.versionMadeBy = 45;
                this.versionNeeded = 45;

                this.compressedSize   = UInt32.MaxValue;
                this.uncompressedSize = UInt32.MaxValue;
                this.diskStart        = UInt16.MaxValue;

                ZipExtraFileField field = new ZipExtraFileField();
                field.fieldType = ZipExtraFileFieldType.ZIP64;
                field.SetZip64Data(localFileHeader.compressedSize, localFileHeader.uncompressedSize, localFileHeader.localHeaderOffset, localFileHeader.diskStart);
                this.extraFields = new ZipExtraFileField[] { field };
            }
            else
            {
                this.versionMadeBy = 20;
                this.versionNeeded = 20;

                this.localHeaderOffset = localFileHeader.localHeaderOffset;
                this.compressedSize    = localFileHeader.compressedSize;
                this.uncompressedSize  = localFileHeader.uncompressedSize;
            }
        }
Beispiel #2
0
        public void AddFile(Stream stream, string packageUri, string mimeType, CompressionLevel level)
        {
            string      partName    = this.DeterminePartName(packageUri);
            ContentType contentType = this.DetermineContentType(partName, mimeType);

            ZipFileHeader localFileHeader = new ZipFileHeader(false);

            localFileHeader.localHeaderOffset = (uint)this.BaseStream.Position;
            localFileHeader.zip64             = stream.Length > 0xFFFFFFFF;
            localFileHeader.versionMadeBy     = 0;
            localFileHeader.versionNeeded     = localFileHeader.zip64 ? (ushort)45 : (ushort)20;
            localFileHeader.fileName          = partName;
            localFileHeader.compressionMethod = (level == CompressionLevel.NoCompression) ? ZipCompressionMethod.Store : ZipCompressionMethod.Deflate;
            localFileHeader.flags             = this.BaseStream.CanSeek ? ZipFileFlags.None : ZipFileFlags.DataDescriptor;

            localFileHeader.Write(this.BaseStream);

            BlockMapFile blockMapFile = new BlockMapFile(partName)
            {
                Size = stream.Length, ZipLocalFileHeaderSize = localFileHeader.GetSize()
            };

            this.blockMapFiles.Add(blockMapFile);

            ZipCrc             crc     = new ZipCrc();
            BlockDeflateStream deflate = (level == CompressionLevel.NoCompression) ? null : new BlockDeflateStream(this.BaseStream, (BlockDeflateCompressionLevel)level);

            long outputStart = this.BaseStream.Position;

            int read = 0;

            byte[] buffer = new byte[64 * 1024];
            while (0 < (read = stream.Read(buffer, 0, buffer.Length)))
            {
                crc.UpdateCrc(buffer, 0, read);

                string hash;
                using (SHA256 sha256 = SHA256.Create())
                {
                    byte[] hashedBytes = sha256.ComputeHash(buffer, 0, read);
                    hash = Convert.ToBase64String(hashedBytes);
                }

                long compressedBlockSize = 0;
                if (deflate != null)
                {
                    compressedBlockSize = deflate.Deflate(buffer, 0, read);
                }
                else
                {
                    this.BaseStream.Write(buffer, 0, read);
                    compressedBlockSize = -1;
                }

                BlockMapFileBlock block = new BlockMapFileBlock()
                {
                    Hash = hash, CompressedSize = compressedBlockSize
                };
                blockMapFile.Blocks.Add(block);
            }

            if (deflate != null)
            {
                deflate.Flush();
            }
            else
            {
                this.BaseStream.Flush();
            }

            // Update the local file header with data discovered while processing file data.
            localFileHeader.crc32            = crc.Crc;
            localFileHeader.compressedSize   = (uint)(this.BaseStream.Position - outputStart); // (uint)compressedSize;
            localFileHeader.uncompressedSize = (uint)stream.Length;

            // If we're using the data descriptor (because we can't see), append the updated information to the file data.
            if ((localFileHeader.flags & ZipFileFlags.DataDescriptor) == ZipFileFlags.DataDescriptor)
            {
                localFileHeader.WriteDataDescriptor(this.BaseStream);
            }
            else // go back to re-write the updated local file header in place, then seek back to our current location.
            {
                long position = this.BaseStream.Position;

                this.BaseStream.Seek(localFileHeader.localHeaderOffset, SeekOrigin.Begin);
                localFileHeader.Write(this.BaseStream);

                this.BaseStream.Seek(position, SeekOrigin.Begin);
            }

            // If we have a 64-bit local header then the central directory must be
            // ZIP64 as well.
            if (localFileHeader.zip64)
            {
                this.eocd.zip64         = true;
                this.eocd.versionMadeBy = 45;
                this.eocd.versionNeeded = 45;
            }

            ZipFileHeader centralFileHeader = new ZipFileHeader(localFileHeader);

            this.eocd.CentralDirectory.Add(centralFileHeader);
        }
        public ZipEndOfCentralDirectory(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);

            // Start searching for the Zip End of Central Directory signature from the end
            // of the file backwards (towards the beginning of the file). This allows us to
            // find Zip archives with extra data appended to the archive (for whatever reason
            // someone might want to do that).
            long offset = stream.Length - ZipEndOfCentralDirectory.EOCD_RECORD_FIXEDSIZE;

            for (; offset >= 0; --offset)
            {
                stream.Seek(offset, SeekOrigin.Begin);

                uint sig = reader.ReadUInt32();
                if (sig == ZipEndOfCentralDirectory.EOCDSIG)
                {
                    break;
                }
            }

            if (offset < 0)
            {
                throw new InvalidDataException("Failed to find end of central directory record.");
            }

            stream.Seek(offset, SeekOrigin.Begin);
            this.Read(stream);

            // If the offset to the central directory is DWORD_MAX then this must be a 64-bit
            // archive.
            if (this.dirOffset == (long)UInt32.MaxValue)
            {
                string saveComment = this.comment;

                stream.Seek(offset - Zip64EndOfCentralDirectoryLocator.EOCDL64_SIZE, SeekOrigin.Begin);

                Zip64EndOfCentralDirectoryLocator eocdl = new Zip64EndOfCentralDirectoryLocator(stream);
                if (eocdl.dirStartDiskNumber == eocdl.totalDisks - 1)
                {
                    // ZIP64 eocd is entirely in current stream.
                    stream.Seek(eocdl.dirOffset, SeekOrigin.Begin);
                    this.Read64(stream);
                }
                else
                {
                    // TODO: handle EOCD64 spanning archives!
                    throw new NotImplementedException("Zip implementation does not handle end of central directory record that spans archives.");
                }

                this.comment = saveComment;
            }

            // Read the central directory for the archive.
            stream.Seek(this.dirOffset, SeekOrigin.Begin);

            while (this.headers.Count < this.totalEntries)
            {
                ZipFileHeader header = new ZipFileHeader(true);
                if (!header.Read(stream))
                {
                    throw new InvalidDataException("Missing or invalid central directory file header");
                }

                this.headers.Add(header);

                if (this.headers.Count < this.totalEntries && stream.Position == stream.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);
                    //}
                }
            }
        }
Beispiel #4
0
        public IList <ZipFileHeader> GetCentralDirectory(Stream streamContext)
        {
            Stream archiveStream = null;

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

                ZipEndOfCentralDirectory eocd = this.GetEOCD(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(true);
                    if (!header.Read(archiveStream))
                    {
                        throw new InvalidDataException("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);
                //}
            }
        }