View | Details | Raw Unified | Return to bug 44366
Collapse All | Expand All

(-)src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java (-16 / +100 lines)
Lines 19-24 Link Here
19
19
20
package org.apache.poi.poifs.filesystem;
20
package org.apache.poi.poifs.filesystem;
21
21
22
import java.io.ByteArrayInputStream;
22
import java.io.FileInputStream;
23
import java.io.FileInputStream;
23
import java.io.FileOutputStream;
24
import java.io.FileOutputStream;
24
import java.io.IOException;
25
import java.io.IOException;
Lines 30-35 Link Here
30
import java.util.Iterator;
31
import java.util.Iterator;
31
import java.util.List;
32
import java.util.List;
32
33
34
import org.apache.commons.logging.Log;
35
import org.apache.commons.logging.LogFactory;
33
import org.apache.poi.poifs.dev.POIFSViewable;
36
import org.apache.poi.poifs.dev.POIFSViewable;
34
import org.apache.poi.poifs.property.DirectoryProperty;
37
import org.apache.poi.poifs.property.DirectoryProperty;
35
import org.apache.poi.poifs.property.Property;
38
import org.apache.poi.poifs.property.Property;
Lines 58-63 Link Here
58
public class POIFSFileSystem
61
public class POIFSFileSystem
59
    implements POIFSViewable
62
    implements POIFSViewable
60
{
63
{
64
    private static final Log _logger = LogFactory.getLog(POIFSFileSystem.class);
65
    
66
    
67
    private static final class CloseIgnoringInputStream extends InputStream {
68
69
        private final InputStream _is;
70
        public CloseIgnoringInputStream(InputStream is) {
71
            _is = is;
72
        }
73
        public int read() throws IOException {
74
            return _is.read();
75
        }
76
        public int read(byte[] b, int off, int len) throws IOException {
77
            return _is.read(b, off, len);
78
        }
79
        public void close() {
80
            // do nothing
81
        }
82
    }
83
    
84
    /**
85
     * Convenience method for clients that want to avoid the auto-close behaviour of the constructor.
86
     */
87
    public static InputStream createNonClosingInputStream(InputStream is) {
88
        return new CloseIgnoringInputStream(is);
89
    }
90
    
61
    private PropertyTable _property_table;
91
    private PropertyTable _property_table;
62
    private List          _documents;
92
    private List          _documents;
63
    private DirectoryNode _root;
93
    private DirectoryNode _root;
Lines 74-96 Link Here
74
    }
104
    }
75
105
76
    /**
106
    /**
77
     * Create a POIFSFileSystem from an InputStream
107
     * Create a POIFSFileSystem from an <tt>InputStream</tt>.  Normally the stream is read until
108
     * EOF.  The stream is always closed.<p/>
109
     * 
110
     * Some streams are usable after reaching EOF (typically those that return <code>true</code> 
111
     * for <tt>markSupported()</tt>).  In the unlikely case that the caller has such a stream 
112
     * <i>and</i> needs to use it after this constructor completes, a work around is to wrap the
113
     * stream in order to trap the <tt>close()</tt> call.  A convenience method (
114
     * <tt>createNonClosingInputStream()</tt>) has been provided for this purpose:
115
     * <pre>
116
     * InputStream wrappedStream = POIFSFileSystem.createNonClosingInputStream(is);
117
     * HSSFWorkbook wb = new HSSFWorkbook(wrappedStream);
118
     * is.reset(); 
119
     * doSomethingElse(is); 
120
     * </pre>
121
     * Note also the special case of <tt>ByteArrayInputStream</tt> for which the <tt>close()</tt>
122
     * method does nothing. 
123
     * <pre>
124
     * ByteArrayInputStream bais = ...
125
     * HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.close() !
126
     * bais.reset(); // no problem
127
     * doSomethingElse(bais);
128
     * </pre>
78
     *
129
     *
79
     * @param stream the InputStream from which to read the data
130
     * @param stream the InputStream from which to read the data
80
     *
131
     *
81
     * @exception IOException on errors reading, or on invalid data
132
     * @exception IOException on errors reading, or on invalid data
82
     */
133
     */
83
134
84
    public POIFSFileSystem(final InputStream stream)
135
    public POIFSFileSystem(InputStream stream)
85
        throws IOException
136
        throws IOException
86
    {
137
    {
87
        this();
138
        this();
139
        boolean success = false;
88
140
89
        // read the header block from the stream
141
        // read the header block from the stream
90
        HeaderBlockReader header_block_reader = new HeaderBlockReader(stream);
142
        HeaderBlockReader header_block_reader;
91
92
        // read the rest of the stream into blocks
143
        // read the rest of the stream into blocks
93
        RawDataBlockList  data_blocks         = new RawDataBlockList(stream);
144
        RawDataBlockList data_blocks;
145
        try {
146
            header_block_reader = new HeaderBlockReader(stream);
147
            data_blocks = new RawDataBlockList(stream);
148
            success = true;
149
        } finally {
150
            closeInputStream(stream, success);
151
        }
152
        
94
153
95
        // set up the block allocation table (necessary for the
154
        // set up the block allocation table (necessary for the
96
        // data_blocks to be manageable
155
        // data_blocks to be manageable
Lines 112-119 Link Here
112
                    .getSBATStart()), data_blocks, properties.getRoot()
171
                    .getSBATStart()), data_blocks, properties.getRoot()
113
                        .getChildren(), null);
172
                        .getChildren(), null);
114
    }
173
    }
115
    
116
    /**
174
    /**
175
     * @param stream the stream to be closed
176
     * @param success <code>false</code> if an exception is currently being thrown in the calling method
177
     */
178
    private void closeInputStream(InputStream stream, boolean success) {
179
        
180
        if(stream.markSupported() && !(stream instanceof ByteArrayInputStream)) {
181
            String msg = "POIFS is closing the supplied input stream of type (" 
182
                    + stream.getClass().getName() + ") which supports mark/reset.  "
183
                    + "This will be a problem for the caller if the stream will still be used.  "
184
                    + "If that is the case the caller should wrap the input stream to avoid this close logic.  "
185
                    + "This warning is only temporary and will not be present in future versions of POI.";
186
            _logger.warn(msg);
187
        }
188
        try {
189
            stream.close();
190
        } catch (IOException e) {
191
            if(success) {
192
                throw new RuntimeException(e);
193
            }
194
            // else not success? Try block did not complete normally 
195
            // just print stack trace and leave original ex to be thrown
196
            e.printStackTrace();
197
        }
198
    }
199
200
    /**
117
     * Checks that the supplied InputStream (which MUST
201
     * Checks that the supplied InputStream (which MUST
118
     *  support mark and reset, or be a PushbackInputStream) 
202
     *  support mark and reset, or be a PushbackInputStream) 
119
     *  has a POIFS (OLE2) header at the start of it.
203
     *  has a POIFS (OLE2) header at the start of it.
Lines 123-145 Link Here
123
     * @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream 
207
     * @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream 
124
     */
208
     */
125
    public static boolean hasPOIFSHeader(InputStream inp) throws IOException {
209
    public static boolean hasPOIFSHeader(InputStream inp) throws IOException {
126
    	// We want to peek at the first 8 bytes 
210
        // We want to peek at the first 8 bytes 
127
    	inp.mark(8);
211
        inp.mark(8);
128
212
129
    	byte[] header = new byte[8];
213
        byte[] header = new byte[8];
130
    	IOUtils.readFully(inp, header);
214
        IOUtils.readFully(inp, header);
131
        LongField signature = new LongField(HeaderBlockConstants._signature_offset, header);
215
        LongField signature = new LongField(HeaderBlockConstants._signature_offset, header);
132
216
133
        // Wind back those 8 bytes
217
        // Wind back those 8 bytes
134
        if(inp instanceof PushbackInputStream) {
218
        if(inp instanceof PushbackInputStream) {
135
        	PushbackInputStream pin = (PushbackInputStream)inp;
219
            PushbackInputStream pin = (PushbackInputStream)inp;
136
        	pin.unread(header);
220
            pin.unread(header);
137
        } else {
221
        } else {
138
        	inp.reset();
222
            inp.reset();
139
        }
223
        }
140
    	
224
        
141
    	// Did it match the signature?
225
        // Did it match the signature?
142
    	return (signature.get() == HeaderBlockConstants._signature);
226
        return (signature.get() == HeaderBlockConstants._signature);
143
    }
227
    }
144
228
145
    /**
229
    /**

Return to bug 44366