Beispiel #1
0
        // Initializes, attaches it to archive
        internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd)
        {
            Archive = archive;

            _diskNumberStart       = cd.DiskNumberStart;
            _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag;
            _compressionMethod     = (CompressionMethodValues)cd.CompressionMethod;

            // Leave this as a uint and let the caller convert it if it wants (perf optimization)
            LastWriteTime = cd.LastModified;

            CompressedLength     = cd.CompressedSize;
            Length               = cd.UncompressedSize;
            ExternalAttributes   = (int)cd.ExternalFileAttributes;
            _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader;

            // we don't know this yet: should be _offsetOfLocalHeader + 30 + _storedEntryNameBytes.Length + extrafieldlength
            // but entryname/extra length could be different in LH
            _storedOffsetOfCompressedData = null;

            Crc32 = cd.Crc32;

            // Sacrifice a slight amount of time for safety. Zips entry names are emphatically NOT supposed to
            // have backslashes according to the spec, but they might anyway, so normalize them all to forward slashes.
            FullName = DecodeEntryName(cd.Filename)?.Replace('\\', '/') ?? throw new ArgumentNullException(nameof(FullName));
            Name     = ParseFileName(FullName, (ZipVersionMadeByPlatform)cd.VersionMadeByCompatibility);
        }
        // Initializes, attaches it to archive
        internal ZipArchiveEntry(ZipArchiveFast archive, ZipCentralDirectoryFileHeader cd)
        {
            Archive = archive;

            _diskNumberStart       = cd.DiskNumberStart;
            _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag;
            _compressionMethod     = (CompressionMethodValues)cd.CompressionMethod;

            // Leave this as a uint and let the caller convert it if it wants (perf optimization)
            LastWriteTime = cd.LastModified;

            CompressedLength     = cd.CompressedSize;
            Length               = cd.UncompressedSize;
            _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader;

            // we don't know this yet: should be _offsetOfLocalHeader + 30 + _storedEntryNameBytes.Length + extrafieldlength
            // but entryname/extra length could be different in LH
            _storedOffsetOfCompressedData = null;

            // Sacrifice a slight amount of time for safety. Zips entry names are emphatically NOT supposed to
            // have backslashes according to the spec, but they might anyway, so normalize them all to forward slashes.
            FullName = DecodeEntryName(cd.Filename).Replace('\\', '/');
            // Lazy-load Name so we don't preemptively do a ton of Substring() calls when we don't need to.
            _versionMadeByCompatibility = (ZipVersionMadeByPlatform)cd.VersionMadeByCompatibility;
        }
Beispiel #3
0
        private void ReadCentralDirectory()
        {
            try
            {
                // assume ReadEndOfCentralDirectory has been called and has populated _centralDirectoryStart

                ArchiveStream.Seek(_centralDirectoryStart, SeekOrigin.Begin);

                long numberOfEntries = 0;

                //read the central directory
                while (ZipCentralDirectoryFileHeader.TryReadBlock(ArchiveReader, out var currentHeader))
                {
                    AddEntry(new ZipArchiveEntry(this, currentHeader));
                    numberOfEntries++;
                }

                if (numberOfEntries != _expectedNumberOfEntries)
                {
                    throw new InvalidDataException(SR.NumEntriesWrong);
                }
            }
            catch (EndOfStreamException ex)
            {
                throw new InvalidDataException(SR.Format(SR.CentralDirectoryInvalid, ex));
            }
        }
Beispiel #4
0
        // if saveExtraFieldsAndComments is false, FileComment and ExtraFields will be null
        // in either case, the zip64 extra field info will be incorporated into other fields
        internal static bool TryReadBlock(BinaryReader reader, out ZipCentralDirectoryFileHeader header)
        {
            header = new ZipCentralDirectoryFileHeader();

            if (reader.ReadUInt32() != SignatureConstant)
            {
                return(false);
            }

            reader.ReadByte();   // VersionMadeBySpecification
            header.VersionMadeByCompatibility = reader.ReadByte();
            reader.ReadUInt16(); // VersionNeededToExtract
            header.GeneralPurposeBitFlag = reader.ReadUInt16();
            header.CompressionMethod     = reader.ReadUInt16();
            header.LastModified          = reader.ReadUInt32();
            reader.ReadUInt32(); // Crc32
            uint compressedSizeSmall   = reader.ReadUInt32();
            uint uncompressedSizeSmall = reader.ReadUInt32();

            header.FilenameLength    = reader.ReadUInt16();
            header.ExtraFieldLength  = reader.ReadUInt16();
            header.FileCommentLength = reader.ReadUInt16();
            ushort diskNumberStartSmall = reader.ReadUInt16();

            reader.ReadUInt16(); // InternalFileAttributes
            reader.ReadUInt32(); // ExternalFileAttributes
            uint relativeOffsetOfLocalHeaderSmall = reader.ReadUInt32();

            header.Filename = reader.ReadBytes(header.FilenameLength);

            bool uncompressedSizeInZip64 = uncompressedSizeSmall == ZipHelper.Mask32Bit;
            bool compressedSizeInZip64   = compressedSizeSmall == ZipHelper.Mask32Bit;
            bool relativeOffsetInZip64   = relativeOffsetOfLocalHeaderSmall == ZipHelper.Mask32Bit;
            bool diskNumberStartInZip64  = diskNumberStartSmall == ZipHelper.Mask16Bit;

            Zip64ExtraField zip64;

            long endExtraFields = reader.BaseStream.Position + header.ExtraFieldLength;

            using (Stream str = new SubReadStream(reader.BaseStream, reader.BaseStream.Position, header.ExtraFieldLength))
            {
                zip64 = Zip64ExtraField.GetJustZip64Block(str,
                                                          uncompressedSizeInZip64, compressedSizeInZip64,
                                                          relativeOffsetInZip64, diskNumberStartInZip64);
            }

            // There are zip files that have malformed ExtraField blocks in which GetJustZip64Block() silently
            // bails out without reading all the way to the end of the ExtraField block. Thus we must force the
            // stream's position to the proper place.

            // Fen's note: Original did a seek here, which for some reason is like 300x slower than a read, and
            // also inexplicably causes ReadUInt32() to be 4x as slow and/or occur 4x as often(?!)
            // Buffer alignments...? I dunno. Anyway. Speed.
            // Also maybe not a good idea to use something that's faster when I don't know why it's faster.
            // But my results are the same as the old method, so herpaderp.
            reader.BaseStream.AdvanceToPosition(endExtraFields + header.FileCommentLength);

            header.UncompressedSize            = zip64.UncompressedSize ?? uncompressedSizeSmall;
            header.CompressedSize              = zip64.CompressedSize ?? compressedSizeSmall;
            header.RelativeOffsetOfLocalHeader = zip64.LocalHeaderOffset ?? relativeOffsetOfLocalHeaderSmall;
            header.DiskNumberStart             = zip64.StartDiskNumber ?? diskNumberStartSmall;

            return(true);
        }