/// <summary> /// Reads one entry from the zip directory structure in the zip file. /// </summary> /// /// <param name="zf"> /// The zipfile for which a directory entry will be read. From this param, the /// method gets the ReadStream and the expected text encoding /// (ProvisionalAlternateEncoding) which is used if the entry is not marked /// UTF-8. /// </param> /// /// <param name="previouslySeen"> /// a list of previously seen entry names; used to prevent duplicates. /// </param> /// /// <returns>the entry read from the archive.</returns> internal static ZipEntry ReadDirEntry(ZipFile zf, Dictionary <String, Object> previouslySeen) { System.IO.Stream s = zf.ReadStream; System.Text.Encoding expectedEncoding = (zf.AlternateEncodingUsage == ZipOption.Always) ? zf.AlternateEncoding : ZipFile.DefaultEncoding; int signature = SharedUtilities.ReadSignature(s); // return null if this is not a local file header signature if (IsNotValidZipDirEntrySig(signature)) { s.Seek(-4, System.IO.SeekOrigin.Current); // workitem 10178 SharedUtilities.Workaround_Ladybug318918(s); // Getting "not a ZipDirEntry signature" here is not always wrong or an // error. This can happen when walking through a zipfile. After the // last ZipDirEntry, we expect to read an // EndOfCentralDirectorySignature. When we get this is how we know // we've reached the end of the central directory. if (signature != ZipConstants.EndOfCentralDirectorySignature && signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature && signature != ZipConstants.ZipEntrySignature // workitem 8299 ) { throw new BadReadException(String.Format(" Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position)); } return(null); } int bytesRead = 42 + 4; byte[] block = new byte[42]; int n = s.Read(block, 0, block.Length); if (n != block.Length) { return(null); } int i = 0; ZipEntry zde = new ZipEntry(); zde.AlternateEncoding = expectedEncoding; zde._Source = ZipEntrySource.ZipFile; zde._container = new ZipContainer(zf); unchecked { zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256); zde._VersionNeeded = (short)(block[i++] + block[i++] * 256); zde._BitField = (short)(block[i++] + block[i++] * 256); zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256); zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._LastModified = SharedUtilities.PackedToDateTime(zde._TimeBlob); zde._timestamp |= ZipEntryTimestamp.DOS; zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); } // preserve zde._CompressionMethod_FromZipFile = zde._CompressionMethod; zde._filenameLength = (short)(block[i++] + block[i++] * 256); zde._extraFieldLength = (short)(block[i++] + block[i++] * 256); zde._commentLength = (short)(block[i++] + block[i++] * 256); zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256); zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256); zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); // workitem 7801 zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01); block = new byte[zde._filenameLength]; n = s.Read(block, 0, block.Length); bytesRead += n; if ((zde._BitField & 0x0800) == 0x0800) { // UTF-8 is in use zde._FileNameInArchive = SharedUtilities.Utf8StringFromBuffer(block); } else { zde._FileNameInArchive = SharedUtilities.StringFromBuffer(block, expectedEncoding); } // workitem 10330 // insure unique entry names while (previouslySeen.ContainsKey(zde._FileNameInArchive)) { zde._FileNameInArchive = CopyHelper.AppendCopyToFileName(zde._FileNameInArchive); zde._metadataChanged = true; } if (zde.AttributesIndicateDirectory) { zde.MarkAsDirectory(); // may append a slash to filename if nec. } // workitem 6898 else if (zde._FileNameInArchive.EndsWith("/")) { zde.MarkAsDirectory(); } zde._CompressedFileDataSize = zde._CompressedSize; if ((zde._BitField & 0x01) == 0x01) { // this may change after processing the Extra field zde._Encryption_FromZipFile = zde._Encryption = EncryptionAlgorithm.PkzipWeak; zde._sourceIsEncrypted = true; } if (zde._extraFieldLength > 0) { zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF || zde._UncompressedSize == 0xFFFFFFFF || zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF); // Console.WriteLine(" Input uses Z64?: {0}", zde._InputUsesZip64); bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength); zde._CompressedFileDataSize = zde._CompressedSize; } // we've processed the extra field, so we know the encryption method is set now. if (zde._Encryption == EncryptionAlgorithm.PkzipWeak) { // the "encryption header" of 12 bytes precedes the file data zde._CompressedFileDataSize -= 12; } #if AESCRYPTO else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 || zde.Encryption == EncryptionAlgorithm.WinZipAes256) { zde._CompressedFileDataSize = zde.CompressedSize - (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10); zde._LengthOfTrailer = 10; } #endif // tally the trailing descriptor if ((zde._BitField & 0x0008) == 0x0008) { // sig, CRC, Comp and Uncomp sizes if (zde._InputUsesZip64) { zde._LengthOfTrailer += 24; } else { zde._LengthOfTrailer += 16; } } // workitem 12744 zde.AlternateEncoding = ((zde._BitField & 0x0800) == 0x0800) ? System.Text.Encoding.UTF8 :expectedEncoding; zde.AlternateEncodingUsage = ZipOption.Always; if (zde._commentLength > 0) { block = new byte[zde._commentLength]; n = s.Read(block, 0, block.Length); bytesRead += n; if ((zde._BitField & 0x0800) == 0x0800) { // UTF-8 is in use zde._Comment = SharedUtilities.Utf8StringFromBuffer(block); } else { zde._Comment = SharedUtilities.StringFromBuffer(block, expectedEncoding); } } //zde._LengthOfDirEntry = bytesRead; return(zde); }
private static void ReadCentralDirectoryFooter(ZipFile zf) { Stream s = zf.ReadStream; int signature = SharedUtilities.ReadSignature(s); byte[] block = null; int j = 0; if (signature == ZipConstants.Zip64EndOfCentralDirectoryRecordSignature) { // We have a ZIP64 EOCD // This data block is 4 bytes sig, 8 bytes size, 44 bytes fixed data, // followed by a variable-sized extension block. We have read the sig already. // 8 - datasize (64 bits) // 2 - version made by // 2 - version needed to extract // 4 - number of this disk // 4 - number of the disk with the start of the CD // 8 - total number of entries in the CD on this disk // 8 - total number of entries in the CD // 8 - size of the CD // 8 - offset of the CD // ----------------------- // 52 bytes block = new byte[8 + 44]; s.Read(block, 0, block.Length); Int64 DataSize = BitConverter.ToInt64(block, 0); // == 44 + the variable length if (DataSize < 44) { throw new ZipException("Bad size in the ZIP64 Central Directory."); } zf._versionMadeBy = BitConverter.ToUInt16(block, j); j += 2; zf._versionNeededToExtract = BitConverter.ToUInt16(block, j); j += 2; zf._diskNumberWithCd = BitConverter.ToUInt32(block, j); j += 2; //zf._diskNumberWithCd++; // hack!! // read the extended block block = new byte[DataSize - 44]; s.Read(block, 0, block.Length); // discard the result signature = SharedUtilities.ReadSignature(s); if (signature != ZipConstants.Zip64EndOfCentralDirectoryLocatorSignature) { throw new ZipException("Inconsistent metadata in the ZIP64 Central Directory."); } block = new byte[16]; s.Read(block, 0, block.Length); // discard the result signature = SharedUtilities.ReadSignature(s); } // Throw if this is not a signature for "end of central directory record" // This is a sanity check. if (signature != ZipConstants.EndOfCentralDirectorySignature) { s.Seek(-4, SeekOrigin.Current); throw new BadReadException(String.Format("Bad signature ({0:X8}) at position 0x{1:X8}", signature, s.Position)); } // read the End-of-Central-Directory-Record block = new byte[16]; zf.ReadStream.Read(block, 0, block.Length); // off sz data // ------------------------------------------------------- // 0 4 end of central dir signature (0x06054b50) // 4 2 number of this disk // 6 2 number of the disk with start of the central directory // 8 2 total number of entries in the central directory on this disk // 10 2 total number of entries in the central directory // 12 4 size of the central directory // 16 4 offset of start of central directory with respect to the starting disk number // 20 2 ZIP file comment length // 22 ?? ZIP file comment if (zf._diskNumberWithCd == 0) { zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2); //zf._diskNumberWithCd++; // hack!! } // read the comment here ReadZipFileComment(zf); }