1 16 package org.mortbay.util; 17 18 import java.io.ByteArrayInputStream ; 19 import java.io.FilterInputStream ; 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.InputStreamReader ; 23 import java.io.UnsupportedEncodingException ; 24 25 import org.apache.commons.logging.Log; 26 import org.mortbay.log.LogFactory; 27 28 29 30 52 public class LineInput extends FilterInputStream 53 { 54 private static Log log = LogFactory.getLog(LineInput.class); 55 56 57 private byte _buf[]; 58 private ByteBuffer _byteBuffer; 59 private InputStreamReader _reader; 60 private int _mark=-1; private int _pos; private int _avail; private int _contents; private int _byteLimit=-1; 65 private boolean _newByteLimit; 66 private LineBuffer _lineBuffer; 67 private String _encoding; 68 private boolean _eof=false; 69 private boolean _lastCr=false; 70 private boolean _seenCrLf=false; 71 72 private final static int LF=10; 73 private final static int CR=13; 74 75 76 77 81 public LineInput(InputStream in) 82 { 83 this(in,0); 84 } 85 86 87 91 public LineInput(InputStream in, int bufferSize) 92 { 93 super(in); 94 _mark=-1; 95 if (bufferSize==0) 96 bufferSize=8192; 97 _buf=ByteArrayPool.getByteArray(bufferSize); 98 _byteBuffer=new ByteBuffer(_buf); 99 _lineBuffer=new LineBuffer(bufferSize); 100 101 try 102 { 103 _reader=new InputStreamReader (_byteBuffer,"UTF-8"); 104 } 105 catch (UnsupportedEncodingException e) 106 { 107 _reader=new InputStreamReader (_byteBuffer); 108 } 109 } 110 111 112 118 public LineInput(InputStream in, int bufferSize, String encoding) 119 throws UnsupportedEncodingException 120 { 121 super(in); 122 _mark=-1; 123 if (bufferSize==0) 124 bufferSize=2048; 125 _buf=ByteArrayPool.getByteArray(bufferSize); 126 _byteBuffer=new ByteBuffer(_buf); 127 _lineBuffer=new LineBuffer(bufferSize); 128 _reader=new InputStreamReader (_byteBuffer,encoding); 129 _encoding=encoding; 130 } 131 132 133 public InputStream getInputStream() 134 { 135 return in; 136 } 137 138 139 143 public void setByteLimit(int bytes) 144 { 145 _byteLimit=bytes; 146 147 if (bytes>=0) 148 { 149 _newByteLimit=true; 150 _byteLimit-=_contents-_pos; 151 if (_byteLimit<0) 152 { 153 _avail+=_byteLimit; 154 _byteLimit=0; 155 } 156 } 157 else 158 { 159 _newByteLimit=false; 160 _avail=_contents; 161 _eof=false; 162 } 163 } 164 165 166 167 170 public int getByteLimit() 171 { 172 if (_byteLimit<0) 173 return _byteLimit; 174 175 return _byteLimit+_avail-_pos; 176 } 177 178 179 185 public synchronized String readLine() 186 throws IOException 187 { 188 int len=fillLine(_buf.length); 189 190 if (len<0) 191 return null; 192 193 String s=null; 194 if (_encoding==null) 195 s=new String (_buf,_mark,len); 196 else 197 { 198 try 199 { 200 s=new String (_buf,_mark,len,_encoding); 201 } 202 catch(UnsupportedEncodingException e) 203 { 204 log.warn(LogSupport.EXCEPTION,e); 205 } 206 } 207 _mark=-1; 208 209 return s; 210 } 211 212 213 222 public int readLine(char[] c,int off,int len) 223 throws IOException 224 { 225 int blen=fillLine(len); 226 227 if (blen<0) 228 return -1; 229 if (blen==0) 230 return 0; 231 232 _byteBuffer.setStream(_mark,blen); 233 234 int read=0; 235 while(read<len && _reader.ready()) 236 { 237 int r = _reader.read(c,off+read,len-read); 238 if (r<=0) 239 break; 240 read+=r; 241 } 242 243 _mark=-1; 244 245 return read; 246 } 247 248 249 256 public int readLine(byte[] b,int off,int len) 257 throws IOException 258 { 259 len=fillLine(len); 260 261 if (len<0) 262 return -1; 263 if (len==0) 264 return 0; 265 266 System.arraycopy(_buf,_mark, b, off, len); 267 _mark=-1; 268 269 return len; 270 } 271 272 273 274 282 public LineBuffer readLineBuffer() 283 throws IOException 284 { 285 return readLineBuffer(_buf.length); 286 } 287 288 289 298 public LineBuffer readLineBuffer(int len) 299 throws IOException 300 { 301 len=fillLine(len>0?len:_buf.length); 302 303 if (len<0) 304 return null; 305 306 if (len==0) 307 { 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 { 318 int r = _reader.read(_lineBuffer.buffer, 319 read, 320 len-read); 321 if (r<=0) 322 break; 323 read+=r; 324 } 325 _lineBuffer.size=read; 326 _mark=-1; 327 328 return _lineBuffer; 329 } 330 331 332 public synchronized int read() throws IOException 333 { 334 int b; 335 if (_pos >=_avail) 336 fill(); 337 if (_pos >=_avail) 338 b=-1; 339 else 340 b=_buf[_pos++]&255; 341 342 return b; 343 } 344 345 346 347 public synchronized int read(byte b[], int off, int len) throws IOException 348 { 349 int avail=_avail-_pos; 350 if (avail <=0) 351 { 352 fill(); 353 avail=_avail-_pos; 354 } 355 356 if (avail <=0) 357 len=-1; 358 else 359 { 360 len=(avail < len) ? avail : len; 361 System.arraycopy(_buf,_pos,b,off,len); 362 _pos +=len; 363 } 364 365 return len; 366 } 367 368 369 public long skip(long n) throws IOException 370 { 371 int avail=_avail-_pos; 372 if (avail <=0) 373 { 374 fill(); 375 avail=_avail-_pos; 376 } 377 378 if (avail <=0) 379 n=0; 380 else 381 { 382 n=(avail < n) ? avail : n; 383 _pos +=n; 384 } 385 386 return n; 387 } 388 389 390 391 public synchronized int available() 392 throws IOException 393 { 394 int in_stream=in.available(); 395 if (_byteLimit>=0 && in_stream>_byteLimit) 396 in_stream=_byteLimit; 397 398 return _avail - _pos + in_stream; 399 } 400 401 402 public synchronized void mark(int limit) 403 throws IllegalArgumentException 404 { 405 if (limit>_buf.length) 406 { 407 byte[] new_buf=new byte[limit]; 408 System.arraycopy(_buf,_pos,new_buf,_pos,_avail-_pos); 409 _buf=new_buf; 410 if (_byteBuffer!=null) 411 _byteBuffer.setBuffer(_buf); 412 } 413 _mark=_pos; 414 } 415 416 417 public synchronized void reset() 418 throws IOException 419 { 420 if (_mark < 0) 421 throw new IOException ("Resetting to invalid mark"); 422 _pos=_mark; 423 _mark=-1; 424 } 425 426 427 public boolean markSupported() 428 { 429 return true; 430 } 431 432 433 private void fill() 434 throws IOException 435 { 436 if (_mark > 0) 438 { 439 int saved=_contents - _mark; 441 System.arraycopy(_buf, _mark, _buf, 0, saved); 442 _pos-=_mark; 443 _avail-=_mark; 444 _contents=saved; 445 _mark=0; 446 } 447 else if (_mark<0 && _pos>0) 448 { 449 int saved=_contents-_pos; 451 System.arraycopy(_buf,_pos, _buf, 0, saved); 452 _avail-=_pos; 453 _contents=saved; 454 _pos=0; 455 } 456 else if (_mark==0 && _pos>0 && _contents==_buf.length) 457 { 458 _mark=-1; 460 fill(); 461 return; 462 } 463 464 int n=0; 466 _eof=false; 467 468 if (_byteLimit==0) 470 _eof=true; 471 else while (!_eof && n==0 && _buf.length>_contents) 473 { 474 int space=_buf.length-_contents; 476 477 n=in.read(_buf,_contents,space); 478 479 if (n<=0) 480 { 481 if (n==0) 484 { 485 Thread.yield(); 487 488 int b = in.read(); 490 if (b>=0) 491 { 492 n=1; 493 _buf[_contents++]=(byte)b; 494 } 495 else 496 _eof=true; 497 } 498 else 499 _eof=true; 500 } 501 else 502 _contents+=n; 503 _avail=_contents; 504 505 if (_byteLimit>0) 507 { 508 if (_contents-_pos >=_byteLimit) 510 _avail=_byteLimit+_pos; 511 512 if (n>_byteLimit) 513 _byteLimit=0; 514 else if (n>=0) 515 _byteLimit-=n; 516 else if (n==-1) 517 throw new IOException ("Premature EOF"); 518 } 519 } 520 521 if (_avail-_pos>0 && _lastCr && _buf[_pos]==LF) 524 { 525 _seenCrLf=true; 526 _pos++; 527 if (_mark>=0) 528 _mark++; 529 _lastCr=false; 530 531 if(_byteLimit>=0 && _newByteLimit) 534 { 535 if (_avail<_contents) 536 _avail++; 537 else 538 _byteLimit++; 539 } 540 if (_pos==_avail) 542 fill(); 543 } 544 _newByteLimit=false; 545 } 546 547 548 549 private int fillLine(int maxLen) 550 throws IOException 551 { 552 _mark=_pos; 553 554 if (_pos>=_avail) 555 fill(); 556 if (_pos>=_avail) 557 return -1; 558 559 byte b; 560 boolean cr=_lastCr; 561 boolean lf=false; 562 _lastCr=false; 563 int len=0; 564 565 LineLoop: 566 while (_pos<=_avail) 567 { 568 while (_pos==_avail) 570 { 571 if (_eof || (_mark==0 && _contents==_buf.length)) 574 { 575 _lastCr=!_eof && _buf[_avail-1]==CR; 576 577 cr=true; 578 lf=true; 579 break LineLoop; 580 } 581 582 if (cr && in.available()==0 && !_seenCrLf) 584 { 585 _lastCr=true; 586 cr=true; 587 lf=true; 588 break LineLoop; 589 } 590 else 591 { 592 _pos=_mark; 594 fill(); 595 _pos=len; 596 cr=false; 597 } 598 } 599 600 b=_buf[_pos++]; 602 603 switch(b) 604 { 605 case LF: 606 if (cr) _seenCrLf=true; 607 lf=true; 608 break LineLoop; 609 610 case CR: 611 if (cr) 612 { 613 if (_pos>1) 615 { 616 _pos--; 617 break LineLoop; 618 } 619 } 620 cr=true; 621 break; 622 623 default: 624 if(cr) 625 { 626 if (_pos==1) 627 cr=false; 628 else 629 { 630 _pos--; 631 break LineLoop; 632 } 633 } 634 635 len++; 636 if (len==maxLen) 637 { 638 if (_mark!=0 && _pos+2>=_avail && _avail<_buf.length) 640 fill(); 641 642 if (_pos<_avail && _buf[_pos]==CR) 643 { 644 cr=true; 645 _pos++; 646 } 647 if (_pos<_avail && _buf[_pos]==LF) 648 { 649 lf=true; 650 _pos++; 651 } 652 653 if (!cr && !lf) 654 { 655 lf=true; 657 cr=true; 658 } 659 break LineLoop; 660 } 661 662 break; 663 } 664 } 665 666 if (!cr && !lf && len==0) 667 len=-1; 668 669 return len; 670 } 671 672 673 private static class ByteBuffer extends ByteArrayInputStream 674 { 675 ByteBuffer(byte[] buffer) 676 { 677 super(buffer); 678 } 679 680 void setBuffer(byte[] buffer) 681 { 682 buf=buffer; 683 } 684 685 void setStream(int offset,int length) 686 { 687 pos=offset; 688 count=offset+length; 689 mark=-1; 690 } 691 } 692 693 694 697 public static class LineBuffer 698 { 699 public char[] buffer; 700 public int size; 701 public LineBuffer(int maxLineLength) 702 {buffer=new char[maxLineLength];} 703 704 public String toString(){return new String (buffer,0,size);} 705 } 706 707 708 public void destroy() 709 { 710 ByteArrayPool.returnByteArray(_buf); 711 _byteBuffer=null; 712 _reader=null; 713 _lineBuffer=null; 714 _encoding=null; 715 } 716 717 718 } 719 720 | Popular Tags |