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
    21  /**
    22   * @author gregw
    23   *
    24   */
    25  public abstract class AbstractBuffer implements Buffer
    26  {
    27      protected final static String
    28      __IMMUTABLE = "IMMUTABLE",
    29      __READONLY = "READONLY",
    30      __READWRITE = "READWRITE",
    31      __VOLATILE = "VOLATILE";
    32
    33      protected int _access;
    34      protected boolean _volatile;
    35
    36      protected int _get;
    37      protected int _put;
    38      protected int _hash;
    39      protected int _hashGet;
    40      protected int _hashPut;
    41      protected int _mark;
    42      protected String _string;
    43      protected View _view;
    44
    45      /**
    46       * Constructor for BufferView
    47       *
    48       * @param access 0==IMMUTABLE, 1==READONLY, 2==READWRITE
    49       */
    50      public AbstractBuffer(int access, boolean isVolatile)
    51      {
    52          if (access == IMMUTABLE && isVolatile)
    53                  throw new IllegalArgumentException("IMMUTABLE && VOLATILE");
    54          setMarkIndex(-1);
    55          _access = access;
    56          _volatile = isVolatile;
    57      }
    58
    59      /*
    60       * @see org.mortbay.io.Buffer#toArray()
    61       */
    62      public byte[] asArray()
    63      {
    64          byte[] bytes = new byte[length()];
    65          byte[] array = array();
    66          if (array != null)
    67              Portable.arraycopy(array, getIndex(), bytes, 0, bytes.length);
    68          else
    69              peek(getIndex(), bytes, 0, length());
    70          return bytes;
    71      }
    72
    73      public ByteArrayBuffer duplicate(int access)
    74      {
    75          Buffer b=this.buffer();
    76          if (b instanceof Buffer.CaseInsensitve)
    77              return new ByteArrayBuffer.CaseInsensitive(asArray(), 0, length(),access);
    78          else
    79              return new ByteArrayBuffer(asArray(), 0, length(), access);
    80      }
    81
    82      /*
    83       * @see org.mortbay.io.Buffer#asNonVolatile()
    84       */
    85      public Buffer asNonVolatileBuffer()
    86      {
    87          if (!isVolatile()) return this;
    88          return duplicate(_access);
    89      }
    90
    91      public Buffer asImmutableBuffer()
    92      {
    93          if (isImmutable()) return this;
    94          return duplicate(IMMUTABLE);
    95      }
    96
    97      /*
    98       * @see org.mortbay.util.Buffer#asReadOnlyBuffer()
    99       */
    100     public Buffer asReadOnlyBuffer()
    101     {
    102         if (isReadOnly()) return this;
    103         return new View(this, markIndex(), getIndex(), putIndex(), READONLY);
    104     }
    105
    106     public Buffer asMutableBuffer()
    107     {
    108         if (!isImmutable()) return this;
    109
    110         Buffer b=this.buffer();
    111         if (b.isReadOnly())
    112         {
    113             return duplicate(READWRITE);
    114         }
    115         return new View(b, markIndex(), getIndex(), putIndex(), _access);
    116     }
    117
    118     public Buffer buffer()
    119     {
    120         return this;
    121     }
    122
    123     public void clear()
    124     {
    125         setMarkIndex(-1);
    126         setGetIndex(0);
    127         setPutIndex(0);
    128     }
    129
    130     public void compact()
    131     {
    132         if (isReadOnly()) throw new IllegalStateException(__READONLY);
    133         int s = markIndex() >= 0 ? markIndex() : getIndex();
    134         if (s > 0)
    135         {
    136             byte array[] = array();
    137             int length = putIndex() - s;
    138             if (length > 0)
    139             {
    140                 if (array != null)
    141                     Portable.arraycopy(array(), s, array(), 0, length);
    142                 else
    143                     poke(0, peek(s, length));
    144             }
    145             if (markIndex() > 0) setMarkIndex(markIndex() - s);
    146             setGetIndex(getIndex() - s);
    147             setPutIndex(putIndex() - s);
    148         }
    149     }
    150
    151     public boolean equals(Object obj)
    152     {
    153         if (obj==this)
    154             return true;
    155
    156         // reject non buffers;
    157         if (obj == null || !(obj instanceof Buffer)) return false;
    158         Buffer b = (Buffer) obj;
    159
    160         if (this instanceof Buffer.CaseInsensitve ||  b instanceof Buffer.CaseInsensitve)
    161             return equalsIgnoreCase(b);
    162
    163         // reject different lengths
    164         if (b.length() != length()) return false;
    165
    166         // reject AbstractBuffer with different hash value
    167         if (_hash != 0 && obj instanceof AbstractBuffer)
    168         {
    169             AbstractBuffer ab = (AbstractBuffer) obj;
    170             if (ab._hash != 0 && _hash != ab._hash) return false;
    171         }
    172
    173         // Nothing for it but to do the hard grind.
    174         int get=getIndex();
    175         int bi=b.putIndex();
    176         for (int i = putIndex(); i-->get;)
    177         {
    178             byte b1 = peek(i);
    179             byte b2 = b.peek(--bi);
    180             if (b1 != b2) return false;
    181         }
    182         return true;
    183     }
    184
    185     public boolean equalsIgnoreCase(Buffer b)
    186     {
    187         if (b==this)
    188             return true;
    189
    190         // reject different lengths
    191         if (b.length() != length()) return false;
    192
    193         // reject AbstractBuffer with different hash value
    194         if (_hash != 0 && b instanceof AbstractBuffer)
    195         {
    196             AbstractBuffer ab = (AbstractBuffer) b;
    197             if (ab._hash != 0 && _hash != ab._hash) return false;
    198         }
    199
    200         // Nothing for it but to do the hard grind.
    201         int get=getIndex();
    202         int bi=b.putIndex();
    203
    204         byte[] array = array();
    205         byte[] barray= b.array();
    206         if (array!=null && barray!=null)
    207         {
    208             for (int i = putIndex(); i-->get;)
    209             {
    210                 byte b1 = array[i];
    211                 byte b2 = barray[--bi];
    212                 if (b1 != b2)
    213                 {
    214                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
    215                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
    216                     if (b1 != b2) return false;
    217                 }
    218             }
    219         }
    220         else
    221         {
    222             for (int i = putIndex(); i-->get;)
    223             {
    224                 byte b1 = peek(i);
    225                 byte b2 = b.peek(--bi);
    226                 if (b1 != b2)
    227                 {
    228                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
    229                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
    230                     if (b1 != b2) return false;
    231                 }
    232             }
    233         }
    234         return true;
    235     }
    236
    237     public byte get()
    238     {
    239         return peek(_get++);
    240     }
    241
    242     public int get(byte[] b, int offset, int length)
    243     {
    244         int gi = getIndex();
    245         int l=length();
    246         if (l==0)
    247             return -1;
    248
    249         if (length>l)
    250             length=l;
    251
    252         length = peek(gi, b, offset, length);
    253         if (length>0)
    254             setGetIndex(gi + length);
    255         return length;
    256     }
    257
    258     public Buffer get(int length)
    259     {
    260         int gi = getIndex();
    261         Buffer view = peek(gi, length);
    262         setGetIndex(gi + length);
    263         return view;
    264     }
    265
    266     public final int getIndex()
    267     {
    268         return _get;
    269     }
    270
    271     public boolean hasContent()
    272     {
    273         return _put > _get;
    274     }
    275
    276     public int hashCode()
    277     {
    278         if (_hash == 0 || _hashGet!=_get || _hashPut!=_put)
    279         {
    280             int get=getIndex();
    281             byte[] array = array();
    282             if (array==null)
    283             {
    284                 for (int i = putIndex(); i-- >get;)
    285                 {
    286                     byte b = peek(i);
    287                     if ('a' <= b && b <= 'z')
    288                         b = (byte) (b - 'a' + 'A');
    289                     _hash = 31 * _hash + b;
    290                 }
    291             }
    292             else
    293             {
    294                 for (int i = putIndex(); i-- >get;)
    295                 {
    296                     byte b = array[i];
    297                     if ('a' <= b && b <= 'z')
    298                         b = (byte) (b - 'a' + 'A');
    299                     _hash = 31 * _hash + b;
    300                 }
    301             }
    302             if (_hash == 0)
    303                 _hash = -1;
    304             _hashGet=_get;
    305             _hashPut=_put;
    306
    307         }
    308         return _hash;
    309     }
    310
    311     public boolean isImmutable()
    312     {
    313         return _access <= IMMUTABLE;
    314     }
    315
    316     public boolean isReadOnly()
    317     {
    318         return _access <= READONLY;
    319     }
    320
    321     public boolean isVolatile()
    322     {
    323         return _volatile;
    324     }
    325
    326     public int length()
    327     {
    328         return _put - _get;
    329     }
    330
    331     public void mark()
    332     {
    333         setMarkIndex(_get - 1);
    334     }
    335
    336     public void mark(int offset)
    337     {
    338         setMarkIndex(_get + offset);
    339     }
    340
    341     public int markIndex()
    342     {
    343         return _mark;
    344     }
    345
    346     public byte peek()
    347     {
    348         return peek(_get);
    349     }
    350
    351     public Buffer peek(int index, int length)
    352     {
    353         if (_view == null)
    354         {
    355             _view = new View(this, -1, index, index + length, isReadOnly() ? READONLY : READWRITE);
    356         }
    357         else
    358         {
    359             _view.update(this.buffer());
    360             _view.setMarkIndex(-1);
    361             _view.setGetIndex(0);
    362             _view.setPutIndex(index + length);
    363             _view.setGetIndex(index);
    364
    365         }
    366         return _view;
    367     }
    368
    369     public int poke(int index, Buffer src)
    370     {
    371         _hash=0;
    372         /*
    373         if (isReadOnly())
    374             throw new IllegalStateException(__READONLY);
    375         if (index < 0)
    376             throw new IllegalArgumentException("index<0: " + index + "<0");
    377         */
    378
    379         int length=src.length();
    380         if (index + length > capacity())
    381         {
    382             length=capacity()-index;
    383             /*
    384             if (length<0)
    385                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
    386             */
    387         }
    388
    389         byte[] src_array = src.array();
    390         byte[] dst_array = array();
    391         if (src_array != null && dst_array != null)
    392             Portable.arraycopy(src_array, src.getIndex(), dst_array, index, length);
    393         else if (src_array != null)
    394         {
    395             int s=src.getIndex();
    396             for (int i=0;i<length;i++)
    397                 poke(index++,src_array[s++]);
    398         }
    399         else if (dst_array != null)
    400         {
    401             int s=src.getIndex();
    402             for (int i=0;i<length;i++)
    403                 dst_array[index++]=src.peek(s++);
    404         }
    405         else
    406         {
    407             int s=src.getIndex();
    408             for (int i=0;i<length;i++)
    409                 poke(index++,src.peek(s++));
    410         }
    411
    412         return length;
    413     }
    414
    415
    416     public int poke(int index, byte[] b, int offset, int length)
    417     {
    418         _hash=0;
    419         /*
    420         if (isReadOnly())
    421             throw new IllegalStateException(__READONLY);
    422         if (index < 0)
    423             throw new IllegalArgumentException("index<0: " + index + "<0");
    424         */
    425         if (index + length > capacity())
    426         {
    427             length=capacity()-index;
    428             /* if (length<0)
    429                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
    430             */
    431         }
    432
    433         byte[] dst_array = array();
    434         if (dst_array != null)
    435             Portable.arraycopy(b, offset, dst_array, index, length);
    436         else
    437         {
    438             int s=offset;
    439             for (int i=0;i<length;i++)
    440                 poke(index++,b[s++]);
    441         }
    442         return length;
    443     }
    444
    445     public int put(Buffer src)
    446     {
    447         int pi = putIndex();
    448         int l=poke(pi, src);
    449         setPutIndex(pi + l);
    450         return l;
    451     }
    452
    453     public void put(byte b)
    454     {
    455         int pi = putIndex();
    456         poke(pi, b);
    457         setPutIndex(pi + 1);
    458     }
    459
    460     public int put(byte[] b, int offset, int length)
    461     {
    462         int pi = putIndex();
    463         int l = poke(pi, b, offset, length);
    464         setPutIndex(pi + l);
    465         return l;
    466     }
    467
    468     public int put(byte[] b)
    469     {
    470         int pi = putIndex();
    471         int l = poke(pi, b, 0, b.length);
    472         setPutIndex(pi + l);
    473         return l;
    474     }
    475
    476     public final int putIndex()
    477     {
    478         return _put;
    479     }
    480
    481     public void reset()
    482     {
    483         if (markIndex() >= 0) setGetIndex(markIndex());
    484     }
    485
    486     public void rewind()
    487     {
    488         setGetIndex(0);
    489         setMarkIndex(-1);
    490     }
    491
    492     public void setGetIndex(int getIndex)
    493     {
    494         /* bounds checking
    495         if (isImmutable())
    496             throw new IllegalStateException(__IMMUTABLE);
    497         if (getIndex < 0)
    498             throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0");
    499         if (getIndex > putIndex())
    500             throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex());
    501          */
    502         _get = getIndex;
    503         _hash=0;
    504     }
    505
    506     public void setMarkIndex(int index)
    507     {
    508         /*
    509         if (index>=0 && isImmutable())
    510             throw new IllegalStateException(__IMMUTABLE);
    511         */
    512         _mark = index;
    513     }
    514
    515     public void setPutIndex(int putIndex)
    516     {
    517         /* bounds checking
    518         if (isImmutable())
    519             throw new IllegalStateException(__IMMUTABLE);
    520         if (putIndex > capacity())
    521                 throw new IllegalArgumentException("putIndex>capacity: " + putIndex + ">" + capacity());
    522         if (getIndex() > putIndex)
    523                 throw new IllegalArgumentException("getIndex>putIndex: " + getIndex() + ">" + putIndex);
    524          */
    525         _put = putIndex;
    526         _hash=0;
    527     }
    528
    529     public int skip(int n)
    530     {
    531         if (length() < n) n = length();
    532         setGetIndex(getIndex() + n);
    533         return n;
    534     }
    535
    536     public Buffer slice()
    537     {
    538         return peek(getIndex(), length());
    539     }
    540
    541     public Buffer sliceFromMark()
    542     {
    543         return sliceFromMark(getIndex() - markIndex() - 1);
    544     }
    545
    546     public Buffer sliceFromMark(int length)
    547     {
    548         if (markIndex() < 0) return null;
    549         Buffer view = peek(markIndex(), length);
    550         setMarkIndex(-1);
    551         return view;
    552     }
    553
    554     public int space()
    555     {
    556         return capacity() - _put;
    557     }
    558
    559     public String toDetailString()
    560     {
    561         StringBuffer buf = new StringBuffer();
    562         buf.append("[");
    563         buf.append(super.hashCode());
    564         buf.append(",");
    565         buf.append(this.array().hashCode());
    566         buf.append(",m=");
    567         buf.append(markIndex());
    568         buf.append(",g=");
    569         buf.append(getIndex());
    570         buf.append(",p=");
    571         buf.append(putIndex());
    572         buf.append(",c=");
    573         buf.append(capacity());
    574         buf.append("]={");
    575         if (markIndex() >= 0)
    576         {
    577             for (int i = markIndex(); i < getIndex(); i++)
    578             {
    579                 char c = (char) peek(i);
    580                 if (Character.isISOControl(c))
    581                 {
    582                     buf.append(c < 16 ? "\\0" : "\\");
    583                     buf.append(Integer.toString(c, 16));
    584                 }
    585                 else
    586                     buf.append(c);
    587             }
    588             buf.append("}{");
    589         }
    590         int count = 0;
    591         for (int i = getIndex(); i < putIndex(); i++)
    592         {
    593             char c = (char) peek(i);
    594             if (Character.isISOControl(c))
    595             {
    596                 buf.append(c < 16 ? "\\0" : "\\");
    597                 buf.append(Integer.toString(c, 16));
    598             }
    599             else
    600                 buf.append(c);
    601             if (count++ == 50)
    602             {
    603                 if (putIndex() - i > 20)
    604                 {
    605                     buf.append(" ... ");
    606                     i = putIndex() - 20;
    607                 }
    608             }
    609         }
    610         buf.append('}');
    611         return buf.toString();
    612     }
    613
    614     /* ------------------------------------------------------------ */
    615     public String toString()
    616     {
    617         if (isImmutable())
    618         {
    619             if (_string == null)
    620                 _string = new String(asArray(), 0, length());
    621             return _string;
    622         }
    623         return new String(asArray(), 0, length());
    624     }
    625
    626     /* ------------------------------------------------------------ */
    627     public String toDebugString()
    628     {
    629         return getClass()+"@"+super.hashCode();
    630     }
    631
    632     /* ------------------------------------------------------------ */
    633     public void writeTo(OutputStream out)
    634     	throws IOException
    635     {
    636         byte[] array = array();
    637
    638         if (array!=null)
    639         {
    640             out.write(array,getIndex(),length());
    641         }
    642         else
    643         {
    644             int len = this.length();
    645             byte[] buf=new byte[len>1024?1024:len];
    646             int offset=_get;
    647             while (len>0)
    648             {
    649                 int l=peek(offset,buf,0,len>buf.length?buf.length:len);
    650                 out.write(buf,0,l);
    651                 offset+=l;
    652                 len-=l;
    653             }
    654         }
    655         clear();
    656     }
    657
    658     /* ------------------------------------------------------------ */
    659     public int readFrom(InputStream in,int max) throws IOException
    660     {
    661         byte[] array = array();
    662         int s=space();
    663         if (s>max)
    664             s=max;
    665
    666         if (array!=null)
    667         {
    668             int l=in.read(array,_put,s);
    669             if (l>0)
    670                 _put+=l;
    671             return l;
    672         }
    673         else
    674         {
    675             byte[] buf=new byte[s>1024?1024:s];
    676             int total=0;
    677             while (s>0)
    678             {
    679                 int l=in.read(buf,0,buf.length);
    680                 if (l<0)
    681                     return total>0?total:-1;
    682                 int p=put(buf,0,l);
    683                 assert l==p;
    684                 s-=l;
    685             }
    686             return total;
    687         }
    688     }
    689 }