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