From c204206f19a277ac9c02e8217da5c555178c28e4 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Thu, 23 Dec 2010 09:21:49 +0000 Subject: [PATCH] Start on PropertyTable support for NPOIFS, and more NPOIFS tests git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1052205 13f79535-47bb-0310-9956-ffa450edef68 --- .../poifs/filesystem/NPOIFSFileSystem.java | 22 +-- .../poi/poifs/property/NPropertyTable.java | 128 +++++++++++++++ .../filesystem/TestNPOIFSFileSystem.java | 154 +++++++++++------- 3 files changed, 233 insertions(+), 71 deletions(-) create mode 100644 src/java/org/apache/poi/poifs/property/NPropertyTable.java diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java index d4fb341037..11f2ff5978 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java @@ -43,6 +43,7 @@ import org.apache.poi.poifs.nio.ByteArrayBackedDataSource; import org.apache.poi.poifs.nio.DataSource; import org.apache.poi.poifs.nio.FileBackedDataSource; import org.apache.poi.poifs.property.DirectoryProperty; +import org.apache.poi.poifs.property.NPropertyTable; import org.apache.poi.poifs.property.Property; import org.apache.poi.poifs.property.PropertyTable; import org.apache.poi.poifs.storage.BATBlock; @@ -82,8 +83,8 @@ public class NPOIFSFileSystem return new CloseIgnoringInputStream(is); } - private PropertyTable _property_table; - private List _bat_blocks; + private NPropertyTable _property_table; + private List _bat_blocks; private HeaderBlock _header; private DirectoryNode _root; @@ -104,7 +105,7 @@ public class NPOIFSFileSystem public NPOIFSFileSystem() { _header = new HeaderBlock(bigBlockSize); - _property_table = new PropertyTable(_header);// TODO Needs correct type + _property_table = new NPropertyTable(_header); _bat_blocks = new ArrayList(); _root = null; } @@ -191,8 +192,9 @@ public class NPOIFSFileSystem int maxSize = BATBlock.calculateMaximumSize(_header); ByteBuffer data = ByteBuffer.allocate(maxSize); // Copy in the header + headerBuffer.position(0); data.put(headerBuffer); - data.position(_header.getBigBlockSize().getBigBlockSize()); + data.position(headerBuffer.capacity()); // Now read the rest of the stream IOUtils.readFully(channel, data); success = true; @@ -292,7 +294,7 @@ public class NPOIFSFileSystem // We're now able to load steams // Use this to read in the properties - // TODO + _property_table = new NPropertyTable(_header, this); } /** @@ -479,10 +481,6 @@ public class NPOIFSFileSystem public void writeFilesystem(final OutputStream stream) throws IOException { - - // get the property table ready - _property_table.preWrite(); - // create the small block store, and the SBAT SmallBlockTableWriter sbtw = new SmallBlockTableWriter(bigBlockSize, _documents, _property_table.getRoot()); @@ -550,7 +548,6 @@ public class NPOIFSFileSystem writers.add(header_block_writer); writers.addAll(_documents); - writers.add(_property_table); writers.add(sbtw); writers.add(sbtw.getSBAT()); writers.add(bat); @@ -567,6 +564,11 @@ public class NPOIFSFileSystem writer.writeBlocks(stream); } + + // Finally have the property table serialise itself + _property_table.write( + new NPOIFSStream(this, _header.getPropertyStart()) + ); } /** diff --git a/src/java/org/apache/poi/poifs/property/NPropertyTable.java b/src/java/org/apache/poi/poifs/property/NPropertyTable.java new file mode 100644 index 0000000000..36ded35789 --- /dev/null +++ b/src/java/org/apache/poi/poifs/property/NPropertyTable.java @@ -0,0 +1,128 @@ +/* ==================================================================== + 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.property; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.poifs.common.POIFSBigBlockSize; +import org.apache.poi.poifs.common.POIFSConstants; +import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; +import org.apache.poi.poifs.filesystem.NPOIFSStream; +import org.apache.poi.poifs.storage.HeaderBlock; + +/** + * This class embodies the Property Table for a {@link NPOIFSFileSystem}; + * this is basically the directory for all of the documents in the + * filesystem. + */ +public final class NPropertyTable extends PropertyTableBase { + private POIFSBigBlockSize _bigBigBlockSize; + + public NPropertyTable(HeaderBlock headerBlock) + { + super(headerBlock); + _bigBigBlockSize = headerBlock.getBigBlockSize(); + } + + /** + * reading constructor (used when we've read in a file and we want + * to extract the property table from it). Populates the + * properties thoroughly + * + * @param headerBlock the header block of the file + * @param filesystem the filesystem to read from + * + * @exception IOException if anything goes wrong (which should be + * a result of the input being NFG) + */ + public NPropertyTable(final HeaderBlock headerBlock, + final NPOIFSFileSystem filesystem) + throws IOException + { + super( + headerBlock, + buildProperties( + (new NPOIFSStream(filesystem, headerBlock.getPropertyStart())).iterator(), + headerBlock.getBigBlockSize() + ) + ); + _bigBigBlockSize = headerBlock.getBigBlockSize(); + } + + /** + * Builds + * @param startAt + * @param filesystem + * @return + * @throws IOException + */ + private static List buildProperties(final Iterator dataSource, + final POIFSBigBlockSize bigBlockSize) throws IOException + { + List properties = new ArrayList(); + while(dataSource.hasNext()) { + ByteBuffer bb = dataSource.next(); + + // Turn it into an array + byte[] data; + if(bb.hasArray() && bb.arrayOffset() == 0 && + bb.array().length == bigBlockSize.getBigBlockSize()) { + data = bb.array(); + } else { + data = new byte[bigBlockSize.getBigBlockSize()]; + bb.get(data, 0, data.length); + } + + PropertyFactory.convertToProperties(data, properties); + } + return properties; + } + + /** + * Return the number of BigBlock's this instance uses + * + * @return count of BigBlock instances + */ + public int countBlocks() + { + int size = _properties.size() * POIFSConstants.PROPERTY_SIZE; + return (int)Math.ceil(size / _bigBigBlockSize.getBigBlockSize()); + } + + /** + * Writes the properties out into the given low-level stream + */ + public void write(NPOIFSStream stream) throws IOException { + // TODO - Use a streaming write + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for(Property property : _properties) { + property.writeData(baos); + } + stream.updateContents(baos.toByteArray()); + + // Update the start position if needed + if(getStartBlock() != stream.getStartBlock()) { + setStartBlock(stream.getStartBlock()); + } + } +} diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java index 828315e3db..afd2419951 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java @@ -55,8 +55,19 @@ public final class TestNPOIFSFileSystem extends TestCase { fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) { - // Check the FAT was properly processed - // TODO + // Check the FAT was properly processed: + // Verify we only got one block + fs.getBATBlockAndIndex(0); + fs.getBATBlockAndIndex(1); + try { + fs.getBATBlockAndIndex(140); + fail("Should only be one BAT, but a 2nd was found"); + } catch(IndexOutOfBoundsException e) {} + + // Verify a few next offsets + // 97 -> 98 -> END + assertEquals(98, fs.getNextBlock(97)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); // Check the properties // TODO @@ -67,7 +78,19 @@ public final class TestNPOIFSFileSystem extends TestCase { fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) { // Check the FAT was properly processed - // TODO + // Verify we only got one block + fs.getBATBlockAndIndex(0); + fs.getBATBlockAndIndex(1); + try { + fs.getBATBlockAndIndex(1040); + fail("Should only be one BAT, but a 2nd was found"); + } catch(IndexOutOfBoundsException e) {} + + // Verify a few next offsets + // 0 -> 1 -> 2 -> END + assertEquals(1, fs.getNextBlock(0)); + assertEquals(2, fs.getNextBlock(1)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // Check the properties // TODO @@ -79,72 +102,81 @@ public final class TestNPOIFSFileSystem extends TestCase { * out what the next one is */ public void testNextBlock() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); - - // 0 -> 21 are simple - for(int i=0; i<21; i++) { - assertEquals(i+1, fs.getNextBlock(i)); - } - // 21 jumps to 89, then ends - assertEquals(89, fs.getNextBlock(21)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89)); - - // 22 -> 88 simple sequential stream - for(int i=22; i<88; i++) { - assertEquals(i+1, fs.getNextBlock(i)); - } - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88)); - - // 90 -> 96 is another stream - for(int i=90; i<96; i++) { - assertEquals(i+1, fs.getNextBlock(i)); + NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) { + // 0 -> 21 are simple + for(int i=0; i<21; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + // 21 jumps to 89, then ends + assertEquals(89, fs.getNextBlock(21)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89)); + + // 22 -> 88 simple sequential stream + for(int i=22; i<88; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88)); + + // 90 -> 96 is another stream + for(int i=90; i<96; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(96)); + + // 97+98 is another + assertEquals(98, fs.getNextBlock(97)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); + + // 99 is our FAT block + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); + + // 100 onwards is free + for(int i=100; i