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  import java.io.UnsupportedEncodingException;
20  
21  import org.eclipse.jetty.util.StringUtil;
22  
23  /* ------------------------------------------------------------------------------- */
24  /**
25   * 
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 = StringUtil.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     @Override
101     public void compact()
102     {
103         if (isReadOnly()) 
104             throw new IllegalStateException(__READONLY);
105         int s = markIndex() >= 0 ? markIndex() : getIndex();
106         if (s > 0)
107         {
108             int length = putIndex() - s;
109             if (length > 0)
110             {
111                 System.arraycopy(_bytes, s,_bytes, 0, length);
112             }
113             if (markIndex() > 0) setMarkIndex(markIndex() - s);
114             setGetIndex(getIndex() - s);
115             setPutIndex(putIndex() - s);
116         }
117     }
118 
119 
120     @Override
121     public boolean equals(Object obj)
122     {
123         if (obj==this)
124             return true;
125 
126         if (obj == null || !(obj instanceof Buffer)) 
127             return false;
128         
129         if (obj instanceof Buffer.CaseInsensitve)
130             return equalsIgnoreCase((Buffer)obj);
131         
132 
133         Buffer b = (Buffer) obj;
134         
135         // reject different lengths
136         if (b.length() != length()) 
137             return false;
138 
139         // reject AbstractBuffer with different hash value
140         if (_hash != 0 && obj instanceof AbstractBuffer)
141         {
142             AbstractBuffer ab = (AbstractBuffer) obj;
143             if (ab._hash != 0 && _hash != ab._hash) 
144                 return false;
145         }
146 
147         // Nothing for it but to do the hard grind.
148         int get=getIndex();
149         int bi=b.putIndex();
150         for (int i = putIndex(); i-->get;)
151         {
152             byte b1 = _bytes[i];
153             byte b2 = b.peek(--bi);
154             if (b1 != b2) return false;
155         }
156         return true;
157     }
158 
159 
160     @Override
161     public boolean equalsIgnoreCase(Buffer b)
162     {
163         if (b==this)
164             return true;
165         
166         // reject different lengths
167         if (b==null || b.length() != length()) 
168             return false;
169 
170         // reject AbstractBuffer with different hash value
171         if (_hash != 0 && b instanceof AbstractBuffer)
172         {
173             AbstractBuffer ab = (AbstractBuffer) b;
174             if (ab._hash != 0 && _hash != ab._hash) return false;
175         }
176 
177         // Nothing for it but to do the hard grind.
178         int get=getIndex();
179         int bi=b.putIndex();
180         byte[] barray=b.array();
181         if (barray==null)
182         {
183             for (int i = putIndex(); i-->get;)
184             {
185                 byte b1 = _bytes[i];
186                 byte b2 = b.peek(--bi);
187                 if (b1 != b2)
188                 {
189                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
190                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
191                     if (b1 != b2) return false;
192                 }
193             }
194         }
195         else
196         {
197             for (int i = putIndex(); i-->get;)
198             {
199                 byte b1 = _bytes[i];
200                 byte b2 = barray[--bi];
201                 if (b1 != b2)
202                 {
203                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
204                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
205                     if (b1 != b2) return false;
206                 }
207             }
208         }
209         return true;
210     }
211 
212     @Override
213     public byte get()
214     {
215         return _bytes[_get++];
216     }
217 
218     @Override
219     public int hashCode()
220     {
221         if (_hash == 0 || _hashGet!=_get || _hashPut!=_put) 
222         {
223             int get=getIndex();
224             for (int i = putIndex(); i-- >get;)
225             {
226                 byte b = _bytes[i];
227                 if ('a' <= b && b <= 'z') 
228                     b = (byte) (b - 'a' + 'A');
229                 _hash = 31 * _hash + b;
230             }
231             if (_hash == 0) 
232                 _hash = -1;
233             _hashGet=_get;
234             _hashPut=_put;
235         }
236         return _hash;
237     }
238     
239     
240     public byte peek(int index)
241     {
242         return _bytes[index];
243     }
244     
245     public int peek(int index, byte[] b, int offset, int length)
246     {
247         int l = length;
248         if (index + l > capacity())
249         {
250             l = capacity() - index;
251             if (l==0)
252                 return -1;
253         }
254         
255         if (l < 0) 
256             return -1;
257         
258         System.arraycopy(_bytes, index, b, offset, l);
259         return l;
260     }
261 
262     public void poke(int index, byte b)
263     {
264         /* 
265         if (isReadOnly()) 
266             throw new IllegalStateException(__READONLY);
267         
268         if (index < 0) 
269             throw new IllegalArgumentException("index<0: " + index + "<0");
270         if (index > capacity())
271                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
272         */
273         _bytes[index] = b;
274     }
275     
276     @Override
277     public int poke(int index, Buffer src)
278     {
279         _hash=0;
280         
281         /* 
282         if (isReadOnly()) 
283             throw new IllegalStateException(__READONLY);
284         if (index < 0) 
285             throw new IllegalArgumentException("index<0: " + index + "<0");
286         */
287         
288         int length=src.length();
289         if (index + length > capacity())
290         {
291             length=capacity()-index;
292             /*
293             if (length<0)
294                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
295             */
296         }
297         
298         byte[] src_array = src.array();
299         if (src_array != null)
300             System.arraycopy(src_array, src.getIndex(), _bytes, index, length);
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     @Override
313     public int poke(int index, byte[] b, int offset, int length)
314     {
315         _hash=0;
316         /*
317         if (isReadOnly()) 
318             throw new IllegalStateException(__READONLY);
319         if (index < 0) 
320             throw new IllegalArgumentException("index<0: " + index + "<0");
321         */
322         
323         if (index + length > capacity())
324         {
325             length=capacity()-index;
326             /* if (length<0)
327                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
328             */
329         }
330         
331         System.arraycopy(b, offset, _bytes, index, length);
332         
333         return length;
334     }
335 
336     /* ------------------------------------------------------------ */
337     /** Wrap a byte array.
338      * @param b
339      * @param off
340      * @param len
341      */
342     public void wrap(byte[] b, int off, int len)
343     {
344         if (b==null)
345             throw new IllegalArgumentException();
346         if (isReadOnly()) throw new IllegalStateException(__READONLY);
347         if (isImmutable()) throw new IllegalStateException(__IMMUTABLE);
348         _bytes=b;
349         clear();
350         setGetIndex(off);
351         setPutIndex(off+len);
352     }
353 
354     /* ------------------------------------------------------------ */
355     /** Wrap a byte array
356      * @param b
357      */
358     public void wrap(byte[] b)
359     {
360         if (isReadOnly()) throw new IllegalStateException(__READONLY);
361         if (isImmutable()) throw new IllegalStateException(__IMMUTABLE);
362         _bytes=b;
363         setGetIndex(0);
364         setPutIndex(b.length);
365     }
366 
367     /* ------------------------------------------------------------ */
368     @Override
369     public void writeTo(OutputStream out)
370         throws IOException
371     {
372         out.write(_bytes,getIndex(),length());
373         if (!isImmutable())
374             clear();
375     }
376     
377     /* ------------------------------------------------------------ */
378     @Override
379     public int readFrom(InputStream in,int max) throws IOException
380     {
381         if (max<0||max>space())
382             max=space();
383         int p = putIndex();
384         
385         int len=0, total=0, available=max;
386         while (total<max) 
387         {
388             len=in.read(_bytes,p,available);
389             if (len<0)
390                 break;
391             else if (len>0)
392             {
393                 p += len;
394                 total += len;
395                 available -= len;
396                 setPutIndex(p);
397             }
398             if (in.available()<=0)
399                 break;
400         }
401         if (len<0 && total==0)
402             return -1;
403         return total;
404     }
405 
406     /* ------------------------------------------------------------ */
407     @Override
408     public int space()
409     {
410         return _bytes.length - _put;
411     }
412 
413     
414     /* ------------------------------------------------------------ */
415     /* ------------------------------------------------------------ */
416     /* ------------------------------------------------------------ */
417     public static class CaseInsensitive extends ByteArrayBuffer implements Buffer.CaseInsensitve
418     {
419         public CaseInsensitive(String s)
420         {
421             super(s);
422         }
423 
424         public CaseInsensitive(byte[] b, int o, int l, int rw)
425         {
426             super(b,o,l,rw);
427         }
428 
429         @Override
430         public boolean equals(Object obj)
431         {
432             return obj instanceof Buffer && equalsIgnoreCase((Buffer)obj);
433         }
434         
435     }
436 }