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