--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.jdbc.LOBInputStream\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one\r
+ or more contributor license agreements. See the NOTICE file\r
+ distributed with this work for additional information\r
+ regarding copyright ownership. The ASF licenses this file\r
+ to you under the Apache License, Version 2.0 (the\r
+ "License"); you may not use this file except in compliance\r
+ with the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing,\r
+ software distributed under the License is distributed on an\r
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
+ KIND, either express or implied. See the License for the\r
+ specific language governing permissions and limitations\r
+ under the License.\r
+\r
+ */\r
+package org.apache.derby.impl.jdbc;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.sql.SQLException;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.shared.common.error.ExceptionUtil;\r
+\r
+/**\r
+ * This input stream is built on top of {@link LOBStreamControl}.\r
+ * <p>\r
+ * All the read methods are routed to {@link LOBStreamControl}.\r
+ */\r
+\r
+public class LOBInputStream extends InputStream {\r
+\r
+ private boolean closed;\r
+ private final LOBStreamControl control;\r
+ private long pos;\r
+ private long updateCount;\r
+\r
+ LOBInputStream(LOBStreamControl control, long position) {\r
+ closed = false;\r
+ this.control = control;\r
+ pos = position;\r
+ updateCount = control.getUpdateCount ();\r
+ }\r
+\r
+ /**\r
+ * Reads up to <code>len</code> bytes of data from the input stream into\r
+ * an array of bytes. An attempt is made to read as many as\r
+ * <code>len</code> bytes, but a smaller number may be read.\r
+ * The number of bytes actually read is returned as an integer.\r
+ *\r
+ * <p> This method blocks until input data is available, end of file is\r
+ * detected, or an exception is thrown.\r
+ *\r
+ * <p> If <code>b</code> is <code>null</code>, a\r
+ * <code>NullPointerException</code> is thrown.\r
+ *\r
+ * <p> If <code>off</code> is negative, or <code>len</code> is negative, or\r
+ * <code>off+len</code> is greater than the length of the array\r
+ * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is\r
+ * thrown.\r
+ *\r
+ * <p> If <code>len</code> is zero, then no bytes are read and\r
+ * <code>0</code> is returned; otherwise, there is an attempt to read at\r
+ * least one byte. If no byte is available because the stream is at end of\r
+ * file, the value <code>-1</code> is returned; otherwise, at least one\r
+ * byte is read and stored into <code>b</code>.\r
+ *\r
+ * <p> The first byte read is stored into element <code>b[off]</code>, the\r
+ * next one into <code>b[off+1]</code>, and so on. The number of bytes read\r
+ * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of\r
+ * bytes actually read; these bytes will be stored in elements\r
+ * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,\r
+ * leaving elements <code>b[off+</code><i>k</i><code>]</code> through\r
+ * <code>b[off+len-1]</code> unaffected.\r
+ *\r
+ * <p> In every case, elements <code>b[0]</code> through\r
+ * <code>b[off]</code> and elements <code>b[off+len]</code> through\r
+ * <code>b[b.length-1]</code> are unaffected.\r
+ *\r
+ * <p> If the first byte cannot be read for any reason other than end of\r
+ * file, then an <code>IOException</code> is thrown. In particular, an\r
+ * <code>IOException</code> is thrown if the input stream has been closed.\r
+ *\r
+ * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method\r
+ * for class <code>InputStream</code> simply calls the method\r
+ * <code>read()</code> repeatedly. If the first such call results in an\r
+ * <code>IOException</code>, that exception is returned from the call to\r
+ * the <code>read(b,</code> <code>off,</code> <code>len)</code> method. If\r
+ * any subsequent call to <code>read()</code> results in a\r
+ * <code>IOException</code>, the exception is caught and treated as if it\r
+ * were end of file; the bytes read up to that point are stored into\r
+ * <code>b</code> and the number of bytes read before the exception\r
+ * occurred is returned. Subclasses are encouraged to provide a more\r
+ * efficient implementation of this method.\r
+ *\r
+ * @param b the buffer into which the data is read.\r
+ * @param off the start offset in array <code>b</code>\r
+ * at which the data is written.\r
+ * @param len the maximum number of bytes to read.\r
+ * @return the total number of bytes read into the buffer, or\r
+ * <code>-1</code> if there is no more data because the end of\r
+ * the stream has been reached.\r
+ * @exception IOException if an I/O error occurs.\r
+ * @exception NullPointerException if <code>b</code> is <code>null</code>.\r
+ * @see java.io.InputStream#read()\r
+ */\r
+ public int read(byte[] b, int off, int len) throws IOException {\r
+ if (closed)\r
+ throw new IOException (\r
+ MessageService.getTextMessage(SQLState.LANG_STREAM_CLOSED));\r
+ try {\r
+ int ret = control.read(b, off, len, pos);\r
+ if (ret != -1) {\r
+ pos += ret;\r
+ return ret;\r
+ }\r
+ return -1;\r
+ } catch (SQLException e) {\r
+ return handleSQLException (e);\r
+ }\r
+ catch (StandardException se) {\r
+ throw new IOException (se.getMessage());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Closes this input stream and releases any system resources associated\r
+ * with the stream.\r
+ *\r
+ * <p> The <code>close</code> method of <code>InputStream</code> does\r
+ * nothing.\r
+ *\r
+ * @exception IOException if an I/O error occurs.\r
+ */\r
+ public void close() throws IOException {\r
+ closed = true;\r
+ }\r
+\r
+ /**\r
+ * Reads the next byte of data from the input stream. The value byte is\r
+ * returned as an <code>int</code> in the range <code>0</code> to\r
+ * <code>255</code>. If no byte is available because the end of the stream\r
+ * has been reached, the value <code>-1</code> is returned. This method\r
+ * blocks until input data is available, the end of the stream is detected,\r
+ * or an exception is thrown.\r
+ *\r
+ * <p> A subclass must provide an implementation of this method.\r
+ *\r
+ * @return the next byte of data, or <code>-1</code> if the end of the\r
+ * stream is reached.\r
+ * @exception IOException if an I/O error occurs.\r
+ */\r
+ public int read() throws IOException {\r
+ if (closed)\r
+ throw new IOException (\r
+ MessageService.getTextMessage (SQLState.LANG_STREAM_CLOSED));\r
+ try {\r
+ int ret = control.read(pos);\r
+ if (ret != -1)\r
+ pos += 1;\r
+ return ret;\r
+ } catch (SQLException e) {\r
+ throw new IOException(e.getMessage());\r
+ } catch (StandardException se) {\r
+ throw new IOException (se.getMessage());\r
+ }\r
+ }\r
+\r
+ private int handleSQLException (SQLException e) throws IOException {\r
+ if (e.getSQLState().equals(\r
+ ExceptionUtil.getSQLStateFromIdentifier(\r
+ SQLState.BLOB_POSITION_TOO_LARGE)))\r
+ return -1;\r
+ if (e.getSQLState().equals(\r
+ ExceptionUtil.getSQLStateFromIdentifier(\r
+ SQLState.BLOB_INVALID_OFFSET)))\r
+ throw new ArrayIndexOutOfBoundsException (e.getMessage());\r
+ throw new IOException(e.getMessage());\r
+ }\r
+ \r
+ /**\r
+ * Checks if underlying StreamControl has been updated.\r
+ * @return if stream is modified since created\r
+ */\r
+ boolean isObsolete () {\r
+ return updateCount != control.getUpdateCount();\r
+ }\r
+ \r
+ /**\r
+ * Reinitializes the stream and sets the current pointer to zero.\r
+ */\r
+ void reInitialize () {\r
+ updateCount = control.getUpdateCount();\r
+ pos = 0;\r
+ }\r
+ \r
+ /**\r
+ * Returns size of stream in bytes.\r
+ * @return size of stream.\r
+ */\r
+ long length () throws IOException {\r
+ return control.getLength();\r
+ }\r
+}\r