poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n...@apache.org
Subject svn commit: r1051795 - in /poi/trunk/src: java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java java/org/apache/poi/poifs/filesystem/NPOIFSStream.java testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
Date Wed, 22 Dec 2010 08:52:18 GMT
Author: nick
Date: Wed Dec 22 08:52:17 2010
New Revision: 1051795

URL: http://svn.apache.org/viewvc?rev=1051795&view=rev
Log:
Initial NPOIFS low level stream reader and writer. Still needs unit tests, but should allow
reading and writing to a basic stream of (big) blocks

Added:
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java
Modified:
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java
    poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java?rev=1051795&r1=1051794&r2=1051795&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java Wed Dec 22 08:52:17
2010
@@ -56,6 +56,7 @@ import org.apache.poi.poifs.storage.Head
 import org.apache.poi.poifs.storage.RawDataBlockList;
 import org.apache.poi.poifs.storage.SmallBlockTableReader;
 import org.apache.poi.poifs.storage.SmallBlockTableWriter;
+import org.apache.poi.poifs.storage.BATBlock.BATBlockAndIndex;
 import org.apache.poi.util.CloseIgnoringInputStream;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LongField;
@@ -81,10 +82,10 @@ public class NPOIFSFileSystem
        return new CloseIgnoringInputStream(is);
     }
    
-    private PropertyTable _property_table;
-	 private List<BATBlock> _blocks;
-    private HeaderBlock   _header;
-    private DirectoryNode _root;
+    private PropertyTable  _property_table;
+	 private List<BATBlock> _bat_blocks;
+    private HeaderBlock    _header;
+    private DirectoryNode  _root;
     
     private DataSource _data;
     
@@ -104,7 +105,7 @@ public class NPOIFSFileSystem
     {
         _header         = new HeaderBlock(bigBlockSize);
         _property_table = new PropertyTable(_header);// TODO Needs correct type
-        _blocks         = new ArrayList<BATBlock>();
+        _bat_blocks     = new ArrayList<BATBlock>();
         _root           = null;
     }
 
@@ -187,11 +188,7 @@ public class NPOIFSFileSystem
            // We need to buffer the whole file into memory when
            //  working with an InputStream.
            // The max possible size is when each BAT block entry is used
-           int maxSize = 
-                 _header.getBATCount() * 
-                 _header.getBigBlockSize().getBATEntriesPerBlock() *
-                 _header.getBigBlockSize().getBigBlockSize()
-           ;
+           int maxSize = BATBlock.calculateMaximumSize(_header); 
            ByteBuffer data = ByteBuffer.allocate(maxSize);
            // Copy in the header
            data.put(headerBuffer);
@@ -275,7 +272,7 @@ public class NPOIFSFileSystem
        for(int fatAt : _header.getBATArray()) {
           loopDetector.claim(fatAt);
           ByteBuffer fatData = getBlockAt(fatAt);
-          _blocks.add(BATBlock.createBATBlock(bigBlockSize, fatData));
+          _bat_blocks.add(BATBlock.createBATBlock(bigBlockSize, fatData));
        }
        
        // Now read the XFAT blocks
@@ -287,7 +284,7 @@ public class NPOIFSFileSystem
           xfat = BATBlock.createBATBlock(bigBlockSize, fatData);
           nextAt = xfat.getValueAt(bigBlockSize.getNextXBATChainOffset());
           
-          _blocks.add(xfat);
+          _bat_blocks.add(xfat);
        }
        
        // We're now able to load steams
@@ -305,10 +302,41 @@ public class NPOIFSFileSystem
        long startAt = (offset+1) * bigBlockSize.getBigBlockSize();
        return _data.read(bigBlockSize.getBigBlockSize(), startAt);
     }
+    
+    /**
+     * Returns the BATBlock that handles the specified offset,
+     *  and the relative index within it
+     */
+    protected BATBlockAndIndex getBATBlockAndIndex(final int offset) {
+       return BATBlock.getBATBlockAndIndex(
+             offset, _header, _bat_blocks
+       );
+    }
+    
     /**
      * Works out what block follows the specified one.
      */
     protected int getNextBlock(final int offset) {
+       BATBlockAndIndex bai = getBATBlockAndIndex(offset);
+       return bai.getBlock().getValueAt( bai.getIndex() );
+    }
+    
+    /**
+     * Changes the record of what block follows the specified one.
+     */
+    protected void setNextBlock(final int offset, final int nextBlock) {
+       BATBlockAndIndex bai = getBATBlockAndIndex(offset);
+       bai.getBlock().setValueAt(
+             bai.getIndex(), nextBlock
+       );
+    }
+    
+    /**
+     * Finds a free block, and returns its offset.
+     * This method will extend the file if needed, and if doing
+     *  so, allocate new FAT blocks to address the extra space.
+     */
+    protected int getFreeBlock() {
        // TODO
        return -1;
     }

Added: poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java?rev=1051795&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java (added)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java Wed Dec 22 08:52:17
2010
@@ -0,0 +1,172 @@
+
+/* ====================================================================
+   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.IOException;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.poifs.property.Property;
+import org.apache.poi.poifs.storage.HeaderBlock;
+
+/**
+ * This handles reading and writing a stream within a
+ *  {@link NPOIFSFileSystem}. It can supply an iterator
+ *  to read blocks, and way to write out to existing and
+ *  new blocks.
+ * Most users will want a higher level version of this, 
+ *  which deals with properties to track which stream
+ *  this is.
+ * This only works on big block streams, it doesn't
+ *  handle small block ones.
+ * This uses the new NIO code
+ */
+
+public class NPOIFSStream implements Iterable<ByteBuffer>
+{
+	private NPOIFSFileSystem filesystem;
+	private int startBlock;
+	
+	/**
+	 * Constructor for an existing stream. It's up to you
+	 *  to know how to get the start block (eg from a 
+	 *  {@link HeaderBlock} or a {@link Property}) 
+	 */
+	public NPOIFSStream(NPOIFSFileSystem filesystem, int startBlock) {
+	   this.filesystem = filesystem;
+	   this.startBlock = startBlock;
+	}
+	
+	/**
+	 * Constructor for a new stream. A start block won't
+	 *  be allocated until you begin writing to it.
+	 */
+	public NPOIFSStream(NPOIFSFileSystem filesystem) {
+	   this.filesystem = filesystem;
+	   this.startBlock = POIFSConstants.END_OF_CHAIN;
+	}
+	
+	/**
+	 * What block does this stream start at?
+	 * Will be {@link POIFSConstants#END_OF_CHAIN} for a
+	 *  new stream that hasn't been written to yet.
+	 */
+	public int getStartBlock() {
+	   return startBlock;
+	}
+
+	/**
+	 * Returns an iterator that'll supply one {@link ByteBuffer}
+	 *  per block in the stream.
+	 */
+   public Iterator<ByteBuffer> iterator() {
+      return getBlockIterator();
+   }
+	
+   public Iterator<ByteBuffer> getBlockIterator() {
+      if(startBlock == POIFSConstants.END_OF_CHAIN) {
+         throw new IllegalStateException(
+               "Can't read from a new stream before it has been written to"
+         );
+      }
+      return new StreamBlockByteBufferIterator(startBlock);
+   }
+   
+   /**
+    * Updates the contents of the stream to the new
+    *  set of bytes.
+    * Note - if this is property based, you'll still
+    *  need to 
+    */
+   public void updateContents(byte[] contents) throws IOException {
+      // How many blocks are we going to need?
+      int blocks = (int)Math.ceil(contents.length / filesystem.getBigBlockSize());
+      
+      // Start writing
+      int prevBlock = POIFSConstants.END_OF_CHAIN;
+      int nextBlock = startBlock;
+      for(int i=0; i<blocks; i++) {
+         int thisBlock = nextBlock;
+         
+         // Allocate a block if needed, otherwise figure
+         //  out what the next block will be
+         if(thisBlock == POIFSConstants.END_OF_CHAIN) {
+            thisBlock = filesystem.getFreeBlock();
+            nextBlock = POIFSConstants.END_OF_CHAIN;
+            
+            // Mark the previous block as carrying on
+            if(prevBlock != POIFSConstants.END_OF_CHAIN) {
+               filesystem.setNextBlock(prevBlock, thisBlock);
+            }
+         } else {
+            nextBlock = filesystem.getNextBlock(thisBlock);
+         }
+         
+         // Write it
+         ByteBuffer buffer = filesystem.getBlockAt(thisBlock);
+         buffer.put(contents, i*filesystem.getBigBlockSize(), filesystem.getBigBlockSize());
+         
+         // Update pointers
+         prevBlock = thisBlock;
+      }
+      
+      // Mark the end of the stream
+      filesystem.setNextBlock(nextBlock, POIFSConstants.END_OF_CHAIN);
+   }
+   
+   // TODO Streaming write too
+   
+   /**
+    * Class that handles a streaming read of one stream
+    */
+   protected class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> {
+      private int nextBlock;
+      protected StreamBlockByteBufferIterator(int firstBlock) {
+         nextBlock = firstBlock;
+      }
+
+      public boolean hasNext() {
+         if(nextBlock == POIFSConstants.END_OF_CHAIN) {
+            return false;
+         }
+         return true;
+      }
+
+      public ByteBuffer next() {
+         if(nextBlock == POIFSConstants.END_OF_CHAIN) {
+            throw new IndexOutOfBoundsException("Can't read past the end of the stream");
+         }
+         
+         try {
+            ByteBuffer data = filesystem.getBlockAt(nextBlock);
+            nextBlock = filesystem.getNextBlock(nextBlock);
+            return data;
+         } catch(IOException e) {
+            throw new RuntimeException(e);
+         }
+      }
+
+      public void remove() {
+         throw new UnsupportedOperationException();
+      }
+   }
+}
+

Modified: poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java?rev=1051795&r1=1051794&r2=1051795&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java Wed
Dec 22 08:52:17 2010
@@ -17,20 +17,10 @@
 
 package org.apache.poi.poifs.filesystem;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Iterator;
-
 import junit.framework.TestCase;
 
 import org.apache.poi.POIDataSamples;
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.poifs.common.POIFSBigBlockSize;
-import org.apache.poi.poifs.storage.HeaderBlock;
-import org.apache.poi.poifs.storage.RawDataBlockList;
+import org.apache.poi.poifs.common.POIFSConstants;
 
 /**
  * Tests for the new NIO POIFSFileSystem implementation
@@ -81,4 +71,51 @@ public final class TestNPOIFSFileSystem 
          // TODO
       }
    }
+   
+   /**
+    * Check that for a given block, we can correctly figure
+    *  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));
+      }
+      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));
+      }
+   }
+
+   /**
+    * Check we get the right data back for each block
+    */
+   public void testGetBlock() throws Exception {
+      // TODO
+   }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message