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