View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
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       * Constructor for BufferView
59       * 
60       * @param access 0==IMMUTABLE, 1==READONLY, 2==READWRITE
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       * @see org.eclipse.io.Buffer#toArray()
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       * @see org.eclipse.io.Buffer#asNonVolatile()
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      * @see org.eclipse.util.Buffer#asReadOnlyBuffer()
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         // reject non buffers;
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         // reject different lengths
177         if (b.length() != length()) return false;
178 
179         // reject AbstractBuffer with different hash value
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         // Nothing for it but to do the hard grind.
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         // reject different lengths
204         if (b.length() != length()) return false;
205 
206         // reject AbstractBuffer with different hash value
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         // Nothing for it but to do the hard grind.
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         if (isReadOnly()) 
388             throw new IllegalStateException(__READONLY);
389         if (index < 0) 
390             throw new IllegalArgumentException("index<0: " + index + "<0");
391         */
392         
393         int length=src.length();
394         if (index + length > capacity())
395         {
396             length=capacity()-index;
397             /*
398             if (length<0)
399                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
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         if (isReadOnly()) 
435             throw new IllegalStateException(__READONLY);
436         if (index < 0) 
437             throw new IllegalArgumentException("index<0: " + index + "<0");
438         */
439         if (index + length > capacity())
440         {
441             length=capacity()-index;
442             /* if (length<0)
443                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
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         /* bounds checking */
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             /* bounds checking */
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 }