Author: kiwiwings
Date: Thu Jun 16 22:56:47 2022
New Revision: 1901996

URL: http://svn.apache.org/viewvc?rev=1901996&view=rev
Log:
#66115 - Some Password protected XLS files are not read

Modified:
    poi/site/src/documentation/content/xdocs/changes.xml
    poi/trunk/poi-integration/src/test/java/org/apache/poi/stress/ExcInfo.java
    
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java
    
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/WriteAccessRecord.java
    
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
    
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java
    poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffViewer.java
    poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestEFBiffViewer.java
    poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestFormulaViewer.java
    poi/trunk/test-data/spreadsheet/stress.xls

Modified: poi/site/src/documentation/content/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/changes.xml?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/changes.xml (original)
+++ poi/site/src/documentation/content/xdocs/changes.xml Thu Jun 16 22:56:47 
2022
@@ -99,6 +99,7 @@
             <action type="add" fixes-bug="66097" context="SS_Common">Support 
CEILING.PRECISE and FLOOR.PRECISE functions</action>
             <action type="add" fixes-bug="66098" context="SS_Common">D* 
functions should support wildcard matches</action>
             <action type="add" fixes-bug="66105" context="SS_Common">Support 
excel correl, covar, pearson and forecast functions</action>
+            <action type="fix" fixes-bug="66115" context="HSSF">Some Password 
protected XLS files are not read</action>
         </actions>
     </release>
 

Modified: 
poi/trunk/poi-integration/src/test/java/org/apache/poi/stress/ExcInfo.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-integration/src/test/java/org/apache/poi/stress/ExcInfo.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- poi/trunk/poi-integration/src/test/java/org/apache/poi/stress/ExcInfo.java 
(original)
+++ poi/trunk/poi-integration/src/test/java/org/apache/poi/stress/ExcInfo.java 
Thu Jun 16 22:56:47 2022
@@ -90,7 +90,7 @@ public class ExcInfo {
     public boolean isValid(String testName, String handler) {
         return
             !IGNORED_TESTS.equals(tests) &&
-            (tests == null || tests.contains(testName)) &&
-            (this.handler == null || this.handler.contains(handler));
+            (tests == null || (tests.contains(testName) && 
!tests.contains("!"+testName))) &&
+            (this.handler == null || (this.handler.contains(handler) && 
!this.handler.contains("!"+handler)));
     }
 }

Modified: 
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- 
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java 
(original)
+++ 
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordInputStream.java 
Thu Jun 16 22:56:47 2022
@@ -533,4 +533,9 @@ public final class RecordInputStream imp
         ((InputStream)_dataInput).reset();
         _currentDataOffset = _markedDataOffset;
     }
+
+    @Internal
+    public boolean isEncrypted() {
+        return _dataInput instanceof Biff8DecryptingStream && 
((Biff8DecryptingStream)_dataInput).isCurrentRecordEncrypted();
+    }
 }

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=1901996&r1=1901995&r2=1901996&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 
Thu Jun 16 22:56:47 2022
@@ -17,11 +17,17 @@
 
 package org.apache.poi.hssf.record;
 
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.GenericRecordUtil;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
@@ -36,10 +42,14 @@ import org.apache.poi.util.StringUtil;
 public final class WriteAccessRecord extends StandardRecord {
     public static final short sid = 0x005C;
 
+    private static final BitField UTF16FLAG = BitFieldFactory.getInstance(1);
+
     private static final byte PAD_CHAR = (byte) ' ';
     private static final int DATA_SIZE = 112;
+    private static final int STRING_SIZE = DATA_SIZE - 3;
+
     /** this record is always padded to a constant length */
-    private static final byte[] PADDING = new byte[DATA_SIZE];
+    private static final byte[] PADDING = new byte[STRING_SIZE];
     static {
         Arrays.fill(PADDING, PAD_CHAR);
     }
@@ -58,42 +68,57 @@ public final class WriteAccessRecord ext
 
     public WriteAccessRecord(RecordInputStream in) {
         if (in.remaining() > DATA_SIZE) {
-            throw new RecordFormatException("Expected data size (" + DATA_SIZE 
+ ") but got ("
-                    + in.remaining() + ")");
+            throw new RecordFormatException("Expected data size (" + DATA_SIZE 
+ ") but got (" + in.remaining() + ")");
         }
-        // The string is always 112 characters (padded with spaces), therefore
+
+        // The string is always 109 characters (padded with spaces), therefore
         // this record can not be continued.
 
         int nChars = in.readUShort();
         int is16BitFlag = in.readUByte();
-        if (nChars > DATA_SIZE || (is16BitFlag & 0xFE) != 0) {
-            // String header looks wrong (probably missing)
-            // OOO doc says this is optional anyway.
-            // reconstruct data
-            byte[] data = new byte[3 + in.remaining()];
-            LittleEndian.putUShort(data, 0, nChars);
-            LittleEndian.putByte(data, 2, is16BitFlag);
-            in.readFully(data, 3, data.length-3);
-            String rawValue = new String(data, StringUtil.UTF8);
-            setUsername(rawValue.trim());
-            return;
-        }
-
-        String rawText;
-        if ((is16BitFlag & 0x01) == 0x00) {
-            rawText = StringUtil.readCompressedUnicode(in, nChars);
+        final byte[] data;
+        final Charset charset;
+        final int byteCnt;
+        if (nChars > STRING_SIZE || (is16BitFlag & 0xFE) != 0) {
+            // something is wrong - reconstruct data
+            if (in.isEncrypted()) {
+                // WPS Office seems to generate files with this record 
unencrypted (#66115)
+                // Libre Office/Excel can read those, but Excel will convert 
those back to encrypted
+                data = IOUtils.safelyAllocate(in.remaining(), STRING_SIZE);
+                in.readPlain(data, 0, data.length);
+                int i = data.length;
+                // PAD_CHAR is filled for every byte even for UTF16 strings
+                while (i>0 && data[i-1] == PAD_CHAR) {
+                    i--;
+                }
+                byteCnt = i;
+                // poor mans utf16 detection ...
+                charset = (data.length > 1 && data[1] == 0) ? 
StandardCharsets.UTF_16LE : StandardCharsets.ISO_8859_1;
+            } else {
+                // String header looks wrong (probably missing)
+                // OOO doc says this is optional anyway.
+                byteCnt = 3 + in.remaining();
+                data = IOUtils.safelyAllocate(byteCnt, DATA_SIZE);
+                LittleEndian.putUShort(data, 0, nChars);
+                LittleEndian.putByte(data, 2, is16BitFlag);
+                in.readFully(data, 3, byteCnt-3);
+                charset = StandardCharsets.UTF_8;
+            }
         } else {
-            rawText = StringUtil.readUnicodeLE(in, nChars);
+            // the normal case ...
+            data = IOUtils.safelyAllocate(in.remaining(), STRING_SIZE);
+            in.readFully(data);
+            if (UTF16FLAG.isSet(is16BitFlag)) {
+                byteCnt = Math.min(nChars * 2, data.length);
+                charset = StandardCharsets.UTF_16LE;
+            } else {
+                byteCnt = Math.min(nChars, data.length);
+                charset = StandardCharsets.ISO_8859_1;
+            }
         }
-        field_1_username = rawText.trim();
 
-        // consume padding
-        int padSize = in.remaining();
-        while (padSize > 0) {
-            // in some cases this seems to be garbage (non spaces)
-            in.readUByte();
-            padSize--;
-        }
+        String rawValue = new String(data, 0, byteCnt, charset);
+        setUsername(rawValue.trim());
     }
 
     /**
@@ -104,9 +129,8 @@ public final class WriteAccessRecord ext
      */
     public void setUsername(String username) {
         boolean is16bit = StringUtil.hasMultibyte(username);
-        int encodedByteCount = 3 + username.length() * (is16bit ? 2 : 1);
-        int paddingSize = DATA_SIZE - encodedByteCount;
-        if (paddingSize < 0) {
+        int encodedByteCount = username.length() * (is16bit ? 2 : 1);
+        if (encodedByteCount > STRING_SIZE) {
             throw new IllegalArgumentException("Name is too long: " + 
username);
         }
 
@@ -131,14 +155,14 @@ public final class WriteAccessRecord ext
 
         out.writeShort(username.length());
         out.writeByte(is16bit ? 0x01 : 0x00);
+
+        byte[] buf = PADDING.clone();
         if (is16bit) {
-            StringUtil.putUnicodeLE(username, out);
+            StringUtil.putUnicodeLE(username, buf, 0);
         } else {
-            StringUtil.putCompressedUnicode(username, out);
+            StringUtil.putCompressedUnicode(username, buf, 0);
         }
-        int encodedByteCount = 3 + username.length() * (is16bit ? 2 : 1);
-        int paddingSize = DATA_SIZE - encodedByteCount;
-        out.write(PADDING, 0, paddingSize);
+        out.write(buf);
     }
 
     @Override

Modified: 
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- 
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
 (original)
+++ 
poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
 Thu Jun 16 22:56:47 2022
@@ -26,6 +26,7 @@ import org.apache.poi.poifs.crypt.Chunke
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.crypt.EncryptionInfo;
 import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInput;
@@ -208,4 +209,8 @@ public final class Biff8DecryptingStream
         ccis.readPlain(b, off, len);
     }
 
+    @Internal
+    public boolean isCurrentRecordEncrypted() {
+        return !shouldSkipEncryptionOnCurrentRecord;
+    }
 }

Modified: 
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- 
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java 
(original)
+++ 
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java 
Thu Jun 16 22:56:47 2022
@@ -53,6 +53,7 @@ class TestBiffDrawingToXml extends BaseT
         // HSSFWorkbook cannot open it as well
         excludes.put("43493.xls", 
RecordInputStream.LeftoverDataException.class);
         excludes.put("44958_1.xls", 
RecordInputStream.LeftoverDataException.class);
+        excludes.put("protected_66115.xls", EncryptedDocumentException.class);
         return excludes;
     }
 

Modified: 
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffViewer.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffViewer.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffViewer.java 
(original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestBiffViewer.java Thu 
Jun 16 22:56:47 2022
@@ -20,6 +20,7 @@ import java.io.File;
 import java.io.IOException;
 import java.util.Map;
 
+import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.util.RecordFormatException;
 
 class TestBiffViewer extends BaseTestIteratingXLS {
@@ -41,6 +42,7 @@ class TestBiffViewer extends BaseTestIte
 
         excludes.put("61300.xls", IndexOutOfBoundsException.class);
         excludes.put("poi-fuzz.xls", RecordFormatException.class);
+        excludes.put("protected_66115.xls", RecordFormatException.class);
 
         return excludes;
     }

Modified: 
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestEFBiffViewer.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestEFBiffViewer.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestEFBiffViewer.java 
(original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestEFBiffViewer.java 
Thu Jun 16 22:56:47 2022
@@ -26,6 +26,7 @@ import org.apache.poi.hssf.eventusermode
 import org.apache.poi.hssf.eventusermodel.HSSFRequest;
 import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.RecordFormatException;
 import org.junit.jupiter.api.Assertions;
 
 class TestEFBiffViewer extends BaseTestIteratingXLS {
@@ -37,6 +38,7 @@ class TestEFBiffViewer extends BaseTestI
         excludes.put("51832.xls", EncryptedDocumentException.class);
         excludes.put("xor-encryption-abc.xls", 
EncryptedDocumentException.class);
         excludes.put("password.xls", EncryptedDocumentException.class);
+        excludes.put("protected_66115.xls", EncryptedDocumentException.class);
         // HSSFWorkbook cannot open it as well
         excludes.put("43493.xls", 
RecordInputStream.LeftoverDataException.class);
         excludes.put("44958_1.xls", 
RecordInputStream.LeftoverDataException.class);

Modified: 
poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestFormulaViewer.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestFormulaViewer.java?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestFormulaViewer.java 
(original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/hssf/dev/TestFormulaViewer.java 
Thu Jun 16 22:56:47 2022
@@ -44,6 +44,7 @@ class TestFormulaViewer extends BaseTest
         excludes.put("password.xls", EncryptedDocumentException.class);
         excludes.put("43493.xls", 
RecordInputStream.LeftoverDataException.class);  // HSSFWorkbook cannot open it 
as well
         excludes.put("44958_1.xls", 
RecordInputStream.LeftoverDataException.class);
+        excludes.put("protected_66115.xls", EncryptedDocumentException.class);
         return excludes;
     }
 

Modified: poi/trunk/test-data/spreadsheet/stress.xls
URL: 
http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/stress.xls?rev=1901996&r1=1901995&r2=1901996&view=diff
==============================================================================
Binary files - no diff available.



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to