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] = (byte)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 pos) throws 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 pos) throws 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 public Object clone() {
225 InputStream clone = null;
226 try {
227 clone = (InputStream)super.clone();
228 } catch (CloneNotSupportedException e) {}
229
230 if (buffer != null) {
231 clone.buffer = new byte[BUFFER_SIZE];
232 System.arraycopy(buffer, 0, clone.buffer, 0, bufferLength);
233 }
234
235 clone.chars = null;
236
237 return clone;
238 }
239
240 }
|