View Javadoc

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