KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > core > LineInput


1 /*
2  * SSL-Explorer
3  *
4  * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */

19             
20
21 //
22
// Modified for use in SSL-Explorer by 3SP. These portions licensed as above,
23
// everything else licensed as below.
24
//
25
//
26

27 // ========================================================================
28
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
29
// ------------------------------------------------------------------------
30
// Licensed under the Apache License, Version 2.0 (the "License");
31
// you may not use this file except in compliance with the License.
32
// You may obtain a copy of the License at
33
// http://www.apache.org/licenses/LICENSE-2.0
34
// Unless required by applicable law or agreed to in writing, software
35
// distributed under the License is distributed on an "AS IS" BASIS,
36
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37
// See the License for the specific language governing permissions and
38
// limitations under the License.
39
// ========================================================================
40
//
41

42 package com.sslexplorer.core;
43
44 import java.io.ByteArrayInputStream JavaDoc;
45 import java.io.FilterInputStream JavaDoc;
46 import java.io.IOException JavaDoc;
47 import java.io.InputStream JavaDoc;
48 import java.io.InputStreamReader JavaDoc;
49 import java.io.UnsupportedEncodingException JavaDoc;
50
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53
54
55 /**
56  * Fast LineInput InputStream.
57  *
58  * This buffered InputStream provides methods for reading lines of bytes. The
59  * lines can be converted to String or character arrays either using the default
60  * encoding or a user supplied encoding.
61  *
62  * Buffering and data copying are highly optimized, making this an ideal class
63  * for protocols that mix character encoding lines with arbitrary byte data (eg
64  * HTTP).
65  *
66  * The buffer size is also the maximum line length in bytes and/or characters.
67  * If the byte length of a line is less than the max, but the character length
68  * is greater, than then trailing characters are lost.
69  *
70  * Line termination is forgiving and accepts CR, LF, CRLF or EOF. Line input
71  * uses the mark/reset mechanism, so any marks set prior to a readLine call are
72  * lost.
73  *
74  * @author Greg Wilkins (gregw)
75  */

76 public class LineInput extends FilterInputStream JavaDoc {
77     private static Log log = LogFactory.getLog(LineInput.class);
78
79     /* ------------------------------------------------------------ */
80     private byte _buf[];
81     private ByteBuffer _byteBuffer;
82     private InputStreamReader JavaDoc _reader;
83     private int _mark = -1; // reset marker
84
private int _pos; // Start marker
85
private int _avail; // Available back marker, may be byte limited
86
private int _contents; // Absolute back marker of buffer
87
private int _byteLimit = -1;
88     private boolean _newByteLimit;
89     private LineBuffer _lineBuffer;
90     private String JavaDoc _encoding;
91     private boolean _eof = false;
92     private boolean _lastCr = false;
93     private boolean _seenCrLf = false;
94
95     private final static int LF = 10;
96     private final static int CR = 13;
97
98     /* ------------------------------------------------------------ */
99     /**
100      * Constructor. Default buffer and maximum line size is 2048.
101      *
102      * @param in The underlying input stream.
103      */

104     public LineInput(InputStream JavaDoc in) {
105         this(in, 0);
106     }
107
108     /* ------------------------------------------------------------ */
109     /**
110      * Constructor.
111      *
112      * @param in The underlying input stream.
113      * @param bufferSize The buffer size and maximum line length.
114      */

115     public LineInput(InputStream JavaDoc in, int bufferSize) {
116         super(in);
117         _mark = -1;
118         if (bufferSize == 0)
119             bufferSize = 8192;
120         _buf = ByteArrayPool.getByteArray(bufferSize);
121         _byteBuffer = new ByteBuffer(_buf);
122         _lineBuffer = new LineBuffer(bufferSize);
123         _reader = new InputStreamReader JavaDoc(_byteBuffer);
124     }
125
126     /* ------------------------------------------------------------ */
127     /**
128      * Constructor.
129      *
130      * @param in The underlying input stream.
131      * @param bufferSize The buffer size and maximum line length.
132      * @param encoding the character encoding to use for readLine methods.
133      * @exception UnsupportedEncodingException
134      */

135     public LineInput(InputStream JavaDoc in, int bufferSize, String JavaDoc encoding) throws UnsupportedEncodingException JavaDoc {
136         super(in);
137         _mark = -1;
138         if (bufferSize == 0)
139             bufferSize = 2048;
140         _buf = ByteArrayPool.getByteArray(bufferSize);
141         _byteBuffer = new ByteBuffer(_buf);
142         _lineBuffer = new LineBuffer(bufferSize);
143         _reader = new InputStreamReader JavaDoc(_byteBuffer, encoding);
144         _encoding = encoding;
145     }
146
147     /* ------------------------------------------------------------ */
148     public InputStream JavaDoc getInputStream() {
149         return in;
150     }
151
152     /* ------------------------------------------------------------ */
153     /**
154      * Set the byte limit. If set, only this number of bytes are read before
155      * EOF.
156      *
157      * @param bytes Limit number of bytes, or -1 for no limit.
158      */

159     public void setByteLimit(int bytes) {
160         _byteLimit = bytes;
161
162         if (bytes >= 0) {
163             _newByteLimit = true;
164             _byteLimit -= _contents - _pos;
165             if (_byteLimit < 0) {
166                 _avail += _byteLimit;
167                 _byteLimit = 0;
168             }
169         } else {
170             _newByteLimit = false;
171             _avail = _contents;
172             _eof = false;
173         }
174     }
175
176     /* ------------------------------------------------------------ */
177     /**
178      * Get the byte limit.
179      *
180      * @return Number of bytes until EOF is returned or -1 for no limit.
181      */

182     public int getByteLimit() {
183         if (_byteLimit < 0)
184             return _byteLimit;
185
186         return _byteLimit + _avail - _pos;
187     }
188
189     /* ------------------------------------------------------------ */
190     /**
191      * Read a line ended by CR, LF or CRLF. The default or supplied encoding is
192      * used to convert bytes to characters.
193      *
194      * @return The line as a String or null for EOF.
195      * @exception IOException
196      */

197     public synchronized String JavaDoc readLine() throws IOException JavaDoc {
198         int len = fillLine(_buf.length);
199
200         if (len < 0)
201             return null;
202
203         String JavaDoc s = null;
204         if (_encoding == null)
205             s = new String JavaDoc(_buf, _mark, len);
206         else {
207             try {
208                 s = new String JavaDoc(_buf, _mark, len, _encoding);
209             } catch (UnsupportedEncodingException JavaDoc e) {
210                 log.warn(e);
211             }
212         }
213         _mark = -1;
214
215         return s;
216     }
217
218     /* ------------------------------------------------------------ */
219     /**
220      * Read a line ended by CR, LF or CRLF. The default or supplied encoding is
221      * used to convert bytes to characters.
222      *
223      * @param c Character buffer to place the line into.
224      * @param off Offset into the buffer.
225      * @param len Maximum length of line.
226      * @return The length of the line or -1 for EOF.
227      * @exception IOException
228      */

229     public int readLine(char[] c, int off, int len) throws IOException JavaDoc {
230         int blen = fillLine(len);
231
232         if (blen < 0)
233             return -1;
234         if (blen == 0)
235             return 0;
236
237         _byteBuffer.setStream(_mark, blen);
238
239         int read = 0;
240         while (read < len && _reader.ready()) {
241             int r = _reader.read(c, off + read, len - read);
242             if (r <= 0)
243                 break;
244             read += r;
245         }
246
247         _mark = -1;
248
249         return read;
250     }
251
252     /* ------------------------------------------------------------ */
253     /**
254      * Read a line ended by CR, LF or CRLF.
255      *
256      * @param b Byte array to place the line into.
257      * @param off Offset into the buffer.
258      * @param len Maximum length of line.
259      * @return The length of the line or -1 for EOF.
260      * @exception IOException
261      */

262     public int readLine(byte[] b, int off, int len) throws IOException JavaDoc {
263         len = fillLine(len);
264
265         if (len < 0)
266             return -1;
267         if (len == 0)
268             return 0;
269
270         System.arraycopy(_buf, _mark, b, off, len);
271         _mark = -1;
272
273         return len;
274     }
275
276     /* ------------------------------------------------------------ */
277     /**
278      * Read a Line ended by CR, LF or CRLF. Read a line into a shared LineBuffer
279      * instance. The LineBuffer is resused between calls and should not be held
280      * by the caller. The default or supplied encoding is used to convert bytes
281      * to characters.
282      *
283      * @return LineBuffer instance or null for EOF.
284      * @exception IOException
285      */

286     public LineBuffer readLineBuffer() throws IOException JavaDoc {
287         return readLineBuffer(_buf.length);
288     }
289
290     /* ------------------------------------------------------------ */
291     /**
292      * Read a Line ended by CR, LF or CRLF. Read a line into a shared LineBuffer
293      * instance. The LineBuffer is resused between calls and should not be held
294      * by the caller. The default or supplied encoding is used to convert bytes
295      * to characters.
296      *
297      * @param len Maximum length of a line, or 0 for default
298      * @return LineBuffer instance or null for EOF.
299      * @exception IOException
300      */

301     public LineBuffer readLineBuffer(int len) throws IOException JavaDoc {
302         len = fillLine(len > 0 ? len : _buf.length);
303
304         if (len < 0)
305             return null;
306
307         if (len == 0) {
308             _lineBuffer.size = 0;
309             return _lineBuffer;
310         }
311
312         _byteBuffer.setStream(_mark, len);
313
314         _lineBuffer.size = 0;
315         int read = 0;
316         while (read < len && _reader.ready()) {
317             int r = _reader.read(_lineBuffer.buffer, read, len - read);
318             if (r <= 0)
319                 break;
320             read += r;
321         }
322         _lineBuffer.size = read;
323         _mark = -1;
324
325         return _lineBuffer;
326     }
327
328     /* ------------------------------------------------------------ */
329     public synchronized int read() throws IOException JavaDoc {
330         int b;
331         if (_pos >= _avail)
332             fill();
333         if (_pos >= _avail)
334             b = -1;
335         else
336             b = _buf[_pos++] & 255;
337
338         return b;
339     }
340
341     /* ------------------------------------------------------------ */
342     public synchronized int read(byte b[], int off, int len) throws IOException JavaDoc {
343         int avail = _avail - _pos;
344         if (avail <= 0) {
345             fill();
346             avail = _avail - _pos;
347         }
348
349         if (avail <= 0)
350             len = -1;
351         else {
352             len = (avail < len) ? avail : len;
353             System.arraycopy(_buf, _pos, b, off, len);
354             _pos += len;
355         }
356
357         return len;
358     }
359
360     /* ------------------------------------------------------------ */
361     public long skip(long n) throws IOException JavaDoc {
362         int avail = _avail - _pos;
363         if (avail <= 0) {
364             fill();
365             avail = _avail - _pos;
366         }
367
368         if (avail <= 0)
369             n = 0;
370         else {
371             n = (avail < n) ? avail : n;
372             _pos += n;
373         }
374
375         return n;
376     }
377
378     /* ------------------------------------------------------------ */
379     public synchronized int available() throws IOException JavaDoc {
380         int in_stream = in.available();
381         if (_byteLimit >= 0 && in_stream > _byteLimit)
382             in_stream = _byteLimit;
383
384         return _avail - _pos + in_stream;
385     }
386
387     /* ------------------------------------------------------------ */
388     public synchronized void mark(int limit) throws IllegalArgumentException JavaDoc {
389         if (limit > _buf.length) {
390             byte[] new_buf = new byte[limit];
391             System.arraycopy(_buf, _pos, new_buf, _pos, _avail - _pos);
392             _buf = new_buf;
393             if (_byteBuffer != null)
394                 _byteBuffer.setBuffer(_buf);
395         }
396         _mark = _pos;
397     }
398
399     /* ------------------------------------------------------------ */
400     public synchronized void reset() throws IOException JavaDoc {
401         if (_mark < 0)
402             throw new IOException JavaDoc("Resetting to invalid mark");
403         _pos = _mark;
404         _mark = -1;
405     }
406
407     /* ------------------------------------------------------------ */
408     public boolean markSupported() {
409         return true;
410     }
411
412     /* ------------------------------------------------------------ */
413     private void fill() throws IOException JavaDoc {
414         // if the mark is in the middle of the buffer
415
if (_mark > 0) {
416             // moved saved bytes to start of buffer
417
int saved = _contents - _mark;
418             System.arraycopy(_buf, _mark, _buf, 0, saved);
419             _pos -= _mark;
420             _avail -= _mark;
421             _contents = saved;
422             _mark = 0;
423         } else if (_mark < 0 && _pos > 0) {
424             // move remaining bytes to start of buffer
425
int saved = _contents - _pos;
426             System.arraycopy(_buf, _pos, _buf, 0, saved);
427             _avail -= _pos;
428             _contents = saved;
429             _pos = 0;
430         } else if (_mark == 0 && _pos > 0 && _contents == _buf.length) {
431             // Discard the mark as we need the space.
432
_mark = -1;
433             fill();
434             return;
435         }
436
437         // Get ready to top up the buffer
438
int n = 0;
439         _eof = false;
440
441         // Handle byte limited EOF
442
if (_byteLimit == 0)
443             _eof = true;
444         // else loop until something is read.
445
else
446             while (!_eof && n == 0 && _buf.length > _contents) {
447                 // try to read as much as will fit.
448
int space = _buf.length - _contents;
449
450                 n = in.read(_buf, _contents, space);
451
452                 if (n <= 0) {
453                     // If no bytes - we could be NBIO, so we want to avoid
454
// a busy loop.
455
if (n == 0) {
456                         // Yield to give a chance for some bytes to turn up
457
Thread.yield();
458
459                         // Do a byte read as that is blocking
460
int b = in.read();
461                         if (b >= 0) {
462                             n = 1;
463                             _buf[_contents++] = (byte) b;
464                         } else
465                             _eof = true;
466                     } else
467                         _eof = true;
468                 } else
469                     _contents += n;
470                 _avail = _contents;
471
472                 // If we have a byte limit
473
if (_byteLimit > 0) {
474                     // adjust the bytes available
475
if (_contents - _pos >= _byteLimit)
476                         _avail = _byteLimit + _pos;
477
478                     if (n > _byteLimit)
479                         _byteLimit = 0;
480                     else if (n >= 0)
481                         _byteLimit -= n;
482                     else if (n == -1)
483                         throw new IOException JavaDoc("Premature EOF");
484                 }
485             }
486
487         // If we have some characters and the last read was a CR and
488
// the first char is a LF, skip it
489
if (_avail - _pos > 0 && _lastCr && _buf[_pos] == LF) {
490             _seenCrLf = true;
491             _pos++;
492             if (_mark >= 0)
493                 _mark++;
494             _lastCr = false;
495
496             // If the byte limit has just been imposed, dont count
497
// LF as content.
498
if (_byteLimit >= 0 && _newByteLimit) {
499                 if (_avail < _contents)
500                     _avail++;
501                 else
502                     _byteLimit++;
503             }
504             // If we ate all that ws filled, fill some more
505
if (_pos == _avail)
506                 fill();
507         }
508         _newByteLimit = false;
509     }
510
511     /* ------------------------------------------------------------ */
512     private int fillLine(int maxLen) throws IOException JavaDoc {
513         _mark = _pos;
514
515         if (_pos >= _avail)
516             fill();
517         if (_pos >= _avail)
518             return -1;
519
520         byte b;
521         boolean cr = _lastCr;
522         boolean lf = false;
523         _lastCr = false;
524         int len = 0;
525
526         LineLoop: while (_pos <= _avail) {
527             // if we have gone past the end of the buffer
528
while (_pos == _avail) {
529                 // If EOF or no more space in the buffer,
530
// return a line.
531
if (_eof || (_mark == 0 && _contents == _buf.length)) {
532                     _lastCr = !_eof && _buf[_avail - 1] == CR;
533
534                     cr = true;
535                     lf = true;
536                     break LineLoop;
537                 }
538
539                 // If we have a CR and no more characters are available
540
if (cr && in.available() == 0 && !_seenCrLf) {
541                     _lastCr = true;
542                     cr = true;
543                     lf = true;
544                     break LineLoop;
545                 } else {
546                     // Else just wait for more...
547
_pos = _mark;
548                     fill();
549                     _pos = len;
550                     cr = false;
551                 }
552             }
553
554             // Get the byte
555
b = _buf[_pos++];
556
557             switch (b) {
558             case LF:
559                 if (cr)
560                     _seenCrLf = true;
561                 lf = true;
562                 break LineLoop;
563
564             case CR:
565                 if (cr) {
566                     // Double CR
567
if (_pos > 1) {
568                         _pos--;
569                         break LineLoop;
570                     }
571                 }
572                 cr = true;
573                 break;
574
575             default:
576                 if (cr) {
577                     if (_pos == 1)
578                         cr = false;
579                     else {
580                         _pos--;
581                         break LineLoop;
582                     }
583                 }
584
585                 len++;
586                 if (len == maxLen) {
587                     // look for EOL
588
if (_mark != 0 && _pos + 2 >= _avail && _avail < _buf.length)
589                         fill();
590
591                     if (_pos < _avail && _buf[_pos] == CR) {
592                         cr = true;
593                         _pos++;
594                     }
595                     if (_pos < _avail && _buf[_pos] == LF) {
596                         lf = true;
597                         _pos++;
598                     }
599
600                     if (!cr && !lf) {
601                         // fake EOL
602
lf = true;
603                         cr = true;
604                     }
605                     break LineLoop;
606                 }
607
608                 break;
609             }
610         }
611
612         if (!cr && !lf && len == 0)
613             len = -1;
614
615         return len;
616     }
617
618     /* ------------------------------------------------------------ */
619     private static class ByteBuffer extends ByteArrayInputStream JavaDoc {
620         ByteBuffer(byte[] buffer) {
621             super(buffer);
622         }
623
624         void setBuffer(byte[] buffer) {
625             buf = buffer;
626         }
627
628         void setStream(int offset, int length) {
629             pos = offset;
630             count = offset + length;
631             mark = -1;
632         }
633     }
634
635     /* ------------------------------------------------------------ */
636     /**
637      * Reusable LineBuffer. Externalized LineBuffer for fast line parsing.
638      */

639     public static class LineBuffer {
640         public char[] buffer;
641         public int size;
642
643         public LineBuffer(int maxLineLength) {
644             buffer = new char[maxLineLength];
645         }
646
647         public String JavaDoc toString() {
648             return new String JavaDoc(buffer, 0, size);
649         }
650     }
651
652     /* ------------------------------------------------------------ */
653     public void destroy() {
654         ByteArrayPool.returnByteArray(_buf);
655         _byteBuffer = null;
656         _reader = null;
657         _lineBuffer = null;
658         _encoding = null;
659     }
660
661 }
662
Popular Tags