001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.util;
019:
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.Reader;
023:
024: /**
025: * Adapts a <code>Reader</code> as an <code>InputStream</code>.
026: * Adapted from <code>StringInputStream</code>.
027: *
028: */
029: public class ReaderInputStream extends InputStream {
030:
031: /** Source Reader */
032: private Reader in;
033:
034: private String encoding = System.getProperty("file.encoding");
035:
036: private byte[] slack;
037:
038: private int begin;
039:
040: /**
041: * Construct a <code>ReaderInputStream</code>
042: * for the specified <code>Reader</code>.
043: *
044: * @param reader <code>Reader</code>. Must not be <code>null</code>.
045: */
046: public ReaderInputStream(Reader reader) {
047: in = reader;
048: }
049:
050: /**
051: * Construct a <code>ReaderInputStream</code>
052: * for the specified <code>Reader</code>,
053: * with the specified encoding.
054: *
055: * @param reader non-null <code>Reader</code>.
056: * @param encoding non-null <code>String</code> encoding.
057: */
058: public ReaderInputStream(Reader reader, String encoding) {
059: this (reader);
060: if (encoding == null) {
061: throw new IllegalArgumentException(
062: "encoding must not be null");
063: } else {
064: this .encoding = encoding;
065: }
066: }
067:
068: /**
069: * Reads from the <code>Reader</code>, returning the same value.
070: *
071: * @return the value of the next character in the <code>Reader</code>.
072: *
073: * @exception IOException if the original <code>Reader</code> fails to be read
074: */
075: public synchronized int read() throws IOException {
076: if (in == null) {
077: throw new IOException("Stream Closed");
078: }
079:
080: byte result;
081: if (slack != null && begin < slack.length) {
082: result = slack[begin];
083: if (++begin == slack.length) {
084: slack = null;
085: }
086: } else {
087: byte[] buf = new byte[1];
088: if (read(buf, 0, 1) <= 0) {
089: return -1;
090: } else {
091: result = buf[0];
092: }
093: }
094:
095: return result & 0xFF;
096: }
097:
098: /**
099: * Reads from the <code>Reader</code> into a byte array
100: *
101: * @param b the byte array to read into
102: * @param off the offset in the byte array
103: * @param len the length in the byte array to fill
104: * @return the actual number read into the byte array, -1 at
105: * the end of the stream
106: * @exception IOException if an error occurs
107: */
108: public synchronized int read(byte[] b, int off, int len)
109: throws IOException {
110: if (in == null) {
111: throw new IOException("Stream Closed");
112: }
113: if (len == 0) {
114: return 0;
115: }
116: while (slack == null) {
117: char[] buf = new char[len]; // might read too much
118: int n = in.read(buf);
119: if (n == -1) {
120: return -1;
121: }
122: if (n > 0) {
123: slack = new String(buf, 0, n).getBytes(encoding);
124: begin = 0;
125: }
126: }
127:
128: if (len > slack.length - begin) {
129: len = slack.length - begin;
130: }
131:
132: System.arraycopy(slack, begin, b, off, len);
133:
134: if ((begin += len) >= slack.length) {
135: slack = null;
136: }
137:
138: return len;
139: }
140:
141: /**
142: * Marks the read limit of the StringReader.
143: *
144: * @param limit the maximum limit of bytes that can be read before the
145: * mark position becomes invalid
146: */
147: public synchronized void mark(final int limit) {
148: try {
149: in.mark(limit);
150: } catch (IOException ioe) {
151: throw new RuntimeException(ioe.getMessage());
152: }
153: }
154:
155: /**
156: * @return the current number of bytes ready for reading
157: * @exception IOException if an error occurs
158: */
159: public synchronized int available() throws IOException {
160: if (in == null) {
161: throw new IOException("Stream Closed");
162: }
163: if (slack != null) {
164: return slack.length - begin;
165: }
166: if (in.ready()) {
167: return 1;
168: } else {
169: return 0;
170: }
171: }
172:
173: /**
174: * @return false - mark is not supported
175: */
176: public boolean markSupported() {
177: return false; // would be imprecise
178: }
179:
180: /**
181: * Resets the StringReader.
182: *
183: * @exception IOException if the StringReader fails to be reset
184: */
185: public synchronized void reset() throws IOException {
186: if (in == null) {
187: throw new IOException("Stream Closed");
188: }
189: slack = null;
190: in.reset();
191: }
192:
193: /**
194: * Closes the Stringreader.
195: *
196: * @exception IOException if the original StringReader fails to be closed
197: */
198: public synchronized void close() throws IOException {
199: if (in != null) {
200: in.close();
201: slack = null;
202: in = null;
203: }
204: }
205: }
|