com.pdftools.sys.MemoryStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdftools-sdk Show documentation
Show all versions of pdftools-sdk Show documentation
The Pdftools SDK is a comprehensive development library that lets developers integrate advanced PDF functionalities into in-house applications.
The newest version!
package com.pdftools.sys;
import java.util.LinkedList;
import java.util.ListIterator;
/**
* The stream implementation for in-memory processing.
*
* This can be used to read from or write to byte arrays.
*/
public class MemoryStream implements Stream
{
private static final long MAX_MEMORY_SIZE = 2147483648L; // 2GB
private static final int DEFAULT_BLOCK_SIZE = 8192;
/**
* Create a new memory stream.
* @param initialCapacity The initial capacity of the stream. The length of the stream is still 0
* @param blockSize The size of the memory blocks used to store the data
*/
private MemoryStream(long initialCapacity, int blockSize)
{
this.blockSize = blockSize;
this.list = new LinkedList();
this.setMinCapacity(initialCapacity);
}
/**
* Create a new memory stream.
* @param initialCapacity The initial capacity of the stream. The length of the stream is still 0.
*/
private MemoryStream(long initialCapacity)
{
this(initialCapacity, DEFAULT_BLOCK_SIZE);
}
/**
* Create a new memory stream with initial capacity of 0.
*/
public MemoryStream()
{
this(0);
}
/**
* Create a new memory stream by copying from a buffer.
* @param buffer The buffer from which the initial data is copied
* @param offset The offset where the first byte from the buffer is copied
* @param length The number of bytes that are copied from the buffer
* @param blockSize The size of the memory blocks used to store the data
*/
private MemoryStream(byte[] buffer, int offset, int length, int blockSize)
{
this(length, blockSize);
this.write(buffer, offset, length);
}
/**
* Create a new memory stream by copying from a buffer.
* @param buffer The buffer from which the initial data is copied
* @param offset The offset where the first byte from the buffer is copied
* @param length The number of bytes that are copied from the buffer
*/
public MemoryStream(byte[] buffer, int offset, int length)
{
this(buffer, offset, length, DEFAULT_BLOCK_SIZE);
}
/**
* Create a new memory stream by copying from a buffer.
* @param buffer The buffer from which the initial data is copied
*/
public MemoryStream(byte[] buffer)
{
this(buffer, 0, buffer.length);
}
/**
* Create a new memory stream by copying a stream.
* @param stream The stream from which the initial data is copied
* @param blockSize The size of the memory blocks used to store the data
*/
private MemoryStream(Stream stream, int blockSize) throws java.io.IOException
{
this(stream.getLength(), blockSize);
byte[] buffer = new byte[blockSize];
int read;
while ((read = stream.read(buffer, 0, blockSize)) > 0)
write(buffer, 0, read);
}
/**
* Create a new memory stream by copying a stream.
* @param stream The stream from which the initial data is copied
* @throws java.io.IOException if an I/O error occurs
*/
public MemoryStream(Stream stream) throws java.io.IOException
{
this(stream, DEFAULT_BLOCK_SIZE);
}
/**
* Create a new memory stream by copying the given stream.
* @param inStream The stream from which the initial data is copied
* @throws java.io.IOException if an I/O error occurs
*/
public MemoryStream(java.io.InputStream inStream) throws java.io.IOException
{
initialize(inStream, DEFAULT_BLOCK_SIZE);
}
private void initialize(java.io.InputStream inStream, int blockSize) throws java.io.IOException
{
this.blockSize = blockSize;
this.list = new LinkedList();
byte[] buffer = new byte[blockSize];
int read;
while ((read = inStream.read(buffer)) > 0)
write(buffer, 0, read);
}
/**
* Get the length of the stream in bytes.
* @return the length of the stream in bytes
*/
public long getLength()
{
return this.length;
}
/**
* Set byte position.
* @param position The new position of the stream (-1 for EOS)
* @return true if successful
*/
public boolean seek(long position)
{
this.position = position;
return true;
}
/**
* Get current byte position.
* @return byte position, -1 if position unknown
*/
public long tell()
{
return this.position;
}
/**
* Read from the stream.
* @param buffer The buffer where the data is written
* @param offset The starting element in the buffer
* @param length The maximum number of bytes to be read
* @return The actual number of bytes read (-1 if EOS)
*/
public int read(byte[] buffer, int offset, int length)
{
if (buffer == null)
throw new NullPointerException("'buffer'");
if (offset < 0 || offset + length > buffer.length)
throw new IndexOutOfBoundsException();
// EOS
if (this.position == this.length)
return -1;
ListIterator it = this.list.listIterator((int)(this.position / this.blockSize));
int currPos = offset;
while (length > 0 && it.hasNext() && this.position < this.length)
{
int blockPos = (int)(this.position % this.blockSize);
int currLength = Math.min(length, Math.min(this.blockSize - blockPos, (int)(this.length - this.position)));
System.arraycopy(it.next(), blockPos, buffer, currPos, currLength);
currPos += currLength;
this.position += currLength;
length -= currLength;
}
int read = currPos - offset;
return read;
}
/**
* Read from the stream.
* @param buffer The buffer where the data is written to
* @return The actual number of bytes read (-1 if EOS)
*/
public int read(byte[] buffer) {
return read(buffer, 0, buffer.length);
}
/**
* Creates a newly allocated byte array. Its size is the current size of this stream and the contents have been copied into it.
* @return The current contents of this stream as a byte array.
* @throws OutOfMemoryError if an array larger than 2GB would be required to store the bytes.
*/
public byte[] toByteArray()
{
if (this.length > MAX_MEMORY_SIZE)
throw new OutOfMemoryError("Cannot allocate more than 2GB of memory.");
byte[] buffer = new byte[(int)(this.length)];
ListIterator it = this.list.listIterator(0);
int currPos = 0;
while (it.hasNext()) {
int currLength = Math.min(this.blockSize, (int) (this.length - currPos));
System.arraycopy(it.next(), 0, buffer, currPos, currLength);
currPos += currLength;
}
return buffer;
}
/**
* Read data from the input stream and write it to this stream.
* The data is appended at the stream's current byte position.
* @param inStream The stream from which the data is copied
* @return The actual number of transferred bytes
* @throws java.io.IOException if an I/O error occurs
*/
public int transferFrom(java.io.InputStream inStream) throws java.io.IOException
{
if (inStream == null)
throw new NullPointerException("'inStream'");
byte[] buffer = new byte[blockSize];
int read;
int total = 0;
while ((read = inStream.read(buffer)) > 0)
{
write(buffer, 0, read);
total += read;
}
return total;
}
/**
* Read data from this stream and write it to the output stream.
* The data is read starting from the stream's current byte position.
* In order to read the entire stream, make sure to first position
* the stream at the beginning using {@code seek(0)}.
* @param outStream The stream to which the data is copied
* @return The actual number of transfered bytes
* @throws java.io.IOException if an I/O error occurs
*/
public long transferTo(java.io.OutputStream outStream) throws java.io.IOException
{
if (outStream == null)
throw new NullPointerException("'outStream'");
byte[] buffer = new byte[blockSize];
int read;
long total = 0;
while ((read = read(buffer)) > 0)
{
outStream.write(buffer, 0, read);
total += read;
}
return total;
}
/**
* Write to the stream.
* @param buffer The buffer where the data lies
* @param offset The starting element in the buffer
* @param length The maximum number of bytes to be written
*/
public void write(byte[] buffer, int offset, int length)
{
if (buffer == null)
throw new NullPointerException("'buffer'");
if (offset < 0 || offset + length > buffer.length)
throw new IndexOutOfBoundsException();
this.setMinLength(this.position + length);
ListIterator it = this.list.listIterator((int)(this.position / this.blockSize));
int currPos = offset;
while (length > 0 && it.hasNext())
{
int blockPos = (int)(this.position % this.blockSize);
int currLength = Math.min(length, this.blockSize - blockPos);
System.arraycopy(buffer, currPos, it.next(), blockPos, currLength);
currPos += currLength;
this.position += currLength;
length -= currLength;
}
}
public void close() throws java.io.IOException {}
private boolean setMinLength(long number)
{
if (number < 0)
return false;
if (!this.setMinCapacity(number))
return false;
if (this.length < number)
this.length = number;
return true;
}
private boolean setMinCapacity(long number)
{
if (number < 0)
return false;
return this.setMinBlockNumber((int)((number + this.blockSize - 1) / this.blockSize));
}
private boolean setMinBlockNumber(int number)
{
if (number < 0)
return false;
for (int change = number - this.list.size(); change > 0; change--)
this.list.addLast(new byte[this.blockSize]);
return true;
}
private LinkedList list = null;
private long length = 0;
private long position = 0;
int blockSize;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy