InputStream.java
001 package gate.creole.annic.apache.lucene.store;
002 
003 /**
004  * Copyright 2004 The Apache Software Foundation
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * You may obtain a copy of the License at
009  *
010  *     http://www.apache.org/licenses/LICENSE-2.0
011  *
012  * Unless required by applicable law or agreed to in writing, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 
019 import java.io.IOException;
020 
021 /** Abstract base class for input from a file in a {@link Directory}.  A
022  * random-access input stream.  Used for all Lucene index input operations.
023  @see Directory
024  @see OutputStream
025  */
026 public abstract class InputStream implements Cloneable {
027   static final int BUFFER_SIZE = OutputStream.BUFFER_SIZE;
028 
029   private byte[] buffer;
030   private char[] chars;
031 
032   private long bufferStart = 0;        // position in file of buffer
033   private int bufferLength = 0;        // end of valid bytes
034   private int bufferPosition = 0;      // next byte to read
035 
036   protected long length;        // set by subclasses
037 
038   /** Reads and returns a single byte.
039    @see OutputStream#writeByte(byte)
040    */
041   public final byte readByte() throws IOException {
042     if (bufferPosition >= bufferLength)
043       refill();
044     return buffer[bufferPosition++];
045   }
046 
047   /** Reads a specified number of bytes into an array at the specified offset.
048    @param b the array to read bytes into
049    @param offset the offset in the array to start storing bytes
050    @param len the number of bytes to read
051    @see OutputStream#writeBytes(byte[],int)
052    */
053   public final void readBytes(byte[] b, int offset, int len)
054        throws IOException {
055     if (len < BUFFER_SIZE) {
056       for (int i = 0; i < len; i++)      // read byte-by-byte
057   b[i + offset= readByte();
058     else {            // read all-at-once
059       long start = getFilePointer();
060       seekInternal(start);
061       readInternal(b, offset, len);
062 
063       bufferStart = start + len;      // adjust stream variables
064       bufferPosition = 0;
065       bufferLength = 0;          // trigger refill() on read
066     }
067   }
068 
069   /** Reads four bytes and returns an int.
070    @see OutputStream#writeInt(int)
071    */
072   public final int readInt() throws IOException {
073     return ((readByte() 0xFF<< 24((readByte() 0xFF<< 16)
074          ((readByte() 0xFF<<  8|  (readByte() 0xFF);
075   }
076 
077   /** Reads an int stored in variable-length format.  Reads between one and
078    * five bytes.  Smaller values take fewer bytes.  Negative numbers are not
079    * supported.
080    @see OutputStream#writeVInt(int)
081    */
082   public final int readVInt() throws IOException {
083     byte b = readByte();
084     int i = b & 0x7F;
085     for (int shift = 7(b & 0x80!= 0; shift += 7) {
086       b = readByte();
087       i |= (b & 0x7F<< shift;
088     }
089     return i;
090   }
091 
092   /** Reads eight bytes and returns a long.
093    @see OutputStream#writeLong(long)
094    */
095   public final long readLong() throws IOException {
096     return (((long)readInt()) << 32(readInt() 0xFFFFFFFFL);
097   }
098 
099   /** Reads a long stored in variable-length format.  Reads between one and
100    * nine bytes.  Smaller values take fewer bytes.  Negative numbers are not
101    * supported. */
102   public final long readVLong() throws IOException {
103     byte b = readByte();
104     long i = b & 0x7F;
105     for (int shift = 7(b & 0x80!= 0; shift += 7) {
106       b = readByte();
107       i |= (b & 0x7FL<< shift;
108     }
109     return i;
110   }
111 
112   /** Reads a string.
113    @see OutputStream#writeString(String)
114    */
115   public final String readString() throws IOException {
116     int length = readVInt();
117     if (chars == null || length > chars.length)
118       chars = new char[length];
119     readChars(chars, 0, length);
120     return new String(chars, 0, length);
121   }
122 
123   /** Reads UTF-8 encoded characters into an array.
124    @param buffer the array to read characters into
125    @param start the offset in the array to start storing characters
126    @param length the number of characters to read
127    @see OutputStream#writeChars(String,int,int)
128    */
129   public final void readChars(char[] buffer, int start, int length)
130        throws IOException {
131     final int end = start + length;
132     for (int i = start; i < end; i++) {
133       byte b = readByte();
134       if ((b & 0x80== 0)
135   buffer[i(char)(b & 0x7F);
136       else if ((b & 0xE0!= 0xE0) {
137   buffer[i(char)(((b & 0x1F<< 6)
138      (readByte() 0x3F));
139       else
140   buffer[i(char)(((b & 0x0F<< 12)
141     ((readByte() 0x3F<< 6)
142           |  (readByte() 0x3F));
143     }
144   }
145 
146 
147   private void refill() throws IOException {
148     long start = bufferStart + bufferPosition;
149     long end = start + BUFFER_SIZE;
150     if (end > length)          // don't read past EOF
151       end = length;
152     bufferLength = (int)(end - start);
153     if (bufferLength == 0) {
154       try {
155         throw new Exception("My Exception");
156       catch(Exception e) {
157         e.printStackTrace();
158       }
159       throw new IOException("read past EOF");
160     }
161 
162     if (buffer == null)
163       buffer = new byte[BUFFER_SIZE];      // allocate buffer lazily
164     readInternal(buffer, 0, bufferLength);
165 
166     bufferStart = start;
167     bufferPosition = 0;
168   }
169 
170   /** Expert: implements buffer refill.  Reads bytes from the current position
171    * in the input.
172    @param b the array to read bytes into
173    @param offset the offset in the array to start storing bytes
174    @param length the number of bytes to read
175    */
176   protected abstract void readInternal(byte[] b, int offset, int length)
177        throws IOException;
178 
179   /** Closes the stream to futher operations. */
180   public abstract void close() throws IOException;
181 
182   /** Returns the current position in this file, where the next read will
183    * occur.
184    @see #seek(long)
185    */
186   public final long getFilePointer() {
187     return bufferStart + bufferPosition;
188   }
189 
190   /** Sets current position in this file, where the next read will occur.
191    @see #getFilePointer()
192    */
193   public final void seek(long posthrows IOException {
194     if (pos >= bufferStart && pos < (bufferStart + bufferLength))
195       bufferPosition = (int)(pos - bufferStart);  // seek within buffer
196     else {
197       bufferStart = pos;
198       bufferPosition = 0;
199       bufferLength = 0;          // trigger refill() on read()
200       seekInternal(pos);
201     }
202   }
203 
204   /** Expert: implements seek.  Sets current position in this file, where the
205    * next {@link #readInternal(byte[],int,int)} will occur.
206    @see #readInternal(byte[],int,int)
207    */
208   protected abstract void seekInternal(long posthrows IOException;
209 
210   /** The number of bytes in the file. */
211   public final long length() {
212     return length;
213   }
214 
215   /** Returns a clone of this stream.
216    *
217    <p>Clones of a stream access the same data, and are positioned at the same
218    * point as the stream they were cloned from.
219    *
220    <p>Expert: Subclasses must ensure that clones may be positioned at
221    * different points in the input from each other and from the stream they
222    * were cloned from.
223    */
224   @Override
225   public Object clone() {
226     InputStream clone = null;
227     try {
228       clone = (InputStream)super.clone();
229     catch (CloneNotSupportedException e) {}
230 
231     if (buffer != null) {
232       clone.buffer = new byte[BUFFER_SIZE];
233       System.arraycopy(buffer, 0, clone.buffer, 0, bufferLength);
234     }
235 
236     clone.chars = null;
237 
238     return clone;
239   }
240 
241 }