示例#1
0
        /// <summary>
        /// ctor: Create class from data returned by the Reader
        /// </summary>
        /// <param name="reader">A binary data reader for this type of data - positioned at last page</param>
        public p4kEndOfCentralDirRecord(p4kRecReader reader)
        {
            // sanity check only
            System.Diagnostics.Trace.Assert(Marshal.SizeOf(typeof(MyRecord)) == RecordLength,
                                            "Record size does not match!(" + Marshal.SizeOf(typeof(MyRecord)).ToString( ) + ")");

            if (reader.IsOpen( ))
            {
                try {
                    long cPos = p4kSignatures.FindSignatureInPage(reader, p4kSignatures.EndOfCentralDirRecord);
                    if (cPos >= 0)
                    {
                        m_recordOffset = cPos;
                        reader.Seek(cPos);
                        m_item      = p4kRecReader.ByteToType <MyRecord>(reader.TheReader);
                        m_itemValid = true;
                    }
                }
                catch {
                    m_itemValid    = false;
                    m_recordOffset = -1;
                }
                finally {
                    if (!m_itemValid)
                    {
                        throw new OperationCanceledException(string.Format("EOF - cannot find EndOfCentralDirRecord"));
                    }
                }
            }
        }
示例#2
0
        /// <summary>
        /// ctor: Create class from data returned by the Reader; starts reading at current stream position
        /// </summary>
        /// <param name="reader">A binary data reader for this type of data - positioned already</param>
        public p4kDirectoryEntry(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 {
                    // get the next Directory record
                    long cPos = p4kSignatures.FindSignatureInPage(reader, p4kSignatures.CentralDirRecord);
                    if (cPos >= 0)
                    {
                        m_recordOffset = cPos;
                        reader.Seek(cPos);
                        m_item      = p4kRecReader.ByteToType <MyRecord>(reader.TheReader);
                        m_itemValid = true; // implicite from Find..
                    }

                    // 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); // get the file time given in the container

                        // 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;
                        }
                    }
                }
                catch (Exception e) {
                    m_itemValid    = false;
                    m_recordOffset = -1;
                }
                finally {
                    if (!m_itemValid)
                    {
                        throw new OperationCanceledException(string.Format("EOF - cannot find CentralDirRec in this page"));
                    }
                }
            }
        }
示例#3
0
 /// <summary>
 /// Read the extra data
 /// </summary>
 /// <param name="reader"></param>
 private void ReadExtradata(p4kRecReader reader)
 {
     // first the Zip64 extra record
     m_z64Item = p4kRecReader.ByteToType <MyZ64ExtraRecord>(reader.TheReader);
     // then the rest of the extra record (is another item with tag 0x0666 and the rest lenght (ignored)
     m_extraBytes = new byte[m_item.ExtraFieldLength - Z64ExtraRecordLength];
     m_extraBytes = reader.ReadBytes(m_extraBytes.Length);
     m_extraBytes = null; // dump it ...
     // now we would be able to read the file content
 }
示例#4
0
        //  4.3.6 Overall.ZIP file format:
        //[local file header 1]
        //[encryption header 1]
        //[file data 1]
        //[data descriptor 1]
        //  .
        //  .
        //  .
        //[local file header n]
        //[encryption header n]
        //[file data n]
        //[data descriptor n]

        //[archive decryption header]
        //[archive extra data record]

        //[central directory header 1]
        //  .
        //  .
        //  .
        //[central directory header n]
        //[zip64 end of central directory record]
        //[zip64 end of central directory locator]
        //[end of central directory record]


        /// <summary>
        /// Retrieve the file given by the descriptor (from our list)
        /// and return the content as string
        /// </summary>
        /// <param name="file">A file descriptor from this list</param>
        /// <returns>The content of the file or an empty string</returns>
        public byte[] GetFile(string p4kFilename, p4kFile file)
        {
            if (!File.Exists(p4kFilename))
            {
                return new byte[] { }
            }
            ;

            using (p4kRecReader reader = new p4kRecReader(p4kFilename)) {
                return(file.GetFile(reader));
            }
        }
示例#5
0
        /// <summary>
        /// Return the file related to this entry
        /// </summary>
        /// <param name="reader">An open p4k File reader</param>
        /// <returns>The content of the file or an empty string</returns>
        public byte[] GetFile(p4kRecReader reader)
        {
            if (!m_itemValid)
            {
                return new byte[] { }
            }
            ;                                    // ERROR cannot..

            reader.Seek(FileHeaderOffset);
            p4kFileHeader p4Kfh = new p4kFileHeader(reader);

            return(p4Kfh.GetFile(reader));
        }
示例#6
0
        /// <summary>
        /// Returns the position of the Signature within the stream
        ///  Searches one page from current location starting at the end of the page
        /// </summary>
        /// <param name="reader">A positioned reader</param>
        /// <returns>The position within the stream or -1 if not found</returns>
        public static long FindSignatureInPageBackwards(p4kRecReader reader, byte[] signature)
        {
            long pos = reader.Position;

            byte[] lPage = reader.GetPage( );
            for (int i = lPage.Length - 4; i > 0; i--)
            {
                if (lPage.Skip(i).Take(4).SequenceEqual(signature))
                {
                    // now this should be the start of the item [end of central directory record]
                    return(pos + i);
                }
            }
            return(-1); // not found...
        }
示例#7
0
        public static readonly byte[] EndOfCentralDirRecord     = { 0x50, 0x4B, 0x05, 0x06 }; // (0x06054b50) 4.3.16  End of central directory record:

        /// <summary>
        /// Returns the position of the Signature within the stream
        ///  Searches one page from current location
        /// </summary>
        /// <param name="reader">A positioned reader</param>
        /// <returns>The position within the stream or -1 if not found</returns>
        public static long FindSignatureInPage(p4kRecReader reader, byte[] signature)
        {
            long pos = reader.Position;

            byte[] lPage = reader.GetPage( );
            for (int i = 0; i < lPage.Length - 4; i++)
            {
                if (lPage.Skip(i).Take(4).SequenceEqual(signature))
                {
                    // now this should be the start of the item
                    return(pos + i);
                }
            }
            return(-1); // not found...
        }
        /// <summary>
        /// ctor: Create class from data returned by the Reader
        /// </summary>
        /// <param name="reader">A binary data reader for this type of data - positioned at last page</param>
        public p4kEndOfCentralDirRecord(p4kRecReader reader)
        {
            // sanity check only
            System.Diagnostics.Trace.Assert(Marshal.SizeOf(typeof(MyRecord)) == RecordLength,
                                            "Record size does not match!(" + Marshal.SizeOf(typeof(MyRecord)).ToString( ) + ")");

            if (reader.IsOpen( ))
            {
                try {
                    long thisPos = 0;
                    // 20180804BM- fix when the last page is barely used and the sig is one or more pages before
                    //  - backup one or more pages to find end of dir (max 10 times)
                    int tries = 10;
                    while (!m_itemValid && (tries > 0))
                    {
                        thisPos = reader.Position;
                        long cPos = p4kSignatures.FindSignatureInPage(reader, p4kSignatures.EndOfCentralDirRecord);
                        if (cPos >= 0)
                        {
                            m_recordOffset = cPos;
                            reader.Seek(cPos);
                            m_item      = p4kRecReader.ByteToType <MyRecord>(reader.TheReader);
                            m_itemValid = true;
                        }
                        else
                        {
                            // backup one page again
                            reader.Seek(thisPos);
                            reader.BackwardPage( );
                            tries--;
                        }
                    }
                }
                catch {
                    m_itemValid    = false;
                    m_recordOffset = -1;
                }
                finally {
                    if (!m_itemValid)
                    {
                        throw new OperationCanceledException(string.Format("EOF - cannot find EndOfCentralDirRecord"));
                    }
                }
            }
        }
示例#9
0
        /// <summary>
        /// Return the file related to this entry
        /// </summary>
        /// <param name="reader">An open p4k File reader</param>
        /// <returns>The content of the file or an empty string</returns>
        public byte[] GetFile(p4kRecReader reader)
        {
            if (!m_itemValid)
            {
                return new byte[] { }
            }
            ;                                    // ERROR cannot..

            reader.Seek(m_fileOffset);
            // ?? big files may have trouble here - may be we need to read and write chunks for this
            // but for now we only want to get XMLs out and that is OK with byte alloc on the heap
            byte[] fileBytes = new byte[m_fileSizeComp];
            fileBytes = reader.ReadBytes(fileBytes.Length);

            byte[] decompFile = null;
            if (m_item.CompressionMethod == 0x64)
            {
                // this indicates p4k ZStd compression
                using (var decompressor = new Decompressor( )) {
                    try {
                        decompFile = decompressor.Unwrap(fileBytes);
                        return(decompFile);
                    }
                    catch (ZstdException e) {
                        Console.WriteLine("ZStd - Cannot decode file: " + m_filename);
                        Console.WriteLine("Error: " + e.Message);
                        //Console.ReadLine();
                        return(new byte[] { });
                    }
                }
            }
            else
            {
                // plain write - might be wrong if another compression was applied..
                decompFile = fileBytes;

                return(decompFile);
            }
        }
示例#10
0
        /// <summary>
        /// Scans directory entries and return the a file descriptor (string.EndsWith is used)
        /// </summary>
        /// <param name="p4kFilename">The p4k file</param>
        /// <param name="filename">The filename to look for</param>
        public p4kFile ScanDirectoryFor(string p4kFilename, string filename)
        {
            if (!File.Exists(p4kFilename))
            {
                return(null);
            }

            using (p4kRecReader reader = new p4kRecReader(p4kFilename)) {
                // work from the end of the file
                reader.GotoLastPage( );
                m_endOfCentralDirRecord = new p4kEndOfCentralDirRecord(reader);

                // position first
                reader.Seek(m_endOfCentralDirRecord.RecordOffset - p4kRecReader.PageSize);
                m_z64EndOfCentralDirLocator = new p4kZ64EndOfCentralDirLocator(reader);

                // for the next the position should be found already - seek it
                reader.Seek(m_z64EndOfCentralDirLocator.Z64EndOfCentralDir);
                m_z64EndOfCentralDirRecord = new p4kZ64EndOfCentralDirRecord(reader);
                // now we should have the start of the directory entries...


                // position first
                reader.Seek(m_z64EndOfCentralDirRecord.Z64StartOfCentralDir);
                // loop all file - as per dir reporting
                for (long i = 0; i < m_z64EndOfCentralDirRecord.NumberOfEntries; i++)
                {
                    p4kDirectoryEntry de = new p4kDirectoryEntry(reader);
                    if (!string.IsNullOrEmpty(filename) && de.Filename.ToLower( ).EndsWith(filename.ToLower( )))
                    {
                        var p = new p4kFile(de); // FOUND
                        reader.TheReader.Close( );
                        return(p);               // bail out if found
                    }
                }
            }
            return(null);
        }
示例#11
0
        /// <summary>
        /// Scans directory entries and return the a list of matching file descriptors (string.Contains is used)
        /// </summary>
        /// <param name="p4kFilename">The p4k file</param>
        /// <param name="filenamepart">The filename part to look for</param>
        public IList <p4kFile> ScanDirectoryContaining(string p4kFilename, string filenamepart)
        {
            if (!File.Exists(p4kFilename))
            {
                return(null);
            }

            List <p4kFile> fileList = new List <p4kFile>( );

            using (p4kRecReader reader = new p4kRecReader(p4kFilename)) {
                // work from the end of the file
                reader.GotoLastPage( );
                m_endOfCentralDirRecord = new p4kEndOfCentralDirRecord(reader);

                // position first
                reader.Seek(m_endOfCentralDirRecord.RecordOffset - p4kRecReader.PageSize);
                m_z64EndOfCentralDirLocator = new p4kZ64EndOfCentralDirLocator(reader);

                // for the next the position should be found already - seek it
                reader.Seek(m_z64EndOfCentralDirLocator.Z64EndOfCentralDir);
                m_z64EndOfCentralDirRecord = new p4kZ64EndOfCentralDirRecord(reader);
                // now we should have the start of the directory entries...

                // position first
                reader.Seek(m_z64EndOfCentralDirRecord.Z64StartOfCentralDir);
                // loop all file - as per dir reporting
                for (long i = 0; i < m_z64EndOfCentralDirRecord.NumberOfEntries; i++)
                {
                    p4kDirectoryEntry de = new p4kDirectoryEntry(reader);
                    if (!string.IsNullOrEmpty(filenamepart) && de.Filename.ToLower( ).Contains(filenamepart.ToLower( )))
                    {
                        var p = new p4kFile(de); // FOUND
                        fileList.Add(p);
                    }
                }
            }
            return(fileList);
        }
示例#12
0
 /// <summary>
 /// Get the filename from the data
 /// </summary>
 /// <param name="reader">The open and positioned reader</param>
 private void ReadFilename(p4kRecReader reader)
 {
     byte[] fileNameBytes = new byte[m_item.FilenameLength];
     fileNameBytes = reader.ReadBytes(m_item.FilenameLength);
     m_filename    = Encoding.ASCII.GetString(fileNameBytes);
 }
示例#13
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( )));
                        }
                    }
                }
            }
        }