]> source.dussan.org Git - poi.git/commitdiff
Finish NPOIFS support for writing to mini streams where the big block stream needs...
authorNick Burch <nick@apache.org>
Thu, 12 May 2011 21:00:04 +0000 (21:00 +0000)
committerNick Burch <nick@apache.org>
Thu, 12 May 2011 21:00:04 +0000 (21:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1102458 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java
src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSMiniStore.java
src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java

index cc0b65671f754de10b710df76d817cb9ca8d7785..db3adb4e1b50e0680b3fc70ec946eba7c546874c 100644 (file)
@@ -34,6 +34,7 @@
 
     <changes>
         <release version="3.8-beta3" date="2011-??-??">
+           <action dev="poi-developers" type="add">NPOIFS Mini Streams now support extending the underlying big block stream to fit more data</action>
            <action dev="poi-developers" type="fix">51148 - XWPFDocument now properly tracks paragraphs and tables when adding/removing them</action>
            <action dev="poi-developers" type="fix">51153 - Correct sizing of LbsDataSubRecord with unused padding fields</action>
            <action dev="poi-developers" type="fix">51143 - NameCommentRecord correction for writing non ASCII strings</action>
index 6d43c3f714958e7e0aedb43602d6c8c5fddf92e5..33d0b25418540ad9cc747db8ff6688a27538edf6 100644 (file)
@@ -69,6 +69,9 @@ public class NPOIFSMiniStore extends BlockStore
           it.next();
        }
        ByteBuffer dataBlock = it.next();
+       if(dataBlock == null) {
+          throw new IndexOutOfBoundsException("Big block " + bigBlockNumber + " outside stream");
+       }
 
        // Position ourselves, and take a slice 
        dataBlock.position(
@@ -83,9 +86,35 @@ public class NPOIFSMiniStore extends BlockStore
      * Load the block, extending the underlying stream if needed
      */
     protected ByteBuffer createBlockIfNeeded(final int offset) throws IOException {
-       // TODO Extend the stream if needed
-       // TODO Needs append support on the underlying stream
-       return getBlockAt(offset);
+       // Try to get it without extending the stream
+       try {
+          return getBlockAt(offset);
+       } catch(IndexOutOfBoundsException e) {
+          // Need to extend the stream
+          // TODO Replace this with proper append support
+          // For now, do the extending by hand...
+          
+          // Ask for another block
+          int newBigBlock = _filesystem.getFreeBlock();
+          _filesystem.createBlockIfNeeded(newBigBlock);
+          
+          // Tack it onto the end of our chain
+          ChainLoopDetector loopDetector = _filesystem.getChainLoopDetector();
+          int block = _mini_stream.getStartBlock();
+          while(true) {
+             loopDetector.claim(block);
+             int next = _filesystem.getNextBlock(block);
+             if(next == POIFSConstants.END_OF_CHAIN) {
+                break;
+             }
+             block = next;
+          }
+          _filesystem.setNextBlock(block, newBigBlock);
+          _filesystem.setNextBlock(newBigBlock, POIFSConstants.END_OF_CHAIN);
+
+          // Now try again to get it
+          return createBlockIfNeeded(offset);
+       }
     }
     
     /**
index 8f495903b7cb4daaea63bd17311114cdc9ecb0cd..90daf160aa4c0d198ec3d2145d940a41645955d3 100644 (file)
@@ -18,6 +18,7 @@
 package org.apache.poi.poifs.filesystem;
 
 import java.nio.ByteBuffer;
+import java.util.Iterator;
 
 import junit.framework.TestCase;
 
@@ -245,7 +246,80 @@ public final class TestNPOIFSMiniStore extends TestCase {
     *  big blocks that make up the ministream as needed
     */
    public void testCreateBlockIfNeeded() throws Exception {
-      // TODO Add underlying implementation
-      // TODO Add unit test
+      NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
+      NPOIFSMiniStore ministore = fs.getMiniStore();
+      
+      // 178 -> 179 -> 180, 181+ is free
+      assertEquals(179                        , ministore.getNextBlock(178));
+      assertEquals(180                        , ministore.getNextBlock(179));
+      assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180));
+      for(int i=181; i<256; i++) {
+         assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i));
+      }
+      
+      // However, the ministore data only covers blocks to 183
+      for(int i=0; i<=183; i++) {
+         ministore.getBlockAt(i);
+      }
+      try {
+         ministore.getBlockAt(184);
+         fail("No block at 184");
+      } catch(IndexOutOfBoundsException e) {}
+      
+      // The ministore itself is made up of 23 big blocks
+      Iterator<ByteBuffer> it = new NPOIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator();
+      int count = 0;
+      while(it.hasNext()) {
+         count++;
+         it.next();
+      }
+      assertEquals(23, count);
+      
+      // Ask it to get block 184 with creating, it will do
+      ministore.createBlockIfNeeded(184);
+      
+      // The ministore should be one big block bigger now
+      it = new NPOIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator();
+      count = 0;
+      while(it.hasNext()) {
+         count++;
+         it.next();
+      }
+      assertEquals(24, count);
+      
+      // The mini block block counts now run to 191
+      for(int i=0; i<=191; i++) {
+         ministore.getBlockAt(i);
+      }
+      try {
+         ministore.getBlockAt(192);
+         fail("No block at 192");
+      } catch(IndexOutOfBoundsException e) {}
+      
+      
+      // Now try writing through to 192, check that the SBAT and blocks are there
+      byte[] data = new byte[15*64];
+      NPOIFSStream stream = new NPOIFSStream(ministore, 178);
+      stream.updateContents(data);
+      
+      // Check now
+      assertEquals(179                        , ministore.getNextBlock(178));
+      assertEquals(180                        , ministore.getNextBlock(179));
+      assertEquals(181                        , ministore.getNextBlock(180));
+      assertEquals(182                        , ministore.getNextBlock(181));
+      assertEquals(183                        , ministore.getNextBlock(182));
+      assertEquals(184                        , ministore.getNextBlock(183));
+      assertEquals(185                        , ministore.getNextBlock(184));
+      assertEquals(186                        , ministore.getNextBlock(185));
+      assertEquals(187                        , ministore.getNextBlock(186));
+      assertEquals(188                        , ministore.getNextBlock(187));
+      assertEquals(189                        , ministore.getNextBlock(188));
+      assertEquals(190                        , ministore.getNextBlock(189));
+      assertEquals(191                        , ministore.getNextBlock(190));
+      assertEquals(192                        , ministore.getNextBlock(191));
+      assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(192));
+      for(int i=193; i<256; i++) {
+         assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i));
+      }
    }
 }
index ca9dd6677b7b0bdfb6202dca34cc3050a2cded03..256037100c2324e3205f061ba4d74f1737cb7110 100644 (file)
@@ -731,8 +731,61 @@ public final class TestNPOIFSStream extends TestCase {
       assertEquals((byte)0x04, b182.get(1));
 
       
-      // Write lots, so it needs another big block 
-      // TODO
+      // Write lots, so it needs another big block
+      ministore.getBlockAt(183);
+      try {
+         ministore.getBlockAt(184);
+         fail("Block 184 should be off the end of the list");
+      } catch(IndexOutOfBoundsException e) {}
+      
+      data = new byte[64*6 + 12];
+      for(int i=0; i<data.length; i++) {
+         data[i] = (byte)(i+1);
+      }
+      stream = new NPOIFSStream(ministore, 178);
+      stream.updateContents(data);
+      
+      // Should have added 2 more blocks to the chain
+      assertEquals(179, ministore.getNextBlock(178));
+      assertEquals(180, ministore.getNextBlock(179));
+      assertEquals(181, ministore.getNextBlock(180));
+      assertEquals(182, ministore.getNextBlock(181));
+      assertEquals(183, ministore.getNextBlock(182));
+      assertEquals(184, ministore.getNextBlock(183));
+      assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(184));
+      assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(185));
+      
+      // Block 184 should exist
+      ministore.getBlockAt(183);
+      ministore.getBlockAt(184);
+      ministore.getBlockAt(185);
+      
+      // Check contents
+      stream = new NPOIFSStream(ministore, 178);
+      it = stream.getBlockIterator();
+      b178 = it.next();
+      b179 = it.next();
+      b180 = it.next();
+      b181 = it.next();
+      b182 = it.next();
+      ByteBuffer b183 = it.next();
+      ByteBuffer b184 = it.next();
+      assertEquals(false, it.hasNext());
+      
+      assertEquals((byte)0x01, b178.get(0));
+      assertEquals((byte)0x02, b178.get(1));
+      assertEquals((byte)0x41, b179.get(0));
+      assertEquals((byte)0x42, b179.get(1));
+      assertEquals((byte)0x81, b180.get(0));
+      assertEquals((byte)0x82, b180.get(1));
+      assertEquals((byte)0xc1, b181.get(0));
+      assertEquals((byte)0xc2, b181.get(1));
+      assertEquals((byte)0x01, b182.get(0));
+      assertEquals((byte)0x02, b182.get(1));
+      assertEquals((byte)0x41, b183.get(0));
+      assertEquals((byte)0x42, b183.get(1));
+      assertEquals((byte)0x81, b184.get(0));
+      assertEquals((byte)0x82, b184.get(1));
    }
 
    /**