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]

Reply via email to