From 080fef17f3de297763b0762351d9835ea4f766e3 Mon Sep 17 00:00:00 2001 From: Brian Maloney Date: Thu, 5 Mar 2026 12:32:00 -0600 Subject: [PATCH] Fix load time --- src/XstReader.Api/LTP.cs | 57 ++++++++++++++++++++++++++++++++-------- src/XstReader.Api/NDB.cs | 15 ++++++----- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/XstReader.Api/LTP.cs b/src/XstReader.Api/LTP.cs index ef2bcdf..c4d6720 100644 --- a/src/XstReader.Api/LTP.cs +++ b/src/XstReader.Api/LTP.cs @@ -828,21 +828,44 @@ private List ReadHeapOnNode(UInt64 dataBid) private byte[] GetBytesForHNID(List blocks, BTree subNodeTree, HNID hnid) { byte[] buf = null; - - if (hnid.hidType == EnidType.HID) + + try { - if (hnid.GetIndex(ndb.IsUnicode4K) != 0) + if (hnid.hidType == EnidType.HID) + { + var index = hnid.GetIndex(ndb.IsUnicode4K); + + if (index > 0) + { + var blockIndex = hnid.HID.GetBlockIndex(ndb.IsUnicode4K); + + // Validate block index + if (blockIndex >= 0 && blockIndex < blocks.Count) + { + var size = HidSize(blocks, hnid.HID); + + if (size > 0) + { + buf = MapArray(blocks, hnid.HID, size); + } + } + } + } + else if (hnid.nidType == EnidType.LTP) { - buf = MapArray(blocks, hnid.HID, HidSize(blocks, hnid.HID)); + buf = ndb.ReadSubNodeDataBlock(subNodeTree, hnid.NID); + } + else + { + throw new XstException("Data storage style not implemented"); } } - else if (hnid.nidType == EnidType.LTP) + catch (IndexOutOfRangeException) { - buf = ndb.ReadSubNodeDataBlock(subNodeTree, hnid.NID); + // Corrupt heap allocation or bad HID reference + return null; } - else - throw new XstException("Data storage style not implemented"); - + return buf; } @@ -851,9 +874,21 @@ private byte[] GetBytesForHNID(List blocks, BTree subNodeTree private int HidSize(List blocks, HID hid) { var index = hid.GetIndex(ndb.IsUnicode4K); - if (index == 0) // Check for empty + if (index <= 0) return 0; - var b = blocks[hid.GetBlockIndex(ndb.IsUnicode4K)]; + + var blockIndex = hid.GetBlockIndex(ndb.IsUnicode4K); + + // Validate block index + if (blockIndex < 0 || blockIndex >= blocks.Count) + return 0; + + var b = blocks[blockIndex]; + + // Validate allocation index + if (index >= b.rgibAlloc.Length || index - 1 < 0) + return 0; + return b.rgibAlloc[index] - b.rgibAlloc[index - 1]; } diff --git a/src/XstReader.Api/NDB.cs b/src/XstReader.Api/NDB.cs index cbc54a4..3881e11 100644 --- a/src/XstReader.Api/NDB.cs +++ b/src/XstReader.Api/NDB.cs @@ -536,13 +536,16 @@ private byte[] ReadAndDecompress(DataRef rb, out int read, byte[] buffer = null, { if (buffer == null) buffer = new byte[rb.InflatedLength]; - - var writable = new MemoryStream(buffer, offset, rb.InflatedLength, true); - decompressionStream.CopyTo(writable); - - if (writable.Position != writable.Length) + int curPos = 0; + int buffLen = buffer.Length; + int batchSize = buffLen > 65536 ? 16384 : 4096; + while (curPos < buffer.Length) { - throw new EndOfStreamException(); + int count = Math.Min(batchSize, buffLen - curPos); + int bytesRead = decompressionStream.Read(buffer, curPos, count); + if (bytesRead == 0) + throw new EndOfStreamException(); // restore safety; + curPos += bytesRead; } } read = rb.InflatedLength;