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