You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2024/06/02 06:36:59 UTC
svn commit: r1918110 - in /pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter: FlateFilter.java FlateFilterDecoderStream.java
Author: lehmi
Date: Sun Jun 2 06:36:59 2024
New Revision: 1918110
URL: http://svn.apache.org/viewvc?rev=1918110&view=rev
Log:
PDFBOX-5675: switch to stream based decoding for streams using a flate filter
Added:
pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilterDecoderStream.java (with props)
Modified:
pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java
Modified: pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java?rev=1918110&r1=1918109&r2=1918110&view=diff
==============================================================================
--- pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java (original)
+++ pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilter.java Sun Jun 2 06:36:59 2024
@@ -19,12 +19,9 @@ package org.apache.pdfbox.filter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.io.IOUtils;
@@ -37,89 +34,21 @@ import org.apache.pdfbox.io.IOUtils;
*/
final class FlateFilter extends Filter
{
- private static final Log LOG = LogFactory.getLog(FlateFilter.class);
-
@Override
public DecodeResult decode(InputStream encoded, OutputStream decoded,
COSDictionary parameters, int index) throws IOException
{
final COSDictionary decodeParams = getDecodeParams(parameters, index);
- try
- {
- decompress(encoded, Predictor.wrapPredictor(decoded, decodeParams));
- }
- catch (DataFormatException e)
+ try (FlateFilterDecoderStream decoderStream = new FlateFilterDecoderStream(encoded))
{
- // if the stream is corrupt a DataFormatException may occur
- LOG.error("FlateFilter: stop reading corrupt stream due to a DataFormatException");
-
- // re-throw the exception
- throw new IOException(e);
+ OutputStream wrapPredictor = Predictor.wrapPredictor(decoded, decodeParams);
+ IOUtils.copy(decoderStream, wrapPredictor);
+ wrapPredictor.flush();
}
return new DecodeResult(parameters);
}
- // Use Inflater instead of InflateInputStream to avoid an EOFException due to a probably
- // missing Z_STREAM_END, see PDFBOX-1232 for details
- private void decompress(InputStream in, OutputStream out) throws IOException, DataFormatException
- {
- byte[] buf = new byte[2048];
- // skip zlib header
- in.read();
- in.read();
- int read = in.read(buf);
- if (read > 0)
- {
- // use nowrap mode to bypass zlib-header and checksum to avoid a DataFormatException
- Inflater inflater = new Inflater(true);
- inflater.setInput(buf,0,read);
- byte[] res = new byte[1024];
- boolean dataWritten = false;
- try
- {
- while (true)
- {
- int resRead = 0;
- try
- {
- resRead = inflater.inflate(res);
- }
- catch(DataFormatException exception)
- {
- if (dataWritten)
- {
- // some data could be read -> don't throw an exception
- LOG.warn("FlateFilter: premature end of stream due to a DataFormatException");
- break;
- }
- else
- {
- // nothing could be read -> re-throw exception
- throw exception;
- }
- }
- if (resRead != 0)
- {
- out.write(res,0,resRead);
- dataWritten = true;
- continue;
- }
- if (inflater.finished() || inflater.needsDictionary() || in.available() == 0)
- {
- break;
- }
- read = in.read(buf);
- inflater.setInput(buf,0,read);
- }
- }
- finally
- {
- inflater.end();
- }
- }
- out.flush();
- }
@Override
protected void encode(InputStream input, OutputStream encoded, COSDictionary parameters)
Added: pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilterDecoderStream.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilterDecoderStream.java?rev=1918110&view=auto
==============================================================================
--- pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilterDecoderStream.java (added)
+++ pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilterDecoderStream.java Sun Jun 2 06:36:59 2024
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.filter;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Stream based decoder for the flate filter which uses zlib/deflate compression.
+ *
+ * Use Inflater instead of InflateInputStream to avoid an EOFException due to a probably missing Z_STREAM_END, see
+ * PDFBOX-1232 for details.
+ *
+ */
+public final class FlateFilterDecoderStream extends FilterInputStream
+{
+ private static final Log LOG = LogFactory.getLog(FlateFilterDecoderStream.class);
+
+ private boolean isEOF = false;
+ private int currentDataIndex = 0;
+ private int bytesRead = 0;
+ private int bytesDecoded = 0;
+
+ private byte[] buffer = new byte[2048];
+ private byte[] decodedData = new byte[4096];
+ // use nowrap mode to bypass zlib-header and checksum to avoid a DataFormatException
+ private final Inflater inflater = new Inflater(true);
+ private boolean dataDecoded = false;
+
+ /**
+ * Constructor.
+ *
+ * @param inputStream The input stream to actually read from.
+ */
+ public FlateFilterDecoderStream(InputStream inputStream) throws IOException
+ {
+ super(inputStream);
+ // skip zlib header
+ in.read();
+ in.read();
+ }
+
+ private boolean fetch() throws IOException
+ {
+ currentDataIndex = 0;
+ if (isEOF || inflater.finished())
+ {
+ isEOF = true;
+ bytesDecoded = 0;
+ bytesRead = 0;
+ return false;
+ }
+ if (inflater.needsInput())
+ {
+ bytesRead = in.read(buffer);
+ if (bytesRead > -1)
+ {
+ inflater.setInput(buffer, 0, bytesRead);
+ }
+ else
+ {
+ isEOF = true;
+ return false;
+ }
+ }
+ try
+ {
+ bytesDecoded = inflater.inflate(decodedData);
+ dataDecoded |= bytesDecoded > 0;
+ }
+ catch (DataFormatException exception)
+ {
+ isEOF = true;
+ if (dataDecoded)
+ {
+ // some data could be decoded -> don't throw an exception
+ LOG.warn("FlateFilter: premature end of stream due to a DataFormatException");
+ return false;
+ }
+ else
+ {
+ // nothing could be read -> re-throw exception wrapped in an IOException
+ throw new IOException(exception);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This will read the next byte from the stream.
+ *
+ * @return The next byte read from the stream.
+ *
+ * @throws IOException If there is an error reading from the wrapped stream.
+ */
+ @Override
+ public int read() throws IOException
+ {
+ if (isEOF)
+ {
+ return -1;
+ }
+ if (currentDataIndex == bytesDecoded)
+ {
+ if (!fetch())
+ {
+ return -1;
+ }
+ }
+ return decodedData[currentDataIndex++] & 0xFF;
+ }
+
+ /**
+ * This will read a chunk of data.
+ *
+ * @param data The buffer to write data to.
+ * @param offset The offset into the data stream.
+ * @param length The number of byte to attempt to read.
+ *
+ * @return The number of bytes actually read.
+ *
+ * @throws IOException If there is an error reading data from the underlying stream.
+ */
+ @Override
+ public int read(byte[] data, int offset, int length) throws IOException
+ {
+ if (isEOF)
+ {
+ return -1;
+ }
+ int numberOfBytesRead = 0;
+ while (numberOfBytesRead < length)
+ {
+ int available = bytesDecoded - currentDataIndex;
+ if (available > 0)
+ {
+ int bytes2Copy = Math.min(length - numberOfBytesRead, available);
+ System.arraycopy(decodedData, currentDataIndex, data, numberOfBytesRead + offset,
+ bytes2Copy);
+ currentDataIndex += bytes2Copy;
+ numberOfBytesRead += bytes2Copy;
+ }
+ else if (!fetch())
+ {
+ break;
+ }
+ }
+ return numberOfBytesRead;
+ }
+
+ /**
+ * This will close the underlying stream and release any resources.
+ *
+ * @throws IOException If there is an error closing the underlying stream.
+ */
+ @Override
+ public void close() throws IOException
+ {
+ inflater.end();
+ super.close();
+ }
+
+ /**
+ * mark/reset isn't supported.
+ *
+ * @return always false.
+ */
+ @Override
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @param n ignored.
+ *
+ * @return always zero.
+ */
+ @Override
+ public long skip(long n)
+ {
+ return 0;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @return always zero.
+ */
+ @Override
+ public int available()
+ {
+ return 0;
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @param readlimit ignored.
+ */
+ @Override
+ public synchronized void mark(int readlimit)
+ {
+ }
+
+ /**
+ * Unsupported.
+ *
+ * @throws IOException always throw as reset is an unsupported feature.
+ */
+ @Override
+ public synchronized void reset() throws IOException
+ {
+ throw new IOException("reset is not supported");
+ }
+}
Propchange: pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/filter/FlateFilterDecoderStream.java
------------------------------------------------------------------------------
svn:eol-style = native