]> source.dussan.org Git - poi.git/commitdiff
Start on PropertyTable support for NPOIFS, and more NPOIFS tests
authorNick Burch <nick@apache.org>
Thu, 23 Dec 2010 09:21:49 +0000 (09:21 +0000)
committerNick Burch <nick@apache.org>
Thu, 23 Dec 2010 09:21:49 +0000 (09:21 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1052205 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java
src/java/org/apache/poi/poifs/property/NPropertyTable.java [new file with mode: 0644]
src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java

index d4fb3410379a852d0f5fe32e1ac9b9285f3b9670..11f2ff5978e65482010f27993abb8f2c61e835cc 100644 (file)
@@ -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<BATBlock> _bat_blocks;
+    private NPropertyTable  _property_table;
+    private List<BATBlock> _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<BATBlock>();
         _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 (file)
index 0000000..36ded35
--- /dev/null
@@ -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<Property> buildProperties(final Iterator<ByteBuffer> dataSource,
+          final POIFSBigBlockSize bigBlockSize) throws IOException
+    {
+       List<Property> properties = new ArrayList<Property>();
+       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());
+       }
+    }
+}
index 828315e3db6303bd1103c2cf1ffb3f385d89b6ec..afd2419951fb4cf174e7b9c3e6d40caf65a48425 100644 (file)
@@ -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<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
+            assertEquals(POIFSConstants.UNUSED_BLOCK, 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<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
-         assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i));
-      }
+      // TODO Check a few bits of a 4096 byte file
    }
 
    /**
     * Check we get the right data back for each block
     */
    public void testGetBlock() throws Exception {
-      NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
-      ByteBuffer b;
-      
-      // The 0th block is the first data block
-      b = fs.getBlockAt(0);
-      assertEquals((byte)0x9e, b.get());
-      assertEquals((byte)0x75, b.get());
-      assertEquals((byte)0x97, b.get());
-      assertEquals((byte)0xf6, b.get());
-      
-      // And the next block
-      b = fs.getBlockAt(1);
-      assertEquals((byte)0x86, b.get());
-      assertEquals((byte)0x09, b.get());
-      assertEquals((byte)0x22, b.get());
-      assertEquals((byte)0xfb, b.get());
-      
-      // Check the final block too
-      b = fs.getBlockAt(99);
-      assertEquals((byte)0x01, b.get());
-      assertEquals((byte)0x00, b.get());
-      assertEquals((byte)0x00, b.get());
-      assertEquals((byte)0x00, b.get());
-      assertEquals((byte)0x02, b.get());
-      assertEquals((byte)0x00, b.get());
-      assertEquals((byte)0x00, b.get());
-      assertEquals((byte)0x00, b.get());
+      NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
+      NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
+      for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
+         ByteBuffer b;
+         
+         // The 0th block is the first data block
+         b = fs.getBlockAt(0);
+         assertEquals((byte)0x9e, b.get());
+         assertEquals((byte)0x75, b.get());
+         assertEquals((byte)0x97, b.get());
+         assertEquals((byte)0xf6, b.get());
+         
+         // And the next block
+         b = fs.getBlockAt(1);
+         assertEquals((byte)0x86, b.get());
+         assertEquals((byte)0x09, b.get());
+         assertEquals((byte)0x22, b.get());
+         assertEquals((byte)0xfb, b.get());
+         
+         // Check the final block too
+         b = fs.getBlockAt(99);
+         assertEquals((byte)0x01, b.get());
+         assertEquals((byte)0x00, b.get());
+         assertEquals((byte)0x00, b.get());
+         assertEquals((byte)0x00, b.get());
+         assertEquals((byte)0x02, b.get());
+         assertEquals((byte)0x00, b.get());
+         assertEquals((byte)0x00, b.get());
+         assertEquals((byte)0x00, b.get());
+      }
+      
+      // TODO Check a few bits of a 4096 byte file
    }
    
    /**