View Javadoc

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