From cf76af521d94dbfa3baaa77a1ce64629b5acdf6d Mon Sep 17 00:00:00 2001
From: Tim Allison <tallison@apache.org>
Date: Wed, 10 Apr 2019 19:11:02 +0000
Subject: [PATCH] Bug 63330 -- use skipfully instead of hoping skip() works

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1857277 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/poi/poifs/filesystem/DocumentInputStream.java | 5 +++++
 src/java/org/apache/poi/poifs/macros/VBAMacroReader.java | 5 +----
 src/java/org/apache/poi/util/BoundedInputStream.java     | 4 ++--
 .../org/apache/poi/util/LittleEndianInputStream.java     | 6 +++++-
 .../org/apache/poi/util/RLEDecompressingInputStream.java | 3 ++-
 .../openxml4j/util/ZipArchiveThresholdInputStream.java   | 3 ++-
 .../java/org/apache/poi/xssf/binary/XSSFBParser.java     | 2 +-
 .../src/org/apache/poi/hemf/record/emf/HemfFont.java     | 9 +++++----
 src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java     | 3 ++-
 src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java    | 3 ++-
 src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java     | 6 ++++--
 11 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java b/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
index e808d357ce..e0ad436e2a 100644
--- a/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
+++ b/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
@@ -36,6 +36,11 @@ import org.apache.poi.util.LittleEndianInput;
  * {@link POIFSFileSystem} instance.
  */
 public final class DocumentInputStream extends InputStream implements LittleEndianInput {
+
+    private static int SKIP_BUFFER_SIZE = 2048;
+
+    private static byte[] SKIP_BYTE_BUFFER = new byte[SKIP_BUFFER_SIZE];
+
     /** returned by read operations if we're at end of document */
     private static final int EOF = -1;
 
diff --git a/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java b/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
index cbb4ccba54..783ab9fdfa 100644
--- a/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
+++ b/src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
@@ -260,10 +260,7 @@ public class VBAMacroReader implements Closeable {
             InputStream compressed = new DocumentInputStream(documentNode);
             try {
                 // we know the offset already, so decompress immediately on-the-fly
-                long skippedBytes = compressed.skip(module.offset);
-                if (skippedBytes != module.offset) {
-                    throw new IOException("tried to skip " + module.offset + " bytes, but actually skipped " + skippedBytes + " bytes");
-                }
+                trySkip(compressed, module.offset);
                 decompressed = new RLEDecompressingInputStream(compressed);
                 module.read(decompressed);
                 return;
diff --git a/src/java/org/apache/poi/util/BoundedInputStream.java b/src/java/org/apache/poi/util/BoundedInputStream.java
index 8b5a7a8dd5..df63cbc11b 100644
--- a/src/java/org/apache/poi/util/BoundedInputStream.java
+++ b/src/java/org/apache/poi/util/BoundedInputStream.java
@@ -131,13 +131,13 @@ public class BoundedInputStream extends InputStream {
     /**
      * Invokes the delegate's <code>skip(long)</code> method.
      * @param n the number of bytes to skip
-     * @return the actual number of bytes skipped
+     * @return the actual number of bytes skipped; might be fewer than requested
      * @throws IOException if an I/O error occurs
      */
     @Override
     public long skip(long n) throws IOException {
         long toSkip = max>=0 ? Math.min(n, max-pos) : n;
-        long skippedBytes = in.skip(toSkip);
+        long skippedBytes = IOUtils.skipFully(in, toSkip);
         pos+=skippedBytes;
         return skippedBytes;
     }
diff --git a/src/java/org/apache/poi/util/LittleEndianInputStream.java b/src/java/org/apache/poi/util/LittleEndianInputStream.java
index 9a9652eb32..af61d375f2 100644
--- a/src/java/org/apache/poi/util/LittleEndianInputStream.java
+++ b/src/java/org/apache/poi/util/LittleEndianInputStream.java
@@ -204,6 +204,10 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
 
 
 	public void skipFully(int len) throws IOException {
-		IOUtils.skipFully(this, len);
+		long skipped = IOUtils.skipFully(this, len);
+		if (skipped > Integer.MAX_VALUE) {
+			throw new IOException("can't skip further than "+Integer.MAX_VALUE);
+		}
+		checkEOF((int)skipped, len);
 	}
 }
diff --git a/src/java/org/apache/poi/util/RLEDecompressingInputStream.java b/src/java/org/apache/poi/util/RLEDecompressingInputStream.java
index 7cc68483c2..c84966ff22 100644
--- a/src/java/org/apache/poi/util/RLEDecompressingInputStream.java
+++ b/src/java/org/apache/poi/util/RLEDecompressingInputStream.java
@@ -123,6 +123,7 @@ public class RLEDecompressingInputStream extends InputStream {
 
     @Override
     public long skip(long n) throws IOException {
+        //this relies on readChunk's readFully to skipFully
         long length = n;
         while (length > 0) {
             if (pos >= len) {
@@ -165,7 +166,7 @@ public class RLEDecompressingInputStream extends InputStream {
         }
         boolean rawChunk = (w & 0x8000) == 0;
         if (rawChunk) {
-            if (in.read(buf, 0, chunkSize) < chunkSize) {
+            if (IOUtils.readFully(in, buf, 0, chunkSize) < chunkSize) {
                 throw new IllegalStateException(String.format(Locale.ROOT, "Not enough bytes read, expected %d", chunkSize));
             }
             return chunkSize;
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java b/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
index af76ffcd9e..5bcfd8f1c0 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
@@ -31,6 +31,7 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 import org.apache.commons.compress.utils.InputStreamStatistics;
 import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 
 @Internal
@@ -85,7 +86,7 @@ public class ZipArchiveThresholdInputStream extends FilterInputStream {
 
     @Override
     public long skip(long n) throws IOException {
-        long cnt = super.skip(n);
+        long cnt = IOUtils.skipFully(super.in, n);
         if (cnt > 0) {
             checkThreshold();
         }
diff --git a/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBParser.java b/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBParser.java
index ac24ecd909..f2b0b7be67 100644
--- a/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBParser.java
+++ b/src/ooxml/java/org/apache/poi/xssf/binary/XSSFBParser.java
@@ -96,7 +96,7 @@ public abstract class XSSFBParser {
             is.readFully(buff);
             handleRecord(recordId, buff);
         } else {
-            long length = is.skip(recordLength);
+            long length = IOUtils.skipFully(is, recordLength);
             if (length != recordLength) {
                 throw new XSSFBParseException("End of file reached before expected.\t"+
                 "Tried to skip "+recordLength + ", but only skipped "+length);
diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java
index 256a7618e5..dd42fe63be 100644
--- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java
+++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java
@@ -19,12 +19,10 @@ package org.apache.poi.hemf.record.emf;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
 
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.common.usermodel.fonts.FontCharset;
 import org.apache.poi.hwmf.record.HwmfFont;
-import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -418,7 +416,10 @@ public class HemfFont extends HwmfFont {
             logPan.xHeight = LogFontPanose.XHeight.values()[leis.readUByte()];
 
             // skip 2 byte to ensure 32-bit alignment of this structure.
-            leis.skip(2);
+            long skipped = IOUtils.skipFully(leis,2);
+            if (skipped != 2) {
+                throw new IOException("Didn't skip 2: "+skipped);
+            }
 
             size += 6*LittleEndianConsts.INT_SIZE+10* LittleEndianConsts.BYTE_SIZE+2;
         } else {
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java b/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java
index 59ace3b599..ba90372f85 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java
@@ -26,6 +26,7 @@ import java.util.zip.InflaterInputStream;
 
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.sl.image.ImageHeaderEMF;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Units;
 
 /**
@@ -42,7 +43,7 @@ public final class EMF extends Metafile {
             InputStream is = new ByteArrayInputStream( rawdata );
             Header header = new Header();
             header.read(rawdata, CHECKSUM_SIZE);
-            long len = is.skip(header.getSize() + (long)CHECKSUM_SIZE);
+            long len = IOUtils.skipFully(is,header.getSize() + (long)CHECKSUM_SIZE);
             assert(len == header.getSize() + CHECKSUM_SIZE);
 
             InflaterInputStream inflater = new InflaterInputStream( is );
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
index df55f4c687..59670e1298 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
@@ -26,6 +26,7 @@ import java.util.zip.InflaterInputStream;
 
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.sl.image.ImageHeaderPICT;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
@@ -58,7 +59,7 @@ public final class PICT extends Metafile {
         Header header = new Header();
         header.read(data, pos);
         long bs_exp = (long)pos + header.getSize();
-        long bs_act = bis.skip(bs_exp);
+        long bs_act = IOUtils.skipFully(bis, bs_exp);
         if (bs_exp != bs_act) {
             throw new EOFException();
         }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java b/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
index 8f02df41de..632c6f68c1 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
@@ -26,6 +26,7 @@ import java.util.zip.InflaterInputStream;
 
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.sl.image.ImageHeaderWMF;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Units;
 
 /**
@@ -42,8 +43,9 @@ public final class WMF extends Metafile {
             InputStream is = new ByteArrayInputStream( rawdata );
             Header header = new Header();
             header.read(rawdata, CHECKSUM_SIZE*getUIDInstanceCount());
-            long len = is.skip(header.getSize() + (long)CHECKSUM_SIZE*getUIDInstanceCount());
-            assert(len == header.getSize() + CHECKSUM_SIZE*getUIDInstanceCount());
+            long skipLen = header.getSize() + CHECKSUM_SIZE*getUIDInstanceCount();
+            long skipped = IOUtils.skipFully(is, skipLen);
+            assert(skipped == skipLen);
 
             ImageHeaderWMF aldus = new ImageHeaderWMF(header.getBounds());
             aldus.write(out);