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 EmptyChannelBuffer();
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} 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 * Creates a new composite buffer which wraps the slices of the specified
452 * NIO buffers without copying them. A modification on the content of the
453 * specified buffers will be visible to the returned buffer.
454 *
455 * @throws IllegalArgumentException
456 * if the specified buffers' endianness are different from each
457 * other
458 */
459 public static ChannelBuffer wrappedBuffer(ByteBuffer... buffers) {
460 return wrappedBuffer(false, buffers);
461 }
462
463 /**
464 * Creates a new composite buffer which wraps the slices of the specified
465 * NIO buffers without copying them. A modification on the content of the
466 * specified buffers will be visible to the returned buffer.
467 * If gathering is {@code true} then gathering writes will be used when ever
468 * possible.
469 *
470 * @throws IllegalArgumentException
471 * if the specified buffers' endianness are different from each
472 * other
473 */
474 public static ChannelBuffer wrappedBuffer(boolean gathering, ByteBuffer... buffers) {
475 switch (buffers.length) {
476 case 0:
477 break;
478 case 1:
479 if (buffers[0].hasRemaining()) {
480 return wrappedBuffer(buffers[0]);
481 }
482 break;
483 default:
484 ByteOrder order = null;
485 final List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(buffers.length);
486 for (ByteBuffer b: buffers) {
487 if (b == null) {
488 break;
489 }
490 if (b.hasRemaining()) {
491 if (order != null) {
492 if (!order.equals(b.order())) {
493 throw new IllegalArgumentException(
494 "inconsistent byte order");
495 }
496 } else {
497 order = b.order();
498 }
499 components.add(wrappedBuffer(b));
500 }
501 }
502 return compositeBuffer(order, components, gathering);
503 }
504
505 return EMPTY_BUFFER;
506 }
507
508 /**
509 * Creates a new big-endian buffer whose content is a copy of the
510 * specified {@code array}. The new buffer's {@code readerIndex} and
511 * {@code writerIndex} are {@code 0} and {@code array.length} respectively.
512 */
513 public static ChannelBuffer copiedBuffer(byte[] array) {
514 return copiedBuffer(BIG_ENDIAN, array);
515 }
516
517 /**
518 * Creates a new buffer with the specified {@code endianness} whose
519 * content is a copy of the specified {@code array}. The new buffer's
520 * {@code readerIndex} and {@code writerIndex} are {@code 0} and
521 * {@code array.length} respectively.
522 */
523 public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[] array) {
524 if (endianness == BIG_ENDIAN) {
525 if (array.length == 0) {
526 return EMPTY_BUFFER;
527 }
528 return new BigEndianHeapChannelBuffer(array.clone());
529 } else if (endianness == LITTLE_ENDIAN) {
530 if (array.length == 0) {
531 return EMPTY_BUFFER;
532 }
533 return new LittleEndianHeapChannelBuffer(array.clone());
534 } else {
535 throw new NullPointerException("endianness");
536 }
537 }
538
539 /**
540 * Creates a new big-endian buffer whose content is a copy of the
541 * specified {@code array}'s sub-region. The new buffer's
542 * {@code readerIndex} and {@code writerIndex} are {@code 0} and
543 * the specified {@code length} respectively.
544 */
545 public static ChannelBuffer copiedBuffer(byte[] array, int offset, int length) {
546 return copiedBuffer(BIG_ENDIAN, array, offset, length);
547 }
548
549 /**
550 * Creates a new buffer with the specified {@code endianness} whose
551 * content is a copy of the specified {@code array}'s sub-region. The new
552 * buffer's {@code readerIndex} and {@code writerIndex} are {@code 0} and
553 * the specified {@code length} respectively.
554 */
555 public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[] array, int offset, int length) {
556 if (endianness == null) {
557 throw new NullPointerException("endianness");
558 }
559 if (length == 0) {
560 return EMPTY_BUFFER;
561 }
562 byte[] copy = new byte[length];
563 System.arraycopy(array, offset, copy, 0, length);
564 return wrappedBuffer(endianness, copy);
565 }
566
567 /**
568 * Creates a new buffer whose content is a copy of the specified
569 * {@code buffer}'s current slice. The new buffer's {@code readerIndex}
570 * and {@code writerIndex} are {@code 0} and {@code buffer.remaining}
571 * respectively.
572 */
573 public static ChannelBuffer copiedBuffer(ByteBuffer buffer) {
574 int length = buffer.remaining();
575 if (length == 0) {
576 return EMPTY_BUFFER;
577 }
578 byte[] copy = new byte[length];
579 int position = buffer.position();
580 try {
581 buffer.get(copy);
582 } finally {
583 buffer.position(position);
584 }
585 return wrappedBuffer(buffer.order(), copy);
586 }
587
588 /**
589 * Creates a new buffer whose content is a copy of the specified
590 * {@code buffer}'s readable bytes. The new buffer's {@code readerIndex}
591 * and {@code writerIndex} are {@code 0} and {@code buffer.readableBytes}
592 * respectively.
593 */
594 public static ChannelBuffer copiedBuffer(ChannelBuffer buffer) {
595 if (buffer.readable()) {
596 return buffer.copy();
597 } else {
598 return EMPTY_BUFFER;
599 }
600 }
601
602 /**
603 * Creates a new big-endian buffer whose content is a merged copy of
604 * the specified {@code arrays}. The new buffer's {@code readerIndex}
605 * and {@code writerIndex} are {@code 0} and the sum of all arrays'
606 * {@code length} respectively.
607 */
608 public static ChannelBuffer copiedBuffer(byte[]... arrays) {
609 return copiedBuffer(BIG_ENDIAN, arrays);
610 }
611
612 /**
613 * Creates a new buffer with the specified {@code endianness} whose
614 * content is a merged copy of the specified {@code arrays}. The new
615 * buffer's {@code readerIndex} and {@code writerIndex} are {@code 0}
616 * and the sum of all arrays' {@code length} respectively.
617 */
618 public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[]... arrays) {
619 switch (arrays.length) {
620 case 0:
621 return EMPTY_BUFFER;
622 case 1:
623 if (arrays[0].length == 0) {
624 return EMPTY_BUFFER;
625 } else {
626 return copiedBuffer(endianness, arrays[0]);
627 }
628 }
629
630 // Merge the specified arrays into one array.
631 int length = 0;
632 for (byte[] a: arrays) {
633 if (Integer.MAX_VALUE - length < a.length) {
634 throw new IllegalArgumentException(
635 "The total length of the specified arrays is too big.");
636 }
637 length += a.length;
638 }
639
640 if (length == 0) {
641 return EMPTY_BUFFER;
642 }
643
644 byte[] mergedArray = new byte[length];
645 for (int i = 0, j = 0; i < arrays.length; i ++) {
646 byte[] a = arrays[i];
647 System.arraycopy(a, 0, mergedArray, j, a.length);
648 j += a.length;
649 }
650
651 return wrappedBuffer(endianness, mergedArray);
652 }
653
654 /**
655 * Creates a new buffer whose content is a merged copy of the specified
656 * {@code buffers}' readable bytes. The new buffer's {@code readerIndex}
657 * and {@code writerIndex} are {@code 0} and the sum of all buffers'
658 * {@code readableBytes} respectively.
659 *
660 * @throws IllegalArgumentException
661 * if the specified buffers' endianness are different from each
662 * other
663 */
664 public static ChannelBuffer copiedBuffer(ChannelBuffer... buffers) {
665 switch (buffers.length) {
666 case 0:
667 return EMPTY_BUFFER;
668 case 1:
669 return copiedBuffer(buffers[0]);
670 }
671
672 ChannelBuffer[] copiedBuffers = new ChannelBuffer[buffers.length];
673 for (int i = 0; i < buffers.length; i ++) {
674 copiedBuffers[i] = copiedBuffer(buffers[i]);
675 }
676 return wrappedBuffer(false, copiedBuffers);
677 }
678
679 /**
680 * Creates a new buffer whose content is a merged copy of the specified
681 * {@code buffers}' slices. The new buffer's {@code readerIndex} and
682 * {@code writerIndex} are {@code 0} and the sum of all buffers'
683 * {@code remaining} respectively.
684 *
685 * @throws IllegalArgumentException
686 * if the specified buffers' endianness are different from each
687 * other
688 */
689 public static ChannelBuffer copiedBuffer(ByteBuffer... buffers) {
690 switch (buffers.length) {
691 case 0:
692 return EMPTY_BUFFER;
693 case 1:
694 return copiedBuffer(buffers[0]);
695 }
696
697 ChannelBuffer[] copiedBuffers = new ChannelBuffer[buffers.length];
698 for (int i = 0; i < buffers.length; i ++) {
699 copiedBuffers[i] = copiedBuffer(buffers[i]);
700 }
701 return wrappedBuffer(false, copiedBuffers);
702 }
703
704 /**
705 * Creates a new big-endian buffer whose content is the specified
706 * {@code string} encoded in the specified {@code charset}.
707 * The new buffer's {@code readerIndex} and {@code writerIndex} are
708 * {@code 0} and the length of the encoded string respectively.
709 */
710 public static ChannelBuffer copiedBuffer(CharSequence string, Charset charset) {
711 return copiedBuffer(BIG_ENDIAN, string, charset);
712 }
713
714 /**
715 * Creates a new big-endian buffer whose content is a subregion of
716 * the specified {@code string} encoded in the specified {@code charset}.
717 * The new buffer's {@code readerIndex} and {@code writerIndex} are
718 * {@code 0} and the length of the encoded string respectively.
719 */
720 public static ChannelBuffer copiedBuffer(
721 CharSequence string, int offset, int length, Charset charset) {
722 return copiedBuffer(BIG_ENDIAN, string, offset, length, charset);
723 }
724
725 /**
726 * Creates a new buffer with the specified {@code endianness} whose
727 * content is the specified {@code string} encoded in the specified
728 * {@code charset}. The new buffer's {@code readerIndex} and
729 * {@code writerIndex} are {@code 0} and the length of the encoded string
730 * respectively.
731 */
732 public static ChannelBuffer copiedBuffer(ByteOrder endianness, CharSequence string, Charset charset) {
733 if (string == null) {
734 throw new NullPointerException("string");
735 }
736
737 if (string instanceof CharBuffer) {
738 return copiedBuffer(endianness, (CharBuffer) string, charset);
739 }
740
741 return copiedBuffer(endianness, CharBuffer.wrap(string), charset);
742 }
743
744 /**
745 * Creates a new buffer with the specified {@code endianness} whose
746 * content is a subregion of the specified {@code string} encoded in the
747 * specified {@code charset}. The new buffer's {@code readerIndex} and
748 * {@code writerIndex} are {@code 0} and the length of the encoded string
749 * respectively.
750 */
751 public static ChannelBuffer copiedBuffer(
752 ByteOrder endianness, CharSequence string, int offset, int length, Charset charset) {
753 if (string == null) {
754 throw new NullPointerException("string");
755 }
756 if (length == 0) {
757 return EMPTY_BUFFER;
758 }
759
760 if (string instanceof CharBuffer) {
761 CharBuffer buf = (CharBuffer) string;
762 if (buf.hasArray()) {
763 return copiedBuffer(
764 endianness,
765 buf.array(),
766 buf.arrayOffset() + buf.position() + offset,
767 length, charset);
768 }
769
770 buf = buf.slice();
771 buf.limit(length);
772 buf.position(offset);
773 return copiedBuffer(endianness, buf, charset);
774 }
775
776 return copiedBuffer(
777 endianness, CharBuffer.wrap(string, offset, offset + length),
778 charset);
779 }
780
781 /**
782 * Creates a new big-endian buffer whose content is the specified
783 * {@code array} encoded in the specified {@code charset}.
784 * The new buffer's {@code readerIndex} and {@code writerIndex} are
785 * {@code 0} and the length of the encoded string respectively.
786 */
787 public static ChannelBuffer copiedBuffer(char[] array, Charset charset) {
788 return copiedBuffer(BIG_ENDIAN, array, 0, array.length, charset);
789 }
790
791 /**
792 * Creates a new big-endian buffer whose content is a subregion of
793 * the specified {@code array} encoded in the specified {@code charset}.
794 * The new buffer's {@code readerIndex} and {@code writerIndex} are
795 * {@code 0} and the length of the encoded string respectively.
796 */
797 public static ChannelBuffer copiedBuffer(
798 char[] array, int offset, int length, Charset charset) {
799 return copiedBuffer(BIG_ENDIAN, array, offset, length, charset);
800 }
801
802 /**
803 * Creates a new buffer with the specified {@code endianness} whose
804 * content is the specified {@code array} encoded in the specified
805 * {@code charset}. The new buffer's {@code readerIndex} and
806 * {@code writerIndex} are {@code 0} and the length of the encoded string
807 * respectively.
808 */
809 public static ChannelBuffer copiedBuffer(ByteOrder endianness, char[] array, Charset charset) {
810 return copiedBuffer(endianness, array, 0, array.length, charset);
811 }
812
813 /**
814 * Creates a new buffer with the specified {@code endianness} whose
815 * content is a subregion of the specified {@code array} encoded in the
816 * specified {@code charset}. The new buffer's {@code readerIndex} and
817 * {@code writerIndex} are {@code 0} and the length of the encoded string
818 * respectively.
819 */
820 public static ChannelBuffer copiedBuffer(
821 ByteOrder endianness, char[] array, int offset, int length, Charset charset) {
822 if (array == null) {
823 throw new NullPointerException("array");
824 }
825 if (length == 0) {
826 return EMPTY_BUFFER;
827 }
828 return copiedBuffer(
829 endianness, CharBuffer.wrap(array, offset, length), charset);
830 }
831
832 private static ChannelBuffer copiedBuffer(ByteOrder endianness, CharBuffer buffer, Charset charset) {
833 CharBuffer src = buffer;
834 ByteBuffer dst = encodeString(src, charset);
835 ChannelBuffer result = wrappedBuffer(endianness, dst.array());
836 result.writerIndex(dst.remaining());
837 return result;
838 }
839
840 /**
841 * Creates a read-only buffer which disallows any modification operations
842 * on the specified {@code buffer}. The new buffer has the same
843 * {@code readerIndex} and {@code writerIndex} with the specified
844 * {@code buffer}.
845 */
846 public static ChannelBuffer unmodifiableBuffer(ChannelBuffer buffer) {
847 if (buffer instanceof ReadOnlyChannelBuffer) {
848 buffer = ((ReadOnlyChannelBuffer) buffer).unwrap();
849 }
850 return new ReadOnlyChannelBuffer(buffer);
851 }
852
853 /**
854 * Create a {@link ChannelBuffer} from the given <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
855 */
856 public static ChannelBuffer hexDump(String hexString) {
857 int len = hexString.length();
858 byte[] hexData = new byte[len / 2];
859 for (int i = 0; i < len; i += 2) {
860 hexData[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
861 + Character.digit(hexString.charAt(i + 1), 16));
862 }
863 return wrappedBuffer(hexData);
864 }
865
866 /**
867 * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
868 * of the specified buffer's readable bytes.
869 */
870 public static String hexDump(ChannelBuffer buffer) {
871 return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
872 }
873
874 /**
875 * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
876 * of the specified buffer's sub-region.
877 */
878 public static String hexDump(ChannelBuffer buffer, int fromIndex, int length) {
879 if (length < 0) {
880 throw new IllegalArgumentException("length: " + length);
881 }
882 if (length == 0) {
883 return "";
884 }
885
886 int endIndex = fromIndex + length;
887 char[] buf = new char[length << 1];
888
889 int srcIdx = fromIndex;
890 int dstIdx = 0;
891 for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
892 System.arraycopy(
893 HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1,
894 buf, dstIdx, 2);
895 }
896
897 return new String(buf);
898 }
899
900 /**
901 * Calculates the hash code of the specified buffer. This method is
902 * useful when implementing a new buffer type.
903 */
904 public static int hashCode(ChannelBuffer buffer) {
905 final int aLen = buffer.readableBytes();
906 final int intCount = aLen >>> 2;
907 final int byteCount = aLen & 3;
908
909 int hashCode = 1;
910 int arrayIndex = buffer.readerIndex();
911 if (buffer.order() == BIG_ENDIAN) {
912 for (int i = intCount; i > 0; i --) {
913 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
914 arrayIndex += 4;
915 }
916 } else {
917 for (int i = intCount; i > 0; i --) {
918 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
919 arrayIndex += 4;
920 }
921 }
922
923 for (int i = byteCount; i > 0; i --) {
924 hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
925 }
926
927 if (hashCode == 0) {
928 hashCode = 1;
929 }
930
931 return hashCode;
932 }
933
934 /**
935 * Returns {@code true} if and only if the two specified buffers are
936 * identical to each other as described in {@code ChannelBuffer#equals(Object)}.
937 * This method is useful when implementing a new buffer type.
938 */
939 public static boolean equals(ChannelBuffer bufferA, ChannelBuffer bufferB) {
940 final int aLen = bufferA.readableBytes();
941 if (aLen != bufferB.readableBytes()) {
942 return false;
943 }
944
945 final int longCount = aLen >>> 3;
946 final int byteCount = aLen & 7;
947
948 int aIndex = bufferA.readerIndex();
949 int bIndex = bufferB.readerIndex();
950
951 if (bufferA.order() == bufferB.order()) {
952 for (int i = longCount; i > 0; i --) {
953 if (bufferA.getLong(aIndex) != bufferB.getLong(bIndex)) {
954 return false;
955 }
956 aIndex += 8;
957 bIndex += 8;
958 }
959 } else {
960 for (int i = longCount; i > 0; i --) {
961 if (bufferA.getLong(aIndex) != swapLong(bufferB.getLong(bIndex))) {
962 return false;
963 }
964 aIndex += 8;
965 bIndex += 8;
966 }
967 }
968
969 for (int i = byteCount; i > 0; i --) {
970 if (bufferA.getByte(aIndex) != bufferB.getByte(bIndex)) {
971 return false;
972 }
973 aIndex ++;
974 bIndex ++;
975 }
976
977 return true;
978 }
979
980 /**
981 * Compares the two specified buffers as described in {@link ChannelBuffer#compareTo(ChannelBuffer)}.
982 * This method is useful when implementing a new buffer type.
983 */
984 public static int compare(ChannelBuffer bufferA, ChannelBuffer bufferB) {
985 final int aLen = bufferA.readableBytes();
986 final int bLen = bufferB.readableBytes();
987 final int minLength = Math.min(aLen, bLen);
988 final int uintCount = minLength >>> 2;
989 final int byteCount = minLength & 3;
990
991 int aIndex = bufferA.readerIndex();
992 int bIndex = bufferB.readerIndex();
993
994 if (bufferA.order() == bufferB.order()) {
995 for (int i = uintCount; i > 0; i --) {
996 long va = bufferA.getUnsignedInt(aIndex);
997 long vb = bufferB.getUnsignedInt(bIndex);
998 if (va > vb) {
999 return 1;
1000 }
1001 if (va < vb) {
1002 return -1;
1003 }
1004 aIndex += 4;
1005 bIndex += 4;
1006 }
1007 } else {
1008 for (int i = uintCount; i > 0; i --) {
1009 long va = bufferA.getUnsignedInt(aIndex);
1010 long vb = swapInt(bufferB.getInt(bIndex)) & 0xFFFFFFFFL;
1011 if (va > vb) {
1012 return 1;
1013 }
1014 if (va < vb) {
1015 return -1;
1016 }
1017 aIndex += 4;
1018 bIndex += 4;
1019 }
1020 }
1021
1022 for (int i = byteCount; i > 0; i --) {
1023 short va = bufferA.getUnsignedByte(aIndex);
1024 short vb = bufferB.getUnsignedByte(bIndex);
1025 if (va > vb) {
1026 return 1;
1027 }
1028 if (va < vb) {
1029 return -1;
1030 }
1031 aIndex ++;
1032 bIndex ++;
1033 }
1034
1035 return aLen - bLen;
1036 }
1037
1038 /**
1039 * The default implementation of {@link ChannelBuffer#indexOf(int, int, byte)}.
1040 * This method is useful when implementing a new buffer type.
1041 */
1042 public static int indexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) {
1043 if (fromIndex <= toIndex) {
1044 return firstIndexOf(buffer, fromIndex, toIndex, value);
1045 } else {
1046 return lastIndexOf(buffer, fromIndex, toIndex, value);
1047 }
1048 }
1049
1050 /**
1051 * The default implementation of {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)}.
1052 * This method is useful when implementing a new buffer type.
1053 */
1054 public static int indexOf(
1055 ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
1056 if (fromIndex <= toIndex) {
1057 return firstIndexOf(buffer, fromIndex, toIndex, indexFinder);
1058 } else {
1059 return lastIndexOf(buffer, fromIndex, toIndex, indexFinder);
1060 }
1061 }
1062
1063 /**
1064 * Toggles the endianness of the specified 16-bit short integer.
1065 */
1066 public static short swapShort(short value) {
1067 return (short) (value << 8 | value >>> 8 & 0xff);
1068 }
1069
1070 /**
1071 * Toggles the endianness of the specified 24-bit medium integer.
1072 */
1073 public static int swapMedium(int value) {
1074 return value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff;
1075 }
1076
1077 /**
1078 * Toggles the endianness of the specified 32-bit integer.
1079 */
1080 public static int swapInt(int value) {
1081 return swapShort((short) value) << 16 |
1082 swapShort((short) (value >>> 16)) & 0xffff;
1083 }
1084
1085 /**
1086 * Toggles the endianness of the specified 64-bit long integer.
1087 */
1088 public static long swapLong(long value) {
1089 return (long) swapInt((int) value) << 32 |
1090 swapInt((int) (value >>> 32)) & 0xffffffffL;
1091 }
1092
1093 private static int firstIndexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) {
1094 fromIndex = Math.max(fromIndex, 0);
1095 if (fromIndex >= toIndex || buffer.capacity() == 0) {
1096 return -1;
1097 }
1098
1099 for (int i = fromIndex; i < toIndex; i ++) {
1100 if (buffer.getByte(i) == value) {
1101 return i;
1102 }
1103 }
1104
1105 return -1;
1106 }
1107
1108 private static int lastIndexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) {
1109 fromIndex = Math.min(fromIndex, buffer.capacity());
1110 if (fromIndex < 0 || buffer.capacity() == 0) {
1111 return -1;
1112 }
1113
1114 for (int i = fromIndex - 1; i >= toIndex; i --) {
1115 if (buffer.getByte(i) == value) {
1116 return i;
1117 }
1118 }
1119
1120 return -1;
1121 }
1122
1123 private static int firstIndexOf(
1124 ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
1125 fromIndex = Math.max(fromIndex, 0);
1126 if (fromIndex >= toIndex || buffer.capacity() == 0) {
1127 return -1;
1128 }
1129
1130 for (int i = fromIndex; i < toIndex; i ++) {
1131 if (indexFinder.find(buffer, i)) {
1132 return i;
1133 }
1134 }
1135
1136 return -1;
1137 }
1138
1139 private static int lastIndexOf(
1140 ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
1141 fromIndex = Math.min(fromIndex, buffer.capacity());
1142 if (fromIndex < 0 || buffer.capacity() == 0) {
1143 return -1;
1144 }
1145
1146 for (int i = fromIndex - 1; i >= toIndex; i --) {
1147 if (indexFinder.find(buffer, i)) {
1148 return i;
1149 }
1150 }
1151
1152 return -1;
1153 }
1154
1155 static ByteBuffer encodeString(CharBuffer src, Charset charset) {
1156 final CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
1157 final ByteBuffer dst = ByteBuffer.allocate(
1158 (int) ((double) src.remaining() * encoder.maxBytesPerChar()));
1159 try {
1160 CoderResult cr = encoder.encode(src, dst, true);
1161 if (!cr.isUnderflow()) {
1162 cr.throwException();
1163 }
1164 cr = encoder.flush(dst);
1165 if (!cr.isUnderflow()) {
1166 cr.throwException();
1167 }
1168 } catch (CharacterCodingException x) {
1169 throw new IllegalStateException(x);
1170 }
1171 dst.flip();
1172 return dst;
1173 }
1174
1175 static String decodeString(ByteBuffer src, Charset charset) {
1176 final CharsetDecoder decoder = CharsetUtil.getDecoder(charset);
1177 final CharBuffer dst = CharBuffer.allocate(
1178 (int) ((double) src.remaining() * decoder.maxCharsPerByte()));
1179 try {
1180 CoderResult cr = decoder.decode(src, dst, true);
1181 if (!cr.isUnderflow()) {
1182 cr.throwException();
1183 }
1184 cr = decoder.flush(dst);
1185 if (!cr.isUnderflow()) {
1186 cr.throwException();
1187 }
1188 } catch (CharacterCodingException x) {
1189 throw new IllegalStateException(x);
1190 }
1191 return dst.flip().toString();
1192 }
1193
1194 private ChannelBuffers() {
1195 // Unused
1196 }
1197 }