View Javadoc

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