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