Example #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,
                                                        Boolean readUncompressedSize, Boolean readCompressedSize,
                                                        Boolean readLocalHeaderOffset, Boolean 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);
        }
Example #2
0
        //shouldn't ever read the byte at position endExtraField
        //assumes we are positioned at the beginning of an extra field subfield
        public static Boolean TryReadBlock(BinaryReader reader, Int64 endExtraField, out ZipGenericExtraField field)
        {
            field = new ZipGenericExtraField();

            //not enough bytes to read tag + size
            if (endExtraField - reader.BaseStream.Position < 4)
            {
                return(false);
            }

            field._tag  = reader.ReadUInt16();
            field._size = reader.ReadUInt16();

            //not enough bytes to read the data
            if (endExtraField - reader.BaseStream.Position < field._size)
            {
                return(false);
            }

            field._data = reader.ReadBytes(field._size);
            return(true);
        }
Example #3
0
        static public List <ZipGenericExtraField> GetExtraFields(BinaryReader reader)
        {
            //assumes that TrySkipBlock has already been called, so we don't have to validate twice

            List <ZipGenericExtraField> result;

            const Int32 OffsetToFilenameLength = 26; //from the point before the signature

            reader.BaseStream.Seek(OffsetToFilenameLength, SeekOrigin.Current);

            UInt16 filenameLength   = reader.ReadUInt16();
            UInt16 extraFieldLength = reader.ReadUInt16();

            reader.BaseStream.Seek(filenameLength, SeekOrigin.Current);


            using (Stream str = new SubReadStream(reader.BaseStream, reader.BaseStream.Position, extraFieldLength))
            {
                result = ZipGenericExtraField.ParseExtraField(str);
            }
            Zip64ExtraField.RemoveZip64Blocks(result);

            return(result);
        }
Example #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
        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);
        }
Example #5
0
        private static Boolean TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField,
                                                                     Boolean readUncompressedSize, Boolean readCompressedSize,
                                                                     Boolean readLocalHeaderOffset, Boolean 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;

                    UInt16 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 InvalidDataException(SR.FieldTooBigUncompressedSize);
                    }
                    if (zip64Block._compressedSize < 0)
                    {
                        throw new InvalidDataException(SR.FieldTooBigCompressedSize);
                    }
                    if (zip64Block._localHeaderOffset < 0)
                    {
                        throw new InvalidDataException(SR.FieldTooBigLocalHeaderOffset);
                    }
                    if (zip64Block._startDiskNumber < 0)
                    {
                        throw new InvalidDataException(SR.FieldTooBigStartDiskNumber);
                    }

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