Example #1
0
        internal static ZipIOExtraFieldElement Parse(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage)
        {
            // we can safely parse the Id and Size here
            //  since the minimum size is checked from the caller (ZipIoExtraField)
            UInt16 id   = reader.ReadUInt16();
            UInt16 size = reader.ReadUInt16();

            ZipIOExtraFieldElement newElement;

            if (id == ZipIOExtraFieldZip64Element.ConstantFieldId)  // Found Zip64 Extra Field element
            {
                newElement = new ZipIOExtraFieldZip64Element();
                ((ZipIOExtraFieldZip64Element)newElement).Zip64ExtraFieldUsage = zip64extraFieldUsage;
            }
            else if (id == ZipIOExtraFieldPaddingElement.ConstantFieldId)   // Found potential Padding Extra Field element
            {
                // Even if the id matches Padding Extra Element id, we cannot be sure if it is Microsoft defined one
                // until its signature is verified

                // This extra field matches Padding Extra Element id, but it is not big enough to be ours
                if (size < ZipIOExtraFieldPaddingElement.MinimumFieldDataSize)
                {
                    // Treat it as an unknown Extra Field element
                    newElement = new ZipIOExtraFieldElement(id);
                }
                else
                {
                    // Sniff bytes to check it it matches our Padding extra field signature
                    byte[] sniffedBytes = reader.ReadBytes(ZipIOExtraFieldPaddingElement.SignatureSize);
                    if (ZipIOExtraFieldPaddingElement.MatchesPaddingSignature(sniffedBytes))
                    {
                        // Signature matches the Padding Extra Field signature
                        newElement = new ZipIOExtraFieldPaddingElement();
                    }
                    else
                    {
                        // Signature doesn't match; treat it a an unknown Extra Field element
                        newElement = new ZipIOExtraFieldElement(id, sniffedBytes);
                    }
                }
            }
            else
            {
                newElement = new ZipIOExtraFieldElement(id);
            }

            // Parse the data field of the Extra Field element
            newElement.ParseDataField(reader, size);

            return(newElement);
        }
Example #2
0
        internal static ZipIOExtraFieldElement Parse(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage)
        {
            // we can safely parse the Id and Size here
            //  since the minimum size is checked from the caller (ZipIoExtraField)
            UInt16 id = reader.ReadUInt16();
            UInt16 size = reader.ReadUInt16();

            ZipIOExtraFieldElement newElement;

            if (id == ZipIOExtraFieldZip64Element.ConstantFieldId)  // Found Zip64 Extra Field element
            {
                newElement = new ZipIOExtraFieldZip64Element();
                ((ZipIOExtraFieldZip64Element) newElement).Zip64ExtraFieldUsage = zip64extraFieldUsage;
            }
            else if (id == ZipIOExtraFieldPaddingElement.ConstantFieldId)   // Found potential Padding Extra Field element
            {
                // Even if the id matches Padding Extra Element id, we cannot be sure if it is Microsoft defined one
                // until its signature is verified

                // This extra field matches Padding Extra Element id, but it is not big enough to be ours
                if (size < ZipIOExtraFieldPaddingElement.MinimumFieldDataSize)
                {
                    // Treat it as an unknown Extra Field element
                    newElement = new ZipIOExtraFieldElement(id);
                }
                else
                {
                    // Sniff bytes to check it it matches our Padding extra field signature
                    byte[] sniffedBytes = reader.ReadBytes(ZipIOExtraFieldPaddingElement.SignatureSize);
                    if (ZipIOExtraFieldPaddingElement.MatchesPaddingSignature(sniffedBytes))
                    {
                        // Signature matches the Padding Extra Field signature
                        newElement = new ZipIOExtraFieldPaddingElement();
                    }
                    else
                    {
                        // Signature doesn't match; treat it a an unknown Extra Field element
                        newElement = new ZipIOExtraFieldElement(id, sniffedBytes);
                    }
                }
            }
            else
            {
                newElement = new ZipIOExtraFieldElement(id);
            }

            // Parse the data field of the Extra Field element
            newElement.ParseDataField(reader, size);

            return newElement;
        }
Example #3
0
        internal static ZipIOExtraField CreateNew(bool createPadding)
        {
            // we have been asked to create a new record, current zip io implementation will add at most one Zip64 block
            ZipIOExtraField extraField = new ZipIOExtraField();

            extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew();

            if (createPadding)
            {
                extraField._paddingElement = ZipIOExtraFieldPaddingElement.CreateNew();
            }

            return(extraField);
        }
Example #4
0
        internal static ZipIOExtraField ParseRecord(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage, ushort expectedExtraFieldSize)
        {
            // most of the files are not ZIP 64, and instead of trying to parse it we should create new empty record
            if (expectedExtraFieldSize == 0)
            {
                if (zip64extraFieldUsage != ZipIOZip64ExtraFieldUsage.None)
                {
                    // in case there is an expectation by the caller for a non empty record we should throw
                    throw new FileFormatException(SR.Get(SRID.CorruptedData));
                }

                // We are creating Extra Fields for the existing Local File Header,
                //  so no need to create a new padding field
                return(CreateNew(false));
            }

            ZipIOExtraField extraField = new ZipIOExtraField();

            // Parse all Extra elements from Extra Field
            while (expectedExtraFieldSize > 0)
            {
                if (expectedExtraFieldSize < ZipIOExtraFieldElement.MinimumSize)
                {
                    throw new FileFormatException(SR.Get(SRID.CorruptedData));
                }

                ZipIOExtraFieldElement        newElement     = ZipIOExtraFieldElement.Parse(reader, zip64extraFieldUsage);
                ZipIOExtraFieldZip64Element   zip64Element   = newElement as ZipIOExtraFieldZip64Element;
                ZipIOExtraFieldPaddingElement paddingElement = newElement as ZipIOExtraFieldPaddingElement;

                // if we have found the Zip 64 record. let's remember it
                if (zip64Element != null)
                {
                    if (extraField._zip64Element != null)
                    {
                        // multiple ZIP 64 extra fields are not allowed
                        throw new FileFormatException(SR.Get(SRID.CorruptedData));
                    }

                    extraField._zip64Element = zip64Element;
                }
                else if (paddingElement != null)
                {
                    if (extraField._paddingElement != null)
                    {
                        // multiple padding extra fields are not allowed
                        throw new FileFormatException(SR.Get(SRID.CorruptedData));
                    }

                    extraField._paddingElement = paddingElement;
                }
                else
                {
                    if (extraField._extraFieldElements == null)
                    {
                        extraField._extraFieldElements = new ArrayList(3);    // we expect to see a few records there, as it sould have been produced by other authoring systems.
                    }
                    // any other instances of extra fields with the same id are allowed
                    extraField._extraFieldElements.Add(newElement);
                }

                checked { expectedExtraFieldSize -= newElement.Size; }
            }

            // if we didn't end up at the exact expected position, we are treating this as a corrupted file
            if (expectedExtraFieldSize != 0)
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }

            // As we treat the ZIP 64 extra field as optional for all version >= 4.5
            // we need to explicitly consider a case when it is missing
            if (extraField._zip64Element == null)
            {
                extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew();
            }

            /////////////////////////////////////////////////////////////////////
            //              extraField.Validate();
            // an instance Validate function is removed to fix FxCop violation, please add it back
            // if extra validation steps are required
            //
            // we are checking for uniqueness of the Zip 64 header ID in the Parse function.
            // Although it might be a good idea to check for record id uniqueness in general,
            // we are treating the rest of the field as a bag of bits, so it is probably not worth it to
            // search for other duplicate ID especially as appnote considers ID duplication a possibility
            // and even suggest a work around for file producers.
            /////////////////////////////////////////////////////////////////////

            return(extraField);
        }
Example #5
0
        // Add or remove padding for the given size change
        internal void UpdatePadding(long size)
        {
            // If the local file header changed more than 100 bytes, it means
            //  there are some logical errors
            Debug.Assert(Math.Abs(size) <= 100);

            // The header size change should be no more than what we can hold in UInt16
            if (Math.Abs(size) > UInt16.MaxValue)
            {
                return;
            }

            // Header size increased; need to remove padding if there is an existing padding structure
            if (size > 0 && _paddingElement != null)
            {
                // There is enough padding left over to do size adjustment
                // No need to use checked{} since _paddingElement.PaddingSize >= size
                if (_paddingElement.PaddingSize >= size)
                {
                    _paddingElement.PaddingSize -= (UInt16)size;
                }
                // The size of the whole padding structure exactly matches the size change
                else if (_paddingElement.Size == size)
                {
                    // Then the padding structure can be completely removed
                    //  to accommodate the size change
                    _paddingElement = null;
                }

                return;
            }

            // Header size decreased; need to add padding
            if (size < 0)
            {
                // Padding structure is not there but, the size change is big enough for one
                //  to be created
                if (_paddingElement == null)
                {
                    // No need to use checked{} since size is long type
                    //  and size < 0
                    //  and (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize + ZipIOExtraFieldElement.MinimumSize)
                    //      is small number that can not cause the overflow
                    size += (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize
                             + ZipIOExtraFieldElement.MinimumSize);

                    if (size >= 0)
                    {
                        _paddingElement = new ZipIOExtraFieldPaddingElement();
                        // No need to use checked{} since size > 0 and less than UInt16.MaxValue
                        _paddingElement.PaddingSize = (UInt16)size;
                    }
                }
                else
                {
                    // Check if we hit the max padding allowed
                    if ((_paddingElement.PaddingSize - size) > UInt16.MaxValue)
                    {
                        return;
                    }

                    // No need to use checked{} since we already check the overflow
                    _paddingElement.PaddingSize = (UInt16)(_paddingElement.PaddingSize - size);
                }
            }
        }
        // creates a brand new empty Padding extra field element
        internal static ZipIOExtraFieldPaddingElement CreateNew()
        {
            ZipIOExtraFieldPaddingElement newElement = new ZipIOExtraFieldPaddingElement();

            return(newElement);
        }
        // creates a brand new empty Padding extra field element 
        internal static ZipIOExtraFieldPaddingElement CreateNew()
        {
            ZipIOExtraFieldPaddingElement newElement = new ZipIOExtraFieldPaddingElement();
 
            return newElement;
        } 
Example #8
0
        // Add or remove padding for the given size change
        internal void UpdatePadding(long size) 
        { 
            // If the local file header changed more than 100 bytes, it means
            //  there are some logical errors 
            Debug.Assert(Math.Abs(size) <= 100);

            // The header size change should be no more than what we can hold in UInt16
            if (Math.Abs(size) > UInt16.MaxValue) 
                return;
 
            // Header size increased; need to remove padding if there is an existing padding structure 
            if (size > 0 && _paddingElement != null)
            { 
                // There is enough padding left over to do size adjustment
                // No need to use checked{} since _paddingElement.PaddingSize >= size
                if (_paddingElement.PaddingSize >= size)
                    _paddingElement.PaddingSize -= (UInt16) size; 
                // The size of the whole padding structure exactly matches the size change
                else if (_paddingElement.Size == size) 
                { 
                    // Then the padding structure can be completely removed
                    //  to accommodate the size change 
                    _paddingElement = null;
                }

                return; 
            }
 
            // Header size decreased; need to add padding 
            if (size < 0)
            { 
                // Padding structure is not there but, the size change is big enough for one
                //  to be created
                if (_paddingElement == null)
                { 
                    // No need to use checked{} since size is long type
                    //  and size < 0 
                    //  and (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize + ZipIOExtraFieldElement.MinimumSize) 
                    //      is small number that can not cause the overflow
                    size += (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize 
                                + ZipIOExtraFieldElement.MinimumSize);

                    if (size >= 0)
                    { 
                        _paddingElement = new ZipIOExtraFieldPaddingElement();
                        // No need to use checked{} since size > 0 and less than UInt16.MaxValue 
                        _paddingElement.PaddingSize = (UInt16) size; 
                    }
                } 
                else
                {
                    // Check if we hit the max padding allowed
                    if ((_paddingElement.PaddingSize - size) > UInt16.MaxValue) 
                        return;
 
                    // No need to use checked{} since we already check the overflow 
                    _paddingElement.PaddingSize = (UInt16) (_paddingElement.PaddingSize - size);
                } 
            }
        }