001: /*-------------------------------------------------------------------------
002: *
003: * Copyright (c) 2003-2005, PostgreSQL Global Development Group
004: *
005: * IDENTIFICATION
006: * $PostgreSQL: pgjdbc/org/postgresql/largeobject/BlobInputStream.java,v 1.11 2007/02/19 18:35:29 jurka Exp $
007: *
008: *-------------------------------------------------------------------------
009: */
010: package org.postgresql.largeobject;
011:
012: import java.io.InputStream;
013: import java.io.IOException;
014: import java.sql.SQLException;
015:
016: /**
017: * This is an implementation of an InputStream from a large object.
018: */
019: public class BlobInputStream extends InputStream {
020: /**
021: * The parent LargeObject
022: */
023: private LargeObject lo;
024:
025: /**
026: * Buffer used to improve performance
027: */
028: private byte[] buffer;
029:
030: /**
031: * Position within buffer
032: */
033: private int bpos;
034:
035: /**
036: * The buffer size
037: */
038: private int bsize;
039:
040: /**
041: * The mark position
042: */
043: private int mpos = 0;
044:
045: /**
046: * @param lo LargeObject to read from
047: */
048: public BlobInputStream(LargeObject lo) {
049: this (lo, 1024);
050: }
051:
052: /**
053: * @param lo LargeObject to read from
054: * @param bsize buffer size
055: */
056: public BlobInputStream(LargeObject lo, int bsize) {
057: this .lo = lo;
058: buffer = null;
059: bpos = 0;
060: this .bsize = bsize;
061: }
062:
063: /**
064: * The minimum required to implement input stream
065: */
066: public int read() throws java.io.IOException {
067: checkClosed();
068: try {
069: if (buffer == null || bpos >= buffer.length) {
070: buffer = lo.read(bsize);
071: bpos = 0;
072: }
073:
074: // Handle EOF
075: if (bpos >= buffer.length) {
076: return -1;
077: }
078:
079: int ret = (buffer[bpos] & 0x7F);
080: if ((buffer[bpos] & 0x80) == 0x80) {
081: ret |= 0x80;
082: }
083:
084: bpos++;
085:
086: return ret;
087: } catch (SQLException se) {
088: throw new IOException(se.toString());
089: }
090: }
091:
092: /**
093: * Closes this input stream and releases any system resources associated
094: * with the stream.
095: *
096: * <p> The <code>close</code> method of <code>InputStream</code> does
097: * nothing.
098: *
099: * @exception IOException if an I/O error occurs.
100: */
101: public void close() throws IOException {
102: if (lo != null) {
103: try {
104: lo.close();
105: lo = null;
106: } catch (SQLException se) {
107: throw new IOException(se.toString());
108: }
109: }
110: }
111:
112: /**
113: * Marks the current position in this input stream. A subsequent call to
114: * the <code>reset</code> method repositions this stream at the last marked
115: * position so that subsequent reads re-read the same bytes.
116: *
117: * <p> The <code>readlimit</code> arguments tells this input stream to
118: * allow that many bytes to be read before the mark position gets
119: * invalidated.
120: *
121: * <p> The general contract of <code>mark</code> is that, if the method
122: * <code>markSupported</code> returns <code>true</code>, the stream somehow
123: * remembers all the bytes read after the call to <code>mark</code> and
124: * stands ready to supply those same bytes again if and whenever the method
125: * <code>reset</code> is called. However, the stream is not required to
126: * remember any data at all if more than <code>readlimit</code> bytes are
127: * read from the stream before <code>reset</code> is called.
128: *
129: * <p> Marking a closed stream should not have any effect on the stream.
130: *
131: * @param readlimit the maximum limit of bytes that can be read before
132: * the mark position becomes invalid.
133: * @see java.io.InputStream#reset()
134: */
135: public synchronized void mark(int readlimit) {
136: try {
137: mpos = lo.tell();
138: } catch (SQLException se) {
139: // Can't throw this because mark API doesn't allow it.
140: // throw new IOException(se.toString());
141: }
142: }
143:
144: /**
145: * Repositions this stream to the position at the time the
146: * <code>mark</code> method was last called on this input stream.
147: * NB: If mark is not called we move to the begining.
148: * @see java.io.InputStream#mark(int)
149: * @see java.io.IOException
150: */
151: public synchronized void reset() throws IOException {
152: checkClosed();
153: try {
154: lo.seek(mpos);
155: } catch (SQLException se) {
156: throw new IOException(se.toString());
157: }
158: }
159:
160: /**
161: * Tests if this input stream supports the <code>mark</code> and
162: * <code>reset</code> methods. The <code>markSupported</code> method of
163: * <code>InputStream</code> returns <code>false</code>.
164: *
165: * @return <code>true</code> if this true type supports the mark and reset
166: * method; <code>false</code> otherwise.
167: * @see java.io.InputStream#mark(int)
168: * @see java.io.InputStream#reset()
169: */
170: public boolean markSupported() {
171: return true;
172: }
173:
174: private void checkClosed() throws IOException {
175: if (lo == null)
176: throw new IOException("BlobOutputStream is closed");
177: }
178:
179: }
|