/*
 * 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.cos;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.pdfbox.filter.DecodeOptions;
import org.apache.pdfbox.filter.DecodeResult;
import org.apache.pdfbox.filter.Filter;

/**
 * An InputStream which reads from an encoded COS stream.
 *
 * @author John Hewson
 */
public final class COSInputStream extends FilterInputStream
{
    /**
     * Creates a new COSInputStream from an encoded input stream.
     *
     * @param filters Filters to be applied.
     * @param parameters Filter parameters.
     * @param in Encoded input stream.
     * @return Decoded stream.
     * @throws IOException If the stream could not be read.
     */
    static COSInputStream create(List<Filter> filters, COSDictionary parameters, InputStream in)
            throws IOException
    {
        return create(filters, parameters, in, DecodeOptions.DEFAULT);
    }

    /**
     * Creates a new COSInputStream from an encoded input stream.
     *
     * @param filters Filters to be applied.
     * @param parameters Filter parameters.
     * @param in Encoded input stream.
     * @param options decode options for the encoded stream
     * @return Decoded stream.
     * @throws IOException If the stream could not be read.
     */
    static COSInputStream create(List<Filter> filters, COSDictionary parameters, InputStream in,
            DecodeOptions options) throws IOException
    {
        List<DecodeResult> results = new ArrayList<>();
        InputStream input = in;
        if (!filters.isEmpty())
        {
            Set<Filter> filterSet = new HashSet<>(filters);
            if (filterSet.size() != filters.size())
            {
                throw new IOException("Duplicate");
            }
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            // apply filters
            for (int i = 0; i < filters.size(); i++)
            {
                output.reset();
                results.add(filters.get(i).decode(input, output, parameters, i, options));
                input = new ByteArrayInputStream(output.toByteArray());
            }
        }
        return new COSInputStream(input, results);
    }

    private final List<DecodeResult> decodeResults;

    /**
     * Constructor.
     * 
     * @param input decoded stream
     * @param decodeResults results of decoding
     */
    private COSInputStream(InputStream input, List<DecodeResult> decodeResults)
    {
        super(input);
        this.decodeResults = decodeResults;
    }
    
    /**
     * Returns the result of the last filter, for use by repair mechanisms.
     */
    public DecodeResult getDecodeResult()
    {
        if (decodeResults.isEmpty())
        {
            return DecodeResult.createDefault();
        }
        else
        {
            return decodeResults.get(decodeResults.size() - 1);
        }
    }
}

@@ -1018,24 +1018,54 @@
 .ArrayList;%0A
+import java.util.Collections;%0A
 import java.
@@ -2449,32 +2449,166 @@
 Exception%0A    %7B%0A
+        if (filters.isEmpty())%0A        %7B%0A            return new COSInputStream(in, Collections.%3CDecodeResult%3EemptyList());%0A        %7D%0A%0A
         List%3CDec
@@ -2644,16 +2644,30 @@
 yList%3C%3E(
+filters.size()
 );%0A     
@@ -2697,54 +2697,8 @@
 in;%0A
-        if (!filters.isEmpty())%0A        %7B%0A    
     
@@ -2753,28 +2753,24 @@
 s);%0A        
-   
- 
 if (filterSe
@@ -2801,33 +2801,26 @@
 ())%0A        
-    %7B%0A   
+%7B%0A
             
@@ -2815,25 +2815,24 @@
             
- 
 throw new IO
@@ -2867,25 +2867,18 @@
     
-    %7D%0A   
+%7D%0A
         
  Byt
@@ -2873,17 +2873,16 @@
         
- 
 ByteArra
@@ -2941,20 +2941,16 @@
         
-    
 // apply
@@ -2966,20 +2966,16 @@
         
-   
- 
 for (int
@@ -3011,33 +3011,26 @@
 ++)%0A        
-    %7B%0A   
+%7B%0A
             
@@ -3029,17 +3029,16 @@
         
- 
 output.r
@@ -3041,28 +3041,24 @@
 ut.reset();%0A
-    
             
@@ -3144,20 +3144,16 @@
         
-   
- 
 input = 
@@ -3204,22 +3204,8 @@
 ));%0A
-            %7D%0A
     

optimize memory usage, as suggested by valerybokov