View Javadoc

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