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.position(),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             short va = bufferA.getUnsignedByte(aIndex);
999             short vb = bufferB.getUnsignedByte(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 }