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