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