View Javadoc

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