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