private void ReadCentralDirectory() { try { //assume ReadEndOfCentralDirectory has been called and has populated _centralDirectoryStart _archiveStream.Seek(_centralDirectoryStart, SeekOrigin.Begin); Int64 numberOfEntries = 0; //read the central directory ZipCentralDirectoryFileHeader currentHeader; Boolean saveExtraFieldsAndComments = Mode == ZipArchiveMode.Update; while (ZipCentralDirectoryFileHeader.TryReadBlock(_archiveReader, saveExtraFieldsAndComments, out 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)); } }
//if saveExtraFieldsAndComments is false, FileComment and ExtraFields will be null //in either case, the zip64 extra field info will be incorporated into other fields static public Boolean TryReadBlock(BinaryReader reader, Boolean saveExtraFieldsAndComments, out ZipCentralDirectoryFileHeader header) { header = new ZipCentralDirectoryFileHeader(); if (reader.ReadUInt32() != SignatureConstant) { return(false); } header.VersionMadeBy = reader.ReadUInt16(); header.VersionNeededToExtract = reader.ReadUInt16(); header.GeneralPurposeBitFlag = reader.ReadUInt16(); header.CompressionMethod = reader.ReadUInt16(); header.LastModified = reader.ReadUInt32(); header.Crc32 = reader.ReadUInt32(); UInt32 compressedSizeSmall = reader.ReadUInt32(); UInt32 uncompressedSizeSmall = reader.ReadUInt32(); header.FilenameLength = reader.ReadUInt16(); header.ExtraFieldLength = reader.ReadUInt16(); header.FileCommentLength = reader.ReadUInt16(); UInt16 diskNumberStartSmall = reader.ReadUInt16(); header.InternalFileAttributes = reader.ReadUInt16(); header.ExternalFileAttributes = reader.ReadUInt32(); UInt32 relativeOffsetOfLocalHeaderSmall = reader.ReadUInt32(); header.Filename = reader.ReadBytes(header.FilenameLength); Boolean uncompressedSizeInZip64 = uncompressedSizeSmall == ZipHelper.Mask32Bit; Boolean compressedSizeInZip64 = compressedSizeSmall == ZipHelper.Mask32Bit; Boolean relativeOffsetInZip64 = relativeOffsetOfLocalHeaderSmall == ZipHelper.Mask32Bit; Boolean 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)) { if (saveExtraFieldsAndComments) { header.ExtraFields = ZipGenericExtraField.ParseExtraField(str); zip64 = Zip64ExtraField.GetAndRemoveZip64Block(header.ExtraFields, uncompressedSizeInZip64, compressedSizeInZip64, relativeOffsetInZip64, diskNumberStartInZip64); } else { header.ExtraFields = null; 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. reader.BaseStream.AdvanceToPosition(endExtraFields); if (saveExtraFieldsAndComments) { header.FileComment = reader.ReadBytes(header.FileCommentLength); } else { reader.BaseStream.Position += header.FileCommentLength; header.FileComment = null; } header.UncompressedSize = zip64.UncompressedSize == null ? uncompressedSizeSmall : zip64.UncompressedSize.Value; header.CompressedSize = zip64.CompressedSize == null ? compressedSizeSmall : zip64.CompressedSize.Value; header.RelativeOffsetOfLocalHeader = zip64.LocalHeaderOffset == null ? relativeOffsetOfLocalHeaderSmall : zip64.LocalHeaderOffset.Value; header.DiskNumberStart = zip64.StartDiskNumber == null ? diskNumberStartSmall : zip64.StartDiskNumber.Value; return(true); }