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