com.foundationdb.sql.jdbc.largeobject.BlobInputStream Maven / Gradle / Ivy
/*-------------------------------------------------------------------------
*
* Copyright (c) 2003-2011, PostgreSQL Global Development Group
*
*
*-------------------------------------------------------------------------
*/
package com.foundationdb.sql.jdbc.largeobject;
import java.io.InputStream;
import java.io.IOException;
import java.sql.SQLException;
/**
* This is an implementation of an InputStream from a large object.
*/
public class BlobInputStream extends InputStream
{
/**
* The parent LargeObject
*/
private LargeObject lo;
/**
* Buffer used to improve performance
*/
private byte[] buffer;
/**
* Position within buffer
*/
private int bpos;
/**
* The buffer size
*/
private int bsize;
/**
* The mark position
*/
private int mpos = 0;
/**
* @param lo LargeObject to read from
*/
public BlobInputStream(LargeObject lo)
{
this(lo, 1024);
}
/**
* @param lo LargeObject to read from
* @param bsize buffer size
*/
public BlobInputStream(LargeObject lo, int bsize)
{
this.lo = lo;
buffer = null;
bpos = 0;
this.bsize = bsize;
}
/**
* The minimum required to implement input stream
*/
public int read() throws java.io.IOException
{
checkClosed();
try
{
if (buffer == null || bpos >= buffer.length)
{
buffer = lo.read(bsize);
bpos = 0;
}
// Handle EOF
if (bpos >= buffer.length)
{
return -1;
}
int ret = (buffer[bpos] & 0x7F);
if ((buffer[bpos] &0x80) == 0x80)
{
ret |= 0x80;
}
bpos++;
return ret;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
*
* The close
method of InputStream
does
* nothing.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException
{
if (lo != null) {
try
{
lo.close();
lo = null;
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
}
/**
* Marks the current position in this input stream. A subsequent call to
* the reset
method repositions this stream at the last marked
* position so that subsequent reads re-read the same bytes.
*
*
The readlimit
arguments tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
*
*
The general contract of mark
is that, if the method
* markSupported
returns true
, the stream somehow
* remembers all the bytes read after the call to mark
and
* stands ready to supply those same bytes again if and whenever the method
* reset
is called. However, the stream is not required to
* remember any data at all if more than readlimit
bytes are
* read from the stream before reset
is called.
*
*
Marking a closed stream should not have any effect on the stream.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.InputStream#reset()
*/
public synchronized void mark(int readlimit)
{
try
{
mpos = lo.tell();
}
catch (SQLException se)
{
// Can't throw this because mark API doesn't allow it.
// throw new IOException(se.toString());
}
}
/**
* Repositions this stream to the position at the time the
* mark
method was last called on this input stream.
* NB: If mark is not called we move to the begining.
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
*/
public synchronized void reset()
throws IOException
{
checkClosed();
try
{
lo.seek(mpos);
}
catch (SQLException se)
{
throw new IOException(se.toString());
}
}
/**
* Tests if this input stream supports the mark
and
* reset
methods. The markSupported
method of
* InputStream
returns false
.
*
* @return true
if this true type supports the mark and reset
* method; false
otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
public boolean markSupported()
{
return true;
}
private void checkClosed() throws IOException
{
if (lo == null)
throw new IOException("BlobOutputStream is closed");
}
}