From f6ade446c6940b4c8e67d9a252b1e8007ff417e8 Mon Sep 17 00:00:00 2001 From: gmipf Date: Mon, 19 Oct 2026 03:04:01 +0200 Subject: [PATCH] Locate the PKZIP file data instead of reading it into the model (#102) * Locate the PKZIP file data instead of reading it into the model Co-Authored-By: Claude Opus 5.5 * Keep only the offset of the PKZIP file data The length is the compressed size from the local file header or the ZIP64 extended field, which the printer already shows. Co-Authored-By: Claude Opus 5.5 * Keep the file data property as a comment for documentation Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- SabreTools.Data.Models/PKZIP/LocalFile.cs | 8 +++- .../PKZIPTests.cs | 44 +++++++++++++++++++ SabreTools.Serialization.Readers/PKZIP.cs | 10 ++--- SabreTools.Wrappers/PKZIP.Printing.cs | 11 +---- 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/SabreTools.Data.Models/PKZIP/LocalFile.cs b/SabreTools.Data.Models/PKZIP/LocalFile.cs index 863168cb..df2a26cc 100644 --- a/SabreTools.Data.Models/PKZIP/LocalFile.cs +++ b/SabreTools.Data.Models/PKZIP/LocalFile.cs @@ -22,7 +22,13 @@ namespace SabreTools.Data.Models.PKZIP /// File data, appears after the encryption header /// if it exists or after the local file header otherwise /// - public byte[] FileData { get; set; } = []; + /// Not read into the model, see + // public byte[] FileData { get; set; } = []; + + /// + /// Offset of the file data in the stream + /// + public long FileDataOffset { get; set; } /// /// Data descriptors, appears after the file data diff --git a/SabreTools.Serialization.Readers.Test/PKZIPTests.cs b/SabreTools.Serialization.Readers.Test/PKZIPTests.cs index 5a98b44b..a57af08e 100644 --- a/SabreTools.Serialization.Readers.Test/PKZIPTests.cs +++ b/SabreTools.Serialization.Readers.Test/PKZIPTests.cs @@ -1,4 +1,5 @@ using System.IO; +using System.IO.Compression; using System.Linq; using Xunit; @@ -68,5 +69,48 @@ namespace SabreTools.Serialization.Readers.Test var actual = deserializer.Deserialize(data); Assert.Null(actual); } + + [Fact] + public void ValidStream_FileDataLocated() + { + Stream? data = CreateArchive(); + var deserializer = new PKZIP(); + + var actual = deserializer.Deserialize(data); + Assert.NotNull(actual); + + var localFile = Assert.Single(actual.LocalFiles!); + var header = localFile.LocalFileHeader; + Assert.Equal(30 + header.FileNameLength + header.ExtraFieldLength, localFile.FileDataOffset); + Assert.Single(actual.CentralDirectoryHeaders!); + } + + [Fact] + public void TruncatedFileData_Null() + { + byte[] archive = CreateArchive().ToArray(); + Stream? data = new MemoryStream(archive, 0, 512); + var deserializer = new PKZIP(); + + var actual = deserializer.Deserialize(data); + Assert.Null(actual); + } + + /// + /// Create an archive with one stored file of 1000 bytes + /// + private static MemoryStream CreateArchive() + { + var stream = new MemoryStream(); + using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true)) + { + var entry = archive.CreateEntry("file.bin", CompressionLevel.NoCompression); + using var entryStream = entry.Open(); + entryStream.Write([.. Enumerable.Range(0, 1000).Select(i => (byte)i)], 0, 1000); + } + + stream.Position = 0; + return stream; + } } } diff --git a/SabreTools.Serialization.Readers/PKZIP.cs b/SabreTools.Serialization.Readers/PKZIP.cs index 82170375..99562060 100644 --- a/SabreTools.Serialization.Readers/PKZIP.cs +++ b/SabreTools.Serialization.Readers/PKZIP.cs @@ -472,13 +472,13 @@ namespace SabreTools.Serialization.Readers #region File Data - // Try to read the file data - var fileData = data.ReadBytes((int)compressedSize); - if (fileData.Length < (long)compressedSize) + // The file data is skipped, so a large archive is not read into memory + if (compressedSize > (ulong)(data.Length - data.Position)) return null; - // Set the file data - obj.FileData = fileData; + // Set the location of the file data + obj.FileDataOffset = data.Position; + data.SeekIfPossible((long)compressedSize, SeekOrigin.Current); #endregion diff --git a/SabreTools.Wrappers/PKZIP.Printing.cs b/SabreTools.Wrappers/PKZIP.Printing.cs index 298dff90..1ac9e771 100644 --- a/SabreTools.Wrappers/PKZIP.Printing.cs +++ b/SabreTools.Wrappers/PKZIP.Printing.cs @@ -89,16 +89,7 @@ namespace SabreTools.Wrappers #region File Data - var fileData = localFile.FileData; - if (fileData is null) - { - builder.AppendLine(" [File Data]: [NULL]"); - } - else - { - builder.AppendLine(fileData.Length, " [File Data] Length"); - //builder.AppendLine(fileData, " [File Data] Data"); - } + builder.AppendLine(localFile.FileDataOffset, " [File Data] Offset"); #endregion