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  import java.io.UnsupportedEncodingException;
21  import java.util.Arrays;
22  
23  /* ------------------------------------------------------------------------------- */
24  /**
25   * @author gregw
26   */
27  public class ByteArrayBuffer extends AbstractBuffer
28  {
29      protected byte[] _bytes;
30  
31      protected ByteArrayBuffer(int access, boolean isVolatile)
32      {
33          super(access, isVolatile);
34      }
35      
36      public ByteArrayBuffer(byte[] bytes)
37      {
38          this(bytes, 0, bytes.length, READWRITE);
39      }
40  
41      public ByteArrayBuffer(byte[] bytes, int index, int length)
42      {
43          this(bytes, index, length, READWRITE);
44      }
45  
46      public ByteArrayBuffer(byte[] bytes, int index, int length, int access)
47      {
48          super(READWRITE, NON_VOLATILE);
49          _bytes = bytes;
50          setPutIndex(index + length);
51          setGetIndex(index);
52          _access = access;
53      }
54  
55      public ByteArrayBuffer(byte[] bytes, int index, int length, int access, boolean isVolatile)
56      {
57          super(READWRITE, isVolatile);
58          _bytes = bytes;
59          setPutIndex(index + length);
60          setGetIndex(index);
61          _access = access;
62      }
63  
64      public ByteArrayBuffer(int size)
65      {
66          this(new byte[size], 0, size, READWRITE);
67          setPutIndex(0);
68      }
69  
70      public ByteArrayBuffer(String value)
71      {
72          super(READWRITE,NON_VOLATILE);
73          _bytes = Portable.getBytes(value);
74          setGetIndex(0);
75          setPutIndex(_bytes.length);
76          _access=IMMUTABLE;
77          _string = value;
78      }
79  
80      public ByteArrayBuffer(String value,String encoding) throws UnsupportedEncodingException
81      {
82          super(READWRITE,NON_VOLATILE);
83          _bytes = value.getBytes(encoding);
84          setGetIndex(0);
85          setPutIndex(_bytes.length);
86          _access=IMMUTABLE;
87          _string = value;
88      }
89  
90      public byte[] array()
91      {
92          return _bytes;
93      }
94  
95      public int capacity()
96      {
97          return _bytes.length;
98      }
99      
100     public void compact()
101     {
102         if (isReadOnly()) 
103             throw new IllegalStateException(__READONLY);
104         int s = markIndex() >= 0 ? markIndex() : getIndex();
105         if (s > 0)
106         {
107             int length = putIndex() - s;
108             if (length > 0)
109             {
110                 Portable.arraycopy(_bytes, s,_bytes, 0, length);
111             }
112             if (markIndex() > 0) setMarkIndex(markIndex() - s);
113             setGetIndex(getIndex() - s);
114             setPutIndex(putIndex() - s);
115         }
116     }
117 
118 
119     public boolean equals(Object obj)
120     {
121         if (obj==this)
122             return true;
123 
124         if (obj == null || !(obj instanceof Buffer)) 
125             return false;
126         
127         if (obj instanceof Buffer.CaseInsensitve)
128             return equalsIgnoreCase((Buffer)obj);
129         
130 
131         Buffer b = (Buffer) obj;
132         
133         // reject different lengths
134         if (b.length() != length()) 
135             return false;
136 
137         // reject AbstractBuffer with different hash value
138         if (_hash != 0 && obj instanceof AbstractBuffer)
139         {
140             AbstractBuffer ab = (AbstractBuffer) obj;
141             if (ab._hash != 0 && _hash != ab._hash) 
142                 return false;
143         }
144 
145         // Nothing for it but to do the hard grind.
146         int get=getIndex();
147         int bi=b.putIndex();
148         for (int i = putIndex(); i-->get;)
149         {
150             byte b1 = _bytes[i];
151             byte b2 = b.peek(--bi);
152             if (b1 != b2) return false;
153         }
154         return true;
155     }
156 
157 
158     public boolean equalsIgnoreCase(Buffer b)
159     {
160         if (b==this)
161             return true;
162         
163         // reject different lengths
164         if (b==null || b.length() != length()) 
165             return false;
166 
167         // reject AbstractBuffer with different hash value
168         if (_hash != 0 && b instanceof AbstractBuffer)
169         {
170             AbstractBuffer ab = (AbstractBuffer) b;
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         byte[] barray=b.array();
178         if (barray==null)
179         {
180             for (int i = putIndex(); i-->get;)
181             {
182                 byte b1 = _bytes[i];
183                 byte b2 = b.peek(--bi);
184                 if (b1 != b2)
185                 {
186                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
187                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
188                     if (b1 != b2) return false;
189                 }
190             }
191         }
192         else
193         {
194             for (int i = putIndex(); i-->get;)
195             {
196                 byte b1 = _bytes[i];
197                 byte b2 = barray[--bi];
198                 if (b1 != b2)
199                 {
200                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
201                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
202                     if (b1 != b2) return false;
203                 }
204             }
205         }
206         return true;
207     }
208 
209     public byte get()
210     {
211         return _bytes[_get++];
212     }
213 
214     public int hashCode()
215     {
216         if (_hash == 0 || _hashGet!=_get || _hashPut!=_put) 
217         {
218             int get=getIndex();
219             for (int i = putIndex(); i-- >get;)
220             {
221                 byte b = _bytes[i];
222                 if ('a' <= b && b <= 'z') 
223                     b = (byte) (b - 'a' + 'A');
224                 _hash = 31 * _hash + b;
225             }
226             if (_hash == 0) 
227                 _hash = -1;
228             _hashGet=_get;
229             _hashPut=_put;
230         }
231         return _hash;
232     }
233     
234     
235     public byte peek(int index)
236     {
237         return _bytes[index];
238     }
239     
240     public int peek(int index, byte[] b, int offset, int length)
241     {
242         int l = length;
243         if (index + l > capacity())
244         {
245             l = capacity() - index;
246             if (l==0)
247                 return -1;
248         }
249         
250         if (l < 0) 
251             return -1;
252         
253         Portable.arraycopy(_bytes, index, b, offset, l);
254         return l;
255     }
256 
257     public void poke(int index, byte b)
258     {
259         /* 
260         if (isReadOnly()) 
261             throw new IllegalStateException(__READONLY);
262         
263         if (index < 0) 
264             throw new IllegalArgumentException("index<0: " + index + "<0");
265         if (index > capacity())
266                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
267         */
268         _bytes[index] = b;
269     }
270     
271     public int poke(int index, Buffer src)
272     {
273         _hash=0;
274         
275         /* 
276         if (isReadOnly()) 
277             throw new IllegalStateException(__READONLY);
278         if (index < 0) 
279             throw new IllegalArgumentException("index<0: " + index + "<0");
280         */
281         
282         int length=src.length();
283         if (index + length > capacity())
284         {
285             length=capacity()-index;
286             /*
287             if (length<0)
288                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
289             */
290         }
291         
292         byte[] src_array = src.array();
293         if (src_array != null)
294             Portable.arraycopy(src_array, src.getIndex(), _bytes, index, length);
295         else if (src_array != null)
296         {
297             int s=src.getIndex();
298             for (int i=0;i<length;i++)
299                 poke(index++,src_array[s++]);
300         }
301         else 
302         {
303             int s=src.getIndex();
304             for (int i=0;i<length;i++)
305                 _bytes[index++]=src.peek(s++);
306         }
307         
308         return length;
309     }
310     
311 
312     public int poke(int index, byte[] b, int offset, int length)
313     {
314         _hash=0;
315         /*
316         if (isReadOnly()) 
317             throw new IllegalStateException(__READONLY);
318         if (index < 0) 
319             throw new IllegalArgumentException("index<0: " + index + "<0");
320         */
321         
322         if (index + length > capacity())
323         {
324             length=capacity()-index;
325             /* if (length<0)
326                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
327             */
328         }
329         
330         Portable.arraycopy(b, offset, _bytes, index, length);
331         
332         return length;
333     }
334 
335     /* ------------------------------------------------------------ */
336     /** Wrap a byte array.
337      * @param b
338      * @param off
339      * @param len
340      */
341     public void wrap(byte[] b, int off, int len)
342     {
343         if (isReadOnly()) throw new IllegalStateException(__READONLY);
344         if (isImmutable()) throw new IllegalStateException(__IMMUTABLE);
345         _bytes=b;
346         clear();
347         setGetIndex(off);
348         setPutIndex(off+len);
349     }
350 
351     /* ------------------------------------------------------------ */
352     /** Wrap a byte array
353      * @param b
354      */
355     public void wrap(byte[] b)
356     {
357         if (isReadOnly()) throw new IllegalStateException(__READONLY);
358         if (isImmutable()) throw new IllegalStateException(__IMMUTABLE);
359         _bytes=b;
360         setGetIndex(0);
361         setPutIndex(b.length);
362     }
363 
364     /* ------------------------------------------------------------ */
365     public void writeTo(OutputStream out)
366         throws IOException
367     {
368         out.write(_bytes,getIndex(),length());
369         clear();
370     }
371     
372     /* ------------------------------------------------------------ */
373     public int readFrom(InputStream in,int max) throws IOException
374     {
375         if (max<0||max>space())
376             max=space();
377         int p = putIndex();
378         
379         int len=0, total=0, available=max;
380         while (total<max) 
381         {
382             len=in.read(_bytes,p,available);
383             if (len<0)
384                 break;
385             else if (len>0)
386             {
387                 p += len;
388                 total += len;
389                 available -= len;
390                 setPutIndex(p);
391             }
392             if (in.available()<=0)
393                 break;
394         }
395         if (len<0 && total==0)
396             return -1;
397         return total;
398     }
399 
400     /* ------------------------------------------------------------ */
401     public int space()
402     {
403         return _bytes.length - _put;
404     }
405 
406     
407     /* ------------------------------------------------------------ */
408     /* ------------------------------------------------------------ */
409     /* ------------------------------------------------------------ */
410     public static class CaseInsensitive extends ByteArrayBuffer implements Buffer.CaseInsensitve
411     {
412         public CaseInsensitive(String s)
413         {
414             super(s);
415         }
416 
417         public CaseInsensitive(byte[] b, int o, int l, int rw)
418         {
419             super(b,o,l,rw);
420         }
421 
422         public boolean equals(Object obj)
423         {
424             return equalsIgnoreCase((Buffer)obj);
425         }
426         
427     }
428 }