Ejemplo n.º 1
0
        //4.3.7  Local file header:

        //   local file header signature     4 bytes(0x04034b50)
        //   version needed to extract       2 bytes
        //   general purpose bit flag        2 bytes
        //   compression method              2 bytes
        //   last mod file time              2 bytes
        //   last mod file date              2 bytes
        //   crc-32                          4 bytes
        //   compressed size                 4 bytes
        //   uncompressed size               4 bytes
        //   file name length                2 bytes
        //   extra field length              2 bytes

        //   file name( variable size )
        //   extra field( variable size )

        //4.3.8  File data

        //   Immediately following the local header for a file
        //   SHOULD be placed the compressed or stored data for the file.
        //   If the file is encrypted, the encryption header for the file
        //   SHOULD be placed after the local header and before the file
        //   data. The series of[local file header][encryption header]
        //   [file data][data descriptor] repeats for each file in the
        //   .ZIP archive.

        //   Zero-byte files, directories, and other file types that
        //   contain no content MUST not include file data.

        //   4.5.3 -Zip64 Extended Information Extra Field(0x0001):

        //      The following is the layout of the zip64 extended
        //      information "extra" block.If one of the size or
        //      offset fields in the Local or Central directory
        //      record is too small to hold the required data,
        //      a Zip64 extended information record is created.
        //      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.

        //      Note: all fields stored in Intel low - byte / high - byte order.

        //        Value      Size       Description
        //        ---- - ---------------
        //(ZIP64)0x0001     2 bytes    Tag for this "extra" block type
        //        Size       2 bytes    Size of this "extra" block
        //        Original
        //        Size       8 bytes    Original uncompressed file size
        //        Compressed
        //        Size       8 bytes    Size of compressed data
        //        Relative Header
        //        Offset     8 bytes    Offset of local header record
        //        Disk Start
        //        Number     4 bytes    Number of the disk on which
        //                              this file starts

        //      This entry in the Local header MUST include BOTH original
        //      and compressed file size fields.If encrypting the
        //      central directory and bit 13 of the general purpose bit
        //      flag is set indicating masking, the value stored in the
        //      Local Header for the original file size will be zero.

        /// <summary>
        /// ctor: Create class from data returned by the Reader
        /// </summary>
        /// <param name="reader">A binary data reader for this type of data</param>
        public p4kFileHeader(p4kRecReader reader)
        {
            // sanity check only
            System.Diagnostics.Trace.Assert(Marshal.SizeOf(typeof(MyRecord)) == RecordLength,
                                            "Record size does not match!(" + Marshal.SizeOf(typeof(MyRecord)).ToString( ) + ")");
            System.Diagnostics.Trace.Assert(Marshal.SizeOf(typeof(MyZ64ExtraRecord)) == Z64ExtraRecordLength,
                                            "Extra Record size does not match!(" + Marshal.SizeOf(typeof(MyZ64ExtraRecord)).ToString( ) + ")");

            if (reader.IsOpen( ))
            {
                try {
                    long cPos = reader.Position;
                    do
                    {
                        // Fileheaders are Page aligned - scan to find one
                        reader.AdvancePage( ); // to next page
                        cPos = reader.Position;
                        string cPosS = cPos.ToString("X");
                        m_recordOffset = cPos;
                        m_item         = p4kRecReader.ByteToType <MyRecord>(reader.TheReader);
                        m_itemValid    = m_item.ID.SequenceEqual(p4kSignatures.LocalFileHeaderCry);
                    } while ((cPos < reader.Length) && !m_itemValid);

                    // get some file attributes
                    if (m_itemValid)
                    {
                        if (m_item.FilenameLength > 0)
                        {
                            ReadFilename(reader);
                        }
                        if (m_item.ExtraFieldLength > 0)
                        {
                            ReadExtradata(reader); // Likely Zip64 extensions
                        }
                        m_fileDateTime = p4kFileTStamp.FromDos(m_item.LastModDate, m_item.LastModTime);

                        // check if standard fields or extension is used for size information
                        if (m_item.CompressedSize < 0xffffffff)
                        {
                            m_fileSizeComp   = m_item.CompressedSize;
                            m_fileSizeUnComp = m_item.UncompressedSize;
                        }
                        else
                        {
                            m_fileSizeComp   = (long)m_z64Item.CompressedSize;
                            m_fileSizeUnComp = (long)m_z64Item.UncompressedSize;
                        }
                        // now we would be able to read the file content
                        // but we skip it for now to process the next header
                        m_fileOffset = reader.TheReader.BaseStream.Position; // save position of this item
                        reader.TheReader.BaseStream.Seek(m_fileSizeComp, SeekOrigin.Current);
                    }
                    else
                    {
                        // actually invalid but good manner ..
                        m_recordOffset   = -1;
                        m_fileOffset     = -1;
                        m_fileSizeComp   = 0;
                        m_fileSizeUnComp = 0;
                    }
                }
                catch {
                    m_itemValid = false;
                }
                finally {
                    if (!m_itemValid)
                    {
                        if (m_item.ID.SequenceEqual(p4kSignatures.CentralDirRecord))
                        {
                            // read beyond the file entries
                            throw new OperationCanceledException(string.Format("EOF - found Central Directory header {0}", m_item.ID.ToString( )));
                        }
                        else
                        {
                            // other error
                            throw new NotSupportedException(string.Format("Cannot process fileheader ID {0}", m_item.ID.ToString( )));
                        }
                    }
                }
            }
        }