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 }