This is an automated email from the ASF dual-hosted git repository.
pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new 93aebfce39 EscherBSERecord fillFields() to return consumed bytes
(#1105)
93aebfce39 is described below
commit 93aebfce397891fcab2fca0a9871214d9b95de48
Author: jmestwa-coder <[email protected]>
AuthorDate: Wed Jun 3 23:53:44 2026 +0530
EscherBSERecord fillFields() to return consumed bytes (#1105)
---
.../java/org/apache/poi/ddf/EscherBSERecord.java | 5 ++-
.../org/apache/poi/ddf/TestEscherBSERecord.java | 52 ++++++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/poi/src/main/java/org/apache/poi/ddf/EscherBSERecord.java
b/poi/src/main/java/org/apache/poi/ddf/EscherBSERecord.java
index 4e37209115..edab5b2135 100644
--- a/poi/src/main/java/org/apache/poi/ddf/EscherBSERecord.java
+++ b/poi/src/main/java/org/apache/poi/ddf/EscherBSERecord.java
@@ -125,7 +125,10 @@ public final class EscherBSERecord extends EscherRecord {
_remainingData = IOUtils.safelyClone(data, pos, bytesRemaining,
MAX_RECORD_LENGTH);
- return bytesRemaining + 8 + 36 + (field_12_blipRecord == null ? 0 :
field_12_blipRecord.getRecordSize()) ;
+ // fillFields() must return bytes actually consumed from the stream.
+ // Using getRecordSize() can over-report consumption when malformed
+ // embedded blips reconstruct a size larger than the declared record.
+ return bytesRemaining + 8 + 36 + bytesRead;
}
diff --git a/poi/src/test/java/org/apache/poi/ddf/TestEscherBSERecord.java
b/poi/src/test/java/org/apache/poi/ddf/TestEscherBSERecord.java
index 43edb89d0c..7a6536fa7a 100644
--- a/poi/src/test/java/org/apache/poi/ddf/TestEscherBSERecord.java
+++ b/poi/src/test/java/org/apache/poi/ddf/TestEscherBSERecord.java
@@ -26,6 +26,7 @@ import org.apache.poi.poifs.storage.RawDataUtil;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.HexRead;
+import org.apache.poi.util.LittleEndian;
import org.junit.jupiter.api.Test;
final class TestEscherBSERecord {
@@ -51,6 +52,57 @@ final class TestEscherBSERecord {
assertEquals( 0, r.getRemainingData().length );
}
+ /**
+ * fillFields() must report the number of bytes it actually consumed from
the input,
+ * because EscherContainerRecord.fillFields() advances to the next sibling
record by that
+ * amount. The embedded blip's getRecordSize() (a reconstructed serialized
size) must NOT be
+ * used for this, since it can diverge from the bytes actually read on
malformed input.
+ *
+ * Here an EscherMetafileBlip declares a record length of 60
bytes-after-header (10 bytes of
+ * picture data) but its cbSave field claims 30 bytes. The blip honours
its declared length
+ * (consuming 8 + 60 = 68 bytes) yet getRecordSize() reports 8 + 50 + 30 =
88. The BSE record
+ * therefore must still report its own declared on-disk length (8 + 124 =
132), not the
+ * inflated 152 that the reconstructed size would produce - otherwise a
container would skip
+ * 20 bytes and mis-locate the following record.
+ */
+ @Test
+ void fillFieldsReturnsBytesConsumedNotReconstructedSize() {
+ final int blipBodyLen = 16 + 4 + 16 + 8 + 4 + 1 + 1 + 10; // = 60
declared bytes-after-header
+ final int cbSave = 30; //
overstated: only 10 picture bytes declared
+ final int trailing = 20; // BSE
_remainingData
+ final int bseBodyLen = 36 + (8 + blipBodyLen) + trailing; // = 124
+
+ byte[] data = new byte[8 + bseBodyLen]; // = 132
+ int pos = 0;
+
+ // --- BSE header ---
+ LittleEndian.putShort(data, pos, (short) 0x0002);
pos += 2; // options
+ LittleEndian.putShort(data, pos, EscherBSERecord.RECORD_ID);
pos += 2; // recordId 0xF007
+ LittleEndian.putInt(data, pos, bseBodyLen);
pos += 4;
+ // 36 fixed BSE fields (content irrelevant for this test)
+ pos += 36;
+
+ // --- embedded metafile (WMF) blip ---
+ // options = MSOBI_WMF so (options ^ signature) == 0 (no secondary
UID), 50-byte fixed header
+ LittleEndian.putShort(data, pos, (short) 0x2160);
pos += 2; // options
+ LittleEndian.putShort(data, pos, (short)
EscherRecordTypes.BLIP_WMF.typeID); pos += 2; // 0xF01B
+ LittleEndian.putInt(data, pos, blipBodyLen);
pos += 4;
+ pos += 16; // UID1
+ LittleEndian.putInt(data, pos, 0); pos += 4; // cb
(uncompressed size)
+ pos += 16; // rcBounds
+ pos += 8; // ptSize
+ LittleEndian.putInt(data, pos, cbSave); pos += 4; // cbSave
(overstated)
+ data[pos++] = (byte) 0xFE; // fCompression = no
compression
+ data[pos++] = (byte) 0xFE; // fFilter
+ // remaining bytes (10 declared picture bytes + 20 BSE trailing) stay
zero-filled
+
+ EscherBSERecord r = new EscherBSERecord();
+ int bytesWritten = r.fillFields(data, 0, new
DefaultEscherRecordFactory());
+
+ assertEquals(8 + bseBodyLen, bytesWritten,
+ "BSE must report its declared on-disk length, not the blip's
reconstructed size");
+ }
+
@Test
void testSerialize() throws IOException {
EscherBSERecord r = createRecord();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]