001
014
015 package com.liferay.portal.kernel.io;
016
017 import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
018 import com.liferay.portal.kernel.util.StringPool;
019
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.io.Reader;
023
024 import java.nio.ByteBuffer;
025 import java.nio.CharBuffer;
026 import java.nio.charset.CharsetEncoder;
027
028
031 public class ReaderInputStream extends InputStream {
032
033 public ReaderInputStream(Reader reader) {
034 this(
035 reader, StringPool.UTF8, _DEFAULT_INTPUT_BUFFER_SIZE,
036 _DEFAULT_OUTPUT_BUFFER_SIZE);
037 }
038
039 public ReaderInputStream(Reader reader, String charsetName) {
040 this(
041 reader, charsetName, _DEFAULT_INTPUT_BUFFER_SIZE,
042 _DEFAULT_OUTPUT_BUFFER_SIZE);
043 }
044
045 public ReaderInputStream(
046 Reader reader, String charsetName, int inputBufferSize,
047 int outputBufferSize) {
048
049 _reader = reader;
050 _charsetName = charsetName;
051
052 if (inputBufferSize <= 0) {
053 throw new IllegalArgumentException(
054 "Input buffer size " + inputBufferSize +
055 " must be a positive number");
056 }
057
058 _inputBuffer = CharBuffer.allocate(inputBufferSize);
059
060 _charsetEncoder = CharsetEncoderUtil.getCharsetEncoder(charsetName);
061
062 _maxBytesPerChar = (int)Math.ceil(_charsetEncoder.maxBytesPerChar());
063
064 if (outputBufferSize < _maxBytesPerChar) {
065 throw new IllegalArgumentException(
066 "Output buffer size " + outputBufferSize + " is less than " +
067 _maxBytesPerChar);
068 }
069
070 _outputBuffer = ByteBuffer.allocate(outputBufferSize);
071
072 _outputBuffer.flip();
073 }
074
075 @Override
076 public int available() {
077 return _outputBuffer.remaining() + _inputBuffer.position();
078 }
079
080 @Override
081 public void close() throws IOException {
082 if (_inputBuffer != null) {
083 _inputBuffer.clear();
084
085 _inputBuffer = null;
086 }
087
088 if (_outputBuffer != null) {
089 _outputBuffer.clear();
090
091 _outputBuffer = null;
092 }
093
094 _reader.close();
095 }
096
097 public String getEncoding() {
098 return _charsetName;
099 }
100
101 @Override
102 public int read() throws IOException {
103 byte[] bytes = new byte[1];
104
105 int result = read(bytes, 0, 1);
106
107 if (result == 1) {
108 return bytes[0];
109 }
110 else {
111 return -1;
112 }
113 }
114
115 @Override
116 public int read(byte[] bytes) throws IOException {
117 return read(bytes, 0, bytes.length);
118 }
119
120 @Override
121 public int read(byte[] bytes, int offset, int length) throws IOException {
122 if (bytes == null) {
123 throw new NullPointerException();
124 }
125 else if ((offset < 0) || (length < 0) ||
126 (length > (bytes.length - offset))) {
127
128 throw new IndexOutOfBoundsException();
129 }
130 else if (length == 0) {
131 return 0;
132 }
133
134 int originalLength = length;
135
136 while (length > 0) {
137 int blockSize = Math.min(_outputBuffer.remaining(), length);
138
139 if (blockSize > 0) {
140 _outputBuffer.get(bytes, offset, blockSize);
141
142 length -= blockSize;
143 offset += blockSize;
144
145 if (length == 0) {
146 break;
147 }
148 }
149
150 int inputPosition = _inputBuffer.position();
151
152 int result = _reader.read(
153 _inputBuffer.array(), inputPosition, _inputBuffer.remaining());
154
155 if (result != -1) {
156 _inputBuffer.position(inputPosition + result);
157 }
158
159 _inputBuffer.flip();
160
161 int inputRemaining = _inputBuffer.remaining();
162
163 if (inputRemaining <= 0) {
164 break;
165 }
166
167 if ((inputRemaining * _maxBytesPerChar) < length) {
168 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, offset, length);
169
170 _charsetEncoder.encode(_inputBuffer, byteBuffer, true);
171
172 int outputRemaining = byteBuffer.remaining();
173
174 offset += length - outputRemaining;
175 length = outputRemaining;
176 }
177 else {
178 _outputBuffer.clear();
179
180 _charsetEncoder.encode(_inputBuffer, _outputBuffer, true);
181
182 _outputBuffer.flip();
183 }
184
185 _inputBuffer.compact();
186 }
187
188 int result = originalLength - length;
189
190 if (result == 0) {
191 return -1;
192 }
193
194 return result;
195 }
196
197 @Override
198 public long skip(long length) throws IOException {
199 if (length < 0) {
200 throw new IllegalArgumentException();
201 }
202
203 long originalLength = length;
204
205 while (length > 0) {
206 int blockSize = (int)Math.min(_outputBuffer.remaining(), length);
207
208 if (blockSize > 0) {
209 _outputBuffer.position(_outputBuffer.position() + blockSize);
210
211 length -= blockSize;
212
213 if (length == 0) {
214 break;
215 }
216 }
217
218 int inputPosition = _inputBuffer.position();
219
220 int result = _reader.read(
221 _inputBuffer.array(), inputPosition, _inputBuffer.remaining());
222
223 if (result != -1) {
224 _inputBuffer.position(inputPosition + result);
225 }
226
227 _inputBuffer.flip();
228
229 if (_inputBuffer.remaining() <= 0) {
230 break;
231 }
232
233 _outputBuffer.clear();
234
235 _charsetEncoder.encode(_inputBuffer, _outputBuffer, true);
236
237 _outputBuffer.flip();
238
239 _inputBuffer.compact();
240 }
241
242 return originalLength - length;
243 }
244
245 private static final int _DEFAULT_INTPUT_BUFFER_SIZE = 128;
246
247 private static final int _DEFAULT_OUTPUT_BUFFER_SIZE = 1024;
248
249 private CharsetEncoder _charsetEncoder;
250 private String _charsetName;
251 private CharBuffer _inputBuffer;
252 private int _maxBytesPerChar;
253 private ByteBuffer _outputBuffer;
254 private Reader _reader;
255
256 }