1. /*
  2. * Copyright 2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.util;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.Reader;
  21. /**
  22. * Adapts a <code>Reader</code> as an <code>InputStream</code>.
  23. * Adapted from <CODE>StringInputStream</CODE>.
  24. *
  25. */
  26. public class ReaderInputStream extends InputStream {
  27. /** Source Reader */
  28. private Reader in;
  29. private String encoding = System.getProperty("file.encoding");
  30. private byte[] slack;
  31. private int begin;
  32. /**
  33. * Construct a <CODE>ReaderInputStream</CODE>
  34. * for the specified <CODE>Reader</CODE>.
  35. *
  36. * @param reader <CODE>Reader</CODE>. Must not be <code>null</code>.
  37. */
  38. public ReaderInputStream(Reader reader) {
  39. in = reader;
  40. }
  41. /**
  42. * Construct a <CODE>ReaderInputStream</CODE>
  43. * for the specified <CODE>Reader</CODE>,
  44. * with the specified encoding.
  45. *
  46. * @param reader non-null <CODE>Reader</CODE>.
  47. * @param encoding non-null <CODE>String</CODE> encoding.
  48. */
  49. public ReaderInputStream(Reader reader, String encoding) {
  50. this(reader);
  51. if (encoding == null) {
  52. throw new IllegalArgumentException("encoding must not be null");
  53. } else {
  54. this.encoding = encoding;
  55. }
  56. }
  57. /**
  58. * Reads from the <CODE>Reader</CODE>, returning the same value.
  59. *
  60. * @return the value of the next character in the <CODE>Reader</CODE>.
  61. *
  62. * @exception IOException if the original <code>Reader</code> fails to be read
  63. */
  64. public synchronized int read() throws IOException {
  65. if (in == null) {
  66. throw new IOException("Stream Closed");
  67. }
  68. byte result;
  69. if (slack != null && begin < slack.length) {
  70. result = slack[begin];
  71. if (++begin == slack.length) {
  72. slack = null;
  73. }
  74. } else {
  75. byte[] buf = new byte[1];
  76. if (read(buf, 0, 1) <= 0) {
  77. result = -1;
  78. }
  79. result = buf[0];
  80. }
  81. if (result < -1) {
  82. result+= 256;
  83. }
  84. return result;
  85. }
  86. /**
  87. * Reads from the <code>Reader</code> into a byte array
  88. *
  89. * @param b the byte array to read into
  90. * @param off the offset in the byte array
  91. * @param len the length in the byte array to fill
  92. * @return the actual number read into the byte array, -1 at
  93. * the end of the stream
  94. * @exception IOException if an error occurs
  95. */
  96. public synchronized int read(byte[] b, int off, int len)
  97. throws IOException {
  98. if (in == null) {
  99. throw new IOException("Stream Closed");
  100. }
  101. while (slack == null) {
  102. char[] buf = new char[len]; // might read too much
  103. int n = in.read(buf);
  104. if (n == -1) {
  105. return -1;
  106. }
  107. if (n > 0) {
  108. slack = new String(buf, 0, n).getBytes(encoding);
  109. begin = 0;
  110. }
  111. }
  112. if (len > slack.length - begin) {
  113. len = slack.length - begin;
  114. }
  115. System.arraycopy(slack, begin, b, off, len);
  116. if ((begin += len) >= slack.length) {
  117. slack = null;
  118. }
  119. return len;
  120. }
  121. /**
  122. * Marks the read limit of the StringReader.
  123. *
  124. * @param limit the maximum limit of bytes that can be read before the
  125. * mark position becomes invalid
  126. */
  127. public synchronized void mark(final int limit) {
  128. try {
  129. in.mark(limit);
  130. } catch (IOException ioe) {
  131. throw new RuntimeException(ioe.getMessage());
  132. }
  133. }
  134. /**
  135. * @return the current number of bytes ready for reading
  136. * @exception IOException if an error occurs
  137. */
  138. public synchronized int available() throws IOException {
  139. if (in == null) {
  140. throw new IOException("Stream Closed");
  141. }
  142. if (slack != null) {
  143. return slack.length - begin;
  144. }
  145. if (in.ready()) {
  146. return 1;
  147. } else {
  148. return 0;
  149. }
  150. }
  151. /**
  152. * @return false - mark is not supported
  153. */
  154. public boolean markSupported () {
  155. return false; // would be imprecise
  156. }
  157. /**
  158. * Resets the StringReader.
  159. *
  160. * @exception IOException if the StringReader fails to be reset
  161. */
  162. public synchronized void reset() throws IOException {
  163. if (in == null) {
  164. throw new IOException("Stream Closed");
  165. }
  166. slack = null;
  167. in.reset();
  168. }
  169. /**
  170. * Closes the Stringreader.
  171. *
  172. * @exception IOException if the original StringReader fails to be closed
  173. */
  174. public synchronized void close() throws IOException {
  175. in.close();
  176. slack = null;
  177. in = null;
  178. }
  179. }