001: /*
002:
003: Derby - Class org.apache.derbyTesting.unitTests.services.MarkedLimitInputStream
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.derbyTesting.unitTests.services;
023:
024: import org.apache.derby.iapi.services.sanity.SanityManager;
025: import java.io.DataInputStream;
026: import java.io.IOException;
027:
028: /**
029: An input stream whose internal data is in blocks, the format of each block is
030: (boolean isLastBlock, int blockLength, sequence of blockLength bytes)
031: All blocks except for the last block must have isLastBlock set to false.
032: The last block must have isLastBlock set to true.
033:
034: This class implements an input stream whose length is limited, yet
035: the creator (writer) of the stream does not need to know the entire length
036: before creating it.
037: */
038:
039: public class MarkedLimitInputStream extends
040: org.apache.derby.iapi.services.io.LimitInputStream {
041: protected boolean isLastBlock;
042: protected int blockLength;
043:
044: public MarkedLimitInputStream(DataInputStream in)
045: throws IOException {
046: super (in);
047: start();
048: }
049:
050: private void start() throws IOException {
051: isLastBlock = ((DataInputStream) in).readBoolean();
052: blockLength = ((DataInputStream) in).readInt();
053:
054: if (SanityManager.DEBUG) {
055: if (!isLastBlock) {
056: SanityManager.ASSERT(blockLength > 0);
057: } else {
058: SanityManager.ASSERT(blockLength >= 0, "blockLength "
059: + blockLength + " is negative");
060: }
061: }
062: setLimit(blockLength);
063:
064: }
065:
066: public int read() throws IOException {
067: int i = super .read();
068: if (i == -1) {
069: if (isLastBlock) {
070: return -1;
071: } else {
072: start();
073: return this .read();
074: }
075: } else {
076: return i;
077: }
078: }
079:
080: public int read(byte b[], int off, int len) throws IOException {
081: if (isLastBlock) {
082: // get as many bytes as we can, superclass may return less
083: // bytes than we asked for without good reason
084: int m = 0;
085: while (m < len) {
086: int count = super .read(b, off + m, len - m);
087: if (count < 0) {
088: break;
089: }
090: m += count;
091: }
092: return m;
093: }
094:
095: // read until either get back all the bytes we asked for
096: // or until we get -1
097: int n = 0;
098: while (n < len) {
099: int count = super .read(b, off + n, len - n);
100: if (count < 0) {
101: break;
102: }
103: n += count;
104: }
105:
106: if (SanityManager.DEBUG) {
107: SanityManager.ASSERT(n <= len);
108: }
109: if (n == len) {
110: return n;
111: }
112:
113: // n < len, we didn't finish yet
114: // init next block
115: start();
116: // read rest
117: if (n < 0) {
118: return this .read(b, off, len);
119: }
120:
121: return n + this .read(b, off + n, len - n);
122: }
123:
124: public long skip(long count) throws IOException {
125: if (isLastBlock) {
126: return super .skip(count);
127: }
128:
129: // long n = super.skip(count);
130: // read until either skip all the bytes we asked to
131: // or until we get a result which is <= 0
132: long n = 0;
133: while (n < count) {
134: long c = super .skip(count - n);
135: if (c <= 0) {
136: break;
137: }
138: n += c;
139: }
140:
141: if (SanityManager.DEBUG) {
142: SanityManager.ASSERT(n <= count);
143: }
144: if (n == count) {
145: return n;
146: }
147: // if n < count, we didn't finish skipping yet
148: // init next block
149: start();
150: // read rest
151: if (n < 0) {
152: return this.skip(count);
153: }
154: return n + this.skip(count - n);
155: }
156:
157: }
|