package org.postgresql.largeobject; import java.io.InputStream; import java.io.IOException; import java.sql.SQLException; /** * This is an initial implementation of an InputStream from a large object. * For now, the bare minimum is implemented. Later (after 7.1) we will overide * the other read methods to optimise them. */ 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 { 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 { 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. * *

The mark method of InputStream does * nothing. * * @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) { //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 { 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; } }