1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.io; 20 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.io.OutputStream; 24 import java.nio.charset.Charset; 25 26 import org.eclipse.jetty.util.TypeUtil; 27 import org.eclipse.jetty.util.log.Log; 28 import org.eclipse.jetty.util.log.Logger; 29 30 /** 31 * 32 * 33 */ 34 public abstract class AbstractBuffer implements Buffer 35 { 36 private static final Logger LOG = Log.getLogger(AbstractBuffer.class); 37 38 private final static boolean __boundsChecking = Boolean.getBoolean("org.eclipse.jetty.io.AbstractBuffer.boundsChecking"); 39 40 protected final static String 41 __IMMUTABLE = "IMMUTABLE", 42 __READONLY = "READONLY", 43 __READWRITE = "READWRITE", 44 __VOLATILE = "VOLATILE"; 45 46 protected int _access; 47 protected boolean _volatile; 48 49 protected int _get; 50 protected int _put; 51 protected int _hash; 52 protected int _hashGet; 53 protected int _hashPut; 54 protected int _mark; 55 protected String _string; 56 protected View _view; 57 58 /** 59 * Constructor for BufferView 60 * 61 * @param access 0==IMMUTABLE, 1==READONLY, 2==READWRITE 62 */ AbstractBuffer(int access, boolean isVolatile)63 public AbstractBuffer(int access, boolean isVolatile) 64 { 65 if (access == IMMUTABLE && isVolatile) 66 throw new IllegalArgumentException("IMMUTABLE && VOLATILE"); 67 setMarkIndex(-1); 68 _access = access; 69 _volatile = isVolatile; 70 } 71 72 /* 73 * @see org.eclipse.io.Buffer#toArray() 74 */ asArray()75 public byte[] asArray() 76 { 77 byte[] bytes = new byte[length()]; 78 byte[] array = array(); 79 if (array != null) 80 System.arraycopy(array, getIndex(), bytes, 0, bytes.length); 81 else 82 peek(getIndex(), bytes, 0, length()); 83 return bytes; 84 } 85 duplicate(int access)86 public ByteArrayBuffer duplicate(int access) 87 { 88 Buffer b=this.buffer(); 89 if (this instanceof Buffer.CaseInsensitve || b instanceof Buffer.CaseInsensitve) 90 return new ByteArrayBuffer.CaseInsensitive(asArray(), 0, length(),access); 91 else 92 return new ByteArrayBuffer(asArray(), 0, length(), access); 93 } 94 95 /* 96 * @see org.eclipse.io.Buffer#asNonVolatile() 97 */ asNonVolatileBuffer()98 public Buffer asNonVolatileBuffer() 99 { 100 if (!isVolatile()) return this; 101 return duplicate(_access); 102 } 103 asImmutableBuffer()104 public Buffer asImmutableBuffer() 105 { 106 if (isImmutable()) return this; 107 return duplicate(IMMUTABLE); 108 } 109 110 /* 111 * @see org.eclipse.util.Buffer#asReadOnlyBuffer() 112 */ asReadOnlyBuffer()113 public Buffer asReadOnlyBuffer() 114 { 115 if (isReadOnly()) return this; 116 return new View(this, markIndex(), getIndex(), putIndex(), READONLY); 117 } 118 asMutableBuffer()119 public Buffer asMutableBuffer() 120 { 121 if (!isImmutable()) return this; 122 123 Buffer b=this.buffer(); 124 if (b.isReadOnly()) 125 { 126 return duplicate(READWRITE); 127 } 128 return new View(b, markIndex(), getIndex(), putIndex(), _access); 129 } 130 buffer()131 public Buffer buffer() 132 { 133 return this; 134 } 135 clear()136 public void clear() 137 { 138 setMarkIndex(-1); 139 setGetIndex(0); 140 setPutIndex(0); 141 } 142 compact()143 public void compact() 144 { 145 if (isReadOnly()) throw new IllegalStateException(__READONLY); 146 int s = markIndex() >= 0 ? markIndex() : getIndex(); 147 if (s > 0) 148 { 149 byte array[] = array(); 150 int length = putIndex() - s; 151 if (length > 0) 152 { 153 if (array != null) 154 System.arraycopy(array(), s, array(), 0, length); 155 else 156 poke(0, peek(s, length)); 157 } 158 if (markIndex() > 0) setMarkIndex(markIndex() - s); 159 setGetIndex(getIndex() - s); 160 setPutIndex(putIndex() - s); 161 } 162 } 163 164 @Override equals(Object obj)165 public boolean equals(Object obj) 166 { 167 if (obj==this) 168 return true; 169 170 // reject non buffers; 171 if (obj == null || !(obj instanceof Buffer)) return false; 172 Buffer b = (Buffer) obj; 173 174 if (this instanceof Buffer.CaseInsensitve || b instanceof Buffer.CaseInsensitve) 175 return equalsIgnoreCase(b); 176 177 // reject different lengths 178 if (b.length() != length()) return false; 179 180 // reject AbstractBuffer with different hash value 181 if (_hash != 0 && obj instanceof AbstractBuffer) 182 { 183 AbstractBuffer ab = (AbstractBuffer) obj; 184 if (ab._hash != 0 && _hash != ab._hash) return false; 185 } 186 187 // Nothing for it but to do the hard grind. 188 int get=getIndex(); 189 int bi=b.putIndex(); 190 for (int i = putIndex(); i-->get;) 191 { 192 byte b1 = peek(i); 193 byte b2 = b.peek(--bi); 194 if (b1 != b2) return false; 195 } 196 return true; 197 } 198 equalsIgnoreCase(Buffer b)199 public boolean equalsIgnoreCase(Buffer b) 200 { 201 if (b==this) 202 return true; 203 204 // reject different lengths 205 if (b.length() != length()) return false; 206 207 // reject AbstractBuffer with different hash value 208 if (_hash != 0 && b instanceof AbstractBuffer) 209 { 210 AbstractBuffer ab = (AbstractBuffer) b; 211 if (ab._hash != 0 && _hash != ab._hash) return false; 212 } 213 214 // Nothing for it but to do the hard grind. 215 int get=getIndex(); 216 int bi=b.putIndex(); 217 218 byte[] array = array(); 219 byte[] barray= b.array(); 220 if (array!=null && barray!=null) 221 { 222 for (int i = putIndex(); i-->get;) 223 { 224 byte b1 = array[i]; 225 byte b2 = barray[--bi]; 226 if (b1 != b2) 227 { 228 if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A'); 229 if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A'); 230 if (b1 != b2) return false; 231 } 232 } 233 } 234 else 235 { 236 for (int i = putIndex(); i-->get;) 237 { 238 byte b1 = peek(i); 239 byte b2 = b.peek(--bi); 240 if (b1 != b2) 241 { 242 if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A'); 243 if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A'); 244 if (b1 != b2) return false; 245 } 246 } 247 } 248 return true; 249 } 250 get()251 public byte get() 252 { 253 return peek(_get++); 254 } 255 get(byte[] b, int offset, int length)256 public int get(byte[] b, int offset, int length) 257 { 258 int gi = getIndex(); 259 int l=length(); 260 if (l==0) 261 return -1; 262 263 if (length>l) 264 length=l; 265 266 length = peek(gi, b, offset, length); 267 if (length>0) 268 setGetIndex(gi + length); 269 return length; 270 } 271 get(int length)272 public Buffer get(int length) 273 { 274 int gi = getIndex(); 275 Buffer view = peek(gi, length); 276 setGetIndex(gi + length); 277 return view; 278 } 279 getIndex()280 public final int getIndex() 281 { 282 return _get; 283 } 284 hasContent()285 public boolean hasContent() 286 { 287 return _put > _get; 288 } 289 290 @Override hashCode()291 public int hashCode() 292 { 293 if (_hash == 0 || _hashGet!=_get || _hashPut!=_put) 294 { 295 int get=getIndex(); 296 byte[] array = array(); 297 if (array==null) 298 { 299 for (int i = putIndex(); i-- >get;) 300 { 301 byte b = peek(i); 302 if ('a' <= b && b <= 'z') 303 b = (byte) (b - 'a' + 'A'); 304 _hash = 31 * _hash + b; 305 } 306 } 307 else 308 { 309 for (int i = putIndex(); i-- >get;) 310 { 311 byte b = array[i]; 312 if ('a' <= b && b <= 'z') 313 b = (byte) (b - 'a' + 'A'); 314 _hash = 31 * _hash + b; 315 } 316 } 317 if (_hash == 0) 318 _hash = -1; 319 _hashGet=_get; 320 _hashPut=_put; 321 322 } 323 return _hash; 324 } 325 isImmutable()326 public boolean isImmutable() 327 { 328 return _access <= IMMUTABLE; 329 } 330 isReadOnly()331 public boolean isReadOnly() 332 { 333 return _access <= READONLY; 334 } 335 isVolatile()336 public boolean isVolatile() 337 { 338 return _volatile; 339 } 340 length()341 public int length() 342 { 343 return _put - _get; 344 } 345 mark()346 public void mark() 347 { 348 setMarkIndex(_get - 1); 349 } 350 mark(int offset)351 public void mark(int offset) 352 { 353 setMarkIndex(_get + offset); 354 } 355 markIndex()356 public int markIndex() 357 { 358 return _mark; 359 } 360 peek()361 public byte peek() 362 { 363 return peek(_get); 364 } 365 peek(int index, int length)366 public Buffer peek(int index, int length) 367 { 368 if (_view == null) 369 { 370 _view = new View(this, -1, index, index + length, isReadOnly() ? READONLY : READWRITE); 371 } 372 else 373 { 374 _view.update(this.buffer()); 375 _view.setMarkIndex(-1); 376 _view.setGetIndex(0); 377 _view.setPutIndex(index + length); 378 _view.setGetIndex(index); 379 380 } 381 return _view; 382 } 383 poke(int index, Buffer src)384 public int poke(int index, Buffer src) 385 { 386 _hash=0; 387 /* 388 if (isReadOnly()) 389 throw new IllegalStateException(__READONLY); 390 if (index < 0) 391 throw new IllegalArgumentException("index<0: " + index + "<0"); 392 */ 393 394 int length=src.length(); 395 if (index + length > capacity()) 396 { 397 length=capacity()-index; 398 /* 399 if (length<0) 400 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity()); 401 */ 402 } 403 404 byte[] src_array = src.array(); 405 byte[] dst_array = array(); 406 if (src_array != null && dst_array != null) 407 System.arraycopy(src_array, src.getIndex(), dst_array, index, length); 408 else if (src_array != null) 409 { 410 int s=src.getIndex(); 411 for (int i=0;i<length;i++) 412 poke(index++,src_array[s++]); 413 } 414 else if (dst_array != null) 415 { 416 int s=src.getIndex(); 417 for (int i=0;i<length;i++) 418 dst_array[index++]=src.peek(s++); 419 } 420 else 421 { 422 int s=src.getIndex(); 423 for (int i=0;i<length;i++) 424 poke(index++,src.peek(s++)); 425 } 426 427 return length; 428 } 429 430 poke(int index, byte[] b, int offset, int length)431 public int poke(int index, byte[] b, int offset, int length) 432 { 433 _hash=0; 434 /* 435 if (isReadOnly()) 436 throw new IllegalStateException(__READONLY); 437 if (index < 0) 438 throw new IllegalArgumentException("index<0: " + index + "<0"); 439 */ 440 if (index + length > capacity()) 441 { 442 length=capacity()-index; 443 /* if (length<0) 444 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity()); 445 */ 446 } 447 448 byte[] dst_array = array(); 449 if (dst_array != null) 450 System.arraycopy(b, offset, dst_array, index, length); 451 else 452 { 453 int s=offset; 454 for (int i=0;i<length;i++) 455 poke(index++,b[s++]); 456 } 457 return length; 458 } 459 put(Buffer src)460 public int put(Buffer src) 461 { 462 int pi = putIndex(); 463 int l=poke(pi, src); 464 setPutIndex(pi + l); 465 return l; 466 } 467 put(byte b)468 public void put(byte b) 469 { 470 int pi = putIndex(); 471 poke(pi, b); 472 setPutIndex(pi + 1); 473 } 474 put(byte[] b, int offset, int length)475 public int put(byte[] b, int offset, int length) 476 { 477 int pi = putIndex(); 478 int l = poke(pi, b, offset, length); 479 setPutIndex(pi + l); 480 return l; 481 } 482 put(byte[] b)483 public int put(byte[] b) 484 { 485 int pi = putIndex(); 486 int l = poke(pi, b, 0, b.length); 487 setPutIndex(pi + l); 488 return l; 489 } 490 putIndex()491 public final int putIndex() 492 { 493 return _put; 494 } 495 reset()496 public void reset() 497 { 498 if (markIndex() >= 0) setGetIndex(markIndex()); 499 } 500 rewind()501 public void rewind() 502 { 503 setGetIndex(0); 504 setMarkIndex(-1); 505 } 506 setGetIndex(int getIndex)507 public void setGetIndex(int getIndex) 508 { 509 /* bounds checking 510 if (isImmutable()) 511 throw new IllegalStateException(__IMMUTABLE); 512 if (getIndex < 0) 513 throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0"); 514 if (getIndex > putIndex()) 515 throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex()); 516 */ 517 _get = getIndex; 518 _hash=0; 519 } 520 setMarkIndex(int index)521 public void setMarkIndex(int index) 522 { 523 /* 524 if (index>=0 && isImmutable()) 525 throw new IllegalStateException(__IMMUTABLE); 526 */ 527 _mark = index; 528 } 529 setPutIndex(int putIndex)530 public void setPutIndex(int putIndex) 531 { 532 /* bounds checking 533 if (isImmutable()) 534 throw new IllegalStateException(__IMMUTABLE); 535 if (putIndex > capacity()) 536 throw new IllegalArgumentException("putIndex>capacity: " + putIndex + ">" + capacity()); 537 if (getIndex() > putIndex) 538 throw new IllegalArgumentException("getIndex>putIndex: " + getIndex() + ">" + putIndex); 539 */ 540 _put = putIndex; 541 _hash=0; 542 } 543 skip(int n)544 public int skip(int n) 545 { 546 if (length() < n) n = length(); 547 setGetIndex(getIndex() + n); 548 return n; 549 } 550 slice()551 public Buffer slice() 552 { 553 return peek(getIndex(), length()); 554 } 555 sliceFromMark()556 public Buffer sliceFromMark() 557 { 558 return sliceFromMark(getIndex() - markIndex() - 1); 559 } 560 sliceFromMark(int length)561 public Buffer sliceFromMark(int length) 562 { 563 if (markIndex() < 0) return null; 564 Buffer view = peek(markIndex(), length); 565 setMarkIndex(-1); 566 return view; 567 } 568 space()569 public int space() 570 { 571 return capacity() - _put; 572 } 573 toDetailString()574 public String toDetailString() 575 { 576 StringBuilder buf = new StringBuilder(); 577 buf.append("["); 578 buf.append(super.hashCode()); 579 buf.append(","); 580 buf.append(this.buffer().hashCode()); 581 buf.append(",m="); 582 buf.append(markIndex()); 583 buf.append(",g="); 584 buf.append(getIndex()); 585 buf.append(",p="); 586 buf.append(putIndex()); 587 buf.append(",c="); 588 buf.append(capacity()); 589 buf.append("]={"); 590 if (markIndex() >= 0) 591 { 592 for (int i = markIndex(); i < getIndex(); i++) 593 { 594 byte b = peek(i); 595 TypeUtil.toHex(b,buf); 596 } 597 buf.append("}{"); 598 } 599 int count = 0; 600 for (int i = getIndex(); i < putIndex(); i++) 601 { 602 byte b = peek(i); 603 TypeUtil.toHex(b,buf); 604 if (count++ == 50) 605 { 606 if (putIndex() - i > 20) 607 { 608 buf.append(" ... "); 609 i = putIndex() - 20; 610 } 611 } 612 } 613 buf.append('}'); 614 return buf.toString(); 615 } 616 617 /* ------------------------------------------------------------ */ 618 @Override toString()619 public String toString() 620 { 621 if (isImmutable()) 622 { 623 if (_string == null) 624 _string = new String(asArray(), 0, length()); 625 return _string; 626 } 627 return new String(asArray(), 0, length()); 628 } 629 630 /* ------------------------------------------------------------ */ toString(String charset)631 public String toString(String charset) 632 { 633 try 634 { 635 byte[] bytes=array(); 636 if (bytes!=null) 637 return new String(bytes,getIndex(),length(),charset); 638 return new String(asArray(), 0, length(),charset); 639 640 } 641 catch(Exception e) 642 { 643 LOG.warn(e); 644 return new String(asArray(), 0, length()); 645 } 646 } 647 648 /* ------------------------------------------------------------ */ toString(Charset charset)649 public String toString(Charset charset) 650 { 651 try 652 { 653 byte[] bytes=array(); 654 if (bytes!=null) 655 return new String(bytes,getIndex(),length(),charset); 656 return new String(asArray(), 0, length(),charset); 657 } 658 catch(Exception e) 659 { 660 LOG.warn(e); 661 return new String(asArray(), 0, length()); 662 } 663 } 664 665 /* ------------------------------------------------------------ */ toDebugString()666 public String toDebugString() 667 { 668 return getClass()+"@"+super.hashCode(); 669 } 670 671 /* ------------------------------------------------------------ */ writeTo(OutputStream out)672 public void writeTo(OutputStream out) 673 throws IOException 674 { 675 byte[] array = array(); 676 677 if (array!=null) 678 { 679 out.write(array,getIndex(),length()); 680 } 681 else 682 { 683 int len = this.length(); 684 byte[] buf=new byte[len>1024?1024:len]; 685 int offset=_get; 686 while (len>0) 687 { 688 int l=peek(offset,buf,0,len>buf.length?buf.length:len); 689 out.write(buf,0,l); 690 offset+=l; 691 len-=l; 692 } 693 } 694 clear(); 695 } 696 697 /* ------------------------------------------------------------ */ readFrom(InputStream in,int max)698 public int readFrom(InputStream in,int max) throws IOException 699 { 700 byte[] array = array(); 701 int s=space(); 702 if (s>max) 703 s=max; 704 705 if (array!=null) 706 { 707 int l=in.read(array,_put,s); 708 if (l>0) 709 _put+=l; 710 return l; 711 } 712 else 713 { 714 byte[] buf=new byte[s>1024?1024:s]; 715 int total=0; 716 while (s>0) 717 { 718 int l=in.read(buf,0,buf.length); 719 if (l<0) 720 return total>0?total:-1; 721 int p=put(buf,0,l); 722 assert l==p; 723 s-=l; 724 } 725 return total; 726 } 727 } 728 } 729