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