You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ce...@apache.org on 2025/05/05 17:23:59 UTC

svn commit: r1925419 - in /poi/trunk/poi/src: main/java/org/apache/poi/hssf/record/WriteAccessRecord.java test/java/org/apache/poi/hssf/record/TestWriteAccessRecord.java

Author: centic
Date: Mon May  5 17:23:59 2025
New Revision: 1925419

URL: http://svn.apache.org/viewvc?rev=1925419&view=rev
Log:
Bug 69667: Handle slightly broken WriteAccessRecord gracefully

It seems some software creates records with invalid length.

If it uses UTF-16LE encoding, we can end up with 109 bytes, 
which is invalid as UTF-16LE always requires an even number of 
bytes.

Therefor we now sanitize the number of bytes we read from the 
record to avoid this issue.

Also improve error message and add tests

Modified:
    poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java
    poi/trunk/poi/src/test/java/org/apache/poi/hssf/record/TestWriteAccessRecord.java

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java?rev=1925419&r1=1925418&r2=1925419&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java Mon May  5 17:23:59 2025
@@ -108,10 +108,19 @@ public final class WriteAccessRecord ext
             data = IOUtils.safelyAllocate(in.remaining(), STRING_SIZE);
             in.readFully(data);
             if (UTF16FLAG.isSet(is16BitFlag)) {
-                byteCnt = Math.min(nChars * 2, data.length);
+                // the spec only allows up to 109 bytes for the string in this record, but it seems some broken
+                // software out there will generate invalid records
+                int min = Math.min(nChars * 2, data.length);
+
+                // make sure byteCnt is divisible by 2 as we read UTF-16LE
+                byteCnt = min - (min % 2);
+
                 charset = StandardCharsets.UTF_16LE;
             } else {
+                // the spec only allows up to 109 bytes for the string in this record, but it seems some broken
+                // software out there will generate invalid records
                 byteCnt = Math.min(nChars, data.length);
+
                 charset = StandardCharsets.ISO_8859_1;
             }
         }
@@ -130,7 +139,8 @@ public final class WriteAccessRecord ext
         boolean is16bit = StringUtil.hasMultibyte(username);
         int encodedByteCount = username.length() * (is16bit ? 2 : 1);
         if (encodedByteCount > STRING_SIZE) {
-            throw new IllegalArgumentException("Name is too long: " + username);
+            throw new IllegalArgumentException("Name is too long, expecting up to " + STRING_SIZE +
+                    " bytes, but had: " + encodedByteCount + " bytes: " + username);
         }
 
         field_1_username = username;

Modified: poi/trunk/poi/src/test/java/org/apache/poi/hssf/record/TestWriteAccessRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/hssf/record/TestWriteAccessRecord.java?rev=1925419&r1=1925418&r2=1925419&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/hssf/record/TestWriteAccessRecord.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/hssf/record/TestWriteAccessRecord.java Mon May  5 17:23:59 2025
@@ -93,4 +93,47 @@ final class TestWriteAccessRecord {
 
         confirmRecordEncoding(WriteAccessRecord.sid, expectedEncoding, rec.serialize());
     }
+
+    @Test
+    void testUTF16LE() {
+        byte[] data = HexRead.readFromString(""
+                + "5c 00 70 00 1C 00 01 "
+                + "44 00 61 00 74 00 61 00 20 00 44 00 79 00 6e 00 "
+                + "61 00 6d 00 69 00 63 00 73 00 27 00 20 00 53 00 "
+                + "70 00 72 00 65 00 61 00 64 00 42 00 75 00 69 00 "
+                + "6c 00 64 00 65 00 72 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00"
+        );
+        RecordInputStream in = TestcaseRecordInputStream.create(data);
+
+        WriteAccessRecord rec = new WriteAccessRecord(in);
+
+        assertEquals("Data Dynamics' SpreadBuilder", rec.getUsername());
+    }
+
+    @Test
+    void testUTF16LE_wrong_size() {
+        // "0x51" on position 5 is an incorrect size, as it would require 162 bytes to encode as UTF-16LE
+        // the spec only allows up to 109 bytes for the string in this record, but it seems some broken
+        // software out there will generate such a file
+        byte[] data = HexRead.readFromString(""
+                + "5c 00 70 00 51 00 01 "
+                + "44 00 61 00 74 00 61 00 20 00 44 00 79 00 6e 00 "
+                + "61 00 6d 00 69 00 63 00 73 00 27 00 20 00 53 00 "
+                + "70 00 72 00 65 00 61 00 64 00 42 00 75 00 69 00 "
+                + "6c 00 64 00 65 00 72 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 "
+                + "20 00 20 00 20 00"
+        );
+        RecordInputStream in = TestcaseRecordInputStream.create(data);
+
+        WriteAccessRecord rec = new WriteAccessRecord(in);
+
+        assertEquals("Data Dynamics' SpreadBuilder", rec.getUsername());
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org