Ejemplo n.º 1
0
        private List <Zip64LocalFileDataField> ReadZip64DataFields(LocalFileHeader entry)
        {
            // The Zip64 data field in the local file header is a subset of the information in the central directory
            // header, so use the central directory flow and map the input/output.
            var centralDirectoryHeader = new CentralDirectoryHeader
            {
                DataFields       = entry.DataFields,
                UncompressedSize = entry.UncompressedSize,
                CompressedSize   = entry.CompressedSize,
            };

            var fields = ReadZip64DataFields(centralDirectoryHeader, ZipConstants.MaximumZip64LocalFileDataFieldSize);

            return(fields
                   .Select(x => new Zip64LocalFileDataField
            {
                CompressedSize = x.CompressedSize,
                UncompressedSize = x.UncompressedSize,
            })
                   .ToList());
        }
Ejemplo n.º 2
0
        private async Task <DataDescriptor> ReadDataDescriptor(
            ZipDirectory directory,
            List <CentralDirectoryHeader> entries,
            CentralDirectoryHeader entry,
            Zip64DataField zip64,
            LocalFileHeader localEntry)
        {
            var compressedSize   = zip64?.CompressedSize ?? entry.CompressedSize;
            var uncompressedSize = zip64?.UncompressedSize ?? entry.UncompressedSize;

            var dataDescriptorPosition = entry.LocalHeaderOffset
                                         + ZipConstants.LocalFileHeaderSize
                                         + localEntry.NameSize
                                         + localEntry.ExtraFieldSize
                                         + compressedSize;

            _stream.Position = (long)dataDescriptorPosition;

            var dataDescriptor = new DataDescriptor();

            using (var buffer = await LoadBinaryReaderAsync(_buffer, ZipConstants.DataDescriptorSize))
            {
                var fieldA = buffer.ReadUInt32();
                var fieldB = buffer.ReadUInt32();
                var fieldC = buffer.ReadUInt32();
                var fieldD = buffer.ReadUInt32();

                // Check the first field to see if is the signature. This is the most reliable check but can yield
                // false negatives. This is because it's possible for the CRC-32 to be the same as the optional
                // data descriptor signature. There is no possibility for false positive. That is, if the first
                // byte does not match signature, then the first byte is definitely the CRC-32.
                var firstFieldImpliesNoSignature = fieldA != ZipConstants.DataDescriptorSignature;

                // 1. Use the known field values from the central directory, given the first field matches the signature.
                var valuesImplySignature = !firstFieldImpliesNoSignature &&
                                           fieldB == entry.Crc32 &&
                                           fieldC == compressedSize &&
                                           fieldD == uncompressedSize;
                if (valuesImplySignature)
                {
                    return(CreateDataDescriptor(fieldB, fieldC, fieldD, hasSignature: true));
                }

                // 2. Use the known field values from the central directory.
                var valuesImplyNoSignature = fieldA == entry.Crc32 &&
                                             fieldB == compressedSize &&
                                             fieldC == uncompressedSize;
                if (valuesImplyNoSignature)
                {
                    return(CreateDataDescriptor(fieldA, fieldB, fieldC, hasSignature: false));
                }

                // 3. Use just the signature.
                if (!firstFieldImpliesNoSignature)
                {
                    return(CreateDataDescriptor(fieldB, fieldC, fieldD, hasSignature: true));
                }

                return(CreateDataDescriptor(fieldA, fieldB, fieldC, hasSignature: false));
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Reads a specific local file header given a central directory header for a file.
        /// </summary>
        /// <param name="directory">The ZIP directory instance containing the provided <paramref name="entry"/>.</param>
        /// <param name="entry">The central directory header to read the local file header for.</param>
        /// <param name="readDataDescriptor">Whether or not to read the data descriptor, if present.</param>
        /// <returns>The local file header.</returns>
        public async Task <LocalFileHeader> ReadLocalFileHeaderAsync(ZipDirectory directory, CentralDirectoryHeader entry, bool readDataDescriptor)
        {
            if (directory == null)
            {
                throw new ArgumentNullException(nameof(directory));
            }

            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            var entries = directory.Entries ?? new List <CentralDirectoryHeader>();

            if (!entries.Contains(entry))
            {
                throw new ArgumentException(Strings.HeaderDoesNotMatchDirectory, nameof(entry));
            }

            if ((entry.Flags & (ushort)ZipEntryFlags.Encrypted) != 0)
            {
                throw new MiniZipException(Strings.EncryptedFilesNotSupported);
            }

            var zip64             = entry.Zip64DataFields.FirstOrDefault();
            var localHeaderOffset = zip64?.LocalHeaderOffset ?? entry.LocalHeaderOffset;

            _stream.Position = (long)localHeaderOffset;

            if (await ReadUInt32Async() != ZipConstants.LocalFileHeaderSignature)
            {
                throw new MiniZipException(Strings.InvalidLocalFileHeaderSignature);
            }

            var localEntry = new LocalFileHeader();

            using (var buffer = await LoadBinaryReaderAsync(_buffer, ZipConstants.LocalFileHeaderSizeWithoutSignature))
            {
                localEntry.VersionToExtract  = buffer.ReadUInt16();
                localEntry.Flags             = buffer.ReadUInt16();
                localEntry.CompressionMethod = buffer.ReadUInt16();
                localEntry.LastModifiedTime  = buffer.ReadUInt16();
                localEntry.LastModifiedDate  = buffer.ReadUInt16();
                localEntry.Crc32             = buffer.ReadUInt32();
                localEntry.CompressedSize    = buffer.ReadUInt32();
                localEntry.UncompressedSize  = buffer.ReadUInt32();
                localEntry.NameSize          = buffer.ReadUInt16();
                localEntry.ExtraFieldSize    = buffer.ReadUInt16();
            }

            localEntry.Name = new byte[localEntry.NameSize];
            await ReadFullyAsync(localEntry.Name);

            localEntry.ExtraField = new byte[localEntry.ExtraFieldSize];
            await ReadFullyAsync(localEntry.ExtraField);

            localEntry.DataFields      = ReadDataFields(localEntry.ExtraField);
            localEntry.Zip64DataFields = ReadZip64DataFields(localEntry);

            // Try to read the data descriptor.
            if (readDataDescriptor && (localEntry.Flags & (ushort)ZipEntryFlags.DataDescriptor) != 0)
            {
                localEntry.DataDescriptor = await ReadDataDescriptor(directory, entries, entry, zip64, localEntry);
            }

            return(localEntry);
        }