001: /*
002:
003: Derby - Class org.apache.derby.iapi.services.io.ArrayInputStream
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.iapi.services.io;
023:
024: import java.io.InputStream;
025: import java.io.IOException;
026: import java.io.ObjectInput;
027: import java.io.EOFException;
028:
029: import org.apache.derby.iapi.services.sanity.SanityManager;
030:
031: import org.apache.derby.iapi.services.io.LimitObjectInput;
032: import org.apache.derby.iapi.services.io.ErrorObjectInput;
033:
034: import java.io.UTFDataFormatException;
035:
036: /**
037: An InputStream that allows reading from an array of bytes. The array
038: of bytes that is read from can be changed without having to create a new
039: instance of this class.
040: */
041: public final class ArrayInputStream extends InputStream implements
042: LimitObjectInput {
043:
044: private byte[] pageData;
045:
046: private int start;
047: private int end; // exclusive
048: private int position;
049:
050: public ArrayInputStream() {
051: this (null);
052: }
053:
054: private ErrorObjectInput oi;
055:
056: public ArrayInputStream(byte[] data) {
057: super ();
058: setData(data);
059: oi = new org.apache.derby.iapi.services.io.FormatIdInputStream(
060: this );
061: }
062:
063: public ArrayInputStream(byte[] data, int offset, int length)
064: throws IOException {
065: this (data);
066: setLimit(offset, length);
067: }
068:
069: /*
070: ** Public methods
071: */
072:
073: /**
074: Set the array of bytes to be read.
075: */
076: public void setData(byte[] data) {
077: pageData = data;
078: clearLimit();
079: }
080:
081: public void setData(byte[] data, int offset, int length)
082: throws IOException {
083: pageData = data;
084: setLimit(offset, length);
085: }
086:
087: /**
088: Return a reference to the array of bytes this stream is going to read
089: from so that caller may load it with stuff
090: */
091: public byte[] getData() {
092: return pageData;
093: }
094:
095: /*
096: ** Methods of InputStream
097: */
098:
099: public int read() throws IOException {
100: if (position == end)
101: return -1; // end of file
102:
103: return pageData[position++] & 0xff;
104:
105: }
106:
107: public int read(byte b[], int off, int len) throws IOException {
108:
109: if ((position + len) > end) {
110:
111: len = end - position;
112:
113: if (len == 0) {
114: return -1; // end of file
115: }
116: }
117:
118: System.arraycopy(pageData, position, b, off, len);
119: position += len;
120: return len;
121: }
122:
123: public long skip(long count) throws IOException {
124:
125: if ((position + count) > end) {
126:
127: count = end - position;
128:
129: if (count == 0)
130: return 0; // end of file
131: }
132:
133: position += count;
134:
135: return count;
136:
137: }
138:
139: public int getPosition() {
140: return position;
141: }
142:
143: public final void setPosition(int newPosition) throws IOException {
144:
145: if ((newPosition >= start) && (newPosition < end))
146: position = newPosition;
147: else
148: throw new EOFException();
149: }
150:
151: public int available() throws IOException {
152:
153: return end - position;
154: }
155:
156: /**
157: A setLimit which also sets the position to be offset.
158:
159: @exception IOException limit is out of range
160: */
161: public int setLimit(int offset, int length) throws IOException {
162:
163: if ((offset < 0) || (length < 0)) {
164: start = end = position = 0;
165: throw new EOFException();
166: }
167:
168: start = offset;
169: end = offset + length;
170:
171: if (end > pageData.length) {
172: start = end = position = 0;
173: throw new EOFException();
174: }
175:
176: position = start;
177:
178: return length;
179: }
180:
181: /*
182: ** Methods of Limit
183: */
184:
185: public final void setLimit(int length) throws IOException {
186:
187: start = position;
188: end = position + length;
189:
190: if (end <= pageData.length) {
191: return;
192: } else {
193: start = end = position = 0;
194: throw new EOFException();
195: }
196: }
197:
198: /**
199: Clears the limit by setting the limit to be the entire byte array.
200:
201: @see Limit#clearLimit
202: */
203: public final int clearLimit() {
204:
205: if (pageData != null) {
206: start = 0;
207: int remainingBytes = end - position;
208: end = pageData.length;
209: return remainingBytes;
210: } else {
211: start = end = position = 0;
212: return 0;
213: }
214: }
215:
216: /*
217: ** Methods of DataInput
218: */
219:
220: public final void readFully(byte b[]) throws IOException {
221: readFully(b, 0, b.length);
222: }
223:
224: public final void readFully(byte b[], int off, int len)
225: throws IOException {
226:
227: if ((position + len) > end) {
228:
229: throw new EOFException();
230: }
231:
232: System.arraycopy(pageData, position, b, off, len);
233: position += len;
234: }
235:
236: public final int skipBytes(int n) throws IOException {
237: if ((position + n) > end) {
238:
239: throw new EOFException();
240: }
241: position += n;
242: return n;
243: }
244:
245: public final boolean readBoolean() throws IOException {
246: if (position == end)
247: throw new EOFException(); // end of file
248:
249: return pageData[position++] != 0;
250: }
251:
252: public final byte readByte() throws IOException {
253: if (position == end)
254: throw new EOFException(); // end of file
255:
256: return pageData[position++];
257: }
258:
259: public final int readUnsignedByte() throws IOException {
260: if (position == end)
261: throw new EOFException(); // end of file
262:
263: return pageData[position++] & 0xff;
264: }
265:
266: public final short readShort() throws IOException {
267:
268: int pos = position;
269: byte[] data = pageData;
270:
271: if (pos >= (end - 1))
272: throw new EOFException(); // end of file
273:
274: int s = ((data[pos++] & 0xff) << 8) | (data[pos++] & 0xff);
275:
276: position = pos;
277:
278: return (short) s;
279: }
280:
281: public final int readUnsignedShort() throws IOException {
282: int pos = position;
283: byte[] data = pageData;
284:
285: if (pos >= (end - 1))
286: throw new EOFException(); // end of file
287:
288: int us = ((data[pos++] & 0xff) << 8) | (data[pos++] & 0xff);
289:
290: position = pos;
291:
292: return us;
293: }
294:
295: public final char readChar() throws IOException {
296: int pos = position;
297: byte[] data = pageData;
298:
299: if (pos >= (end - 1))
300: throw new EOFException(); // end of file
301:
302: int c = ((data[pos++] & 0xff) << 8) | (data[pos++] & 0xff);
303:
304: position = pos;
305:
306: return (char) c;
307: }
308:
309: public final int readInt() throws IOException {
310:
311: int pos = position;
312: byte[] data = pageData;
313:
314: if (pos >= (end - 3))
315: throw new EOFException(); // end of file
316:
317: int i = ((data[pos++] & 0xff) << 24)
318: | ((data[pos++] & 0xff) << 16)
319: | ((data[pos++] & 0xff) << 8) | ((data[pos++] & 0xff));
320:
321: position = pos;
322:
323: return i;
324: }
325:
326: public final long readLong() throws IOException {
327: int pos = position;
328: byte[] data = pageData;
329:
330: if (pos >= (end - 7))
331: throw new EOFException(); // end of file
332:
333: long l = (((long) (data[pos++] & 0xff)) << 56)
334: | (((long) (data[pos++] & 0xff)) << 48)
335: | (((long) (data[pos++] & 0xff)) << 40)
336: | (((long) (data[pos++] & 0xff)) << 32)
337: | (((long) (data[pos++] & 0xff)) << 24)
338: | (((long) (data[pos++] & 0xff)) << 16)
339: | (((long) (data[pos++] & 0xff)) << 8)
340: | (((long) (data[pos++] & 0xff)));
341:
342: position = pos;
343:
344: return l;
345: }
346:
347: public final float readFloat() throws IOException {
348: return Float.intBitsToFloat(readInt());
349: }
350:
351: public final double readDouble() throws IOException {
352: return Double.longBitsToDouble(readLong());
353: }
354:
355: public final String readLine() throws IOException {
356: return oi.readLine();
357: }
358:
359: public final String readUTF() throws IOException {
360: return oi.readUTF();
361: }
362:
363: /**
364: * read in a cloudscape UTF formated string into a char[].
365: * <p>
366: * This routine inline's the code to read a UTF format string from a
367: * byte[] array (pageData), into a char[] array. The string will
368: * be read into the char[] array passed into this routine through
369: * rawData_array[0] if it is big enough. If it is not big enough
370: * a new char[] will be alocated and returned to the caller by putting
371: * it into rawData_array[0].
372: * <p>
373: * To see detailed description of the cloudscape UTF format see
374: * the writeExternal() routine of SQLChar.
375: * <p>
376: * The routine returns the number of char's read into the returned
377: * char[], note that this length may smaller than the actual length
378: * of the char[] array.
379: *
380: * @return The the number of valid char's in the returned char[].
381: *
382: * @param rawData_array This parameter uses a element array to implement
383: * an in/out function parameter. The char[] array
384: * in rawData_array[0] is used to read the data into
385: * unless it is not big enough, then a new array
386: * is allocated and the old one discarded. In
387: * either case on return rawData_array[0] contains
388: * the filled in char[] - caller must allow that
389: * the array may or may not be different from the
390: * one passed in.
391: *
392: * @exception StandardException Standard exception policy.
393: **/
394: public final int readCloudscapeUTF(char[][] rawData_array)
395: throws IOException {
396: // copy globals locally, to give compiler chance to optimize.
397: byte[] data = pageData;
398: int end_pos = end;
399: int pos = position;
400:
401: // get header length - stored as an unsigned short.
402:
403: int utflen;
404: if (pos + 1 < end_pos) {
405: utflen = (((data[pos++] & 0xff) << 8) | (data[pos++] & 0xff));
406: } else {
407: throw new EOFException(); // end of file
408: }
409:
410: /**
411: * 3 cases - can they all happen?
412: *
413: * o utflen == 0 and end is marked E0, 0, 0
414: * o utflen == 0 and there is no data (ie. 0 length string)
415: * o utflen != 0, utflen is exact length of following bytes
416: **/
417:
418: // requiredLength is the amount of bytes to read from the array,
419: // either the utflen in the header length, or the number of bytes
420: // available in the array. Throw an exception if we know up front
421: // that utflen is bigger than number of bytes in the array.
422: int requiredLength;
423: if (utflen != 0) {
424: // this is the only place we need to check for end of file,
425: // the subsequent loop will not read past bytes_available_in_array.
426:
427: if (utflen <= (end_pos - pos)) {
428: requiredLength = utflen;
429: } else {
430: throw new EOFException();
431: }
432: } else {
433: // the byte header returned 0, so read what is left in the array.
434:
435: requiredLength = (end_pos - pos);
436: }
437:
438: // Use the passed in char[] array if it is long enough, otherwise
439: // allocate a new array, and will pass it back to caller at the end.
440: // Note that requiredLength is the worst case length for the array,
441: // as the number of char characters must be <= number of bytes (ie.
442: // all characters were stored compressed in 1 byte each - the ascii
443: // default) - if there are any 2 or 3 byte stored characters then
444: // the array will have extra space at the end. "strlen" tracks the
445: // real number of char's in str[].
446: char[] str = rawData_array[0];
447: if ((str == null) || (requiredLength > str.length)) {
448: str = new char[requiredLength];
449: rawData_array[0] = str;
450: }
451:
452: end_pos = pos + requiredLength;
453: int strlen = 0;
454:
455: while (pos < end_pos) {
456: int char1 = (data[pos++] & 0xff);
457:
458: // top fours bits of the first unsigned byte that maps to a 1,2
459: // or 3 byte character
460: //
461: // 0000xxxx - 0 - 1 byte char
462: // 0001xxxx - 1 - 1 byte char
463: // 0010xxxx - 2 - 1 byte char
464: // 0011xxxx - 3 - 1 byte char
465: // 0100xxxx - 4 - 1 byte char
466: // 0101xxxx - 5 - 1 byte char
467: // 0110xxxx - 6 - 1 byte char
468: // 0111xxxx - 7 - 1 byte char
469: // 1000xxxx - 8 - error
470: // 1001xxxx - 9 - error
471: // 1010xxxx - 10 - error
472: // 1011xxxx - 11 - error
473: // 1100xxxx - 12 - 2 byte char
474: // 1101xxxx - 13 - 2 byte char
475: // 1110xxxx - 14 - 3 byte char
476: // 1111xxxx - 15 - error
477:
478: int char2, char3;
479: if ((char1 & 0x80) == 0x00) {
480: // one byte character
481: str[strlen++] = (char) char1;
482: } else if ((char1 & 0x60) == 0x40) // we know the top bit is set here
483: {
484: // two byte character, make sure read of next byte is in bounds.
485: if (pos >= end_pos)
486: throw new UTFDataFormatException();
487:
488: char2 = (data[pos++] & 0xff);
489:
490: if ((char2 & 0xC0) != 0x80)
491: throw new UTFDataFormatException();
492:
493: str[strlen++] = (char) (((char1 & 0x1F) << 6) | (char2 & 0x3F));
494: } else if ((char1 & 0x70) == 0x60) // we know the top bit is set here
495: {
496: // three byte character
497:
498: // 3 byte character, make sure read of next 2 bytes in bounds.
499: if (pos + 1 >= end_pos)
500: throw new UTFDataFormatException();
501:
502: char2 = (data[pos++] & 0xff);
503: char3 = (data[pos++] & 0xff);
504:
505: if ((char1 == 0xE0) && (char2 == 0) && (char3 == 0)
506: && (utflen == 0)) {
507: // we reached the end of a long string,
508: // that was terminated with
509: // (11100000, 00000000, 00000000)
510: break;
511: } else if (((char2 & 0xC0) != 0x80)
512: || ((char3 & 0xC0) != 0x80)) {
513: throw new UTFDataFormatException();
514: } else {
515: str[strlen++] = (char) (((char1 & 0x0F) << 12)
516: | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
517: }
518: } else {
519: throw new UTFDataFormatException();
520: }
521:
522: }
523:
524: // update global on successful read exit.
525: position = pos;
526:
527: return (strlen);
528: }
529:
530: /**
531: * Read a compressed int from the stream.
532: * <p>
533: * Read a compressed int from the stream, which is assumed to have
534: * been written by a call to CompressNumber.writeInt().
535: * <p>
536: * Code from CompressedNumber is inlined here so that these fields can
537: * be read from the array with a minimum of function calls.
538: * <p>
539: * The format of a compressed int is as follows:
540: *
541: * Formats are (with x representing value bits):
542: * <PRE>
543: * 1 Byte- 00xxxxxx val <= 63 (0x3f)
544: * 2 Byte- 01xxxxxx xxxxxxxx val > 63 && <= 16383 (0x3fff)
545: * 4 byte- 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx val > 16383 && <= MAX_INT
546: * </PRE>
547: *
548: * @exception StandardException Standard exception policy.
549: **/
550: public final int readCompressedInt() throws IOException {
551: int pos = position;
552: byte[] data = pageData;
553:
554: try {
555: int value = data[pos++];
556:
557: if ((value & ~0x3f) == 0) {
558: // entire value is stored in this byte, we also know that the
559: // 0x80 bit was not set, so no need to mask off the sign
560: // extension from the byte to int conversion.
561: } else if ((value & 0x80) == 0) {
562: // value stored in 2 bytes. only use low 6 bits from 1st byte.
563:
564: if (SanityManager.DEBUG) {
565: SanityManager.ASSERT((value & 0x40) == 0x40);
566: }
567:
568: // top 8 bits of 2 byte value is stored in this byte, we also
569: // know that the 0x80 bit was not set, so no need to mask off
570: // the sign extension from the 1st byte to int conversion.
571: // Need to mask the byte in data[pos + 1] to account for
572: // possible sign extension.
573:
574: value = (((value & 0x3f) << 8) | (data[pos++] & 0xff));
575: } else {
576: // value stored in 4 bytes. only use low 7 bits from 1st byte.
577:
578: if (SanityManager.DEBUG) {
579: SanityManager.ASSERT((value & 0x80) == 0x80);
580: }
581:
582: // top 8 bits of 4 byte value is stored in this byte, we also
583: // know that the 0x80 bit was set, so need to mask off the
584: // sign extension from the 1st byte to int conversion. Need to
585: // mask the bytes from the next 3 bytes data[pos + 1,2,3] to
586: // account for possible sign extension.
587: //
588:
589: value = ((value & 0x7f) << 24)
590: | ((data[pos++] & 0xff) << 16)
591: | ((data[pos++] & 0xff) << 8)
592: | ((data[pos++] & 0xff));
593: }
594:
595: position = pos;
596:
597: return (value);
598: } catch (java.lang.ArrayIndexOutOfBoundsException ex) {
599: throw new EOFException(); // end of file
600: }
601:
602: }
603:
604: /**
605: * Read a compressed long from the stream.
606: * <p>
607: * Read a compressed long from the stream, which is assumed to have
608: * been written by a call to CompressNumber.writeLong().
609: * <p>
610: * Code from CompressedNumber is inlined here so that these fields can
611: * be read from the array with a minimum of function calls.
612: * <p>
613: * The format of a compressed int is as follows:
614: *
615: * Formats are (with x representing value bits):
616: * <PRE>
617: * value <= 16383 (0x3fff):
618: * 2 byte - 00xxxxxx xxxxxxxx
619: *
620: * value > 16383 && <= 0x3fffffff:
621: * 4 byte - 01xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
622: *
623: * value > 0x3fffffff && <= MAX_LONG:
624: * 8 byte - 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
625: * </PRE>
626: *
627: **/
628: public final long readCompressedLong() throws IOException {
629: try {
630: // copy globals locally, to give compiler chance to optimize.
631: int pos = position;
632: byte[] data = pageData;
633:
634: // int_value tells whether it is 1, 4, or 8 bytes long.
635: int int_value = data[pos++];
636:
637: // build up long value and return it through this variable.
638: long long_value;
639:
640: if ((int_value & ~0x3f) == 0) {
641: // 2 byte representation
642:
643: // 1st byte of value is stored in int_value, we also know that
644: // the 0x80 bit was not set, so no need to mask off the sign
645: // extension from the 1st byte to int conversion.
646: long_value = ((int_value << 8) | (data[pos++] & 0xff));
647: } else if ((int_value & 0x80) == 0) {
648: // value stored in 4 bytes. only use low 6 bits from 1st byte.
649:
650: // Need to mask the bytes from the next 3 bytes
651: // data[pos + 1,2,3] to account for possible sign extension.
652:
653: long_value = ((int_value & 0x3f) << 24)
654: | ((data[pos++] & 0xff) << 16)
655: | ((data[pos++] & 0xff) << 8)
656: | ((data[pos++] & 0xff));
657: } else {
658: // top 7 bits of 4 byte value is stored in int_value, we also
659: // know that the 0x80 bit was set, so need to mask off the
660: // sign extension from the 1st byte to int conversion. Need to
661: // mask the bytes from the next 7 bytes data[pos + 1,2,...] to
662: // account for possible sign extension.
663: //
664:
665: // value stored in 8 bytes. only use low 6 bits from 1st byte.
666: long_value = (((long) (int_value & 0x7f)) << 56)
667: | (((long) (data[pos++] & 0xff)) << 48)
668: | (((long) (data[pos++] & 0xff)) << 40)
669: | (((long) (data[pos++] & 0xff)) << 32)
670: | (((long) (data[pos++] & 0xff)) << 24)
671: | (((long) (data[pos++] & 0xff)) << 16)
672: | (((long) (data[pos++] & 0xff)) << 8)
673: | (((long) (data[pos++] & 0xff)));
674: }
675:
676: position = pos;
677:
678: return (long_value);
679: } catch (java.lang.ArrayIndexOutOfBoundsException ex) {
680: // let java figure out if we went past end of data[] array.
681:
682: throw new EOFException(); // end of file
683: }
684: }
685:
686: public Object readObject() throws ClassNotFoundException,
687: IOException {
688: return oi.readObject();
689: }
690:
691: public String getErrorInfo() {
692: return oi.getErrorInfo();
693: }
694:
695: public Exception getNestedException() {
696: return oi.getNestedException();
697: }
698: }
|