Exemple #1
0
        // Write the local file header
        // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
        private void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
        {
            CompressionMethod method = entry.CompressionMethod;
            bool headerInfoAvailable = true;             // How to get this?
            bool patchEntryHeader    = false;

            WriteLEInt(ZipConstants.LocalHeaderSignature);

            WriteLEShort(entry.Version);
            WriteLEShort(entry.Flags);
            WriteLEShort((byte)method);
            WriteLEInt((int)entry.DosTime);

            if (headerInfoAvailable == true)
            {
                WriteLEInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLEInt(-1);
                    WriteLEInt(-1);
                }
                else
                {
                    WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
                    WriteLEInt((int)entry.Size);
                }
            }
            else
            {
                if (patchData != null)
                {
                    patchData.CrcPatchOffset = stream_.Position;
                }
                WriteLEInt(0);                  // Crc

                if (patchData != null)
                {
                    patchData.SizePatchOffset = stream_.Position;
                }

                // For local header both sizes appear in Zip64 Extended Information
                if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
                {
                    WriteLEInt(-1);
                    WriteLEInt(-1);
                }
                else
                {
                    WriteLEInt(0);                      // Compressed size
                    WriteLEInt(0);                      // Uncompressed size
                }
            }

            byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new ZipException("Entry name too long.");
            }

            var ed = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader))
            {
                ed.StartNewEntry();
                if (headerInfoAvailable)
                {
                    ed.AddLeLong(entry.Size);
                    ed.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    ed.AddLeLong(-1);
                    ed.AddLeLong(-1);
                }
                ed.AddNewEntry(1);

                if (!ed.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }

                if (patchData != null)
                {
                    patchData.SizePatchOffset = ed.CurrentReadIndex;
                }
            }
            else
            {
                ed.Delete(1);
            }

            byte[] extra = ed.GetEntryData();

            WriteLEShort(name.Length);
            WriteLEShort(extra.Length);

            if (name.Length > 0)
            {
                stream_.Write(name, 0, name.Length);
            }

            if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
            {
                patchData.SizePatchOffset += stream_.Position;
            }

            if (extra.Length > 0)
            {
                stream_.Write(extra, 0, extra.Length);
            }
        }
Exemple #2
0
        /// <summary>
        /// Process extra data fields updating the entry based on the contents.
        /// </summary>
        /// <param name="localHeader">True if the extra data fields should be handled
        /// for a local header, rather than for a central header.
        /// </param>
        internal void ProcessExtraData(bool localHeader)
        {
            var extraData = new ZipExtraData(this.extra);

            if (extraData.Find(0x0001))
            {
                // Version required to extract is ignored here as some archivers dont set it correctly
                // in theory it should be version 45 or higher

                // The recorded size will change but remember that this is zip64.
                forceZip64_ = true;

                if (extraData.ValueLength < 4)
                {
                    throw new ZipException("Extra data extended Zip64 information length is invalid");
                }

                // (localHeader ||) was deleted, because actually there is no specific difference with reading sizes between local header & central directory
                // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
                // ...
                // 4.4  Explanation of fields
                // ...
                //	4.4.8 compressed size: (4 bytes)
                //	4.4.9 uncompressed size: (4 bytes)
                //
                //		The size of the file compressed (4.4.8) and uncompressed,
                //		(4.4.9) respectively.  When a decryption header is present it
                //		will be placed in front of the file data and the value of the
                //		compressed file size will include the bytes of the decryption
                //		header.  If bit 3 of the general purpose bit flag is set,
                //		these fields are set to zero in the local header and the
                //		correct values are put in the data descriptor and
                //		in the central directory.  If an archive is in ZIP64 format
                //		and the value in this field is 0xFFFFFFFF, the size will be
                //		in the corresponding 8 byte ZIP64 extended information
                //		extra field.  When encrypting the central directory, if the
                //		local header is not in ZIP64 format and general purpose bit
                //		flag 13 is set indicating masking, the value stored for the
                //		uncompressed size in the Local Header will be zero.
                //
                // Othewise there is problem with minizip implementation
                if (size == uint.MaxValue)
                {
                    size = (ulong)extraData.ReadLong();
                }

                if (compressedSize == uint.MaxValue)
                {
                    compressedSize = (ulong)extraData.ReadLong();
                }

                if (!localHeader && (offset == uint.MaxValue))
                {
                    offset = extraData.ReadLong();
                }

                // Disk number on which file starts is ignored
            }
            else
            {
                if (
                    ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
                    ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
                    )
                {
                    throw new ZipException("Zip64 Extended information required but is missing.");
                }
            }

            DateTime = GetDateTime(extraData);
            if (method == CompressionMethod.WinZipAES)
            {
                ProcessAESExtraData(extraData);
            }
        }