| /* ==================================================================== |
| 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.poi.poifs.filesystem; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.util.Arrays; |
| |
| import junit.framework.TestCase; |
| |
| import org.apache.poi.POIDataSamples; |
| import org.apache.poi.poifs.property.DirectoryProperty; |
| import org.apache.poi.poifs.storage.RawDataBlock; |
| |
| /** |
| * Class to test DocumentInputStream functionality |
| */ |
| public final class TestDocumentInputStream extends TestCase { |
| private DocumentNode _workbook_n; |
| private DocumentNode _workbook_o; |
| private byte[] _workbook_data; |
| private static final int _workbook_size = 5000; |
| |
| // non-even division of _workbook_size, also non-even division of |
| // any block size |
| private static final int _buffer_size = 6; |
| |
| @Override |
| protected void setUp() throws Exception { |
| int blocks = (_workbook_size + 511) / 512; |
| |
| _workbook_data = new byte[ 512 * blocks ]; |
| Arrays.fill(_workbook_data, ( byte ) -1); |
| for (int j = 0; j < _workbook_size; j++) |
| { |
| _workbook_data[ j ] = ( byte ) (j * j); |
| } |
| |
| // Create the Old POIFS Version |
| RawDataBlock[] rawBlocks = new RawDataBlock[ blocks ]; |
| ByteArrayInputStream stream = |
| new ByteArrayInputStream(_workbook_data); |
| |
| for (int j = 0; j < blocks; j++) |
| { |
| rawBlocks[ j ] = new RawDataBlock(stream); |
| } |
| OPOIFSDocument document = new OPOIFSDocument("Workbook", rawBlocks, |
| _workbook_size); |
| |
| _workbook_o = new DocumentNode( |
| document.getDocumentProperty(), |
| new DirectoryNode( |
| new DirectoryProperty("Root Entry"), (POIFSFileSystem)null, null)); |
| |
| // Now create the NPOIFS Version |
| byte[] _workbook_data_only = new byte[_workbook_size]; |
| System.arraycopy(_workbook_data, 0, _workbook_data_only, 0, _workbook_size); |
| |
| NPOIFSFileSystem npoifs = new NPOIFSFileSystem(); |
| // Make it easy when debugging to see what isn't the doc |
| byte[] minus1 = new byte[512]; |
| Arrays.fill(minus1, (byte)-1); |
| npoifs.getBlockAt(-1).put(minus1); |
| npoifs.getBlockAt(0).put(minus1); |
| npoifs.getBlockAt(1).put(minus1); |
| |
| // Create the NPOIFS document |
| _workbook_n = (DocumentNode)npoifs.createDocument( |
| new ByteArrayInputStream(_workbook_data_only), |
| "Workbook" |
| ); |
| } |
| |
| /** |
| * test constructor |
| */ |
| public void testConstructor() throws IOException { |
| DocumentInputStream ostream = new ODocumentInputStream(_workbook_o); |
| DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); |
| |
| assertEquals(_workbook_size, _workbook_o.getSize()); |
| assertEquals(_workbook_size, _workbook_n.getSize()); |
| |
| assertEquals(_workbook_size, ostream.available()); |
| assertEquals(_workbook_size, nstream.available()); |
| |
| ostream.close(); |
| nstream.close(); |
| } |
| |
| /** |
| * test available() behavior |
| */ |
| public void testAvailable() throws IOException { |
| DocumentInputStream ostream = new DocumentInputStream(_workbook_o); |
| DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); |
| |
| assertEquals(_workbook_size, ostream.available()); |
| assertEquals(_workbook_size, nstream.available()); |
| ostream.close(); |
| nstream.close(); |
| |
| try { |
| ostream.available(); |
| fail("Should have caught IOException"); |
| } catch (IllegalStateException ignored) { |
| // as expected |
| } |
| try { |
| nstream.available(); |
| fail("Should have caught IOException"); |
| } catch (IllegalStateException ignored) { |
| // as expected |
| } |
| } |
| |
| /** |
| * test mark/reset/markSupported. |
| */ |
| public void testMarkFunctions() throws IOException { |
| byte[] buffer = new byte[ _workbook_size / 5 ]; |
| byte[] small_buffer = new byte[212]; |
| |
| DocumentInputStream[] streams = new DocumentInputStream[] { |
| new DocumentInputStream(_workbook_o), |
| new NDocumentInputStream(_workbook_n) |
| }; |
| for(DocumentInputStream stream : streams) { |
| // Read a fifth of it, and check all's correct |
| stream.read(buffer); |
| for (int j = 0; j < buffer.length; j++) { |
| assertEquals( |
| "checking byte " + j, |
| _workbook_data[ j ], buffer[ j ] |
| ); |
| } |
| assertEquals(_workbook_size - buffer.length, stream.available()); |
| |
| // Reset, and check the available goes back to being the |
| // whole of the stream |
| stream.reset(); |
| assertEquals(_workbook_size, stream.available()); |
| |
| |
| // Read part of a block |
| stream.read(small_buffer); |
| for (int j = 0; j < small_buffer.length; j++) { |
| assertEquals( |
| "checking byte " + j, |
| _workbook_data[ j ], small_buffer[ j ] |
| ); |
| } |
| assertEquals(_workbook_size - small_buffer.length, stream.available()); |
| stream.mark(0); |
| |
| // Read the next part |
| stream.read(small_buffer); |
| for (int j = 0; j < small_buffer.length; j++) { |
| assertEquals( |
| "checking byte " + j, |
| _workbook_data[ j+small_buffer.length ], small_buffer[ j ] |
| ); |
| } |
| assertEquals(_workbook_size - 2*small_buffer.length, stream.available()); |
| |
| // Reset, check it goes back to where it was |
| stream.reset(); |
| assertEquals(_workbook_size - small_buffer.length, stream.available()); |
| |
| // Read |
| stream.read(small_buffer); |
| for (int j = 0; j < small_buffer.length; j++) { |
| assertEquals( |
| "checking byte " + j, |
| _workbook_data[ j+small_buffer.length ], small_buffer[ j ] |
| ); |
| } |
| assertEquals(_workbook_size - 2*small_buffer.length, stream.available()); |
| |
| |
| // Now read at various points |
| Arrays.fill(small_buffer, ( byte ) 0); |
| stream.read(small_buffer, 6, 8); |
| stream.read(small_buffer, 100, 10); |
| stream.read(small_buffer, 150, 12); |
| int pos = small_buffer.length * 2; |
| for (int j = 0; j < small_buffer.length; j++) { |
| byte exp = 0; |
| if(j>= 6 && j<6+8) { |
| exp = _workbook_data[pos]; |
| pos++; |
| } |
| if(j>= 100 && j<100+10) { |
| exp = _workbook_data[pos]; |
| pos++; |
| } |
| if(j>= 150 && j<150+12) { |
| exp = _workbook_data[pos]; |
| pos++; |
| } |
| |
| assertEquals("checking byte " + j, exp, small_buffer[j]); |
| } |
| } |
| |
| // Now repeat it with spanning multiple blocks |
| streams = new DocumentInputStream[] { |
| new DocumentInputStream(_workbook_o), |
| new NDocumentInputStream(_workbook_n) |
| }; |
| for(DocumentInputStream stream : streams) { |
| // Read several blocks work |
| buffer = new byte[ _workbook_size / 5 ]; |
| stream.read(buffer); |
| for (int j = 0; j < buffer.length; j++) { |
| assertEquals( |
| "checking byte " + j, |
| _workbook_data[ j ], buffer[ j ] |
| ); |
| } |
| assertEquals(_workbook_size - buffer.length, stream.available()); |
| |
| // Read all of it again, check it began at the start again |
| stream.reset(); |
| assertEquals(_workbook_size, stream.available()); |
| |
| stream.read(buffer); |
| for (int j = 0; j < buffer.length; j++) { |
| assertEquals( |
| "checking byte " + j, |
| _workbook_data[ j ], buffer[ j ] |
| ); |
| } |
| |
| // Mark our position, and read another whole buffer |
| stream.mark(12); |
| stream.read(buffer); |
| assertEquals(_workbook_size - (2 * buffer.length), |
| stream.available()); |
| for (int j = buffer.length; j < (2 * buffer.length); j++) |
| { |
| assertEquals("checking byte " + j, _workbook_data[ j ], |
| buffer[ j - buffer.length ]); |
| } |
| |
| // Reset, should go back to only one buffer full read |
| stream.reset(); |
| assertEquals(_workbook_size - buffer.length, stream.available()); |
| |
| // Read the buffer again |
| stream.read(buffer); |
| assertEquals(_workbook_size - (2 * buffer.length), |
| stream.available()); |
| for (int j = buffer.length; j < (2 * buffer.length); j++) |
| { |
| assertEquals("checking byte " + j, _workbook_data[ j ], |
| buffer[ j - buffer.length ]); |
| } |
| assertTrue(stream.markSupported()); |
| } |
| } |
| |
| /** |
| * test simple read method |
| */ |
| public void testReadSingleByte() throws IOException { |
| DocumentInputStream[] streams = new DocumentInputStream[] { |
| new DocumentInputStream(_workbook_o), |
| new NDocumentInputStream(_workbook_n) |
| }; |
| for(DocumentInputStream stream : streams) { |
| int remaining = _workbook_size; |
| |
| // Try and read each byte in turn |
| for (int j = 0; j < _workbook_size; j++) { |
| int b = stream.read(); |
| assertTrue("checking sign of " + j, b >= 0); |
| assertEquals("validating byte " + j, _workbook_data[ j ], |
| ( byte ) b); |
| remaining--; |
| assertEquals("checking remaining after reading byte " + j, |
| remaining, stream.available()); |
| } |
| |
| // Ensure we fell off the end |
| assertEquals(-1, stream.read()); |
| |
| // Check that after close we can no longer read |
| stream.close(); |
| try { |
| stream.read(); |
| fail("Should have caught IOException"); |
| } catch (IOException ignored) { |
| // as expected |
| } |
| } |
| } |
| |
| /** |
| * Test buffered read |
| */ |
| public void testBufferRead() throws IOException { |
| DocumentInputStream[] streams = new DocumentInputStream[] { |
| new DocumentInputStream(_workbook_o), |
| new NDocumentInputStream(_workbook_n) |
| }; |
| for(DocumentInputStream stream : streams) { |
| // Need to give a byte array to read |
| try { |
| stream.read(null); |
| fail("Should have caught NullPointerException"); |
| } catch (NullPointerException ignored) { |
| // as expected |
| } |
| |
| // test reading zero length buffer |
| assertEquals(0, stream.read(new byte[ 0 ])); |
| assertEquals(_workbook_size, stream.available()); |
| byte[] buffer = new byte[ _buffer_size ]; |
| int offset = 0; |
| |
| while (stream.available() >= buffer.length) |
| { |
| assertEquals(_buffer_size, stream.read(buffer)); |
| for (byte data : buffer) { |
| assertEquals("in main loop, byte " + offset, |
| _workbook_data[ offset ], data); |
| offset++; |
| } |
| assertEquals("offset " + offset, _workbook_size - offset, |
| stream.available()); |
| } |
| assertEquals(_workbook_size % _buffer_size, stream.available()); |
| Arrays.fill(buffer, ( byte ) 0); |
| int count = stream.read(buffer); |
| |
| assertEquals(_workbook_size % _buffer_size, count); |
| for (int j = 0; j < count; j++) |
| { |
| assertEquals("past main loop, byte " + offset, |
| _workbook_data[ offset ], buffer[ j ]); |
| offset++; |
| } |
| assertEquals(_workbook_size, offset); |
| for (int j = count; j < buffer.length; j++) |
| { |
| assertEquals("checking remainder, byte " + j, 0, buffer[ j ]); |
| } |
| assertEquals(-1, stream.read(buffer)); |
| stream.close(); |
| try { |
| stream.read(buffer); |
| fail("Should have caught IOException"); |
| } catch (IOException ignored) { |
| // as expected |
| } |
| } |
| } |
| |
| /** |
| * Test complex buffered read |
| */ |
| public void testComplexBufferRead() throws IOException { |
| DocumentInputStream[] streams = new DocumentInputStream[] { |
| new DocumentInputStream(_workbook_o), |
| new NDocumentInputStream(_workbook_n) |
| }; |
| for(DocumentInputStream stream : streams) { |
| try { |
| stream.read(null, 0, 1); |
| fail("Should have caught NullPointerException"); |
| } catch (IllegalArgumentException ignored) { |
| // as expected |
| } |
| |
| // test illegal offsets and lengths |
| try { |
| stream.read(new byte[ 5 ], -4, 0); |
| fail("Should have caught IndexOutOfBoundsException"); |
| } catch (IndexOutOfBoundsException ignored) { |
| // as expected |
| } |
| try { |
| stream.read(new byte[ 5 ], 0, -4); |
| fail("Should have caught IndexOutOfBoundsException"); |
| } catch (IndexOutOfBoundsException ignored) { |
| // as expected |
| } |
| try { |
| stream.read(new byte[ 5 ], 0, 6); |
| fail("Should have caught IndexOutOfBoundsException"); |
| } catch (IndexOutOfBoundsException ignored) { |
| // as expected |
| } |
| |
| // test reading zero |
| assertEquals(0, stream.read(new byte[ 5 ], 0, 0)); |
| assertEquals(_workbook_size, stream.available()); |
| byte[] buffer = new byte[ _workbook_size ]; |
| int offset = 0; |
| |
| while (stream.available() >= _buffer_size) |
| { |
| Arrays.fill(buffer, ( byte ) 0); |
| assertEquals(_buffer_size, |
| stream.read(buffer, offset, _buffer_size)); |
| for (int j = 0; j < offset; j++) |
| { |
| assertEquals("checking byte " + j, 0, buffer[ j ]); |
| } |
| for (int j = offset; j < (offset + _buffer_size); j++) |
| { |
| assertEquals("checking byte " + j, _workbook_data[ j ], |
| buffer[ j ]); |
| } |
| for (int j = offset + _buffer_size; j < buffer.length; j++) |
| { |
| assertEquals("checking byte " + j, 0, buffer[ j ]); |
| } |
| offset += _buffer_size; |
| assertEquals("offset " + offset, _workbook_size - offset, |
| stream.available()); |
| } |
| assertEquals(_workbook_size % _buffer_size, stream.available()); |
| Arrays.fill(buffer, ( byte ) 0); |
| int count = stream.read(buffer, offset, |
| _workbook_size % _buffer_size); |
| |
| assertEquals(_workbook_size % _buffer_size, count); |
| for (int j = 0; j < offset; j++) |
| { |
| assertEquals("checking byte " + j, 0, buffer[ j ]); |
| } |
| for (int j = offset; j < buffer.length; j++) |
| { |
| assertEquals("checking byte " + j, _workbook_data[ j ], |
| buffer[ j ]); |
| } |
| assertEquals(_workbook_size, offset + count); |
| for (int j = count; j < offset; j++) |
| { |
| assertEquals("byte " + j, 0, buffer[ j ]); |
| } |
| |
| assertEquals(-1, stream.read(buffer, 0, 1)); |
| stream.close(); |
| try { |
| stream.read(buffer, 0, 1); |
| fail("Should have caught IOException"); |
| } catch (IOException ignored) { |
| // as expected |
| } |
| } |
| } |
| |
| /** |
| * Tests that we can skip within the stream |
| */ |
| public void testSkip() throws IOException { |
| DocumentInputStream[] streams = new DocumentInputStream[] { |
| new DocumentInputStream(_workbook_o), |
| new NDocumentInputStream(_workbook_n) |
| }; |
| for(DocumentInputStream stream : streams) { |
| assertEquals(_workbook_size, stream.available()); |
| int count = stream.available(); |
| |
| while (stream.available() >= _buffer_size) { |
| assertEquals(_buffer_size, stream.skip(_buffer_size)); |
| count -= _buffer_size; |
| assertEquals(count, stream.available()); |
| } |
| assertEquals(_workbook_size % _buffer_size, |
| stream.skip(_buffer_size)); |
| assertEquals(0, stream.available()); |
| stream.reset(); |
| assertEquals(_workbook_size, stream.available()); |
| assertEquals(_workbook_size, stream.skip(_workbook_size * 2)); |
| assertEquals(0, stream.available()); |
| stream.reset(); |
| assertEquals(_workbook_size, stream.available()); |
| assertEquals(_workbook_size, |
| stream.skip(2 + ( long ) Integer.MAX_VALUE)); |
| assertEquals(0, stream.available()); |
| } |
| } |
| |
| /** |
| * Test that we can read files at multiple levels down the tree |
| */ |
| public void testReadMultipleTreeLevels() throws Exception { |
| final POIDataSamples _samples = POIDataSamples.getPublisherInstance(); |
| File sample = _samples.getFile("Sample.pub"); |
| |
| DocumentInputStream stream; |
| |
| NPOIFSFileSystem npoifs = new NPOIFSFileSystem(sample); |
| try { |
| OPOIFSFileSystem opoifs = new OPOIFSFileSystem(new FileInputStream(sample)); |
| |
| // Ensure we have what we expect on the root |
| assertEquals(npoifs, npoifs.getRoot().getNFileSystem()); |
| assertEquals(npoifs, npoifs.getRoot().getFileSystem()); |
| assertEquals(null, npoifs.getRoot().getOFileSystem()); |
| assertEquals(null, opoifs.getRoot().getFileSystem()); |
| assertEquals(opoifs, opoifs.getRoot().getOFileSystem()); |
| assertEquals(null, opoifs.getRoot().getNFileSystem()); |
| |
| // Check inside |
| for(DirectoryNode root : new DirectoryNode[] { opoifs.getRoot(), npoifs.getRoot() }) { |
| // Top Level |
| Entry top = root.getEntry("Contents"); |
| assertEquals(true, top.isDocumentEntry()); |
| stream = root.createDocumentInputStream(top); |
| stream.read(); |
| |
| // One Level Down |
| DirectoryNode escher = (DirectoryNode)root.getEntry("Escher"); |
| Entry one = escher.getEntry("EscherStm"); |
| assertEquals(true, one.isDocumentEntry()); |
| stream = escher.createDocumentInputStream(one); |
| stream.read(); |
| |
| // Two Levels Down |
| DirectoryNode quill = (DirectoryNode)root.getEntry("Quill"); |
| DirectoryNode quillSub = (DirectoryNode)quill.getEntry("QuillSub"); |
| Entry two = quillSub.getEntry("CONTENTS"); |
| assertEquals(true, two.isDocumentEntry()); |
| stream = quillSub.createDocumentInputStream(two); |
| stream.read(); |
| } |
| } finally { |
| npoifs.close(); |
| } |
| } |
| } |