예제 #1
0
        // There is a small chance that something very weird could happen here. The code calling into this function
        // will ask for a value from the extra field if the field was masked with FF's. It's theoretically possible
        // that a field was FF's legitimately, and the writer didn't decide to write the corresponding extra field.
        // Also, at the same time, other fields were masked with FF's to indicate looking in the zip64 record.
        // Then, the search for the zip64 record will fail because the expected size is wrong,
        // and a nulled out Zip64ExtraField will be returned. Thus, even though there was Zip64 data,
        // it will not be used. It is questionable whether this situation is possible to detect

        // unlike the other functions that have try-pattern semantics, these functions always return a
        // Zip64ExtraField. If a Zip64 extra field actually doesn't exist, all of the fields in the
        // returned struct will be null
        //
        // If there are more than one Zip64 extra fields, we take the first one that has the expected size
        //
        public static Zip64ExtraField GetJustZip64Block(Stream extraFieldStream,
                                                        bool readUncompressedSize, bool readCompressedSize,
                                                        bool readLocalHeaderOffset, bool readStartDiskNumber)
        {
            Zip64ExtraField zip64Field;

            using (BinaryReader reader = new BinaryReader(extraFieldStream))
            {
                ZipGenericExtraField currentExtraField;
                while (ZipGenericExtraField.TryReadBlock(reader, extraFieldStream.Length, out currentExtraField))
                {
                    if (TryGetZip64BlockFromGenericExtraField(currentExtraField, readUncompressedSize,
                                                              readCompressedSize, readLocalHeaderOffset, readStartDiskNumber, out zip64Field))
                    {
                        return(zip64Field);
                    }
                }
            }

            zip64Field = new Zip64ExtraField();

            zip64Field._compressedSize    = null;
            zip64Field._uncompressedSize  = null;
            zip64Field._localHeaderOffset = null;
            zip64Field._startDiskNumber   = null;

            return(zip64Field);
        }
예제 #2
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
        public static bool TryReadBlock(BinaryReader reader, out ZipCentralDirectoryFileHeader header)
        {
            header = new ZipCentralDirectoryFileHeader();

            if (reader.ReadUInt32() != SignatureConstant)
            {
                return(false);
            }
            header.VersionMadeBySpecification = reader.ReadByte();
            header.VersionMadeByCompatibility = reader.ReadByte();
            header.VersionNeededToExtract     = reader.ReadUInt16();
            header.GeneralPurposeBitFlag      = reader.ReadUInt16();
            header.CompressionMethod          = reader.ReadUInt16();
            header.LastModified = reader.ReadUInt32();
            header.Crc32        = reader.ReadUInt32();
            uint compressedSizeSmall   = reader.ReadUInt32();
            uint uncompressedSizeSmall = reader.ReadUInt32();

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

            header.InternalFileAttributes = reader.ReadUInt16();
            header.ExternalFileAttributes = reader.ReadUInt32();
            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 SubReadOnlyStream(reader.BaseStream, reader.BaseStream.Position, header.ExtraFieldLength, leaveOpen: true))
            {
                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);

            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);
        }
예제 #3
0
        private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField,
                                                                  bool readUncompressedSize, bool readCompressedSize,
                                                                  bool readLocalHeaderOffset, bool readStartDiskNumber,
                                                                  out Zip64ExtraField zip64Block)
        {
            zip64Block = new Zip64ExtraField();

            zip64Block._compressedSize    = null;
            zip64Block._uncompressedSize  = null;
            zip64Block._localHeaderOffset = null;
            zip64Block._startDiskNumber   = null;

            if (extraField.Tag != TagConstant)
            {
                return(false);
            }

            // this pattern needed because nested using blocks trigger CA2202
            MemoryStream ms = null;

            try
            {
                ms = new MemoryStream(extraField.Data);
                using (BinaryReader reader = new BinaryReader(ms))
                {
                    ms = null;

                    zip64Block._size = extraField.Size;

                    ushort expectedSize = 0;

                    if (readUncompressedSize)
                    {
                        expectedSize += 8;
                    }
                    if (readCompressedSize)
                    {
                        expectedSize += 8;
                    }
                    if (readLocalHeaderOffset)
                    {
                        expectedSize += 8;
                    }
                    if (readStartDiskNumber)
                    {
                        expectedSize += 4;
                    }

                    // if it is not the expected size, perhaps there is another extra field that matches
                    if (expectedSize != zip64Block._size)
                    {
                        return(false);
                    }

                    if (readUncompressedSize)
                    {
                        zip64Block._uncompressedSize = reader.ReadInt64();
                    }
                    if (readCompressedSize)
                    {
                        zip64Block._compressedSize = reader.ReadInt64();
                    }
                    if (readLocalHeaderOffset)
                    {
                        zip64Block._localHeaderOffset = reader.ReadInt64();
                    }
                    if (readStartDiskNumber)
                    {
                        zip64Block._startDiskNumber = reader.ReadInt32();
                    }

                    // original values are unsigned, so implies value is too big to fit in signed integer
                    if (zip64Block._uncompressedSize < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigUncompressedSize");
                    }
                    if (zip64Block._compressedSize < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigCompressedSize");
                    }
                    if (zip64Block._localHeaderOffset < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigLocalHeaderOffset");
                    }
                    if (zip64Block._startDiskNumber < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigStartDiskNumber");
                    }

                    return(true);
                }
            }
            finally
            {
                if (ms != null)
                {
                    ms.Dispose();
                }
            }
        }
        private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField,
                                                                  bool readUncompressedSize, bool readCompressedSize,
                                                                  bool readLocalHeaderOffset, bool readStartDiskNumber,
                                                                  out Zip64ExtraField zip64Block)
        {
            zip64Block = new Zip64ExtraField();

            zip64Block._compressedSize    = null;
            zip64Block._uncompressedSize  = null;
            zip64Block._localHeaderOffset = null;
            zip64Block._startDiskNumber   = null;

            if (extraField.Tag != TagConstant)
            {
                return(false);
            }

            MemoryStream ms = null;

            try
            {
                ms = new MemoryStream(extraField.Data);
                using (BinaryReader reader = new BinaryReader(ms))
                {
                    ms = null;

                    zip64Block._size = extraField.Size;

                    ushort expectedSize = 0;

                    if (readUncompressedSize)
                    {
                        expectedSize += 8;
                    }
                    if (readCompressedSize)
                    {
                        expectedSize += 8;
                    }
                    if (readLocalHeaderOffset)
                    {
                        expectedSize += 8;
                    }
                    if (readStartDiskNumber)
                    {
                        expectedSize += 4;
                    }

                    if (expectedSize != zip64Block._size)
                    {
                        return(false);
                    }

                    if (readUncompressedSize)
                    {
                        zip64Block._uncompressedSize = reader.ReadInt64();
                    }
                    if (readCompressedSize)
                    {
                        zip64Block._compressedSize = reader.ReadInt64();
                    }
                    if (readLocalHeaderOffset)
                    {
                        zip64Block._localHeaderOffset = reader.ReadInt64();
                    }
                    if (readStartDiskNumber)
                    {
                        zip64Block._startDiskNumber = reader.ReadInt32();
                    }

                    if (zip64Block._uncompressedSize < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigUncompressedSize");
                    }
                    if (zip64Block._compressedSize < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigCompressedSize");
                    }
                    if (zip64Block._localHeaderOffset < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigLocalHeaderOffset");
                    }
                    if (zip64Block._startDiskNumber < 0)
                    {
                        throw new ZipArchiveException("FieldTooBigStartDiskNumber");
                    }

                    return(true);
                }
            }
            finally
            {
                if (ms != null)
                {
                    ms.Dispose();
                }
            }
        }