001
014
015 package com.liferay.portal.kernel.io.unsync;
016
017 import com.liferay.portal.kernel.util.CharPool;
018 import com.liferay.portal.kernel.util.StringBundler;
019
020 import java.io.IOException;
021 import java.io.Reader;
022
023
030 public class UnsyncBufferedReader extends Reader {
031
032 public UnsyncBufferedReader(Reader reader) {
033 this(reader, _DEFAULT_BUFFER_SIZE);
034 }
035
036 public UnsyncBufferedReader(Reader reader, int size) {
037 this.reader = reader;
038 buffer = new char[size];
039 }
040
041 public void close() throws IOException {
042 if (reader != null) {
043 reader.close();
044
045 reader = null;
046 }
047
048 buffer = null;
049 }
050
051 public void mark(int markLimit) throws IOException {
052 if (reader == null) {
053 throw new IOException("Reader is null");
054 }
055
056 this.markLimit = markLimit;
057 markIndex = index;
058 }
059
060 public boolean markSupported() {
061 return true;
062 }
063
064 public int read() throws IOException {
065 if (reader == null) {
066 throw new IOException("Reader is null");
067 }
068
069 if (index >= firstInvalidIndex) {
070 readUnderlyingReader();
071
072 if (index >= firstInvalidIndex) {
073 return -1;
074 }
075 }
076
077 return buffer[index++];
078 }
079
080 public int read(char[] charArray) throws IOException {
081 return read(charArray, 0, charArray.length);
082 }
083
084 public int read(char[] charArray, int offset, int length)
085 throws IOException {
086
087 if (reader == null) {
088 throw new IOException("Reader is null");
089 }
090
091 if (length <= 0) {
092 return 0;
093 }
094
095 int read = 0;
096
097 while (true) {
098 int available = firstInvalidIndex - index;
099
100 if ((available + read) >= length) {
101
102
103
104 int leftSize = length - read;
105
106 System.arraycopy(buffer, index, charArray, read, leftSize);
107
108 index += leftSize;
109
110 return length;
111 }
112
113 if (available <= 0) {
114
115
116
117 readUnderlyingReader();
118
119 available = firstInvalidIndex - index;
120
121 if (available <= 0) {
122
123
124
125 if (read == 0) {
126 return -1;
127 }
128 else {
129 return read;
130 }
131 }
132 }
133 else {
134
135
136
137 System.arraycopy(buffer, index, charArray, read, available);
138
139 index += available;
140 read += available;
141 }
142 }
143 }
144
145 public String readLine() throws IOException {
146 if (reader == null) {
147 throw new IOException("Reader is null");
148 }
149
150 StringBundler sb = null;
151
152 while (true) {
153 if (index >= firstInvalidIndex) {
154 readUnderlyingReader();
155 }
156
157 if (index >= firstInvalidIndex) {
158 if ((sb != null) && (sb.index() > 0)) {
159 return sb.toString();
160 }
161 else {
162 return null;
163 }
164 }
165
166 boolean hasLineBreak = false;
167 char lineEndChar = 0;
168
169 int x = index;
170 int y = index;
171
172 while (y < firstInvalidIndex) {
173 lineEndChar = buffer[y];
174
175 if ((lineEndChar == CharPool.NEW_LINE) ||
176 (lineEndChar == CharPool.RETURN)) {
177
178 hasLineBreak = true;
179
180 break;
181 }
182
183 y++;
184 }
185
186 String line = new String(buffer, x, y - x);
187
188 index = y;
189
190 if (hasLineBreak) {
191 index++;
192
193 if (lineEndChar == CharPool.RETURN) {
194 if ((index < buffer.length) &&
195 (buffer[index] == CharPool.NEW_LINE)) {
196
197 index++;
198 }
199 }
200
201 if (sb == null) {
202 return line;
203 }
204 else {
205 sb.append(line);
206
207 return sb.toString();
208 }
209 }
210
211 if (sb == null) {
212 sb = new StringBundler();
213 }
214
215 sb.append(line);
216 }
217 }
218
219 public boolean ready() throws IOException {
220 if (reader == null) {
221 throw new IOException("Reader is null");
222 }
223
224 return (index < firstInvalidIndex) || reader.ready();
225 }
226
227 public void reset() throws IOException {
228 if (reader == null) {
229 throw new IOException("Reader is null");
230 }
231
232 if (markIndex < 0) {
233 throw new IOException("Resetting to invalid mark");
234 }
235
236 index = markIndex;
237 }
238
239 public long skip(long skip) throws IOException {
240 if (reader == null) {
241 throw new IOException("Reader is null");
242 }
243
244 if (skip <= 0) {
245 return 0;
246 }
247
248 long available = firstInvalidIndex - index;
249
250 if (available > 0) {
251
252
253
254 if (available < skip) {
255 skip = available;
256 }
257 }
258 else {
259
260
261
262 if (markIndex < 0) {
263
264
265
266 skip = reader.skip(skip);
267 }
268 else {
269
270
271
272 readUnderlyingReader();
273
274 available = firstInvalidIndex - index;
275
276 if (available > 0) {
277
278
279
280 if (available < skip) {
281 skip = available;
282 }
283 }
284 }
285 }
286
287 index += skip;
288
289 return skip;
290 }
291
292 protected void readUnderlyingReader() throws IOException {
293 if (markIndex < 0) {
294
295
296
297 index = firstInvalidIndex = 0;
298
299 int number = reader.read(buffer);
300
301 if (number > 0) {
302 firstInvalidIndex = number;
303 }
304
305 return;
306 }
307
308
309
310 if (index >= buffer.length) {
311
312
313
314 if ((firstInvalidIndex - markIndex) > markLimit) {
315
316
317
318 markIndex = -1;
319 index = 0;
320 }
321 else if (markIndex > _MAX_MARK_WASTE_SIZE) {
322
323
324
325
326 int realDataSize = index - markIndex;
327
328 System.arraycopy(
329 buffer, markIndex, buffer, 0, realDataSize);
330
331 markIndex = 0;
332 index = realDataSize;
333 }
334 else {
335
336
337
338
339 int newBufferSize = index << 1;
340
341 if ((newBufferSize - _MAX_MARK_WASTE_SIZE) > markLimit) {
342
343
344
345 newBufferSize = markLimit + _MAX_MARK_WASTE_SIZE;
346 }
347
348 char[] newBuffer = new char[newBufferSize];
349
350 System.arraycopy(buffer, 0, newBuffer, 0, index);
351
352 buffer = newBuffer;
353 }
354 }
355
356
357
358 firstInvalidIndex = index;
359
360 int number = reader.read(buffer, index, buffer.length - index);
361
362 if (number > 0) {
363 firstInvalidIndex += number;
364 }
365 }
366
367 protected char[] buffer;
368 protected int firstInvalidIndex;
369 protected int index;
370 protected int markIndex = -1;
371 protected int markLimit;
372 protected Reader reader;
373
374 private static int _DEFAULT_BUFFER_SIZE = 8192;
375
376 private static int _MAX_MARK_WASTE_SIZE = 4096;
377
378 }