You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2020/06/02 15:00:32 UTC

svn commit: r1878397 - /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessReadBuffer.java

Author: lehmi
Date: Tue Jun  2 15:00:32 2020
New Revision: 1878397

URL: http://svn.apache.org/viewvc?rev=1878397&view=rev
Log:
PDFBOX-4836: replace array with ByteBuffer, increase chunk size to 4kb, limit last chunk to origin size

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessReadBuffer.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessReadBuffer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessReadBuffer.java?rev=1878397&r1=1878396&r2=1878397&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessReadBuffer.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/io/RandomAccessReadBuffer.java Tue Jun  2 15:00:32 2020
@@ -18,6 +18,7 @@ package org.apache.pdfbox.io;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -27,31 +28,31 @@ import java.util.List;
  */
 public class RandomAccessReadBuffer implements RandomAccessRead, Cloneable
 {
-    // default chunk size is 1kb
-    private static final int DEFAULT_CHUNK_SIZE = 1024;
+    // default chunk size is 4kb
+    private static final int DEFAULT_CHUNK_SIZE_4KB = 1 << 12;
     // use the default chunk size
-    private int chunkSize = DEFAULT_CHUNK_SIZE;
+    private int chunkSize = DEFAULT_CHUNK_SIZE_4KB;
     // list containing all chunks
-    private List<byte[]> bufferList = null;
+    private List<ByteBuffer> bufferList = null;
     // current chunk
-    private byte[] currentBuffer;
+    private ByteBuffer currentBuffer;
     // current pointer to the whole buffer
-    private long pointer;
+    private long pointer = 0;
     // current pointer for the current chunk
-    private int currentBufferPointer;
+    private int currentBufferPointer = 0;
     // size of the whole buffer
-    private long size;
+    private long size = 0;
     // current chunk list index
-    private int bufferListIndex;
+    private int bufferListIndex = 0;
     // maximum chunk list index
-    private int bufferListMaxIndex;
+    private int bufferListMaxIndex = 0;
 
     /**
      * Default constructor.
      */
-    public RandomAccessReadBuffer()
+    private RandomAccessReadBuffer()
     {
-        this(DEFAULT_CHUNK_SIZE);
+        this(DEFAULT_CHUNK_SIZE_4KB);
     }
 
     /**
@@ -62,13 +63,8 @@ public class RandomAccessReadBuffer impl
         // starting with one chunk
         bufferList = new ArrayList<>();
         chunkSize = definedChunkSize;
-        currentBuffer = new byte[chunkSize];
+        currentBuffer = ByteBuffer.allocate(chunkSize);
         bufferList.add(currentBuffer);
-        pointer = 0;
-        currentBufferPointer = 0;
-        size = 0;
-        bufferListIndex = 0;
-        bufferListMaxIndex = 0;
     }
 
     /**
@@ -78,17 +74,12 @@ public class RandomAccessReadBuffer impl
      */
     public RandomAccessReadBuffer(byte[] input)
     {
-        // this is a special case. The given byte array is used as the one
-        // and only chunk.
+        // this is a special case. Wrap the given byte array to one ByteBuffer.
         bufferList = new ArrayList<>(1);
         chunkSize = input.length;
-        currentBuffer = input;
-        bufferList.add(currentBuffer);
-        pointer = 0;
-        currentBufferPointer = 0;
         size = chunkSize;
-        bufferListIndex = 0;
-        bufferListMaxIndex = 0;
+        currentBuffer = ByteBuffer.wrap(input);
+        bufferList.add(currentBuffer);
     }
 
     /**
@@ -100,11 +91,26 @@ public class RandomAccessReadBuffer impl
     public RandomAccessReadBuffer(InputStream input) throws IOException
     {
         this();
-        byte[] byteBuffer = new byte[8192];
         int bytesRead = 0;
-        while ((bytesRead = input.read(byteBuffer)) > -1)
+        while (input.available() > 0)
         {
-            write(byteBuffer, 0, bytesRead);
+            int remainingBytes = chunkSize;
+            int offset = 0;
+            while (remainingBytes > 0
+                    && (bytesRead = input.read(currentBuffer.array(), offset, remainingBytes)) > -1)
+            {
+                remainingBytes -= bytesRead;
+                offset += bytesRead;
+            }
+            size += offset;
+            if (remainingBytes == 0 && input.available() > 0)
+            {
+                expandBuffer();
+            }
+            else
+            {
+                currentBuffer.limit(offset);
+            }
         }
         seek(0);
     }
@@ -115,15 +121,18 @@ public class RandomAccessReadBuffer impl
         RandomAccessReadBuffer copy = new RandomAccessReadBuffer(chunkSize);
 
         copy.bufferList = new ArrayList<>(bufferList.size());
-        for (byte [] buffer : bufferList)
+        for (ByteBuffer buffer : bufferList)
         {
-            byte [] newBuffer = new byte [buffer.length];
-            System.arraycopy(buffer,0,newBuffer,0,buffer.length);
+            ByteBuffer newBuffer = ByteBuffer.allocate(buffer.limit());
+            int originPosition = buffer.position();
+            buffer.rewind();
+            newBuffer.put(buffer);
             copy.bufferList.add(newBuffer);
+            buffer.position(originPosition);
         }
-        if (currentBuffer!=null)
+        if (currentBuffer != null)
         {
-            copy.currentBuffer = copy.bufferList.get(copy.bufferList.size()-1);
+            copy.currentBuffer = copy.bufferList.get(copy.bufferList.size() - 1);
         }
         else
         {
@@ -146,10 +155,6 @@ public class RandomAccessReadBuffer impl
     {
         currentBuffer = null;
         bufferList.clear();
-        pointer = 0;
-        currentBufferPointer = 0;
-        size = 0;
-        bufferListIndex = 0;
     }
 
     /**
@@ -161,14 +166,14 @@ public class RandomAccessReadBuffer impl
         checkClosed();
         if (position < 0)
         {
-            throw new IOException("Invalid position "+position);
+            throw new IOException("Invalid position " + position);
         }
         pointer = position;
         if (pointer < size)
         {
             // calculate the chunk list index
-            bufferListIndex = (int)(pointer / chunkSize);
-            currentBufferPointer = (int)(pointer % chunkSize);
+            bufferListIndex = (int) (pointer / chunkSize);
+            currentBufferPointer = (int) (pointer % chunkSize);
             currentBuffer = bufferList.get(bufferListIndex);
         }
         else
@@ -177,7 +182,7 @@ public class RandomAccessReadBuffer impl
             // jump to the end of the buffer
             bufferListIndex = bufferListMaxIndex;
             currentBuffer = bufferList.get(bufferListIndex);
-            currentBufferPointer = (int)(size % chunkSize);
+            currentBufferPointer = (int) (size % chunkSize);
         }
     }
 
@@ -187,8 +192,8 @@ public class RandomAccessReadBuffer impl
     @Override
     public long getPosition() throws IOException
     {
-       checkClosed();
-       return pointer;
+        checkClosed();
+        return pointer;
     }
     
     /**
@@ -215,7 +220,7 @@ public class RandomAccessReadBuffer impl
             }
         }
         pointer++;
-        return currentBuffer[currentBufferPointer++] & 0xff;
+        return currentBuffer.get(currentBufferPointer++) & 0xff;
     }
 
     /**
@@ -247,7 +252,7 @@ public class RandomAccessReadBuffer impl
         {
             return 0;
         }
-        int maxLength = (int) Math.min(length, size-pointer);
+        int maxLength = (int) Math.min(length, size - pointer);
         int remainingBytes = chunkSize - currentBufferPointer;
         // no more bytes left
         if (remainingBytes == 0)
@@ -257,7 +262,8 @@ public class RandomAccessReadBuffer impl
         if (maxLength >= remainingBytes)
         {
             // copy the remaining bytes from the current buffer
-            System.arraycopy(currentBuffer, currentBufferPointer, b, offset, remainingBytes);
+            System.arraycopy(currentBuffer.array(), currentBufferPointer, b, offset,
+                    remainingBytes);
             // end of file reached
             currentBufferPointer += remainingBytes;
             pointer += remainingBytes;
@@ -266,7 +272,7 @@ public class RandomAccessReadBuffer impl
         else
         {
             // copy the remaining bytes from the whole buffer
-            System.arraycopy(currentBuffer, currentBufferPointer, b, offset, maxLength);
+            System.arraycopy(currentBuffer.array(), currentBufferPointer, b, offset, maxLength);
             // end of file reached
             currentBufferPointer += maxLength;
             pointer += maxLength;
@@ -284,54 +290,6 @@ public class RandomAccessReadBuffer impl
         return size;
     }
 
-    private void write(byte[] b, int offset, int length) throws IOException
-    {
-        checkClosed();
-        long newSize = pointer + length;
-        int remainingBytes = chunkSize - currentBufferPointer;
-        if (length >= remainingBytes)
-        {
-            if (newSize > Integer.MAX_VALUE)
-            {
-                throw new IOException("RandomAccessBuffer overflow");
-            }
-            // copy the first bytes to the current buffer
-            System.arraycopy(b, offset, currentBuffer, currentBufferPointer, remainingBytes);
-            int newOffset = offset + remainingBytes;
-            long remainingBytes2Write = length - remainingBytes;
-            // determine how many buffers are needed for the remaining bytes
-            int numberOfNewArrays = (int) remainingBytes2Write / chunkSize;
-            for (int i = 0; i < numberOfNewArrays; i++)
-            {
-                expandBuffer();
-                System.arraycopy(b, newOffset, currentBuffer, currentBufferPointer, chunkSize);
-                newOffset += chunkSize;
-            }
-            // are there still some bytes to be written?
-            remainingBytes2Write -= numberOfNewArrays * (long) chunkSize;
-            if (remainingBytes2Write >= 0)
-            {
-                expandBuffer();
-                if (remainingBytes2Write > 0)
-                {
-                    System.arraycopy(b, newOffset, currentBuffer, currentBufferPointer,
-                            (int) remainingBytes2Write);
-                }
-                currentBufferPointer = (int) remainingBytes2Write;
-            }
-        }
-        else
-        {
-            System.arraycopy(b, offset, currentBuffer, currentBufferPointer, length);
-            currentBufferPointer += length;
-        }
-        pointer += length;
-        if (pointer > this.size)
-        {
-            this.size = pointer;
-        }
-    }
-
     /**
      * create a new buffer chunk and adjust all pointers and indices.
      */
@@ -345,7 +303,7 @@ public class RandomAccessReadBuffer impl
         else
         {
             // create a new chunk and add it to the buffer
-            currentBuffer = new byte[chunkSize];
+            currentBuffer = ByteBuffer.allocate(chunkSize);
             bufferList.add(currentBuffer);
             currentBufferPointer = 0;
             bufferListMaxIndex++;
@@ -372,12 +330,11 @@ public class RandomAccessReadBuffer impl
      */
     private void checkClosed() throws IOException
     {
-        if (currentBuffer==null)
+        if (currentBuffer == null)
         {
             // consider that the rab is closed if there is no current buffer
             throw new IOException("RandomAccessBuffer already closed");
         }
-        
     }
 
     /**
@@ -440,4 +397,5 @@ public class RandomAccessReadBuffer impl
     {
         return read(b, 0, b.length);
     }
+
 }