]> source.dussan.org Git - poi.git/commitdiff
Tweak comments, layout and exceptions in IOUtils and RawDataBlock. It should now...
authorNick Burch <nick@apache.org>
Wed, 9 Jan 2008 16:31:25 +0000 (16:31 +0000)
committerNick Burch <nick@apache.org>
Wed, 9 Jan 2008 16:31:25 +0000 (16:31 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@610439 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/poifs/storage/RawDataBlock.java
src/java/org/apache/poi/util/IOUtils.java
src/testcases/org/apache/poi/poifs/storage/TestRawDataBlock.java

index 4403966343c6cd84545a058fa415698630ed4e5c..d554298400e76e398cf5c070200490fc95bb48a9 100644 (file)
@@ -42,34 +42,44 @@ public class RawDataBlock
      * @param stream the InputStream from which the data will be read
      *
      * @exception IOException on I/O errors, and if an insufficient
-     *            amount of data is read
+     *            amount of data is read (the InputStream must
+     *            be an exact multiple of the block size)
      */
-
     public RawDataBlock(final InputStream stream)
-        throws IOException
-    {
-        _data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
+               throws IOException {
+       this(stream, POIFSConstants.BIG_BLOCK_SIZE);
+    }
+    /**
+     * Constructor RawDataBlock
+     *
+     * @param stream the InputStream from which the data will be read
+     * @param blockSize the size of the POIFS blocks, normally 512 bytes {@link POIFSConstants#BIG_BLOCK_SIZE}
+     *
+     * @exception IOException on I/O errors, and if an insufficient
+     *            amount of data is read (the InputStream must
+     *            be an exact multiple of the block size)
+     */
+    public RawDataBlock(final InputStream stream, int blockSize)
+               throws IOException {
+        _data = new byte[ blockSize ];
         int count = IOUtils.readFully(stream, _data);
 
-        if (count == -1)
-        {
+        if (count == -1) {
             _eof = true;
         }
-        else if (count != POIFSConstants.BIG_BLOCK_SIZE)
-        {
-               if (count == -1)
-                       //Cant have -1 bytes read in the error message!
-                       count = 0;
-               
+        else if (count != blockSize) {
+               // IOUtils.readFully will always read the
+               //  requested number of bytes, unless it hits
+               //  an EOF
+            _eof = true;
             String type = " byte" + ((count == 1) ? ("")
                                                   : ("s"));
 
             throw new IOException("Unable to read entire block; " + count
-                                  + type + " read; expected "
-                                  + POIFSConstants.BIG_BLOCK_SIZE + " bytes");
+                                  + type + " read before EOF; expected "
+                                  + blockSize + " bytes");
         }
-        else
-        {
+        else {
             _eof = false;
         }
     }
@@ -82,7 +92,6 @@ public class RawDataBlock
      *
      * @exception IOException
      */
-
     public boolean eof()
         throws IOException
     {
@@ -98,7 +107,6 @@ public class RawDataBlock
      *
      * @exception IOException if there is no data
      */
-
     public byte [] getData()
         throws IOException
     {
index 42b69c850b8de1c67511737ed1e429c687bd347a..c3aa8695e25c45f3f2a83e9da6a34f7740a2cd1c 100644 (file)
@@ -58,11 +58,16 @@ public class IOUtils
     }
 
     /**
-     * Same as the normal <tt>in.read(b, off, len)</tt>, but tries to ensure that
-     * the entire len number of bytes is read.
+     * Same as the normal <tt>in.read(b, off, len)</tt>, but
+     *  tries to ensure that the entire len number of bytes
+     *  is read.
      * <p>
-     * If the end of file is reached before any bytes are read, returns -1.
-     * Otherwise, returns the number of bytes read.
+     * If the end of file is reached before any bytes
+     *  are read, returns -1.
+     * If the end of the file is reached after some bytes are
+     *  read, returns the number of bytes read.
+     * If the end of the file isn't reached before len
+     *  bytes have been read, will return len bytes.
      */
     public static int readFully(InputStream in, byte[] b, int off, int len)
     throws IOException
@@ -79,5 +84,4 @@ public class IOUtils
             }
         }
     }
-}
-
+}
\ No newline at end of file
index 4756629e7aa4db2acff57cfc0a53f8ce5173d2ca..1473fa82ea1cafad887598259a1a5dc261251abf 100644 (file)
@@ -20,6 +20,7 @@
 package org.apache.poi.poifs.storage;
 
 import java.io.*;
+import java.util.Random;
 
 import junit.framework.*;
 
@@ -124,6 +125,118 @@ public class TestRawDataBlock
             }
         }
     }
+    
+    /**
+     * Tests that when using a slow input stream, which
+     *  won't return a full block at a time, we don't
+     *  incorrectly think that there's not enough data
+     */
+    public void testSlowInputStream() throws Exception {
+        for (int k = 1; k < 512; k++) {
+            byte[] data = new byte[ 512 ];
+            for (int j = 0; j < data.length; j++) {
+                data[j] = (byte) j;
+            }
+            
+            // Shouldn't complain, as there is enough data,
+            //  even if it dribbles through
+            RawDataBlock block = 
+               new RawDataBlock(new SlowInputStream(data, k));
+            assertFalse(block.eof());
+        }
+        
+        // But if there wasn't enough data available, will
+        //  complain
+        for (int k = 1; k < 512; k++) {
+            byte[] data = new byte[ 511 ];
+            for (int j = 0; j < data.length; j++) {
+                data[j] = (byte) j;
+            }
+            
+            // Shouldn't complain, as there is enough data
+            try {
+                   RawDataBlock block = 
+                       new RawDataBlock(new SlowInputStream(data, k));
+                   fail();
+            } catch(IOException e) {
+               // as expected
+            }
+        }
+    }
+    
+    /**
+     * An input stream which will return a maximum of
+     *  a given number of bytes to read, and often claims
+     *  not to have any data
+     */
+    public static class SlowInputStream extends InputStream {
+       private Random rnd = new Random();
+       private byte[] data;
+       private int chunkSize;
+       private int pos = 0;
+       
+       public SlowInputStream(byte[] data, int chunkSize) {
+               this.chunkSize = chunkSize;
+               this.data = data;
+       }
+       
+       /**
+        * 75% of the time, claim there's no data available
+        */
+       private boolean claimNoData() {
+               if(rnd.nextFloat() < 0.25f) {
+                       return false;
+               }
+               return true;
+       }
+       
+               public int read() throws IOException {
+                       if(pos >= data.length) {
+                               return -1;
+                       }
+                       int ret = data[pos];
+                       pos++;
+                       
+                       if(ret < 0) ret += 256;
+                       return ret;
+               }
+
+               /**
+                * Reads the requested number of bytes, or the chunk
+                *  size, whichever is lower.
+                * Quite often will simply claim to have no data
+                */
+               public int read(byte[] b, int off, int len) throws IOException {
+                       // Keep the length within the chunk size
+                       if(len > chunkSize) {
+                               len = chunkSize;
+                       }
+                       // Don't read off the end of the data
+                       if(pos + len > data.length) {
+                               len = data.length - pos;
+                               
+                               // Spot when we're out of data
+                               if(len == 0) {
+                                       return -1;
+                               }
+                       }
+                       
+                       // 75% of the time, claim there's no data
+                       if(claimNoData()) {
+                               return 0;
+                       }
+                       
+                       // Copy, and return what we read
+                       System.arraycopy(data, pos, b, off, len);
+                       pos += len;
+                       return len;
+               }
+
+               public int read(byte[] b) throws IOException {
+                       return read(b, 0, b.length);
+               }
+               
+    }
 
     /**
      * main method to run the unit tests