001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.kvem.midp.pim;
028:
029: import java.io.ByteArrayOutputStream;
030: import java.io.IOException;
031: import java.io.InputStream;
032:
033: /**
034: * InputStream that supports mark() with an infinite lookahead.
035: *
036: */
037: public class MarkableInputStream extends InputStream {
038: /** Input stream. */
039: private final InputStream in;
040: /** Internal buffered stream. */
041: private ByteArrayOutputStream baos;
042: /** Current buffer. */
043: private byte[] buffer;
044: /** Current index in buffer. */
045: private int bufferIndex;
046:
047: /**
048: * Constructs a markable input stream.
049: * @param in input data
050: */
051: public MarkableInputStream(InputStream in) {
052: this .in = in;
053: }
054:
055: /**
056: * Checks if mark is supported.
057: * @return <code>true</code> if mark is supported
058: */
059: public boolean markSupported() {
060: return true;
061: }
062:
063: /**
064: * This implementation of mark() supports infinite lookahead.
065: *
066: * @param lookahead The value of this parameter is ignored.
067: */
068: public void mark(int lookahead) {
069: baos = new ByteArrayOutputStream();
070: }
071:
072: /**
073: * Reset the line markers.
074: * @throws IOException if an error occurs accessing the
075: * input stream
076: */
077: public void reset() throws IOException {
078: if (baos == null) {
079: throw new IOException("Cannot reset an unmarked stream");
080: }
081: if (baos.size() == 0) {
082: // no data was read since the call to mark()
083: baos = null;
084: } else {
085: buffer = baos.toByteArray();
086: baos = null;
087: bufferIndex = 0;
088: }
089: }
090:
091: /**
092: * Closes the input stream.
093: * @throws IOException if any error occurs
094: */
095: public void close() throws IOException {
096: in.close();
097: baos.close();
098: baos = null;
099: buffer = null;
100: }
101:
102: /**
103: * Reads a byte from the stream.
104: * @return next byte from stream
105: * @throws IOException if an error occurs
106: */
107: public int read() throws IOException {
108: if (buffer != null) {
109: return readFromBuffer();
110: } else {
111: return readFromStream();
112: }
113: }
114:
115: /**
116: * Reads a byte from the internal buffer.
117: * @return next byte from the buffer.
118: */
119: private int readFromBuffer() {
120: int i = buffer[bufferIndex++];
121: if (baos != null) {
122: baos.write(i);
123: }
124: if (bufferIndex == buffer.length) {
125: buffer = null;
126: }
127: return i;
128: }
129:
130: /**
131: * Reads next value from the input stream.
132: * @return next value from stream
133: * @throws IOException if an error occurs
134: */
135: private int readFromStream() throws IOException {
136: int i = in.read();
137: if (i != -1 && baos != null) {
138: baos.write(i);
139: }
140: return i;
141: }
142:
143: /**
144: * Reads next block of bytes from the stream.
145: * @param b buffer to hold data
146: * @param offset in buffer for data read
147: * @param length size of data to read
148: * @return number of bytes read
149: * @throws IOException if an error occurs
150: */
151: public int read(byte[] b, int offset, int length)
152: throws IOException {
153: if (buffer != null) {
154: return readFromBuffer(b, offset, length);
155: } else {
156: return readFromStream(b, offset, length);
157: }
158: }
159:
160: /**
161: * Reads next block of bytes from the internal buffer.
162: * @param b buffer to hold data
163: * @param offset in buffer for data read
164: * @param length size of data to read
165: * @return number of bytes read
166: */
167: private int readFromBuffer(byte[] b, int offset, int length) {
168: int bytesRead = -1;
169: if (length <= buffer.length - bufferIndex) {
170: System.arraycopy(buffer, bufferIndex, b, offset, length);
171: bufferIndex += length;
172: bytesRead = length;
173: } else {
174: int count = buffer.length - bufferIndex;
175: System.arraycopy(buffer, bufferIndex, b, offset, count);
176: buffer = null;
177: bytesRead = count;
178: }
179: if (baos != null) {
180: baos.write(b, offset, bytesRead);
181: }
182: return bytesRead;
183: }
184:
185: /**
186: * Reads next block of bytes from the stream.
187: * @param b buffer to hold data
188: * @param offset in buffer for data read
189: * @param length size of data to read
190: * @return number of bytes read
191: * @throws IOException if an error occurs
192: */
193: private int readFromStream(byte[] b, int offset, int length)
194: throws IOException {
195:
196: int i = in.read(b, offset, length);
197: if (i != -1 && baos != null) {
198: baos.write(b, offset, i);
199: }
200: return i;
201: }
202:
203: /**
204: * Reads next block of bytes from the stream.
205: * @param b buffer to hold data
206: * @return number of bytes read
207: * @throws IOException if an error occurs
208: */
209: public int read(byte[] b) throws IOException {
210: return read(b, 0, b.length);
211: }
212:
213: }
|