View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.buffer;
    17
    18  import java.nio.ByteBuffer;
    19  import java.nio.ByteOrder;
    20  import java.nio.CharBuffer;
    21  import java.nio.charset.CharacterCodingException;
    22  import java.nio.charset.Charset;
    23  import java.nio.charset.CharsetDecoder;
    24  import java.nio.charset.CharsetEncoder;
    25  import java.nio.charset.CoderResult;
    26  import java.util.ArrayList;
    27  import java.util.List;
    28
    29  import org.jboss.netty.util.CharsetUtil;
    30
    31
    32  /**
    33   * Creates a new {@link ChannelBuffer} by allocating new space or by wrapping
    34   * or copying existing byte arrays, byte buffers and a string.
    35   *
    36   * <h3>Use static import</h3>
    37   * This classes is intended to be used with Java 5 static import statement:
    38   *
    39   * <pre>
    40   * import static org.jboss.netty.buffer.{@link ChannelBuffers}.*;
    41   *
    42   * {@link ChannelBuffer} heapBuffer    = buffer(128);
    43   * {@link ChannelBuffer} directBuffer  = directBuffer(256);
    44   * {@link ChannelBuffer} dynamicBuffer = dynamicBuffer(512);
    45   * {@link ChannelBuffer} wrappedBuffer = wrappedBuffer(new byte[128], new byte[256]);
    46   * {@link ChannelBuffer} copiedBuffe r = copiedBuffer({@link ByteBuffer}.allocate(128));
    47   * </pre>
    48   *
    49   * <h3>Allocating a new buffer</h3>
    50   *
    51   * Three buffer types are provided out of the box.
    52   *
    53   * <ul>
    54   * <li>{@link #buffer(int)} allocates a new fixed-capacity heap buffer.</li>
    55   * <li>{@link #directBuffer(int)} allocates a new fixed-capacity direct buffer.</li>
    56   * <li>{@link #dynamicBuffer(int)} allocates a new dynamic-capacity heap
    57   *     buffer, whose capacity increases automatically as needed by a write
    58   *     operation.</li>
    59   * </ul>
    60   *
    61   * <h3>Creating a wrapped buffer</h3>
    62   *
    63   * Wrapped buffer is a buffer which is a view of one or more existing
    64   * byte arrays and byte buffers.  Any changes in the content of the original
    65   * array or buffer will be visible in the wrapped buffer.  Various wrapper
    66   * methods are provided and their name is all {@code wrappedBuffer()}.
    67   * You might want to take a look at the methods that accept varargs closely if
    68   * you want to create a buffer which is composed of more than one array to
    69   * reduce the number of memory copy.
    70   *
    71   * <h3>Creating a copied buffer</h3>
    72   *
    73   * Copied buffer is a deep copy of one or more existing byte arrays, byte
    74   * buffers or a string.  Unlike a wrapped buffer, there's no shared data
    75   * between the original data and the copied buffer.  Various copy methods are
    76   * provided and their name is all {@code copiedBuffer()}.  It is also convenient
    77   * to use this operation to merge multiple buffers into one buffer.
    78   *
    79   * <h3>Miscellaneous utility methods</h3>
    80   *
    81   * This class also provides various utility methods to help implementation
    82   * of a new buffer type, generation of hex dump and swapping an integer's
    83   * byte order.
    84   *
    85   * @apiviz.landmark
    86   * @apiviz.has org.jboss.netty.buffer.ChannelBuffer oneway - - creates
    87   */
    88  public final class ChannelBuffers {
    89
    90      /**
    91       * Big endian byte order.
    92       */
    93      public static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
    94
    95      /**
    96       * Little endian byte order.
    97       */
    98      public static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
    99
    100     /**
    101      * A buffer whose capacity is {@code 0}.
    102      */
    103     public static final ChannelBuffer EMPTY_BUFFER = new BigEndianHeapChannelBuffer(0);
    104
    105     private static final char[] HEXDUMP_TABLE = new char[256 * 4];
    106
    107     static {
    108         final char[] DIGITS = "0123456789abcdef".toCharArray();
    109         for (int i = 0; i < 256; i ++) {
    110             HEXDUMP_TABLE[i << 1] = DIGITS[i >>> 4 & 0x0F];
    111             HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F];
    112         }
    113     }
    114
    115     /**
    116      * Creates a new big-endian Java heap buffer with the specified
    117      * {@code capacity}.  The new buffer's {@code readerIndex} and
    118      * {@code writerIndex} are {@code 0}.
    119      */
    120     public static ChannelBuffer buffer(int capacity) {
    121         return buffer(BIG_ENDIAN, capacity);
    122     }
    123
    124     /**
    125      * Creates a new Java heap buffer with the specified {@code endianness}
    126      * and {@code capacity}.  The new buffer's {@code readerIndex} and
    127      * {@code writerIndex} are {@code 0}.
    128      */
    129     public static ChannelBuffer buffer(ByteOrder endianness, int capacity) {
    130         if (endianness == BIG_ENDIAN) {
    131             if (capacity == 0) {
    132                 return EMPTY_BUFFER;
    133             }
    134             return new BigEndianHeapChannelBuffer(capacity);
    135         } else if (endianness == LITTLE_ENDIAN) {
    136             if (capacity == 0) {
    137                 return EMPTY_BUFFER;
    138             }
    139             return new LittleEndianHeapChannelBuffer(capacity);
    140         } else {
    141             throw new NullPointerException("endianness");
    142         }
    143     }
    144
    145     /**
    146      * Creates a new big-endian direct buffer with the specified
    147      * {@code capacity}.  The new buffer's {@code readerIndex} and
    148      * {@code writerIndex} are {@code 0}.
    149      */
    150     public static ChannelBuffer directBuffer(int capacity) {
    151         return directBuffer(BIG_ENDIAN, capacity);
    152     }
    153
    154     /**
    155      * Creates a new direct buffer with the specified {@code endianness} and
    156      * {@code capacity}.  The new buffer's {@code readerIndex} and
    157      * {@code writerIndex} are {@code 0}.
    158      */
    159     public static ChannelBuffer directBuffer(ByteOrder endianness, int capacity) {
    160         if (endianness == null) {
    161             throw new NullPointerException("endianness");
    162         }
    163         if (capacity == 0) {
    164             return EMPTY_BUFFER;
    165         }
    166
    167         ChannelBuffer buffer = new ByteBufferBackedChannelBuffer(
    168                 ByteBuffer.allocateDirect(capacity).order(endianness));
    169         buffer.clear();
    170         return buffer;
    171     }
    172
    173     /**
    174      * Creates a new big-endian dynamic buffer whose estimated data length is
    175      * {@code 256} bytes.  The new buffer's {@code readerIndex} and
    176      * {@code writerIndex} are {@code 0}.
    177      */
    178     public static ChannelBuffer dynamicBuffer() {
    179         return dynamicBuffer(BIG_ENDIAN, 256);
    180     }
    181
    182     public static ChannelBuffer dynamicBuffer(ChannelBufferFactory factory) {
    183         if (factory == null) {
    184             throw new NullPointerException("factory");
    185         }
    186
    187         return new DynamicChannelBuffer(factory.getDefaultOrder(), 256, factory);
    188     }
    189
    190     /**
    191      * Creates a new big-endian dynamic buffer with the specified estimated
    192      * data length.  More accurate estimation yields less unexpected
    193      * reallocation overhead.  The new buffer's {@code readerIndex} and
    194      * {@code writerIndex} are {@code 0}.
    195      */
    196     public static ChannelBuffer dynamicBuffer(int estimatedLength) {
    197         return dynamicBuffer(BIG_ENDIAN, estimatedLength);
    198     }
    199
    200     /**
    201      * Creates a new dynamic buffer with the specified endianness and
    202      * the specified estimated data length.  More accurate estimation yields
    203      * less unexpected reallocation overhead.  The new buffer's
    204      * {@code readerIndex} and {@code writerIndex} are {@code 0}.
    205      */
    206     public static ChannelBuffer dynamicBuffer(ByteOrder endianness, int estimatedLength) {
    207         return new DynamicChannelBuffer(endianness, estimatedLength);
    208     }
    209
    210     /**
    211      * Creates a new big-endian dynamic buffer with the specified estimated
    212      * data length using the specified factory.  More accurate estimation yields
    213      * less unexpected reallocation overhead.  The new buffer's {@code readerIndex}
    214      * and {@code writerIndex} are {@code 0}.
    215      */
    216     public static ChannelBuffer dynamicBuffer(int estimatedLength, ChannelBufferFactory factory) {
    217         if (factory == null) {
    218             throw new NullPointerException("factory");
    219         }
    220
    221         return new DynamicChannelBuffer(factory.getDefaultOrder(), estimatedLength, factory);
    222     }
    223
    224     /**
    225      * Creates a new dynamic buffer with the specified endianness and
    226      * the specified estimated data length using the specified factory.
    227      * More accurate estimation yields less unexpected reallocation overhead.
    228      * The new buffer's {@code readerIndex} and {@code writerIndex} are {@code 0}.
    229      */
    230     public static ChannelBuffer dynamicBuffer(
    231             ByteOrder endianness, int estimatedLength, ChannelBufferFactory factory) {
    232         return new DynamicChannelBuffer(endianness, estimatedLength, factory);
    233     }
    234
    235     /**
    236      * Creates a new big-endian buffer which wraps the specified {@code array}.
    237      * A modification on the specified array's content will be visible to the
    238      * returned buffer.
    239      */
    240     public static ChannelBuffer wrappedBuffer(byte[] array) {
    241         return wrappedBuffer(BIG_ENDIAN, array);
    242     }
    243
    244     /**
    245      * Creates a new buffer which wraps the specified {@code array} with the
    246      * specified {@code endianness}.  A modification on the specified array's
    247      * content will be visible to the returned buffer.
    248      */
    249     public static ChannelBuffer wrappedBuffer(ByteOrder endianness, byte[] array) {
    250         if (endianness == BIG_ENDIAN) {
    251             if (array.length == 0) {
    252                 return EMPTY_BUFFER;
    253             }
    254             return new BigEndianHeapChannelBuffer(array);
    255         } else if (endianness == LITTLE_ENDIAN) {
    256             if (array.length == 0) {
    257                 return EMPTY_BUFFER;
    258             }
    259             return new LittleEndianHeapChannelBuffer(array);
    260         } else {
    261             throw new NullPointerException("endianness");
    262         }
    263     }
    264
    265     /**
    266      * Creates a new big-endian buffer which wraps the sub-region of the
    267      * specified {@code array}.  A modification on the specified array's
    268      * content will be visible to the returned buffer.
    269      */
    270     public static ChannelBuffer wrappedBuffer(byte[] array, int offset, int length) {
    271         return wrappedBuffer(BIG_ENDIAN, array, offset, length);
    272     }
    273
    274     /**
    275      * Creates a new buffer which wraps the sub-region of the specified
    276      * {@code array} with the specified {@code endianness}.  A modification on
    277      * the specified array's content will be visible to the returned buffer.
    278      */
    279     public static ChannelBuffer wrappedBuffer(ByteOrder endianness, byte[] array, int offset, int length) {
    280         if (endianness == null) {
    281             throw new NullPointerException("endianness");
    282         }
    283         if (offset == 0) {
    284             if (length == array.length) {
    285                 return wrappedBuffer(endianness, array);
    286             } else {
    287                 if (length == 0) {
    288                     return EMPTY_BUFFER;
    289                 } else {
    290                     return new TruncatedChannelBuffer(wrappedBuffer(endianness, array), length);
    291                 }
    292             }
    293         } else {
    294             if (length == 0) {
    295                 return EMPTY_BUFFER;
    296             } else {
    297                 return new SlicedChannelBuffer(wrappedBuffer(endianness, array), offset, length);
    298             }
    299         }
    300     }
    301
    302     /**
    303      * Creates a new buffer which wraps the specified NIO buffer's current
    304      * slice.  A modification on the specified buffer's content will be
    305      * visible to the returned buffer.
    306      */
    307     public static ChannelBuffer wrappedBuffer(ByteBuffer buffer) {
    308         if (!buffer.hasRemaining()) {
    309             return EMPTY_BUFFER;
    310         }
    311         if (buffer.hasArray()) {
    312             return wrappedBuffer(
    313                     buffer.order(), buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
    314         } else {
    315             return new ByteBufferBackedChannelBuffer(buffer);
    316         }
    317     }
    318
    319     /**
    320      * Creates a new buffer which wraps the specified buffer's readable bytes.
    321      * A modification on the specified buffer's content will be visible to the
    322      * returned buffer.
    323      */
    324     public static ChannelBuffer wrappedBuffer(ChannelBuffer buffer) {
    325         if (buffer.readable()) {
    326             return buffer.slice();
    327         } else {
    328             return EMPTY_BUFFER;
    329         }
    330     }
    331
    332     /**
    333      * Creates a new big-endian composite buffer which wraps the specified
    334      * arrays without copying them.  A modification on the specified arrays'
    335      * content will be visible to the returned buffer.
    336      */
    337     public static ChannelBuffer wrappedBuffer(byte[]... arrays) {
    338         return wrappedBuffer(BIG_ENDIAN, arrays);
    339     }
    340
    341     /**
    342      * Creates a new composite buffer which wraps the specified arrays without
    343      * copying them.  A modification on the specified arrays' content will be
    344      * visible to the returned buffer.
    345      *
    346      * @param endianness the endianness of the new buffer
    347      */
    348     public static ChannelBuffer wrappedBuffer(ByteOrder endianness, byte[]... arrays) {
    349         switch (arrays.length) {
    350         case 0:
    351             break;
    352         case 1:
    353             if (arrays[0].length != 0) {
    354                 return wrappedBuffer(endianness, arrays[0]);
    355             }
    356             break;
    357         default:
    358             // Get the list of the component, while guessing the byte order.
    359             final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(arrays.length);
    360             for (byte[] a: arrays) {
    361                 if (a == null) {
    362                     break;
    363                 }
    364                 if (a.length > 0) {
    365                     components.add(wrappedBuffer(endianness, a));
    366                 }
    367             }
    368             return compositeBuffer(endianness, components, false);
    369         }
    370
    371         return EMPTY_BUFFER;
    372     }
    373
    374     private static ChannelBuffer compositeBuffer(
    375             ByteOrder endianness, List<ChannelBuffer> components, boolean gathering) {
    376         switch (components.size()) {
    377         case 0:
    378             return EMPTY_BUFFER;
    379         case 1:
    380             return components.get(0);
    381         default:
    382             return new CompositeChannelBuffer(endianness, components, gathering);
    383         }
    384     }
    385
    386     /**
    387      * Creates a new composite buffer which wraps the readable bytes of the
    388      * specified buffers without copying them.  A modification on the content
    389      * of the specified buffers will be visible to the returned buffer.
    390      *
    391      * @throws IllegalArgumentException
    392      *         if the specified buffers' endianness are different from each
    393      *         other
    394      */
    395     public static ChannelBuffer wrappedBuffer(ChannelBuffer... buffers) {
    396         return wrappedBuffer(false, buffers);
    397     }
    398     /**
    399      * Creates a new composite buffer which wraps the readable bytes of the
    400      * specified buffers without copying them.  A modification on the content
    401      * of the specified buffers will be visible to the returned buffer.
    402      * If gathering is <code>true</code> then gathering writes will be used when ever
    403      * possible.
    404      *
    405      * @throws IllegalArgumentException
    406      *         if the specified buffers' endianness are different from each
    407      *         other
    408      */
    409     public static ChannelBuffer wrappedBuffer(boolean gathering, ChannelBuffer... buffers) {
    410         switch (buffers.length) {
    411         case 0:
    412             break;
    413         case 1:
    414             if (buffers[0].readable()) {
    415                 return wrappedBuffer(buffers[0]);
    416             }
    417             break;
    418         default:
    419             ByteOrder order = null;
    420             final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(buffers.length);
    421             for (ChannelBuffer c: buffers) {
    422                 if (c == null) {
    423                     break;
    424                 }
    425                 if (c.readable()) {
    426                     if (order != null) {
    427                         if (!order.equals(c.order())) {
    428                             throw new IllegalArgumentException(
    429                                     "inconsistent byte order");
    430                         }
    431                     } else {
    432                         order = c.order();
    433                     }
    434                     if (c instanceof CompositeChannelBuffer) {
    435                         // Expand nested composition.
    436                         components.addAll(
    437                                 ((CompositeChannelBuffer) c).decompose(
    438                                         c.readerIndex(), c.readableBytes()));
    439                     } else {
    440                         // An ordinary buffer (non-composite)
    441                         components.add(c.slice());
    442                     }
    443                 }
    444             }
    445             return compositeBuffer(order, components, gathering);
    446         }
    447         return EMPTY_BUFFER;
    448     }
    449
    450
    451     /**
    452      * Creates a new composite buffer which wraps the slices of the specified
    453      * NIO buffers without copying them.  A modification on the content of the
    454      * specified buffers will be visible to the returned buffer.
    455      *
    456      * @throws IllegalArgumentException
    457      *         if the specified buffers' endianness are different from each
    458      *         other
    459      */
    460     public static ChannelBuffer wrappedBuffer(ByteBuffer... buffers) {
    461         return wrappedBuffer(false, buffers);
    462     }
    463
    464     /**
    465      * Creates a new composite buffer which wraps the slices of the specified
    466      * NIO buffers without copying them.  A modification on the content of the
    467      * specified buffers will be visible to the returned buffer.
    468      * If gathering is <code>true</code> then gathering writes will be used when ever
    469      * possible.
    470      *
    471      * @throws IllegalArgumentException
    472      *         if the specified buffers' endianness are different from each
    473      *         other
    474      */
    475     public static ChannelBuffer wrappedBuffer(boolean gathering, ByteBuffer... buffers) {
    476         switch (buffers.length) {
    477         case 0:
    478             break;
    479         case 1:
    480             if (buffers[0].hasRemaining()) {
    481                 return wrappedBuffer(buffers[0]);
    482             }
    483             break;
    484         default:
    485             ByteOrder order = null;
    486             final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(buffers.length);
    487             for (ByteBuffer b: buffers) {
    488                 if (b == null) {
    489                     break;
    490                 }
    491                 if (b.hasRemaining()) {
    492                     if (order != null) {
    493                         if (!order.equals(b.order())) {
    494                             throw new IllegalArgumentException(
    495                                     "inconsistent byte order");
    496                         }
    497                     } else {
    498                         order = b.order();
    499                     }
    500                     components.add(wrappedBuffer(b));
    501                 }
    502             }
    503             return compositeBuffer(order, components, gathering);
    504         }
    505
    506         return EMPTY_BUFFER;
    507     }
    508
    509     /**
    510      * Creates a new big-endian buffer whose content is a copy of the
    511      * specified {@code array}.  The new buffer's {@code readerIndex} and
    512      * {@code writerIndex} are {@code 0} and {@code array.length} respectively.
    513      */
    514     public static ChannelBuffer copiedBuffer(byte[] array) {
    515         return copiedBuffer(BIG_ENDIAN, array);
    516     }
    517
    518     /**
    519      * Creates a new buffer with the specified {@code endianness} whose
    520      * content is a copy of the specified {@code array}.  The new buffer's
    521      * {@code readerIndex} and {@code writerIndex} are {@code 0} and
    522      * {@code array.length} respectively.
    523      */
    524     public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[] array) {
    525         if (endianness == BIG_ENDIAN) {
    526             if (array.length == 0) {
    527                 return EMPTY_BUFFER;
    528             }
    529             return new BigEndianHeapChannelBuffer(array.clone());
    530         } else if (endianness == LITTLE_ENDIAN) {
    531             if (array.length == 0) {
    532                 return EMPTY_BUFFER;
    533             }
    534             return new LittleEndianHeapChannelBuffer(array.clone());
    535         } else {
    536             throw new NullPointerException("endianness");
    537         }
    538     }
    539
    540     /**
    541      * Creates a new big-endian buffer whose content is a copy of the
    542      * specified {@code array}'s sub-region.  The new buffer's
    543      * {@code readerIndex} and {@code writerIndex} are {@code 0} and
    544      * the specified {@code length} respectively.
    545      */
    546     public static ChannelBuffer copiedBuffer(byte[] array, int offset, int length) {
    547         return copiedBuffer(BIG_ENDIAN, array, offset, length);
    548     }
    549
    550     /**
    551      * Creates a new buffer with the specified {@code endianness} whose
    552      * content is a copy of the specified {@code array}'s sub-region.  The new
    553      * buffer's {@code readerIndex} and {@code writerIndex} are {@code 0} and
    554      * the specified {@code length} respectively.
    555      */
    556     public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[] array, int offset, int length) {
    557         if (endianness == null) {
    558             throw new NullPointerException("endianness");
    559         }
    560         if (length == 0) {
    561             return EMPTY_BUFFER;
    562         }
    563         byte[] copy = new byte[length];
    564         System.arraycopy(array, offset, copy, 0, length);
    565         return wrappedBuffer(endianness, copy);
    566     }
    567
    568     /**
    569      * Creates a new buffer whose content is a copy of the specified
    570      * {@code buffer}'s current slice.  The new buffer's {@code readerIndex}
    571      * and {@code writerIndex} are {@code 0} and {@code buffer.remaining}
    572      * respectively.
    573      */
    574     public static ChannelBuffer copiedBuffer(ByteBuffer buffer) {
    575         int length = buffer.remaining();
    576         if (length == 0) {
    577             return EMPTY_BUFFER;
    578         }
    579         byte[] copy = new byte[length];
    580         int position = buffer.position();
    581         try {
    582             buffer.get(copy);
    583         } finally {
    584             buffer.position(position);
    585         }
    586         return wrappedBuffer(buffer.order(), copy);
    587     }
    588
    589     /**
    590      * Creates a new buffer whose content is a copy of the specified
    591      * {@code buffer}'s readable bytes.  The new buffer's {@code readerIndex}
    592      * and {@code writerIndex} are {@code 0} and {@code buffer.readableBytes}
    593      * respectively.
    594      */
    595     public static ChannelBuffer copiedBuffer(ChannelBuffer buffer) {
    596         if (buffer.readable()) {
    597             return buffer.copy();
    598         } else {
    599             return EMPTY_BUFFER;
    600         }
    601     }
    602
    603     /**
    604      * Creates a new big-endian buffer whose content is a merged copy of
    605      * the specified {@code arrays}.  The new buffer's {@code readerIndex}
    606      * and {@code writerIndex} are {@code 0} and the sum of all arrays'
    607      * {@code length} respectively.
    608      */
    609     public static ChannelBuffer copiedBuffer(byte[]... arrays) {
    610         return copiedBuffer(BIG_ENDIAN, arrays);
    611     }
    612
    613     /**
    614      * Creates a new buffer with the specified {@code endianness} whose
    615      * content is a merged copy of the specified {@code arrays}.  The new
    616      * buffer's {@code readerIndex} and {@code writerIndex} are {@code 0}
    617      * and the sum of all arrays' {@code length} respectively.
    618      */
    619     public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[]... arrays) {
    620         switch (arrays.length) {
    621         case 0:
    622             return EMPTY_BUFFER;
    623         case 1:
    624             if (arrays[0].length == 0) {
    625                 return EMPTY_BUFFER;
    626             } else {
    627                 return copiedBuffer(endianness, arrays[0]);
    628             }
    629         }
    630
    631         // Merge the specified arrays into one array.
    632         int length = 0;
    633         for (byte[] a: arrays) {
    634             if (Integer.MAX_VALUE - length < a.length) {
    635                 throw new IllegalArgumentException(
    636                         "The total length of the specified arrays is too big.");
    637             }
    638             length += a.length;
    639         }
    640
    641         if (length == 0) {
    642             return EMPTY_BUFFER;
    643         }
    644
    645         byte[] mergedArray = new byte[length];
    646         for (int i = 0, j = 0; i < arrays.length; i ++) {
    647             byte[] a = arrays[i];
    648             System.arraycopy(a, 0, mergedArray, j, a.length);
    649             j += a.length;
    650         }
    651
    652         return wrappedBuffer(endianness, mergedArray);
    653     }
    654
    655     /**
    656      * Creates a new buffer whose content is a merged copy of the specified
    657      * {@code buffers}' readable bytes.  The new buffer's {@code readerIndex}
    658      * and {@code writerIndex} are {@code 0} and the sum of all buffers'
    659      * {@code readableBytes} respectively.
    660      *
    661      * @throws IllegalArgumentException
    662      *         if the specified buffers' endianness are different from each
    663      *         other
    664      */
    665     public static ChannelBuffer copiedBuffer(ChannelBuffer... buffers) {
    666         switch (buffers.length) {
    667         case 0:
    668             return EMPTY_BUFFER;
    669         case 1:
    670             return copiedBuffer(buffers[0]);
    671         }
    672
    673         ChannelBuffer[] copiedBuffers = new ChannelBuffer[buffers.length];
    674         for (int i = 0; i < buffers.length; i ++) {
    675             copiedBuffers[i] = copiedBuffer(buffers[i]);
    676         }
    677         return wrappedBuffer(false, copiedBuffers);
    678     }
    679
    680     /**
    681      * Creates a new buffer whose content is a merged copy of the specified
    682      * {@code buffers}' slices.  The new buffer's {@code readerIndex} and
    683      * {@code writerIndex} are {@code 0} and the sum of all buffers'
    684      * {@code remaining} respectively.
    685      *
    686      * @throws IllegalArgumentException
    687      *         if the specified buffers' endianness are different from each
    688      *         other
    689      */
    690     public static ChannelBuffer copiedBuffer(ByteBuffer... buffers) {
    691         switch (buffers.length) {
    692         case 0:
    693             return EMPTY_BUFFER;
    694         case 1:
    695             return copiedBuffer(buffers[0]);
    696         }
    697
    698         ChannelBuffer[] copiedBuffers = new ChannelBuffer[buffers.length];
    699         for (int i = 0; i < buffers.length; i ++) {
    700             copiedBuffers[i] = copiedBuffer(buffers[i]);
    701         }
    702         return wrappedBuffer(false, copiedBuffers);
    703     }
    704
    705     /**
    706      * Creates a new big-endian buffer whose content is the specified
    707      * {@code string} encoded in the specified {@code charset}.
    708      * The new buffer's {@code readerIndex} and {@code writerIndex} are
    709      * {@code 0} and the length of the encoded string respectively.
    710      */
    711     public static ChannelBuffer copiedBuffer(CharSequence string, Charset charset) {
    712         return copiedBuffer(BIG_ENDIAN, string, charset);
    713     }
    714
    715     /**
    716      * Creates a new big-endian buffer whose content is a subregion of
    717      * the specified {@code string} encoded in the specified {@code charset}.
    718      * The new buffer's {@code readerIndex} and {@code writerIndex} are
    719      * {@code 0} and the length of the encoded string respectively.
    720      */
    721     public static ChannelBuffer copiedBuffer(
    722             CharSequence string, int offset, int length, Charset charset) {
    723         return copiedBuffer(BIG_ENDIAN, string, offset, length, charset);
    724     }
    725
    726     /**
    727      * Creates a new buffer with the specified {@code endianness} whose
    728      * content is the specified {@code string} encoded in the specified
    729      * {@code charset}.  The new buffer's {@code readerIndex} and
    730      * {@code writerIndex} are {@code 0} and the length of the encoded string
    731      * respectively.
    732      */
    733     public static ChannelBuffer copiedBuffer(ByteOrder endianness, CharSequence string, Charset charset) {
    734         if (string == null) {
    735             throw new NullPointerException("string");
    736         }
    737
    738         if (string instanceof CharBuffer) {
    739             return copiedBuffer(endianness, (CharBuffer) string, charset);
    740         }
    741
    742         return copiedBuffer(endianness, CharBuffer.wrap(string), charset);
    743     }
    744
    745     /**
    746      * Creates a new buffer with the specified {@code endianness} whose
    747      * content is a subregion of the specified {@code string} encoded in the
    748      * specified {@code charset}.  The new buffer's {@code readerIndex} and
    749      * {@code writerIndex} are {@code 0} and the length of the encoded string
    750      * respectively.
    751      */
    752     public static ChannelBuffer copiedBuffer(
    753             ByteOrder endianness, CharSequence string, int offset, int length, Charset charset) {
    754         if (string == null) {
    755             throw new NullPointerException("string");
    756         }
    757         if (length == 0) {
    758             return EMPTY_BUFFER;
    759         }
    760
    761         if (string instanceof CharBuffer) {
    762             CharBuffer buf = (CharBuffer) string;
    763             if (buf.hasArray()) {
    764                 return copiedBuffer(
    765                         endianness,
    766                         buf.array(),
    767                         buf.arrayOffset() + buf.position() + offset,
    768                         length, charset);
    769             }
    770
    771             buf = buf.slice();
    772             buf.limit(length);
    773             buf.position(offset);
    774             return copiedBuffer(endianness, buf, charset);
    775         }
    776
    777         return copiedBuffer(
    778                 endianness, CharBuffer.wrap(string, offset, offset + length),
    779                 charset);
    780     }
    781
    782     /**
    783      * Creates a new big-endian buffer whose content is the specified
    784      * {@code array} encoded in the specified {@code charset}.
    785      * The new buffer's {@code readerIndex} and {@code writerIndex} are
    786      * {@code 0} and the length of the encoded string respectively.
    787      */
    788     public static ChannelBuffer copiedBuffer(char[] array, Charset charset) {
    789         return copiedBuffer(BIG_ENDIAN, array, 0, array.length, charset);
    790     }
    791
    792     /**
    793      * Creates a new big-endian buffer whose content is a subregion of
    794      * the specified {@code array} encoded in the specified {@code charset}.
    795      * The new buffer's {@code readerIndex} and {@code writerIndex} are
    796      * {@code 0} and the length of the encoded string respectively.
    797      */
    798     public static ChannelBuffer copiedBuffer(
    799             char[] array, int offset, int length, Charset charset) {
    800         return copiedBuffer(BIG_ENDIAN, array, offset, length, charset);
    801     }
    802
    803     /**
    804      * Creates a new buffer with the specified {@code endianness} whose
    805      * content is the specified {@code array} encoded in the specified
    806      * {@code charset}.  The new buffer's {@code readerIndex} and
    807      * {@code writerIndex} are {@code 0} and the length of the encoded string
    808      * respectively.
    809      */
    810     public static ChannelBuffer copiedBuffer(ByteOrder endianness, char[] array, Charset charset) {
    811         return copiedBuffer(endianness, array, 0, array.length, charset);
    812     }
    813
    814     /**
    815      * Creates a new buffer with the specified {@code endianness} whose
    816      * content is a subregion of the specified {@code array} encoded in the
    817      * specified {@code charset}.  The new buffer's {@code readerIndex} and
    818      * {@code writerIndex} are {@code 0} and the length of the encoded string
    819      * respectively.
    820      */
    821     public static ChannelBuffer copiedBuffer(
    822             ByteOrder endianness, char[] array, int offset, int length, Charset charset) {
    823         if (array == null) {
    824             throw new NullPointerException("array");
    825         }
    826         if (length == 0) {
    827             return EMPTY_BUFFER;
    828         }
    829         return copiedBuffer(
    830                 endianness, CharBuffer.wrap(array, offset, length), charset);
    831     }
    832
    833     private static ChannelBuffer copiedBuffer(ByteOrder endianness, CharBuffer buffer, Charset charset) {
    834         CharBuffer src = buffer;
    835         ByteBuffer dst = ChannelBuffers.encodeString(src, charset);
    836         ChannelBuffer result = wrappedBuffer(endianness, dst.array());
    837         result.writerIndex(dst.remaining());
    838         return result;
    839     }
    840
    841     /**
    842      * @deprecated Use {@link #copiedBuffer(CharSequence, Charset)} instead.
    843      */
    844     @Deprecated
    845     public static ChannelBuffer copiedBuffer(String string, String charsetName) {
    846         return copiedBuffer(string, Charset.forName(charsetName));
    847     }
    848
    849     /**
    850      * @deprecated Use {@link #copiedBuffer(ByteOrder, CharSequence, Charset)} instead.
    851      */
    852     @Deprecated
    853     public static ChannelBuffer copiedBuffer(ByteOrder endianness, String string, String charsetName) {
    854         return copiedBuffer(endianness, string, Charset.forName(charsetName));
    855     }
    856
    857     /**
    858      * Creates a read-only buffer which disallows any modification operations
    859      * on the specified {@code buffer}.  The new buffer has the same
    860      * {@code readerIndex} and {@code writerIndex} with the specified
    861      * {@code buffer}.
    862      */
    863     public static ChannelBuffer unmodifiableBuffer(ChannelBuffer buffer) {
    864         if (buffer instanceof ReadOnlyChannelBuffer) {
    865             buffer = ((ReadOnlyChannelBuffer) buffer).unwrap();
    866         }
    867         return new ReadOnlyChannelBuffer(buffer);
    868     }
    869
    870     /**
    871      * Create a {@link ChannelBuffer} from the given <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
    872      */
    873     public static ChannelBuffer hexDump(String hexString) {
    874         int len = hexString.length();
    875         byte[] hexData = new byte[len / 2];
    876         for (int i = 0; i < len; i += 2) {
    877             hexData[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
    878                                  + Character.digit(hexString.charAt(i + 1), 16));
    879         }
    880         return wrappedBuffer(hexData);
    881     }
    882
    883     /**
    884      * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
    885      * of the specified buffer's readable bytes.
    886      */
    887     public static String hexDump(ChannelBuffer buffer) {
    888         return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
    889     }
    890
    891     /**
    892      * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
    893      * of the specified buffer's sub-region.
    894      */
    895     public static String hexDump(ChannelBuffer buffer, int fromIndex, int length) {
    896         if (length < 0) {
    897             throw new IllegalArgumentException("length: " + length);
    898         }
    899         if (length == 0) {
    900             return "";
    901         }
    902
    903         int endIndex = fromIndex + length;
    904         char[] buf = new char[length << 1];
    905
    906         int srcIdx = fromIndex;
    907         int dstIdx = 0;
    908         for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
    909             System.arraycopy(
    910                     HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1,
    911                     buf, dstIdx, 2);
    912         }
    913
    914         return new String(buf);
    915     }
    916
    917     /**
    918      * Calculates the hash code of the specified buffer.  This method is
    919      * useful when implementing a new buffer type.
    920      */
    921     public static int hashCode(ChannelBuffer buffer) {
    922         final int aLen = buffer.readableBytes();
    923         final int intCount = aLen >>> 2;
    924         final int byteCount = aLen & 3;
    925
    926         int hashCode = 1;
    927         int arrayIndex = buffer.readerIndex();
    928         if (buffer.order() == BIG_ENDIAN) {
    929             for (int i = intCount; i > 0; i --) {
    930                 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
    931                 arrayIndex += 4;
    932             }
    933         } else {
    934             for (int i = intCount; i > 0; i --) {
    935                 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
    936                 arrayIndex += 4;
    937             }
    938         }
    939
    940         for (int i = byteCount; i > 0; i --) {
    941             hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
    942         }
    943
    944         if (hashCode == 0) {
    945             hashCode = 1;
    946         }
    947
    948         return hashCode;
    949     }
    950
    951     /**
    952      * Returns {@code true} if and only if the two specified buffers are
    953      * identical to each other as described in {@code ChannelBuffer#equals(Object)}.
    954      * This method is useful when implementing a new buffer type.
    955      */
    956     public static boolean equals(ChannelBuffer bufferA, ChannelBuffer bufferB) {
    957         final int aLen = bufferA.readableBytes();
    958         if (aLen != bufferB.readableBytes()) {
    959             return false;
    960         }
    961
    962         final int longCount = aLen >>> 3;
    963         final int byteCount = aLen & 7;
    964
    965         int aIndex = bufferA.readerIndex();
    966         int bIndex = bufferB.readerIndex();
    967
    968         if (bufferA.order() == bufferB.order()) {
    969             for (int i = longCount; i > 0; i --) {
    970                 if (bufferA.getLong(aIndex) != bufferB.getLong(bIndex)) {
    971                     return false;
    972                 }
    973                 aIndex += 8;
    974                 bIndex += 8;
    975             }
    976         } else {
    977             for (int i = longCount; i > 0; i --) {
    978                 if (bufferA.getLong(aIndex) != swapLong(bufferB.getLong(bIndex))) {
    979                     return false;
    980                 }
    981                 aIndex += 8;
    982                 bIndex += 8;
    983             }
    984         }
    985
    986         for (int i = byteCount; i > 0; i --) {
    987             if (bufferA.getByte(aIndex) != bufferB.getByte(bIndex)) {
    988                 return false;
    989             }
    990             aIndex ++;
    991             bIndex ++;
    992         }
    993
    994         return true;
    995     }
    996
    997     /**
    998      * Compares the two specified buffers as described in {@link ChannelBuffer#compareTo(ChannelBuffer)}.
    999      * This method is useful when implementing a new buffer type.
    1000      */
    1001     public static int compare(ChannelBuffer bufferA, ChannelBuffer bufferB) {
    1002         final int aLen = bufferA.readableBytes();
    1003         final int bLen = bufferB.readableBytes();
    1004         final int minLength = Math.min(aLen, bLen);
    1005         final int uintCount = minLength >>> 2;
    1006         final int byteCount = minLength & 3;
    1007
    1008         int aIndex = bufferA.readerIndex();
    1009         int bIndex = bufferB.readerIndex();
    1010
    1011         if (bufferA.order() == bufferB.order()) {
    1012             for (int i = uintCount; i > 0; i --) {
    1013                 long va = bufferA.getUnsignedInt(aIndex);
    1014                 long vb = bufferB.getUnsignedInt(bIndex);
    1015                 if (va > vb) {
    1016                     return 1;
    1017                 } else if (va < vb) {
    1018                     return -1;
    1019                 }
    1020                 aIndex += 4;
    1021                 bIndex += 4;
    1022             }
    1023         } else {
    1024             for (int i = uintCount; i > 0; i --) {
    1025                 long va = bufferA.getUnsignedInt(aIndex);
    1026                 long vb = swapInt(bufferB.getInt(bIndex)) & 0xFFFFFFFFL;
    1027                 if (va > vb) {
    1028                     return 1;
    1029                 } else if (va < vb) {
    1030                     return -1;
    1031                 }
    1032                 aIndex += 4;
    1033                 bIndex += 4;
    1034             }
    1035         }
    1036
    1037         for (int i = byteCount; i > 0; i --) {
    1038             short va = bufferA.getUnsignedByte(aIndex);
    1039             short vb = bufferB.getUnsignedByte(bIndex);
    1040             if (va > vb) {
    1041                 return 1;
    1042             } else if (va < vb) {
    1043                 return -1;
    1044             }
    1045             aIndex ++;
    1046             bIndex ++;
    1047         }
    1048
    1049         return aLen - bLen;
    1050     }
    1051
    1052     /**
    1053      * The default implementation of {@link ChannelBuffer#indexOf(int, int, byte)}.
    1054      * This method is useful when implementing a new buffer type.
    1055      */
    1056     public static int indexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) {
    1057         if (fromIndex <= toIndex) {
    1058             return firstIndexOf(buffer, fromIndex, toIndex, value);
    1059         } else {
    1060             return lastIndexOf(buffer, fromIndex, toIndex, value);
    1061         }
    1062     }
    1063
    1064     /**
    1065      * The default implementation of {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)}.
    1066      * This method is useful when implementing a new buffer type.
    1067      */
    1068     public static int indexOf(
    1069             ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
    1070         if (fromIndex <= toIndex) {
    1071             return firstIndexOf(buffer, fromIndex, toIndex, indexFinder);
    1072         } else {
    1073             return lastIndexOf(buffer, fromIndex, toIndex, indexFinder);
    1074         }
    1075     }
    1076
    1077     /**
    1078      * Toggles the endianness of the specified 16-bit short integer.
    1079      */
    1080     public static short swapShort(short value) {
    1081         return (short) (value << 8 | value >>> 8 & 0xff);
    1082     }
    1083
    1084     /**
    1085      * Toggles the endianness of the specified 24-bit medium integer.
    1086      */
    1087     public static int swapMedium(int value) {
    1088         return value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff;
    1089     }
    1090
    1091     /**
    1092      * Toggles the endianness of the specified 32-bit integer.
    1093      */
    1094     public static int swapInt(int value) {
    1095         return swapShort((short) value) <<  16 |
    1096                swapShort((short) (value >>> 16)) & 0xffff;
    1097     }
    1098
    1099     /**
    1100      * Toggles the endianness of the specified 64-bit long integer.
    1101      */
    1102     public static long swapLong(long value) {
    1103         return (long) swapInt((int) value) <<  32 |
    1104                       swapInt((int) (value >>> 32)) & 0xffffffffL;
    1105     }
    1106
    1107     private static int firstIndexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) {
    1108         fromIndex = Math.max(fromIndex, 0);
    1109         if (fromIndex >= toIndex || buffer.capacity() == 0) {
    1110             return -1;
    1111         }
    1112
    1113         for (int i = fromIndex; i < toIndex; i ++) {
    1114             if (buffer.getByte(i) == value) {
    1115                 return i;
    1116             }
    1117         }
    1118
    1119         return -1;
    1120     }
    1121
    1122     private static int lastIndexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) {
    1123         fromIndex = Math.min(fromIndex, buffer.capacity());
    1124         if (fromIndex < 0 || buffer.capacity() == 0) {
    1125             return -1;
    1126         }
    1127
    1128         for (int i = fromIndex - 1; i >= toIndex; i --) {
    1129             if (buffer.getByte(i) == value) {
    1130                 return i;
    1131             }
    1132         }
    1133
    1134         return -1;
    1135     }
    1136
    1137     private static int firstIndexOf(
    1138             ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
    1139         fromIndex = Math.max(fromIndex, 0);
    1140         if (fromIndex >= toIndex || buffer.capacity() == 0) {
    1141             return -1;
    1142         }
    1143
    1144         for (int i = fromIndex; i < toIndex; i ++) {
    1145             if (indexFinder.find(buffer, i)) {
    1146                 return i;
    1147             }
    1148         }
    1149
    1150         return -1;
    1151     }
    1152
    1153     private static int lastIndexOf(
    1154             ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
    1155         fromIndex = Math.min(fromIndex, buffer.capacity());
    1156         if (fromIndex < 0 || buffer.capacity() == 0) {
    1157             return -1;
    1158         }
    1159
    1160         for (int i = fromIndex - 1; i >= toIndex; i --) {
    1161             if (indexFinder.find(buffer, i)) {
    1162                 return i;
    1163             }
    1164         }
    1165
    1166         return -1;
    1167     }
    1168
    1169     static ByteBuffer encodeString(CharBuffer src, Charset charset) {
    1170         final CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
    1171         final ByteBuffer dst = ByteBuffer.allocate(
    1172                 (int) ((double) src.remaining() * encoder.maxBytesPerChar()));
    1173         try {
    1174             CoderResult cr = encoder.encode(src, dst, true);
    1175             if (!cr.isUnderflow()) {
    1176                 cr.throwException();
    1177             }
    1178             cr = encoder.flush(dst);
    1179             if (!cr.isUnderflow()) {
    1180                 cr.throwException();
    1181             }
    1182         } catch (CharacterCodingException x) {
    1183             throw new IllegalStateException(x);
    1184         }
    1185         dst.flip();
    1186         return dst;
    1187     }
    1188
    1189     static String decodeString(ByteBuffer src, Charset charset) {
    1190         final CharsetDecoder decoder = CharsetUtil.getDecoder(charset);
    1191         final CharBuffer dst = CharBuffer.allocate(
    1192                 (int) ((double) src.remaining() * decoder.maxCharsPerByte()));
    1193         try {
    1194             CoderResult cr = decoder.decode(src, dst, true);
    1195             if (!cr.isUnderflow()) {
    1196                 cr.throwException();
    1197             }
    1198             cr = decoder.flush(dst);
    1199             if (!cr.isUnderflow()) {
    1200                 cr.throwException();
    1201             }
    1202         } catch (CharacterCodingException x) {
    1203             throw new IllegalStateException(x);
    1204         }
    1205         return dst.flip().toString();
    1206     }
    1207
    1208     private ChannelBuffers() {
    1209         // Unused
    1210     }
    1211 }