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
505
506
507
508
509
510
511 _get = getIndex;
512 _hash=0;
513 }
514
515 public void setMarkIndex(int index)
516 {
517
518
519
520
521 _mark = index;
522 }
523
524 public void setPutIndex(int putIndex)
525 {
526
527
528
529
530
531
532
533
534 _put = putIndex;
535 _hash=0;
536 }
537
538 public int skip(int n)
539 {
540 if (length() < n) n = length();
541 setGetIndex(getIndex() + n);
542 return n;
543 }
544
545 public Buffer slice()
546 {
547 return peek(getIndex(), length());
548 }
549
550 public Buffer sliceFromMark()
551 {
552 return sliceFromMark(getIndex() - markIndex() - 1);
553 }
554
555 public Buffer sliceFromMark(int length)
556 {
557 if (markIndex() < 0) return null;
558 Buffer view = peek(markIndex(), length);
559 setMarkIndex(-1);
560 return view;
561 }
562
563 public int space()
564 {
565 return capacity() - _put;
566 }
567
568 public String toDetailString()
569 {
570 StringBuilder buf = new StringBuilder();
571 buf.append("[");
572 buf.append(super.hashCode());
573 buf.append(",");
574 buf.append(this.buffer().hashCode());
575 buf.append(",m=");
576 buf.append(markIndex());
577 buf.append(",g=");
578 buf.append(getIndex());
579 buf.append(",p=");
580 buf.append(putIndex());
581 buf.append(",c=");
582 buf.append(capacity());
583 buf.append("]={");
584 if (markIndex() >= 0)
585 {
586 for (int i = markIndex(); i < getIndex(); i++)
587 {
588 byte b = peek(i);
589 TypeUtil.toHex(b,buf);
590 }
591 buf.append("}{");
592 }
593 int count = 0;
594 for (int i = getIndex(); i < putIndex(); i++)
595 {
596 byte b = peek(i);
597 TypeUtil.toHex(b,buf);
598 if (count++ == 50)
599 {
600 if (putIndex() - i > 20)
601 {
602 buf.append(" ... ");
603 i = putIndex() - 20;
604 }
605 }
606 }
607 buf.append('}');
608 return buf.toString();
609 }
610
611
612 @Override
613 public String toString()
614 {
615 if (isImmutable())
616 {
617 if (_string == null)
618 _string = new String(asArray(), 0, length());
619 return _string;
620 }
621 return new String(asArray(), 0, length());
622 }
623
624
625 public String toString(String charset)
626 {
627 try
628 {
629 byte[] bytes=array();
630 if (bytes!=null)
631 return new String(bytes,getIndex(),length(),charset);
632 return new String(asArray(), 0, length(),charset);
633
634 }
635 catch(Exception e)
636 {
637 LOG.warn(e);
638 return new String(asArray(), 0, length());
639 }
640 }
641
642
643 public String toDebugString()
644 {
645 return getClass()+"@"+super.hashCode();
646 }
647
648
649 public void writeTo(OutputStream out)
650 throws IOException
651 {
652 byte[] array = array();
653
654 if (array!=null)
655 {
656 out.write(array,getIndex(),length());
657 }
658 else
659 {
660 int len = this.length();
661 byte[] buf=new byte[len>1024?1024:len];
662 int offset=_get;
663 while (len>0)
664 {
665 int l=peek(offset,buf,0,len>buf.length?buf.length:len);
666 out.write(buf,0,l);
667 offset+=l;
668 len-=l;
669 }
670 }
671 clear();
672 }
673
674
675 public int readFrom(InputStream in,int max) throws IOException
676 {
677 byte[] array = array();
678 int s=space();
679 if (s>max)
680 s=max;
681
682 if (array!=null)
683 {
684 int l=in.read(array,_put,s);
685 if (l>0)
686 _put+=l;
687 return l;
688 }
689 else
690 {
691 byte[] buf=new byte[s>1024?1024:s];
692 int total=0;
693 while (s>0)
694 {
695 int l=in.read(buf,0,buf.length);
696 if (l<0)
697 return total>0?total:-1;
698 int p=put(buf,0,l);
699 assert l==p;
700 s-=l;
701 }
702 return total;
703 }
704 }
705 }