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 
ByteArrayBuffer(int access, boolean isVolatile)31     protected ByteArrayBuffer(int access, boolean isVolatile)
32     {
33         super(access, isVolatile);
34     }
35 
ByteArrayBuffer(byte[] bytes)36     public ByteArrayBuffer(byte[] bytes)
37     {
38         this(bytes, 0, bytes.length, READWRITE);
39     }
40 
ByteArrayBuffer(byte[] bytes, int index, int length)41     public ByteArrayBuffer(byte[] bytes, int index, int length)
42     {
43         this(bytes, index, length, READWRITE);
44     }
45 
ByteArrayBuffer(byte[] bytes, int index, int length, int access)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 
ByteArrayBuffer(byte[] bytes, int index, int length, int access, boolean isVolatile)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 
ByteArrayBuffer(int size)64     public ByteArrayBuffer(int size)
65     {
66         this(new byte[size], 0, size, READWRITE);
67         setPutIndex(0);
68     }
69 
ByteArrayBuffer(String value)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 
ByteArrayBuffer(String value,String encoding)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 
array()90     public byte[] array()
91     {
92         return _bytes;
93     }
94 
capacity()95     public int capacity()
96     {
97         return _bytes.length;
98     }
99 
compact()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 
equals(Object obj)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 
equalsIgnoreCase(Buffer b)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 
get()209     public byte get()
210     {
211         return _bytes[_get++];
212     }
213 
hashCode()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 
peek(int index)235     public byte peek(int index)
236     {
237         return _bytes[index];
238     }
239 
peek(int index, byte[] b, int offset, int length)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 
poke(int index, byte b)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 
poke(int index, Buffer src)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 
poke(int index, byte[] b, int offset, int length)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      */
wrap(byte[] b, int off, int len)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      */
wrap(byte[] b)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     /* ------------------------------------------------------------ */
writeTo(OutputStream out)365     public void writeTo(OutputStream out)
366         throws IOException
367     {
368         out.write(_bytes,getIndex(),length());
369         clear();
370     }
371 
372     /* ------------------------------------------------------------ */
readFrom(InputStream in,int max)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     /* ------------------------------------------------------------ */
space()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     {
CaseInsensitive(String s)412         public CaseInsensitive(String s)
413         {
414             super(s);
415         }
416 
CaseInsensitive(byte[] b, int o, int l, int rw)417         public CaseInsensitive(byte[] b, int o, int l, int rw)
418         {
419             super(b,o,l,rw);
420         }
421 
equals(Object obj)422         public boolean equals(Object obj)
423         {
424             return equalsIgnoreCase((Buffer)obj);
425         }
426 
427     }
428 }
429