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