Beispiel #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);
        }
Beispiel #2
0
        public static Zip64ExtraField GetAndRemoveZip64Block(List <ZipGenericExtraField> extraFields, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber)
        {
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField()
            {
                _compressedSize    = null,
                _uncompressedSize  = null,
                _localHeaderOffset = null,
                _startDiskNumber   = null
            };
            List <ZipGenericExtraField> zipGenericExtraFields = new List <ZipGenericExtraField>();
            bool flag = false;

            foreach (ZipGenericExtraField extraField in extraFields)
            {
                if (extraField.Tag != 1)
                {
                    continue;
                }
                zipGenericExtraFields.Add(extraField);
                if (flag || !Zip64ExtraField.TryGetZip64BlockFromGenericExtraField(extraField, readUncompressedSize, readCompressedSize, readLocalHeaderOffset, readStartDiskNumber, out zip64ExtraField))
                {
                    continue;
                }
                flag = true;
            }
            foreach (ZipGenericExtraField zipGenericExtraField in zipGenericExtraFields)
            {
                extraFields.Remove(zipGenericExtraField);
            }
            return(zip64ExtraField);
        }
Beispiel #3
0
        public static Zip64ExtraField GetJustZip64Block(Stream extraFieldStream, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber)
        {
            Zip64ExtraField      zip64ExtraField;
            ZipGenericExtraField zipGenericExtraField;
            Zip64ExtraField      zip64ExtraField1;

            using (BinaryReader binaryReader = new BinaryReader(extraFieldStream))
            {
                while (ZipGenericExtraField.TryReadBlock(binaryReader, extraFieldStream.Length, out zipGenericExtraField))
                {
                    if (!Zip64ExtraField.TryGetZip64BlockFromGenericExtraField(zipGenericExtraField, readUncompressedSize, readCompressedSize, readLocalHeaderOffset, readStartDiskNumber, out zip64ExtraField))
                    {
                        continue;
                    }
                    zip64ExtraField1 = zip64ExtraField;
                    return(zip64ExtraField1);
                }
                zip64ExtraField = new Zip64ExtraField()
                {
                    _compressedSize    = null,
                    _uncompressedSize  = null,
                    _localHeaderOffset = null,
                    _startDiskNumber   = null
                };
                return(zip64ExtraField);
            }
            return(zip64ExtraField1);
        }
Beispiel #4
0
        public static List <ZipGenericExtraField> GetExtraFields(BinaryReader reader)
        {
            List <ZipGenericExtraField> zipGenericExtraFields;

            reader.BaseStream.Seek((long)26, SeekOrigin.Current);
            ushort num  = reader.ReadUInt16();
            ushort num1 = reader.ReadUInt16();

            reader.BaseStream.Seek((long)num, SeekOrigin.Current);
            using (Stream subReadStream = new SubReadStream(reader.BaseStream, reader.BaseStream.Position, (long)num1))
            {
                zipGenericExtraFields = ZipGenericExtraField.ParseExtraField(subReadStream);
            }
            Zip64ExtraField.RemoveZip64Blocks(zipGenericExtraFields);
            return(zipGenericExtraFields);
        }
Beispiel #5
0
        public static Zip64ExtraField GetAndRemoveZip64Block(List <ZipGenericExtraField> extraFields,
                                                             bool readUncompressedSize, bool readCompressedSize,
                                                             bool readLocalHeaderOffset, bool readStartDiskNumber)
        {
            Zip64ExtraField zip64Field = new Zip64ExtraField();

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

            List <ZipGenericExtraField> markedForDelete = new List <ZipGenericExtraField>();
            bool zip64FieldFound = false;

            foreach (ZipGenericExtraField ef in extraFields)
            {
                if (ef.Tag == TagConstant)
                {
                    markedForDelete.Add(ef);
                    if (!zip64FieldFound)
                    {
                        if (TryGetZip64BlockFromGenericExtraField(ef, readUncompressedSize, readCompressedSize,
                                                                  readLocalHeaderOffset, readStartDiskNumber, out zip64Field))
                        {
                            zip64FieldFound = true;
                        }
                    }
                }
            }

            foreach (ZipGenericExtraField ef in markedForDelete)
            {
                extraFields.Remove(ef);
            }

            return(zip64Field);
        }
Beispiel #6
0
        public static List <ZipGenericExtraField> GetExtraFields(BinaryReader reader)
        {
            // assumes that TrySkipBlock has already been called, so we don't have to validate twice

            List <ZipGenericExtraField> result;

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

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

            ushort filenameLength   = reader.ReadUInt16();
            ushort 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);
        }
Beispiel #7
0
        // return value is true if we allocated an extra field for 64 bit headers, un/compressed size
        private bool WriteLocalFileHeader(bool isEmptyFile)
        {
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            // _entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            // reading in should not be able to produce an entryname longer than ushort.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= ushort.MaxValue);

            // decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            bool            zip64Used = false;
            uint            compressedSizeTruncated, uncompressedSizeTruncated;

            // if we already know that we have an empty file don't worry about anything, just do a straight shot of the header
            if (isEmptyFile)
            {
                CompressionMethod         = CompressionMethodValues.Stored;
                compressedSizeTruncated   = 0;
                uncompressedSizeTruncated = 0;
                Debug.Assert(_compressedSize == 0);
                Debug.Assert(_uncompressedSize == 0);
                Debug.Assert(_crc32 == 0);
            }
            else
            {
                // if we have a non-seekable stream, don't worry about sizes at all, and just set the right bit
                // if we are using the data descriptor, then sizes and crc should be set to 0 in the header
                if (_archive.Mode == ZipArchiveMode.Create && _archive.ArchiveStream.CanSeek == false && !isEmptyFile)
                {
                    _generalPurposeBitFlag |= BitFlagValues.DataDescriptor;
                    zip64Used = false;
                    compressedSizeTruncated   = 0;
                    uncompressedSizeTruncated = 0;
                    // the crc should not have been set if we are in create mode, but clear it just to be sure
                    Debug.Assert(_crc32 == 0);
                }
                else // if we are not in streaming mode, we have to decide if we want to write zip64 headers
                {
                    if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
                        || (_archive._forceZip64 && _archive.Mode == ZipArchiveMode.Update)
#endif
                        )
                    {
                        zip64Used = true;
                        compressedSizeTruncated   = ZipHelper.Mask32Bit;
                        uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                        // prepare Zip64 extra field object. If we have one of the sizes, the other must go in there
                        zip64ExtraField.CompressedSize   = _compressedSize;
                        zip64ExtraField.UncompressedSize = _uncompressedSize;

                        VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
                    }
                    else
                    {
                        zip64Used = false;
                        compressedSizeTruncated   = (uint)_compressedSize;
                        uncompressedSizeTruncated = (uint)_uncompressedSize;
                    }
                }
            }

            // save offset
            _offsetOfLocalHeader = writer.BaseStream.Position;

            // calculate extra field. if zip64 stuff + original extraField aren't going to fit, dump the original extraField, because this is more important
            int bigExtraFieldLength = (zip64Used ? zip64ExtraField.TotalSize : 0)
                                      + (_lhUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_lhUnknownExtraFields) : 0);
            ushort extraFieldLength;
            if (bigExtraFieldLength > ushort.MaxValue)
            {
                extraFieldLength      = (ushort)(zip64Used ? zip64ExtraField.TotalSize : 0);
                _lhUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (ushort)bigExtraFieldLength;
            }

            // write header
            writer.Write(ZipLocalFileHeader.SignatureConstant);
            writer.Write((ushort)_versionToExtract);
            writer.Write((ushort)_generalPurposeBitFlag);
            writer.Write((ushort)CompressionMethod);
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime)); // uint
            writer.Write(_crc32);                                              // uint
            writer.Write(compressedSizeTruncated);                             // uint
            writer.Write(uncompressedSizeTruncated);                           // uint
            writer.Write((ushort)_storedEntryNameBytes.Length);
            writer.Write(extraFieldLength);                                    // ushort

            writer.Write(_storedEntryNameBytes);

            if (zip64Used)
            {
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            }
            if (_lhUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(_lhUnknownExtraFields, _archive.ArchiveStream);
            }

            return(zip64Used);
        }
Beispiel #8
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 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();
                }
            }
        }
Beispiel #9
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;

            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);
                }
            }

            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);
        }
Beispiel #10
0
        private bool WriteLocalFileHeader(bool isEmptyFile)
        {
            uint            num;
            uint            num1;
            ushort          num2;
            ushort          totalSize;
            ushort          num3;
            object          obj;
            BinaryWriter    binaryWriter = new BinaryWriter(this._archive.ArchiveStream);
            Zip64ExtraField nullable     = new Zip64ExtraField();
            bool            flag         = false;

            if (isEmptyFile)
            {
                this.CompressionMethod = ZipArchiveEntry.CompressionMethodValues.Stored;
                num  = 0;
                num1 = 0;
            }
            else if (this._archive.Mode == ZipArchiveMode.Create && !this._archive.ArchiveStream.CanSeek && !isEmptyFile)
            {
                this._generalPurposeBitFlag |= ZipArchiveEntry.BitFlagValues.DataDescriptor;
                flag = false;
                num  = 0;
                num1 = 0;
            }
            else if (!this.SizesTooLarge())
            {
                flag = false;
                num  = (uint)this._compressedSize;
                num1 = (uint)this._uncompressedSize;
            }
            else
            {
                flag = true;
                num  = -1;
                num1 = -1;
                nullable.CompressedSize   = new long?(this._compressedSize);
                nullable.UncompressedSize = new long?(this._uncompressedSize);
                this.VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
            }
            this._offsetOfLocalHeader = binaryWriter.BaseStream.Position;
            if (flag)
            {
                totalSize = nullable.TotalSize;
            }
            else
            {
                totalSize = 0;
            }
            if (this._lhUnknownExtraFields != null)
            {
                num3 = (ushort)ZipGenericExtraField.TotalSize(this._lhUnknownExtraFields);
            }
            else
            {
                num3 = 0;
            }
            int num4 = totalSize + num3;

            if (num4 <= 65535)
            {
                num2 = (ushort)num4;
            }
            else
            {
                if (flag)
                {
                    obj = nullable.TotalSize;
                }
                else
                {
                    obj = null;
                }
                num2 = (ushort)obj;
                this._lhUnknownExtraFields = null;
            }
            binaryWriter.Write((uint)67324752);
            binaryWriter.Write((ushort)this._versionToExtract);
            binaryWriter.Write((ushort)this._generalPurposeBitFlag);
            binaryWriter.Write((ushort)this.CompressionMethod);
            binaryWriter.Write(ZipHelper.DateTimeToDosTime(this._lastModified.DateTime));
            binaryWriter.Write(this._crc32);
            binaryWriter.Write(num);
            binaryWriter.Write(num1);
            binaryWriter.Write((ushort)((int)this._storedEntryNameBytes.Length));
            binaryWriter.Write(num2);
            binaryWriter.Write(this._storedEntryNameBytes);
            if (flag)
            {
                nullable.WriteBlock(this._archive.ArchiveStream);
            }
            if (this._lhUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(this._lhUnknownExtraFields, this._archive.ArchiveStream);
            }
            return(flag);
        }
Beispiel #11
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;
        }
Beispiel #12
0
        //return value is true if we allocated an extra field for 64 bit headers, un/compressed size
        private Boolean WriteLocalFileHeader(Boolean isEmptyFile)
        {
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            //_entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            //reading in should not be able to produce a entryname longer than UInt16.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= UInt16.MaxValue);

            //decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            Boolean zip64Used = false;
            UInt32 compressedSizeTruncated, uncompressedSizeTruncated;

            //if we already know that we have an empty file don't worry about anything, just do a straight shot of the header
            if (isEmptyFile)
            {
                CompressionMethod = CompressionMethodValues.Stored;
                compressedSizeTruncated = 0;
                uncompressedSizeTruncated = 0;
                Debug.Assert(_compressedSize == 0);
                Debug.Assert(_uncompressedSize == 0);
                Debug.Assert(_crc32 == 0);
            }
            else
            {
                //if we have a non-seekable stream, don't worry about sizes at all, and just set the right bit
                //if we are using the data descriptor, then sizes and crc should be set to 0 in the header
                if (_archive.Mode == ZipArchiveMode.Create && _archive.ArchiveStream.CanSeek == false && !isEmptyFile)
                {
                    _generalPurposeBitFlag |= BitFlagValues.DataDescriptor;
                    zip64Used = false;
                    compressedSizeTruncated = 0;
                    uncompressedSizeTruncated = 0;
                    //the crc should not have been set if we are in create mode, but clear it just to be sure
                    Debug.Assert(_crc32 == 0);
                }
                else //if we are not in streaming mode, we have to decide if we want to write zip64 headers
                {
                    if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
 || (_archive._forceZip64 && _archive.Mode == ZipArchiveMode.Update)
#endif
)
                    {
                        zip64Used = true;
                        compressedSizeTruncated = ZipHelper.Mask32Bit;
                        uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                        //prepare Zip64 extra field object. If we have one of the sizes, the other must go in there
                        zip64ExtraField.CompressedSize = _compressedSize;
                        zip64ExtraField.UncompressedSize = _uncompressedSize;

                        VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
                    }
                    else
                    {
                        zip64Used = false;
                        compressedSizeTruncated = (UInt32)_compressedSize;
                        uncompressedSizeTruncated = (UInt32)_uncompressedSize;
                    }
                }
            }

            //save offset
            _offsetOfLocalHeader = writer.BaseStream.Position;

            //calculate extra field. if zip64 stuff + original extraField aren't going to fit, dump the original extraField, because this is more important
            Int32 bigExtraFieldLength = (zip64Used ? zip64ExtraField.TotalSize : 0)
                                      + (_lhUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_lhUnknownExtraFields) : 0);
            UInt16 extraFieldLength;
            if (bigExtraFieldLength > UInt16.MaxValue)
            {
                extraFieldLength = (UInt16)(zip64Used ? zip64ExtraField.TotalSize : 0);
                _lhUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (UInt16)bigExtraFieldLength;
            }

            //write header
            writer.Write(ZipLocalFileHeader.SignatureConstant);
            writer.Write((UInt16)_versionToExtract);
            writer.Write((UInt16)_generalPurposeBitFlag);
            writer.Write((UInt16)CompressionMethod);
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime)); //UInt32
            writer.Write(_crc32);               //UInt32
            writer.Write(compressedSizeTruncated);  //UInt32
            writer.Write(uncompressedSizeTruncated); //UInt32
            writer.Write((UInt16)_storedEntryNameBytes.Length);
            writer.Write(extraFieldLength);    //UInt16

            writer.Write(_storedEntryNameBytes);

            if (zip64Used)
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            if (_lhUnknownExtraFields != null)
                ZipGenericExtraField.WriteAllBlocks(_lhUnknownExtraFields, _archive.ArchiveStream);

            return zip64Used;
        }
Beispiel #13
0
        internal void WriteCentralDirectoryFileHeader()
        {
            uint            num;
            uint            num1;
            uint            num2;
            ushort          num3;
            ushort          totalSize;
            ushort          num4;
            ushort          length;
            object          obj;
            BinaryWriter    binaryWriter = new BinaryWriter(this._archive.ArchiveStream);
            Zip64ExtraField nullable     = new Zip64ExtraField();
            bool            flag         = false;

            if (!this.SizesTooLarge())
            {
                num  = (uint)this._compressedSize;
                num1 = (uint)this._uncompressedSize;
            }
            else
            {
                flag = true;
                num  = -1;
                num1 = -1;
                nullable.CompressedSize   = new long?(this._compressedSize);
                nullable.UncompressedSize = new long?(this._uncompressedSize);
            }
            if (this._offsetOfLocalHeader <= (ulong)-1)
            {
                num2 = (uint)this._offsetOfLocalHeader;
            }
            else
            {
                flag = true;
                num2 = -1;
                nullable.LocalHeaderOffset = new long?(this._offsetOfLocalHeader);
            }
            if (flag)
            {
                this.VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
            }
            if (flag)
            {
                totalSize = nullable.TotalSize;
            }
            else
            {
                totalSize = 0;
            }
            if (this._cdUnknownExtraFields != null)
            {
                num4 = (ushort)ZipGenericExtraField.TotalSize(this._cdUnknownExtraFields);
            }
            else
            {
                num4 = 0;
            }
            int num5 = totalSize + num4;

            if (num5 <= 65535)
            {
                num3 = (ushort)num5;
            }
            else
            {
                if (flag)
                {
                    obj = nullable.TotalSize;
                }
                else
                {
                    obj = null;
                }
                num3 = (ushort)obj;
                this._cdUnknownExtraFields = null;
            }
            binaryWriter.Write((uint)33639248);
            binaryWriter.Write((ushort)this._versionToExtract);
            binaryWriter.Write((ushort)this._versionToExtract);
            binaryWriter.Write((ushort)this._generalPurposeBitFlag);
            binaryWriter.Write((ushort)this.CompressionMethod);
            binaryWriter.Write(ZipHelper.DateTimeToDosTime(this._lastModified.DateTime));
            binaryWriter.Write(this._crc32);
            binaryWriter.Write(num);
            binaryWriter.Write(num1);
            binaryWriter.Write((ushort)((int)this._storedEntryNameBytes.Length));
            binaryWriter.Write(num3);
            BinaryWriter binaryWriter1 = binaryWriter;

            if (this._fileComment != null)
            {
                length = (ushort)((int)this._fileComment.Length);
            }
            else
            {
                length = 0;
            }
            binaryWriter1.Write(length);
            binaryWriter.Write((ushort)0);
            binaryWriter.Write((ushort)0);
            binaryWriter.Write(this._externalFileAttr);
            binaryWriter.Write(num2);
            binaryWriter.Write(this._storedEntryNameBytes);
            if (flag)
            {
                nullable.WriteBlock(this._archive.ArchiveStream);
            }
            if (this._cdUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(this._cdUnknownExtraFields, this._archive.ArchiveStream);
            }
            if (this._fileComment != null)
            {
                binaryWriter.Write(this._fileComment);
            }
        }
Beispiel #14
0
        private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber, out Zip64ExtraField zip64Block)
        {
            bool flag;

            zip64Block = new Zip64ExtraField()
            {
                _compressedSize    = null,
                _uncompressedSize  = null,
                _localHeaderOffset = null,
                _startDiskNumber   = null
            };
            if (extraField.Tag != 1)
            {
                return(false);
            }
            MemoryStream memoryStream = null;

            try
            {
                memoryStream = new MemoryStream(extraField.Data);
                using (BinaryReader binaryReader = new BinaryReader(memoryStream))
                {
                    memoryStream     = null;
                    zip64Block._size = extraField.Size;
                    ushort num = 0;
                    if (readUncompressedSize)
                    {
                        num = (ushort)(num + 8);
                    }
                    if (readCompressedSize)
                    {
                        num = (ushort)(num + 8);
                    }
                    if (readLocalHeaderOffset)
                    {
                        num = (ushort)(num + 8);
                    }
                    if (readStartDiskNumber)
                    {
                        num = (ushort)(num + 4);
                    }
                    if (num == zip64Block._size)
                    {
                        if (readUncompressedSize)
                        {
                            zip64Block._uncompressedSize = new long?(binaryReader.ReadInt64());
                        }
                        if (readCompressedSize)
                        {
                            zip64Block._compressedSize = new long?(binaryReader.ReadInt64());
                        }
                        if (readLocalHeaderOffset)
                        {
                            zip64Block._localHeaderOffset = new long?(binaryReader.ReadInt64());
                        }
                        if (readStartDiskNumber)
                        {
                            zip64Block._startDiskNumber = new int?(binaryReader.ReadInt32());
                        }
                        long?nullable = zip64Block._uncompressedSize;
                        long num1     = (long)0;
                        if ((nullable.GetValueOrDefault() < num1 ? nullable.HasValue : false))
                        {
                            throw new InvalidDataException(Messages.FieldTooBigUncompressedSize);
                        }
                        nullable = zip64Block._compressedSize;
                        num1     = (long)0;
                        if ((nullable.GetValueOrDefault() < num1 ? nullable.HasValue : false))
                        {
                            throw new InvalidDataException(Messages.FieldTooBigCompressedSize);
                        }
                        nullable = zip64Block._localHeaderOffset;
                        num1     = (long)0;
                        if ((nullable.GetValueOrDefault() < num1 ? nullable.HasValue : false))
                        {
                            throw new InvalidDataException(Messages.FieldTooBigLocalHeaderOffset);
                        }
                        int?nullable1 = zip64Block._startDiskNumber;
                        if ((nullable1.GetValueOrDefault() < 0 ? nullable1.HasValue : false))
                        {
                            throw new InvalidDataException(Messages.FieldTooBigStartDiskNumber);
                        }
                        flag = true;
                    }
                    else
                    {
                        flag = false;
                    }
                }
            }
            finally
            {
                if (memoryStream != null)
                {
                    memoryStream.Close();
                }
            }
            return(flag);
        }
Beispiel #15
0
        //should only throw an exception in extremely exceptional cases because it is called from dispose
        internal void WriteCentralDirectoryFileHeader()
        {
            //This part is simple, because we should definitely know the sizes by this time
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            //_entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            //reading in should not be able to produce a entryname longer than UInt16.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= UInt16.MaxValue);

            //decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            UInt32 compressedSizeTruncated, uncompressedSizeTruncated, offsetOfLocalHeaderTruncated;

            Boolean zip64Needed = false;

            if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
 || _archive._forceZip64
#endif
)
            {
                zip64Needed = true;
                compressedSizeTruncated = ZipHelper.Mask32Bit;
                uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                //If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.CompressedSize = _compressedSize;
                zip64ExtraField.UncompressedSize = _uncompressedSize;
            }
            else
            {
                compressedSizeTruncated = (UInt32)_compressedSize;
                uncompressedSizeTruncated = (UInt32)_uncompressedSize;
            }


            if (_offsetOfLocalHeader > UInt32.MaxValue
#if DEBUG_FORCE_ZIP64
 || _archive._forceZip64
#endif
)
            {
                zip64Needed = true;
                offsetOfLocalHeaderTruncated = ZipHelper.Mask32Bit;

                //If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.LocalHeaderOffset = _offsetOfLocalHeader;
            }
            else
            {
                offsetOfLocalHeaderTruncated = (UInt32)_offsetOfLocalHeader;
            }

            if (zip64Needed)
                VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);

            //determine if we can fit zip64 extra field and original extra fields all in
            Int32 bigExtraFieldLength = (zip64Needed ? zip64ExtraField.TotalSize : 0)
                                      + (_cdUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_cdUnknownExtraFields) : 0);
            UInt16 extraFieldLength;
            if (bigExtraFieldLength > UInt16.MaxValue)
            {
                extraFieldLength = (UInt16)(zip64Needed ? zip64ExtraField.TotalSize : 0);
                _cdUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (UInt16)bigExtraFieldLength;
            }

            writer.Write(ZipCentralDirectoryFileHeader.SignatureConstant);      // Central directory file header signature  (4 bytes)
            writer.Write((byte)_versionMadeBySpecification);                    // Version made by Specification (version)  (1 byte)
            writer.Write((byte)CurrentZipPlatform);                             // Version made by Compatibility (type)     (1 byte)
            writer.Write((UInt16)_versionToExtract);                            // Minimum version needed to extract        (2 bytes)
            writer.Write((UInt16)_generalPurposeBitFlag);                       // General Purpose bit flag                 (2 bytes)
            writer.Write((UInt16)CompressionMethod);                            // The Compression method                   (2 bytes)
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime));  // File last modification time and date     (4 bytes)
            writer.Write(_crc32);                                               // CRC-32                                   (4 bytes)
            writer.Write(compressedSizeTruncated);                              // Compressed Size                          (4 bytes)
            writer.Write(uncompressedSizeTruncated);                            // Uncompressed Size                        (4 bytes)
            writer.Write((UInt16)_storedEntryNameBytes.Length);                 // File Name Length                         (2 bytes)
            writer.Write(extraFieldLength);                                     // Extra Field Length                       (2 bytes)

            // This should hold because of how we read it originally in ZipCentralDirectoryFileHeader:
            Debug.Assert((_fileComment == null) || (_fileComment.Length <= UInt16.MaxValue));

            writer.Write(_fileComment != null ? (UInt16)_fileComment.Length : (UInt16)0);    //file comment length
            writer.Write((UInt16)0);    //disk number start
            writer.Write((UInt16)0);    //internal file attributes
            writer.Write((UInt32)0);    //external file attributes
            writer.Write(offsetOfLocalHeaderTruncated); //offset of local header

            writer.Write(_storedEntryNameBytes);

            //write extra fields
            if (zip64Needed)
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            if (_cdUnknownExtraFields != null)
                ZipGenericExtraField.WriteAllBlocks(_cdUnknownExtraFields, _archive.ArchiveStream);

            if (_fileComment != null)
                writer.Write(_fileComment);
        }
Beispiel #16
0
        public static bool TryValidateBlock(BinaryReader reader, ZipArchiveEntry entry)
        {
            const int OffsetToFilename = 26; // from the point after the signature

            if (reader.ReadUInt32() != SignatureConstant)
            {
                return(false);
            }

            if (reader.BaseStream.Length < reader.BaseStream.Position + OffsetToFilename)
            {
                return(false);
            }

            reader.BaseStream.Seek(2, SeekOrigin.Current); // skipping minimum version (using min version from central directory header)
            uint dataDescriptorBit = reader.ReadUInt16() & (uint)ZipArchiveEntry.BitFlagValues.DataDescriptor;

            reader.BaseStream.Seek(10, SeekOrigin.Current); // skipping bytes used for Compression method (2 bytes), last modification time and date (4 bytes) and CRC (4 bytes)
            long compressedSize   = reader.ReadUInt32();
            long uncompressedSize = reader.ReadUInt32();
            int  filenameLength   = reader.ReadUInt16();
            uint extraFieldLength = reader.ReadUInt16();

            if (reader.BaseStream.Length < reader.BaseStream.Position + filenameLength + extraFieldLength)
            {
                return(false);
            }

            reader.BaseStream.Seek(filenameLength, SeekOrigin.Current);  // skipping Filename
            long endExtraFields = reader.BaseStream.Position + extraFieldLength;

            if (dataDescriptorBit == 0)
            {
                bool            isUncompressedSizeInZip64 = uncompressedSize == ZipHelper.Mask32Bit;
                bool            isCompressedSizeInZip64   = compressedSize == ZipHelper.Mask32Bit;
                Zip64ExtraField zip64;

                // Ideally we should also check if the minimumVersion is 64 bit or above, but there could zip files for which this version is not set correctly
                if (isUncompressedSizeInZip64 || isCompressedSizeInZip64)
                {
                    zip64 = Zip64ExtraField.GetJustZip64Block(new SubReadStream(reader.BaseStream, reader.BaseStream.Position, extraFieldLength), isUncompressedSizeInZip64, isCompressedSizeInZip64, false, false);

                    if (zip64.UncompressedSize != null)
                    {
                        uncompressedSize = zip64.UncompressedSize.Value;
                    }

                    if (zip64.CompressedSize != null)
                    {
                        compressedSize = zip64.CompressedSize.Value;
                    }
                }

                reader.BaseStream.AdvanceToPosition(endExtraFields);
            }
            else
            {
                if (reader.BaseStream.Length < reader.BaseStream.Position + extraFieldLength + entry.CompressedLength + 4)
                {
                    return(false);
                }

                reader.BaseStream.Seek(extraFieldLength + entry.CompressedLength, SeekOrigin.Current); // seek to end of compressed file from which Data descriptor starts
                uint dataDescriptorSignature        = reader.ReadUInt32();
                bool wasDataDescriptorSignatureRead = false;
                int  seekSize = 0;
                if (dataDescriptorSignature == DataDescriptorSignature)
                {
                    wasDataDescriptorSignatureRead = true;
                    seekSize = 4;
                }

                bool is64bit = entry._versionToExtract >= ZipVersionNeededValues.Zip64;
                seekSize += (is64bit ? 8 : 4) * 2;   // if Zip64 read by 8 bytes else 4 bytes 2 times (compressed and uncompressed size)

                if (reader.BaseStream.Length < reader.BaseStream.Position + seekSize)
                {
                    return(false);
                }

                // dataDescriptorSignature is optional, if it was the DataDescriptorSignature we need to skip CRC 4 bytes else we can assume CRC is alreadyskipped
                if (wasDataDescriptorSignatureRead)
                {
                    reader.BaseStream.Seek(4, SeekOrigin.Current);
                }

                if (is64bit)
                {
                    compressedSize   = reader.ReadInt64();
                    uncompressedSize = reader.ReadInt64();
                }
                else
                {
                    compressedSize   = reader.ReadInt32();
                    uncompressedSize = reader.ReadInt32();
                }
                reader.BaseStream.Seek(-seekSize - entry.CompressedLength - 4, SeekOrigin.Current); // Seek back to the beginning of compressed stream
            }

            if (entry.CompressedLength != compressedSize)
            {
                return(false);
            }

            if (entry.Length != uncompressedSize)
            {
                return(false);
            }

            return(true);
        }
Beispiel #17
0
        // should only throw an exception in extremely exceptional cases because it is called from dispose
        internal void WriteCentralDirectoryFileHeader()
        {
            // This part is simple, because we should definitely know the sizes by this time
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            // _entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            // reading in should not be able to produce an entryname longer than ushort.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= ushort.MaxValue);

            // decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            uint            compressedSizeTruncated, uncompressedSizeTruncated, offsetOfLocalHeaderTruncated;

            bool zip64Needed = false;

            if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
                || _archive._forceZip64
#endif
                )
            {
                zip64Needed               = true;
                compressedSizeTruncated   = ZipHelper.Mask32Bit;
                uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                // If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.CompressedSize   = _compressedSize;
                zip64ExtraField.UncompressedSize = _uncompressedSize;
            }
            else
            {
                compressedSizeTruncated   = (uint)_compressedSize;
                uncompressedSizeTruncated = (uint)_uncompressedSize;
            }


            if (_offsetOfLocalHeader > uint.MaxValue
#if DEBUG_FORCE_ZIP64
                || _archive._forceZip64
#endif
                )
            {
                zip64Needed = true;
                offsetOfLocalHeaderTruncated = ZipHelper.Mask32Bit;

                // If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.LocalHeaderOffset = _offsetOfLocalHeader;
            }
            else
            {
                offsetOfLocalHeaderTruncated = (uint)_offsetOfLocalHeader;
            }

            if (zip64Needed)
            {
                VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
            }

            // determine if we can fit zip64 extra field and original extra fields all in
            int bigExtraFieldLength = (zip64Needed ? zip64ExtraField.TotalSize : 0)
                                      + (_cdUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_cdUnknownExtraFields) : 0);
            ushort extraFieldLength;
            if (bigExtraFieldLength > ushort.MaxValue)
            {
                extraFieldLength      = (ushort)(zip64Needed ? zip64ExtraField.TotalSize : 0);
                _cdUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (ushort)bigExtraFieldLength;
            }

            writer.Write(ZipCentralDirectoryFileHeader.SignatureConstant);      // Central directory file header signature  (4 bytes)
            writer.Write((byte)_versionMadeBySpecification);                    // Version made by Specification (version)  (1 byte)
            writer.Write((byte)CurrentZipPlatform);                             // Version made by Compatibility (type)     (1 byte)
            writer.Write((ushort)_versionToExtract);                            // Minimum version needed to extract        (2 bytes)
            writer.Write((ushort)_generalPurposeBitFlag);                       // General Purpose bit flag                 (2 bytes)
            writer.Write((ushort)CompressionMethod);                            // The Compression method                   (2 bytes)
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime));  // File last modification time and date     (4 bytes)
            writer.Write(_crc32);                                               // CRC-32                                   (4 bytes)
            writer.Write(compressedSizeTruncated);                              // Compressed Size                          (4 bytes)
            writer.Write(uncompressedSizeTruncated);                            // Uncompressed Size                        (4 bytes)
            writer.Write((ushort)_storedEntryNameBytes.Length);                 // File Name Length                         (2 bytes)
            writer.Write(extraFieldLength);                                     // Extra Field Length                       (2 bytes)

            // This should hold because of how we read it originally in ZipCentralDirectoryFileHeader:
            Debug.Assert((_fileComment == null) || (_fileComment.Length <= ushort.MaxValue));

            writer.Write(_fileComment != null ? (ushort)_fileComment.Length : (ushort)0); // file comment length
            writer.Write((ushort)0);                                                      // disk number start
            writer.Write((ushort)0);                                                      // internal file attributes
            writer.Write(_externalFileAttr);                                              // external file attributes
            writer.Write(offsetOfLocalHeaderTruncated);                                   // offset of local header

            writer.Write(_storedEntryNameBytes);

            // write extra fields
            if (zip64Needed)
            {
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            }
            if (_cdUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(_cdUnknownExtraFields, _archive.ArchiveStream);
            }

            if (_fileComment != null)
            {
                writer.Write(_fileComment);
            }
        }
Beispiel #18
0
        private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField,
                                                                  bool readUncompressedSize, bool readCompressedSize,
                                                                  bool readLocalHeaderOffset, bool readStartDiskNumber,
                                                                  out Zip64ExtraField zip64Block)
        {
            zip64Block = default;

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

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

            zip64Block._size = extraField.Size;

            using (MemoryStream ms = new MemoryStream(extraField.Data))
                using (BinaryReader reader = new BinaryReader(ms))
                {
                    // The spec section 4.5.3:
                    //      The order of the fields in the zip64 extended
                    //      information record is fixed, but the fields MUST
                    //      only appear if the corresponding Local or Central
                    //      directory record field is set to 0xFFFF or 0xFFFFFFFF.
                    // However tools commonly write the fields anyway; the prevailing convention
                    // is to respect the size, but only actually use the values if their 32 bit
                    // values were all 0xFF.

                    if (extraField.Size < sizeof(long))
                    {
                        return(true);
                    }

                    long value64 = reader.ReadInt64();
                    if (readUncompressedSize)
                    {
                        zip64Block._uncompressedSize = value64;
                    }

                    if (ms.Position > extraField.Size - sizeof(long))
                    {
                        return(true);
                    }

                    value64 = reader.ReadInt64();
                    if (readCompressedSize)
                    {
                        zip64Block._compressedSize = value64;
                    }

                    if (ms.Position > extraField.Size - sizeof(long))
                    {
                        return(true);
                    }

                    value64 = reader.ReadInt64();
                    if (readLocalHeaderOffset)
                    {
                        zip64Block._localHeaderOffset = value64;
                    }

                    if (ms.Position > extraField.Size - sizeof(int))
                    {
                        return(true);
                    }

                    int value32 = reader.ReadInt32();
                    if (readStartDiskNumber)
                    {
                        zip64Block._startDiskNumber = value32;
                    }

                    // 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);
                }
        }
Beispiel #19
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 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();
            }
        }
Beispiel #20
0
        public static Zip64ExtraField GetAndRemoveZip64Block(List<ZipGenericExtraField> extraFields,
            bool readUncompressedSize, bool readCompressedSize,
            bool readLocalHeaderOffset, bool readStartDiskNumber)
        {
            Zip64ExtraField zip64Field = new Zip64ExtraField();

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

            List<ZipGenericExtraField> markedForDelete = new List<ZipGenericExtraField>();
            bool zip64FieldFound = false;

            foreach (ZipGenericExtraField ef in extraFields)
            {
                if (ef.Tag == TagConstant)
                {
                    markedForDelete.Add(ef);
                    if (!zip64FieldFound)
                    {
                        if (TryGetZip64BlockFromGenericExtraField(ef, readUncompressedSize, readCompressedSize,
                                    readLocalHeaderOffset, readStartDiskNumber, out zip64Field))
                        {
                            zip64FieldFound = true;
                        }
                    }
                }
            }

            foreach (ZipGenericExtraField ef in markedForDelete)
                extraFields.Remove(ef);

            return zip64Field;
        }
Beispiel #21
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, bool saveExtraFieldsAndComments, 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 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);
        }
Beispiel #22
0
        public static bool TryReadBlock(BinaryReader reader, bool saveExtraFieldsAndComments, out ZipCentralDirectoryFileHeader header)
        {
            Zip64ExtraField justZip64Block;
            long?           uncompressedSize;
            long            value;
            long            num;
            long            value1;

            header = new ZipCentralDirectoryFileHeader();
            if (reader.ReadUInt32() != 33639248)
            {
                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();
            uint num1 = reader.ReadUInt32();
            uint num2 = reader.ReadUInt32();

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

            header.InternalFileAttributes = reader.ReadUInt16();
            header.ExternalFileAttributes = reader.ReadUInt32();
            uint num4 = reader.ReadUInt32();

            header.Filename = reader.ReadBytes((int)header.FilenameLength);
            bool flag     = num2 == -1;
            bool flag1    = num1 == -1;
            bool flag2    = num4 == -1;
            bool flag3    = num3 == 65535;
            long position = (long)(reader.BaseStream.Position + (ulong)header.ExtraFieldLength);

            using (Stream subReadStream = new SubReadStream(reader.BaseStream, reader.BaseStream.Position, (long)header.ExtraFieldLength))
            {
                if (!saveExtraFieldsAndComments)
                {
                    header.ExtraFields = null;
                    justZip64Block     = Zip64ExtraField.GetJustZip64Block(subReadStream, flag, flag1, flag2, flag3);
                }
                else
                {
                    header.ExtraFields = ZipGenericExtraField.ParseExtraField(subReadStream);
                    justZip64Block     = Zip64ExtraField.GetAndRemoveZip64Block(header.ExtraFields, flag, flag1, flag2, flag3);
                }
            }
            reader.BaseStream.AdvanceToPosition(position);
            if (!saveExtraFieldsAndComments)
            {
                Stream baseStream = reader.BaseStream;
                baseStream.Position = (long)(baseStream.Position + (ulong)header.FileCommentLength);
                header.FileComment  = null;
            }
            else
            {
                header.FileComment = reader.ReadBytes((int)header.FileCommentLength);
            }
            if (!justZip64Block.UncompressedSize.HasValue)
            {
                value = (long)((ulong)num2);
            }
            else
            {
                uncompressedSize = justZip64Block.UncompressedSize;
                value            = uncompressedSize.Value;
            }
            header.UncompressedSize = value;
            if (!justZip64Block.CompressedSize.HasValue)
            {
                num = (long)((ulong)num1);
            }
            else
            {
                uncompressedSize = justZip64Block.CompressedSize;
                num = uncompressedSize.Value;
            }
            header.CompressedSize = num;
            if (!justZip64Block.LocalHeaderOffset.HasValue)
            {
                value1 = (long)((ulong)num4);
            }
            else
            {
                uncompressedSize = justZip64Block.LocalHeaderOffset;
                value1           = uncompressedSize.Value;
            }
            header.RelativeOffsetOfLocalHeader = value1;
            header.DiskNumberStart             = (!justZip64Block.StartDiskNumber.HasValue ? (int)num3 : justZip64Block.StartDiskNumber.Value);
            return(true);
        }