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 io.netty.buffer;
17  
18  import io.netty.util.AsciiString;
19  import io.netty.util.ByteProcessor;
20  import io.netty.util.CharsetUtil;
21  import io.netty.util.Recycler;
22  import io.netty.util.Recycler.Handle;
23  import io.netty.util.concurrent.FastThreadLocal;
24  import io.netty.util.internal.PlatformDependent;
25  import io.netty.util.internal.StringUtil;
26  import io.netty.util.internal.SystemPropertyUtil;
27  import io.netty.util.internal.logging.InternalLogger;
28  import io.netty.util.internal.logging.InternalLoggerFactory;
29  
30  import java.io.IOException;
31  import java.io.OutputStream;
32  import java.nio.ByteBuffer;
33  import java.nio.ByteOrder;
34  import java.nio.CharBuffer;
35  import java.nio.charset.CharacterCodingException;
36  import java.nio.charset.Charset;
37  import java.nio.charset.CharsetDecoder;
38  import java.nio.charset.CharsetEncoder;
39  import java.nio.charset.CoderResult;
40  import java.nio.charset.CodingErrorAction;
41  import java.util.Arrays;
42  import java.util.Locale;
43  
44  import static io.netty.util.internal.MathUtil.isOutOfBounds;
45  import static io.netty.util.internal.ObjectUtil.checkNotNull;
46  import static io.netty.util.internal.StringUtil.NEWLINE;
47  import static io.netty.util.internal.StringUtil.isSurrogate;
48  
49  /**
50   * A collection of utility methods that is related with handling {@link ByteBuf},
51   * such as the generation of hex dump and swapping an integer's byte order.
52   */
53  public final class ByteBufUtil {
54  
55      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ByteBufUtil.class);
56      private static final FastThreadLocal<CharBuffer> CHAR_BUFFERS = new FastThreadLocal<CharBuffer>() {
57          @Override
58          protected CharBuffer initialValue() throws Exception {
59              return CharBuffer.allocate(1024);
60          }
61      };
62  
63      private static final byte WRITE_UTF_UNKNOWN = (byte) '?';
64      private static final int MAX_CHAR_BUFFER_SIZE;
65      private static final int THREAD_LOCAL_BUFFER_SIZE;
66      private static final int MAX_BYTES_PER_CHAR_UTF8 =
67              (int) CharsetUtil.encoder(CharsetUtil.UTF_8).maxBytesPerChar();
68  
69      static final int WRITE_CHUNK_SIZE = 8192;
70      static final ByteBufAllocator DEFAULT_ALLOCATOR;
71  
72      static {
73          String allocType = SystemPropertyUtil.get(
74                  "io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
75          allocType = allocType.toLowerCase(Locale.US).trim();
76  
77          ByteBufAllocator alloc;
78          if ("unpooled".equals(allocType)) {
79              alloc = UnpooledByteBufAllocator.DEFAULT;
80              logger.debug("-Dio.netty.allocator.type: {}", allocType);
81          } else if ("pooled".equals(allocType)) {
82              alloc = PooledByteBufAllocator.DEFAULT;
83              logger.debug("-Dio.netty.allocator.type: {}", allocType);
84          } else {
85              alloc = PooledByteBufAllocator.DEFAULT;
86              logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
87          }
88  
89          DEFAULT_ALLOCATOR = alloc;
90  
91          THREAD_LOCAL_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalDirectBufferSize", 0);
92          logger.debug("-Dio.netty.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE);
93  
94          MAX_CHAR_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.maxThreadLocalCharBufferSize", 16 * 1024);
95          logger.debug("-Dio.netty.maxThreadLocalCharBufferSize: {}", MAX_CHAR_BUFFER_SIZE);
96      }
97  
98      /**
99       * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
100      * of the specified buffer's readable bytes.
101      */
102     public static String hexDump(ByteBuf buffer) {
103         return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
104     }
105 
106     /**
107      * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
108      * of the specified buffer's sub-region.
109      */
110     public static String hexDump(ByteBuf buffer, int fromIndex, int length) {
111         return HexUtil.hexDump(buffer, fromIndex, length);
112     }
113 
114     /**
115      * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
116      * of the specified byte array.
117      */
118     public static String hexDump(byte[] array) {
119         return hexDump(array, 0, array.length);
120     }
121 
122     /**
123      * Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
124      * of the specified byte array's sub-region.
125      */
126     public static String hexDump(byte[] array, int fromIndex, int length) {
127         return HexUtil.hexDump(array, fromIndex, length);
128     }
129 
130     /**
131      * Decode a 2-digit hex byte from within a string.
132      */
133     public static byte decodeHexByte(CharSequence s, int pos) {
134         return StringUtil.decodeHexByte(s, pos);
135     }
136 
137     /**
138      * Decodes a string generated by {@link #hexDump(byte[])}
139      */
140     public static byte[] decodeHexDump(CharSequence hexDump) {
141         return StringUtil.decodeHexDump(hexDump, 0, hexDump.length());
142     }
143 
144     /**
145      * Decodes part of a string generated by {@link #hexDump(byte[])}
146      */
147     public static byte[] decodeHexDump(CharSequence hexDump, int fromIndex, int length) {
148         return StringUtil.decodeHexDump(hexDump, fromIndex, length);
149     }
150 
151     /**
152      * Used to determine if the return value of {@link ByteBuf#ensureWritable(int, boolean)} means that there is
153      * adequate space and a write operation will succeed.
154      * @param ensureWritableResult The return value from {@link ByteBuf#ensureWritable(int, boolean)}.
155      * @return {@code true} if {@code ensureWritableResult} means that there is adequate space and a write operation
156      * will succeed.
157      */
158     public static boolean ensureWritableSuccess(int ensureWritableResult) {
159         return ensureWritableResult == 0 || ensureWritableResult == 2;
160     }
161 
162     /**
163      * Calculates the hash code of the specified buffer.  This method is
164      * useful when implementing a new buffer type.
165      */
166     public static int hashCode(ByteBuf buffer) {
167         final int aLen = buffer.readableBytes();
168         final int intCount = aLen >>> 2;
169         final int byteCount = aLen & 3;
170 
171         int hashCode = EmptyByteBuf.EMPTY_BYTE_BUF_HASH_CODE;
172         int arrayIndex = buffer.readerIndex();
173         if (buffer.order() == ByteOrder.BIG_ENDIAN) {
174             for (int i = intCount; i > 0; i --) {
175                 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
176                 arrayIndex += 4;
177             }
178         } else {
179             for (int i = intCount; i > 0; i --) {
180                 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
181                 arrayIndex += 4;
182             }
183         }
184 
185         for (int i = byteCount; i > 0; i --) {
186             hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
187         }
188 
189         if (hashCode == 0) {
190             hashCode = 1;
191         }
192 
193         return hashCode;
194     }
195 
196     /**
197      * Returns the reader index of needle in haystack, or -1 if needle is not in haystack.
198      */
199     public static int indexOf(ByteBuf needle, ByteBuf haystack) {
200         // TODO: maybe use Boyer Moore for efficiency.
201         int attempts = haystack.readableBytes() - needle.readableBytes() + 1;
202         for (int i = 0; i < attempts; i++) {
203             if (equals(needle, needle.readerIndex(),
204                        haystack, haystack.readerIndex() + i,
205                        needle.readableBytes())) {
206                 return haystack.readerIndex() + i;
207             }
208         }
209         return -1;
210     }
211 
212     /**
213      * Returns {@code true} if and only if the two specified buffers are
214      * identical to each other for {@code length} bytes starting at {@code aStartIndex}
215      * index for the {@code a} buffer and {@code bStartIndex} index for the {@code b} buffer.
216      * A more compact way to express this is:
217      * <p>
218      * {@code a[aStartIndex : aStartIndex + length] == b[bStartIndex : bStartIndex + length]}
219      */
220     public static boolean equals(ByteBuf a, int aStartIndex, ByteBuf b, int bStartIndex, int length) {
221         if (aStartIndex < 0 || bStartIndex < 0 || length < 0) {
222             throw new IllegalArgumentException("All indexes and lengths must be non-negative");
223         }
224         if (a.writerIndex() - length < aStartIndex || b.writerIndex() - length < bStartIndex) {
225             return false;
226         }
227 
228         final int longCount = length >>> 3;
229         final int byteCount = length & 7;
230 
231         if (a.order() == b.order()) {
232             for (int i = longCount; i > 0; i --) {
233                 if (a.getLong(aStartIndex) != b.getLong(bStartIndex)) {
234                     return false;
235                 }
236                 aStartIndex += 8;
237                 bStartIndex += 8;
238             }
239         } else {
240             for (int i = longCount; i > 0; i --) {
241                 if (a.getLong(aStartIndex) != swapLong(b.getLong(bStartIndex))) {
242                     return false;
243                 }
244                 aStartIndex += 8;
245                 bStartIndex += 8;
246             }
247         }
248 
249         for (int i = byteCount; i > 0; i --) {
250             if (a.getByte(aStartIndex) != b.getByte(bStartIndex)) {
251                 return false;
252             }
253             aStartIndex ++;
254             bStartIndex ++;
255         }
256 
257         return true;
258     }
259 
260     /**
261      * Returns {@code true} if and only if the two specified buffers are
262      * identical to each other as described in {@link ByteBuf#equals(Object)}.
263      * This method is useful when implementing a new buffer type.
264      */
265     public static boolean equals(ByteBuf bufferA, ByteBuf bufferB) {
266         final int aLen = bufferA.readableBytes();
267         if (aLen != bufferB.readableBytes()) {
268             return false;
269         }
270         return equals(bufferA, bufferA.readerIndex(), bufferB, bufferB.readerIndex(), aLen);
271     }
272 
273     /**
274      * Compares the two specified buffers as described in {@link ByteBuf#compareTo(ByteBuf)}.
275      * This method is useful when implementing a new buffer type.
276      */
277     public static int compare(ByteBuf bufferA, ByteBuf bufferB) {
278         final int aLen = bufferA.readableBytes();
279         final int bLen = bufferB.readableBytes();
280         final int minLength = Math.min(aLen, bLen);
281         final int uintCount = minLength >>> 2;
282         final int byteCount = minLength & 3;
283         int aIndex = bufferA.readerIndex();
284         int bIndex = bufferB.readerIndex();
285 
286         if (uintCount > 0) {
287             boolean bufferAIsBigEndian = bufferA.order() == ByteOrder.BIG_ENDIAN;
288             final long res;
289             int uintCountIncrement = uintCount << 2;
290 
291             if (bufferA.order() == bufferB.order()) {
292                 res = bufferAIsBigEndian ? compareUintBigEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
293                         compareUintLittleEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
294             } else {
295                 res = bufferAIsBigEndian ? compareUintBigEndianA(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
296                         compareUintBigEndianB(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
297             }
298             if (res != 0) {
299                 // Ensure we not overflow when cast
300                 return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, res));
301             }
302             aIndex += uintCountIncrement;
303             bIndex += uintCountIncrement;
304         }
305 
306         for (int aEnd = aIndex + byteCount; aIndex < aEnd; ++aIndex, ++bIndex) {
307             int comp = bufferA.getUnsignedByte(aIndex) - bufferB.getUnsignedByte(bIndex);
308             if (comp != 0) {
309                 return comp;
310             }
311         }
312 
313         return aLen - bLen;
314     }
315 
316     private static long compareUintBigEndian(
317             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
318         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
319             long comp = bufferA.getUnsignedInt(aIndex) - bufferB.getUnsignedInt(bIndex);
320             if (comp != 0) {
321                 return comp;
322             }
323         }
324         return 0;
325     }
326 
327     private static long compareUintLittleEndian(
328             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
329         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
330             long comp = bufferA.getUnsignedIntLE(aIndex) - bufferB.getUnsignedIntLE(bIndex);
331             if (comp != 0) {
332                 return comp;
333             }
334         }
335         return 0;
336     }
337 
338     private static long compareUintBigEndianA(
339             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
340         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
341             long comp =  bufferA.getUnsignedInt(aIndex) - bufferB.getUnsignedIntLE(bIndex);
342             if (comp != 0) {
343                 return comp;
344             }
345         }
346         return 0;
347     }
348 
349     private static long compareUintBigEndianB(
350             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
351         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
352             long comp =  bufferA.getUnsignedIntLE(aIndex) - bufferB.getUnsignedInt(bIndex);
353             if (comp != 0) {
354                 return comp;
355             }
356         }
357         return 0;
358     }
359 
360     /**
361      * The default implementation of {@link ByteBuf#indexOf(int, int, byte)}.
362      * This method is useful when implementing a new buffer type.
363      */
364     public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value) {
365         if (fromIndex <= toIndex) {
366             return firstIndexOf(buffer, fromIndex, toIndex, value);
367         } else {
368             return lastIndexOf(buffer, fromIndex, toIndex, value);
369         }
370     }
371 
372     /**
373      * Toggles the endianness of the specified 16-bit short integer.
374      */
375     public static short swapShort(short value) {
376         return Short.reverseBytes(value);
377     }
378 
379     /**
380      * Toggles the endianness of the specified 24-bit medium integer.
381      */
382     public static int swapMedium(int value) {
383         int swapped = value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff;
384         if ((swapped & 0x800000) != 0) {
385             swapped |= 0xff000000;
386         }
387         return swapped;
388     }
389 
390     /**
391      * Toggles the endianness of the specified 32-bit integer.
392      */
393     public static int swapInt(int value) {
394         return Integer.reverseBytes(value);
395     }
396 
397     /**
398      * Toggles the endianness of the specified 64-bit long integer.
399      */
400     public static long swapLong(long value) {
401         return Long.reverseBytes(value);
402     }
403 
404     /**
405      * Writes a big-endian 16-bit short integer to the buffer.
406      */
407     @SuppressWarnings("deprecation")
408     public static ByteBuf writeShortBE(ByteBuf buf, int shortValue) {
409         return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeShort(shortValue) : buf.writeShortLE(shortValue);
410     }
411 
412     /**
413      * Sets a big-endian 16-bit short integer to the buffer.
414      */
415     @SuppressWarnings("deprecation")
416     public static ByteBuf setShortBE(ByteBuf buf, int index, int shortValue) {
417         return buf.order() == ByteOrder.BIG_ENDIAN? buf.setShort(index, shortValue) : buf.setShortLE(index, shortValue);
418     }
419 
420     /**
421      * Writes a big-endian 24-bit medium integer to the buffer.
422      */
423     @SuppressWarnings("deprecation")
424     public static ByteBuf writeMediumBE(ByteBuf buf, int mediumValue) {
425         return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeMedium(mediumValue) : buf.writeMediumLE(mediumValue);
426     }
427 
428     /**
429      * Read the given amount of bytes into a new {@link ByteBuf} that is allocated from the {@link ByteBufAllocator}.
430      */
431     public static ByteBuf readBytes(ByteBufAllocator alloc, ByteBuf buffer, int length) {
432         boolean release = true;
433         ByteBuf dst = alloc.buffer(length);
434         try {
435             buffer.readBytes(dst);
436             release = false;
437             return dst;
438         } finally {
439             if (release) {
440                 dst.release();
441             }
442         }
443     }
444 
445     private static int firstIndexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value) {
446         fromIndex = Math.max(fromIndex, 0);
447         if (fromIndex >= toIndex || buffer.capacity() == 0) {
448             return -1;
449         }
450 
451         return buffer.forEachByte(fromIndex, toIndex - fromIndex, new ByteProcessor.IndexOfProcessor(value));
452     }
453 
454     private static int lastIndexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value) {
455         fromIndex = Math.min(fromIndex, buffer.capacity());
456         if (fromIndex < 0 || buffer.capacity() == 0) {
457             return -1;
458         }
459 
460         return buffer.forEachByteDesc(toIndex, fromIndex - toIndex, new ByteProcessor.IndexOfProcessor(value));
461     }
462 
463     /**
464      * Encode a {@link CharSequence} in <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
465      * it to a {@link ByteBuf} allocated with {@code alloc}.
466      * @param alloc The allocator used to allocate a new {@link ByteBuf}.
467      * @param seq The characters to write into a buffer.
468      * @return The {@link ByteBuf} which contains the <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoded
469      * result.
470      */
471     public static ByteBuf writeUtf8(ByteBufAllocator alloc, CharSequence seq) {
472         // UTF-8 uses max. 3 bytes per char, so calculate the worst case.
473         ByteBuf buf = alloc.buffer(utf8MaxBytes(seq));
474         writeUtf8(buf, seq);
475         return buf;
476     }
477 
478     /**
479      * Encode a {@link CharSequence} in <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
480      * it to a {@link ByteBuf}.
481      * <p>
482      * It behaves like {@link #reserveAndWriteUtf8(ByteBuf, CharSequence, int)} with {@code reserveBytes}
483      * computed by {@link #utf8MaxBytes(CharSequence)}.<br>
484      * This method returns the actual number of bytes written.
485      */
486     public static int writeUtf8(ByteBuf buf, CharSequence seq) {
487         return reserveAndWriteUtf8(buf, seq, utf8MaxBytes(seq));
488     }
489 
490     /**
491      * Encode a {@link CharSequence} in <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
492      * it into {@code reserveBytes} of a {@link ByteBuf}.
493      * <p>
494      * The {@code reserveBytes} must be computed (ie eagerly using {@link #utf8MaxBytes(CharSequence)}
495      * or exactly with {@link #utf8Bytes(CharSequence)}) to ensure this method to not fail: for performance reasons
496      * the index checks will be performed using just {@code reserveBytes}.<br>
497      * This method returns the actual number of bytes written.
498      */
499     public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int reserveBytes) {
500         for (;;) {
501             if (buf instanceof AbstractByteBuf) {
502                 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
503                 byteBuf.ensureWritable0(reserveBytes);
504                 int written = writeUtf8(byteBuf, byteBuf.writerIndex, seq, seq.length());
505                 byteBuf.writerIndex += written;
506                 return written;
507             } else if (buf instanceof WrappedByteBuf) {
508                 // Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
509                 buf = buf.unwrap();
510             } else {
511                 byte[] bytes = seq.toString().getBytes(CharsetUtil.UTF_8);
512                 buf.writeBytes(bytes);
513                 return bytes.length;
514             }
515         }
516     }
517 
518     // Fast-Path implementation
519     static int writeUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
520         int oldWriterIndex = writerIndex;
521 
522         // We can use the _set methods as these not need to do any index checks and reference checks.
523         // This is possible as we called ensureWritable(...) before.
524         for (int i = 0; i < len; i++) {
525             char c = seq.charAt(i);
526             if (c < 0x80) {
527                 buffer._setByte(writerIndex++, (byte) c);
528             } else if (c < 0x800) {
529                 buffer._setByte(writerIndex++, (byte) (0xc0 | (c >> 6)));
530                 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
531             } else if (isSurrogate(c)) {
532                 if (!Character.isHighSurrogate(c)) {
533                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
534                     continue;
535                 }
536                 final char c2;
537                 try {
538                     // Surrogate Pair consumes 2 characters. Optimistically try to get the next character to avoid
539                     // duplicate bounds checking with charAt. If an IndexOutOfBoundsException is thrown we will
540                     // re-throw a more informative exception describing the problem.
541                     c2 = seq.charAt(++i);
542                 } catch (IndexOutOfBoundsException ignored) {
543                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
544                     break;
545                 }
546                 if (!Character.isLowSurrogate(c2)) {
547                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
548                     buffer._setByte(writerIndex++, Character.isHighSurrogate(c2) ? WRITE_UTF_UNKNOWN : c2);
549                     continue;
550                 }
551                 int codePoint = Character.toCodePoint(c, c2);
552                 // See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
553                 buffer._setByte(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
554                 buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
555                 buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
556                 buffer._setByte(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
557             } else {
558                 buffer._setByte(writerIndex++, (byte) (0xe0 | (c >> 12)));
559                 buffer._setByte(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
560                 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
561             }
562         }
563         return writerIndex - oldWriterIndex;
564     }
565 
566     /**
567      * Returns max bytes length of UTF8 character sequence of the given length.
568      */
569     public static int utf8MaxBytes(final int seqLength) {
570         return seqLength * MAX_BYTES_PER_CHAR_UTF8;
571     }
572 
573     /**
574      * Returns max bytes length of UTF8 character sequence.
575      * <p>
576      * It behaves like {@link #utf8MaxBytes(int)} applied to {@code seq} {@link CharSequence#length()}.
577      */
578     public static int utf8MaxBytes(CharSequence seq) {
579         return utf8MaxBytes(seq.length());
580     }
581 
582     /**
583      * Returns the exact bytes length of UTF8 character sequence.
584      * <p>
585      * This method is producing the exact length according to {@link #writeUtf8(ByteBuf, CharSequence)}.
586      */
587     public static int utf8Bytes(final CharSequence seq) {
588         if (seq instanceof AsciiString) {
589             return seq.length();
590         }
591         int seqLength = seq.length();
592         int i = 0;
593         // ASCII fast path
594         while (i < seqLength && seq.charAt(i) < 0x80) {
595             ++i;
596         }
597         // !ASCII is packed in a separate method to let the ASCII case be smaller
598         return i < seqLength ? i + utf8Bytes(seq, i, seqLength) : i;
599     }
600 
601     private static int utf8Bytes(final CharSequence seq, final int start, final int length) {
602         int encodedLength = 0;
603         for (int i = start; i < length; i++) {
604             final char c = seq.charAt(i);
605             // making it 100% branchless isn't rewarding due to the many bit operations necessary!
606             if (c < 0x800) {
607                 // branchless version of: (c <= 127 ? 0:1) + 1
608                 encodedLength += ((0x7f - c) >>> 31) + 1;
609             } else if (isSurrogate(c)) {
610                 if (!Character.isHighSurrogate(c)) {
611                     encodedLength++;
612                     // WRITE_UTF_UNKNOWN
613                     continue;
614                 }
615                 final char c2;
616                 try {
617                     // Surrogate Pair consumes 2 characters. Optimistically try to get the next character to avoid
618                     // duplicate bounds checking with charAt.
619                     c2 = seq.charAt(++i);
620                 } catch (IndexOutOfBoundsException ignored) {
621                     encodedLength++;
622                     // WRITE_UTF_UNKNOWN
623                     break;
624                 }
625                 if (!Character.isLowSurrogate(c2)) {
626                     // WRITE_UTF_UNKNOWN + (Character.isHighSurrogate(c2) ? WRITE_UTF_UNKNOWN : c2)
627                     encodedLength += 2;
628                     continue;
629                 }
630                 // See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
631                 encodedLength += 4;
632             } else {
633                 encodedLength += 3;
634             }
635         }
636         return encodedLength;
637     }
638 
639     /**
640      * Encode a {@link CharSequence} in <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> and write
641      * it to a {@link ByteBuf} allocated with {@code alloc}.
642      * @param alloc The allocator used to allocate a new {@link ByteBuf}.
643      * @param seq The characters to write into a buffer.
644      * @return The {@link ByteBuf} which contains the <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> encoded
645      * result.
646      */
647     public static ByteBuf writeAscii(ByteBufAllocator alloc, CharSequence seq) {
648         // ASCII uses 1 byte per char
649         ByteBuf buf = alloc.buffer(seq.length());
650         writeAscii(buf, seq);
651         return buf;
652     }
653 
654     /**
655      * Encode a {@link CharSequence} in <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> and write it
656      * to a {@link ByteBuf}.
657      *
658      * This method returns the actual number of bytes written.
659      */
660     public static int writeAscii(ByteBuf buf, CharSequence seq) {
661         // ASCII uses 1 byte per char
662         final int len = seq.length();
663         if (seq instanceof AsciiString) {
664             AsciiString asciiString = (AsciiString) seq;
665             buf.writeBytes(asciiString.array(), asciiString.arrayOffset(), len);
666         } else {
667             for (;;) {
668                 if (buf instanceof AbstractByteBuf) {
669                     AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
670                     byteBuf.ensureWritable0(len);
671                     int written = writeAscii(byteBuf, byteBuf.writerIndex, seq, len);
672                     byteBuf.writerIndex += written;
673                     return written;
674                 } else if (buf instanceof WrappedByteBuf) {
675                     // Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
676                     buf = buf.unwrap();
677                 } else {
678                     byte[] bytes = seq.toString().getBytes(CharsetUtil.US_ASCII);
679                     buf.writeBytes(bytes);
680                     return bytes.length;
681                 }
682             }
683         }
684         return len;
685     }
686 
687     // Fast-Path implementation
688     static int writeAscii(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
689 
690         // We can use the _set methods as these not need to do any index checks and reference checks.
691         // This is possible as we called ensureWritable(...) before.
692         for (int i = 0; i < len; i++) {
693             buffer._setByte(writerIndex++, AsciiString.c2b(seq.charAt(i)));
694         }
695         return len;
696     }
697 
698     /**
699      * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which
700      * is allocated via the {@link ByteBufAllocator}.
701      */
702     public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset) {
703         return encodeString0(alloc, false, src, charset, 0);
704     }
705 
706     /**
707      * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which
708      * is allocated via the {@link ByteBufAllocator}.
709      *
710      * @param alloc The {@link ByteBufAllocator} to allocate {@link ByteBuf}.
711      * @param src The {@link CharBuffer} to encode.
712      * @param charset The specified {@link Charset}.
713      * @param extraCapacity the extra capacity to alloc except the space for decoding.
714      */
715     public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset, int extraCapacity) {
716         return encodeString0(alloc, false, src, charset, extraCapacity);
717     }
718 
719     static ByteBuf encodeString0(ByteBufAllocator alloc, boolean enforceHeap, CharBuffer src, Charset charset,
720                                  int extraCapacity) {
721         final CharsetEncoder encoder = CharsetUtil.encoder(charset);
722         int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar()) + extraCapacity;
723         boolean release = true;
724         final ByteBuf dst;
725         if (enforceHeap) {
726             dst = alloc.heapBuffer(length);
727         } else {
728             dst = alloc.buffer(length);
729         }
730         try {
731             final ByteBuffer dstBuf = dst.internalNioBuffer(dst.readerIndex(), length);
732             final int pos = dstBuf.position();
733             CoderResult cr = encoder.encode(src, dstBuf, true);
734             if (!cr.isUnderflow()) {
735                 cr.throwException();
736             }
737             cr = encoder.flush(dstBuf);
738             if (!cr.isUnderflow()) {
739                 cr.throwException();
740             }
741             dst.writerIndex(dst.writerIndex() + dstBuf.position() - pos);
742             release = false;
743             return dst;
744         } catch (CharacterCodingException x) {
745             throw new IllegalStateException(x);
746         } finally {
747             if (release) {
748                 dst.release();
749             }
750         }
751     }
752 
753     static String decodeString(ByteBuf src, int readerIndex, int len, Charset charset) {
754         if (len == 0) {
755             return StringUtil.EMPTY_STRING;
756         }
757         final CharsetDecoder decoder = CharsetUtil.decoder(charset);
758         final int maxLength = (int) ((double) len * decoder.maxCharsPerByte());
759         CharBuffer dst = CHAR_BUFFERS.get();
760         if (dst.length() < maxLength) {
761             dst = CharBuffer.allocate(maxLength);
762             if (maxLength <= MAX_CHAR_BUFFER_SIZE) {
763                 CHAR_BUFFERS.set(dst);
764             }
765         } else {
766             dst.clear();
767         }
768         if (src.nioBufferCount() == 1) {
769             decodeString(decoder, src.nioBuffer(readerIndex, len), dst);
770         } else {
771             // We use a heap buffer as CharsetDecoder is most likely able to use a fast-path if src and dst buffers
772             // are both backed by a byte array.
773             ByteBuf buffer = src.alloc().heapBuffer(len);
774             try {
775                 buffer.writeBytes(src, readerIndex, len);
776                 // Use internalNioBuffer(...) to reduce object creation.
777                 decodeString(decoder, buffer.internalNioBuffer(buffer.readerIndex(), len), dst);
778             } finally {
779                 // Release the temporary buffer again.
780                 buffer.release();
781             }
782         }
783         return dst.flip().toString();
784     }
785 
786     private static void decodeString(CharsetDecoder decoder, ByteBuffer src, CharBuffer dst) {
787         try {
788             CoderResult cr = decoder.decode(src, dst, true);
789             if (!cr.isUnderflow()) {
790                 cr.throwException();
791             }
792             cr = decoder.flush(dst);
793             if (!cr.isUnderflow()) {
794                 cr.throwException();
795             }
796         } catch (CharacterCodingException x) {
797             throw new IllegalStateException(x);
798         }
799     }
800 
801     /**
802      * Returns a cached thread-local direct buffer, if available.
803      *
804      * @return a cached thread-local direct buffer, if available.  {@code null} otherwise.
805      */
806     public static ByteBuf threadLocalDirectBuffer() {
807         if (THREAD_LOCAL_BUFFER_SIZE <= 0) {
808             return null;
809         }
810 
811         if (PlatformDependent.hasUnsafe()) {
812             return ThreadLocalUnsafeDirectByteBuf.newInstance();
813         } else {
814             return ThreadLocalDirectByteBuf.newInstance();
815         }
816     }
817 
818     /**
819      * Create a copy of the underlying storage from {@code buf} into a byte array.
820      * The copy will start at {@link ByteBuf#readerIndex()} and copy {@link ByteBuf#readableBytes()} bytes.
821      */
822     public static byte[] getBytes(ByteBuf buf) {
823         return getBytes(buf,  buf.readerIndex(), buf.readableBytes());
824     }
825 
826     /**
827      * Create a copy of the underlying storage from {@code buf} into a byte array.
828      * The copy will start at {@code start} and copy {@code length} bytes.
829      */
830     public static byte[] getBytes(ByteBuf buf, int start, int length) {
831         return getBytes(buf, start, length, true);
832     }
833 
834     /**
835      * Return an array of the underlying storage from {@code buf} into a byte array.
836      * The copy will start at {@code start} and copy {@code length} bytes.
837      * If {@code copy} is true a copy will be made of the memory.
838      * If {@code copy} is false the underlying storage will be shared, if possible.
839      */
840     public static byte[] getBytes(ByteBuf buf, int start, int length, boolean copy) {
841         if (isOutOfBounds(start, length, buf.capacity())) {
842             throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
843                     + ") <= " + "buf.capacity(" + buf.capacity() + ')');
844         }
845 
846         if (buf.hasArray()) {
847             if (copy || start != 0 || length != buf.capacity()) {
848                 int baseOffset = buf.arrayOffset() + start;
849                 return Arrays.copyOfRange(buf.array(), baseOffset, baseOffset + length);
850             } else {
851                 return buf.array();
852             }
853         }
854 
855         byte[] v = new byte[length];
856         buf.getBytes(start, v);
857         return v;
858     }
859 
860     /**
861      * Copies the all content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
862      *
863      * @param src the source string to copy
864      * @param dst the destination buffer
865      */
866     public static void copy(AsciiString src, ByteBuf dst) {
867         copy(src, 0, dst, src.length());
868     }
869 
870     /**
871      * Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#setBytes(int, byte[], int, int)}.
872      * Unlike the {@link #copy(AsciiString, ByteBuf)} and {@link #copy(AsciiString, int, ByteBuf, int)} methods,
873      * this method do not increase a {@code writerIndex} of {@code dst} buffer.
874      *
875      * @param src the source string to copy
876      * @param srcIdx the starting offset of characters to copy
877      * @param dst the destination buffer
878      * @param dstIdx the starting offset in the destination buffer
879      * @param length the number of characters to copy
880      */
881     public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int dstIdx, int length) {
882         if (isOutOfBounds(srcIdx, length, src.length())) {
883             throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
884                             + length + ") <= srcLen(" + src.length() + ')');
885         }
886 
887         checkNotNull(dst, "dst").setBytes(dstIdx, src.array(), srcIdx + src.arrayOffset(), length);
888     }
889 
890     /**
891      * Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
892      *
893      * @param src the source string to copy
894      * @param srcIdx the starting offset of characters to copy
895      * @param dst the destination buffer
896      * @param length the number of characters to copy
897      */
898     public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int length) {
899         if (isOutOfBounds(srcIdx, length, src.length())) {
900             throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
901                             + length + ") <= srcLen(" + src.length() + ')');
902         }
903 
904         checkNotNull(dst, "dst").writeBytes(src.array(), srcIdx + src.arrayOffset(), length);
905     }
906 
907     /**
908      * Returns a multi-line hexadecimal dump of the specified {@link ByteBuf} that is easy to read by humans.
909      */
910     public static String prettyHexDump(ByteBuf buffer) {
911         return prettyHexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
912     }
913 
914     /**
915      * Returns a multi-line hexadecimal dump of the specified {@link ByteBuf} that is easy to read by humans,
916      * starting at the given {@code offset} using the given {@code length}.
917      */
918     public static String prettyHexDump(ByteBuf buffer, int offset, int length) {
919         return HexUtil.prettyHexDump(buffer, offset, length);
920     }
921 
922     /**
923      * Appends the prettified multi-line hexadecimal dump of the specified {@link ByteBuf} to the specified
924      * {@link StringBuilder} that is easy to read by humans.
925      */
926     public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf) {
927         appendPrettyHexDump(dump, buf, buf.readerIndex(), buf.readableBytes());
928     }
929 
930     /**
931      * Appends the prettified multi-line hexadecimal dump of the specified {@link ByteBuf} to the specified
932      * {@link StringBuilder} that is easy to read by humans, starting at the given {@code offset} using
933      * the given {@code length}.
934      */
935     public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
936         HexUtil.appendPrettyHexDump(dump, buf, offset, length);
937     }
938 
939     /* Separate class so that the expensive static initialization is only done when needed */
940     private static final class HexUtil {
941 
942         private static final char[] BYTE2CHAR = new char[256];
943         private static final char[] HEXDUMP_TABLE = new char[256 * 4];
944         private static final String[] HEXPADDING = new String[16];
945         private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4];
946         private static final String[] BYTE2HEX = new String[256];
947         private static final String[] BYTEPADDING = new String[16];
948 
949         static {
950             final char[] DIGITS = "0123456789abcdef".toCharArray();
951             for (int i = 0; i < 256; i ++) {
952                 HEXDUMP_TABLE[ i << 1     ] = DIGITS[i >>> 4 & 0x0F];
953                 HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i       & 0x0F];
954             }
955 
956             int i;
957 
958             // Generate the lookup table for hex dump paddings
959             for (i = 0; i < HEXPADDING.length; i ++) {
960                 int padding = HEXPADDING.length - i;
961                 StringBuilder buf = new StringBuilder(padding * 3);
962                 for (int j = 0; j < padding; j ++) {
963                     buf.append("   ");
964                 }
965                 HEXPADDING[i] = buf.toString();
966             }
967 
968             // Generate the lookup table for the start-offset header in each row (up to 64KiB).
969             for (i = 0; i < HEXDUMP_ROWPREFIXES.length; i ++) {
970                 StringBuilder buf = new StringBuilder(12);
971                 buf.append(NEWLINE);
972                 buf.append(Long.toHexString(i << 4 & 0xFFFFFFFFL | 0x100000000L));
973                 buf.setCharAt(buf.length() - 9, '|');
974                 buf.append('|');
975                 HEXDUMP_ROWPREFIXES[i] = buf.toString();
976             }
977 
978             // Generate the lookup table for byte-to-hex-dump conversion
979             for (i = 0; i < BYTE2HEX.length; i ++) {
980                 BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i);
981             }
982 
983             // Generate the lookup table for byte dump paddings
984             for (i = 0; i < BYTEPADDING.length; i ++) {
985                 int padding = BYTEPADDING.length - i;
986                 StringBuilder buf = new StringBuilder(padding);
987                 for (int j = 0; j < padding; j ++) {
988                     buf.append(' ');
989                 }
990                 BYTEPADDING[i] = buf.toString();
991             }
992 
993             // Generate the lookup table for byte-to-char conversion
994             for (i = 0; i < BYTE2CHAR.length; i ++) {
995                 if (i <= 0x1f || i >= 0x7f) {
996                     BYTE2CHAR[i] = '.';
997                 } else {
998                     BYTE2CHAR[i] = (char) i;
999                 }
1000             }
1001         }
1002 
1003         private static String hexDump(ByteBuf buffer, int fromIndex, int length) {
1004             if (length < 0) {
1005               throw new IllegalArgumentException("length: " + length);
1006             }
1007             if (length == 0) {
1008               return "";
1009             }
1010 
1011             int endIndex = fromIndex + length;
1012             char[] buf = new char[length << 1];
1013 
1014             int srcIdx = fromIndex;
1015             int dstIdx = 0;
1016             for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1017               System.arraycopy(
1018                   HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1,
1019                   buf, dstIdx, 2);
1020             }
1021 
1022             return new String(buf);
1023         }
1024 
1025         private static String hexDump(byte[] array, int fromIndex, int length) {
1026             if (length < 0) {
1027               throw new IllegalArgumentException("length: " + length);
1028             }
1029             if (length == 0) {
1030                 return "";
1031             }
1032 
1033             int endIndex = fromIndex + length;
1034             char[] buf = new char[length << 1];
1035 
1036             int srcIdx = fromIndex;
1037             int dstIdx = 0;
1038             for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1039                 System.arraycopy(
1040                     HEXDUMP_TABLE, (array[srcIdx] & 0xFF) << 1,
1041                     buf, dstIdx, 2);
1042             }
1043 
1044             return new String(buf);
1045         }
1046 
1047         private static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1048             if (length == 0) {
1049               return StringUtil.EMPTY_STRING;
1050             } else {
1051                 int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4;
1052                 StringBuilder buf = new StringBuilder(rows * 80);
1053                 appendPrettyHexDump(buf, buffer, offset, length);
1054                 return buf.toString();
1055             }
1056         }
1057 
1058         private static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1059             if (isOutOfBounds(offset, length, buf.capacity())) {
1060                 throw new IndexOutOfBoundsException(
1061                         "expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length
1062                                                     + ") <= " + "buf.capacity(" + buf.capacity() + ')');
1063             }
1064             if (length == 0) {
1065                 return;
1066             }
1067             dump.append(
1068                               "         +-------------------------------------------------+" +
1069                     NEWLINE + "         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |" +
1070                     NEWLINE + "+--------+-------------------------------------------------+----------------+");
1071 
1072             final int startIndex = offset;
1073             final int fullRows = length >>> 4;
1074             final int remainder = length & 0xF;
1075 
1076             // Dump the rows which have 16 bytes.
1077             for (int row = 0; row < fullRows; row ++) {
1078                 int rowStartIndex = (row << 4) + startIndex;
1079 
1080                 // Per-row prefix.
1081                 appendHexDumpRowPrefix(dump, row, rowStartIndex);
1082 
1083                 // Hex dump
1084                 int rowEndIndex = rowStartIndex + 16;
1085                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1086                     dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1087                 }
1088                 dump.append(" |");
1089 
1090                 // ASCII dump
1091                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1092                     dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1093                 }
1094                 dump.append('|');
1095             }
1096 
1097             // Dump the last row which has less than 16 bytes.
1098             if (remainder != 0) {
1099                 int rowStartIndex = (fullRows << 4) + startIndex;
1100                 appendHexDumpRowPrefix(dump, fullRows, rowStartIndex);
1101 
1102                 // Hex dump
1103                 int rowEndIndex = rowStartIndex + remainder;
1104                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1105                     dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1106                 }
1107                 dump.append(HEXPADDING[remainder]);
1108                 dump.append(" |");
1109 
1110                 // Ascii dump
1111                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1112                     dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1113                 }
1114                 dump.append(BYTEPADDING[remainder]);
1115                 dump.append('|');
1116             }
1117 
1118             dump.append(NEWLINE +
1119                         "+--------+-------------------------------------------------+----------------+");
1120         }
1121 
1122         private static void appendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartIndex) {
1123             if (row < HEXDUMP_ROWPREFIXES.length) {
1124                 dump.append(HEXDUMP_ROWPREFIXES[row]);
1125             } else {
1126                 dump.append(NEWLINE);
1127                 dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L));
1128                 dump.setCharAt(dump.length() - 9, '|');
1129                 dump.append('|');
1130             }
1131         }
1132     }
1133 
1134     static final class ThreadLocalUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
1135 
1136         private static final Recycler<ThreadLocalUnsafeDirectByteBuf> RECYCLER =
1137                 new Recycler<ThreadLocalUnsafeDirectByteBuf>() {
1138                     @Override
1139                     protected ThreadLocalUnsafeDirectByteBuf newObject(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1140                         return new ThreadLocalUnsafeDirectByteBuf(handle);
1141                     }
1142                 };
1143 
1144         static ThreadLocalUnsafeDirectByteBuf newInstance() {
1145             ThreadLocalUnsafeDirectByteBuf buf = RECYCLER.get();
1146             buf.setRefCnt(1);
1147             return buf;
1148         }
1149 
1150         private final Handle<ThreadLocalUnsafeDirectByteBuf> handle;
1151 
1152         private ThreadLocalUnsafeDirectByteBuf(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1153             super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1154             this.handle = handle;
1155         }
1156 
1157         @Override
1158         protected void deallocate() {
1159             if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1160                 super.deallocate();
1161             } else {
1162                 clear();
1163                 handle.recycle(this);
1164             }
1165         }
1166     }
1167 
1168     static final class ThreadLocalDirectByteBuf extends UnpooledDirectByteBuf {
1169 
1170         private static final Recycler<ThreadLocalDirectByteBuf> RECYCLER = new Recycler<ThreadLocalDirectByteBuf>() {
1171             @Override
1172             protected ThreadLocalDirectByteBuf newObject(Handle<ThreadLocalDirectByteBuf> handle) {
1173                 return new ThreadLocalDirectByteBuf(handle);
1174             }
1175         };
1176 
1177         static ThreadLocalDirectByteBuf newInstance() {
1178             ThreadLocalDirectByteBuf buf = RECYCLER.get();
1179             buf.setRefCnt(1);
1180             return buf;
1181         }
1182 
1183         private final Handle<ThreadLocalDirectByteBuf> handle;
1184 
1185         private ThreadLocalDirectByteBuf(Handle<ThreadLocalDirectByteBuf> handle) {
1186             super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1187             this.handle = handle;
1188         }
1189 
1190         @Override
1191         protected void deallocate() {
1192             if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1193                 super.deallocate();
1194             } else {
1195                 clear();
1196                 handle.recycle(this);
1197             }
1198         }
1199     }
1200 
1201     /**
1202      * Returns {@code true} if the given {@link ByteBuf} is valid text using the given {@link Charset},
1203      * otherwise return {@code false}.
1204      *
1205      * @param buf The given {@link ByteBuf}.
1206      * @param charset The specified {@link Charset}.
1207      */
1208     public static boolean isText(ByteBuf buf, Charset charset) {
1209         return isText(buf, buf.readerIndex(), buf.readableBytes(), charset);
1210     }
1211 
1212     /**
1213      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1214      * text using the given {@link Charset}, otherwise return {@code false}.
1215      *
1216      * @param buf The given {@link ByteBuf}.
1217      * @param index The start index of the specified buffer.
1218      * @param length The length of the specified buffer.
1219      * @param charset The specified {@link Charset}.
1220      *
1221      * @throws IndexOutOfBoundsException if {@code index} + {@code length} is greater than {@code buf.readableBytes}
1222      */
1223     public static boolean isText(ByteBuf buf, int index, int length, Charset charset) {
1224         checkNotNull(buf, "buf");
1225         checkNotNull(charset, "charset");
1226         final int maxIndex = buf.readerIndex() + buf.readableBytes();
1227         if (index < 0 || length < 0 || index > maxIndex - length) {
1228             throw new IndexOutOfBoundsException("index: " + index + " length: " + length);
1229         }
1230         if (charset.equals(CharsetUtil.UTF_8)) {
1231             return isUtf8(buf, index, length);
1232         } else if (charset.equals(CharsetUtil.US_ASCII)) {
1233             return isAscii(buf, index, length);
1234         } else {
1235             CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
1236             try {
1237                 if (buf.nioBufferCount() == 1) {
1238                     decoder.decode(buf.nioBuffer(index, length));
1239                 } else {
1240                     ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
1241                     try {
1242                         heapBuffer.writeBytes(buf, index, length);
1243                         decoder.decode(heapBuffer.internalNioBuffer(heapBuffer.readerIndex(), length));
1244                     } finally {
1245                         heapBuffer.release();
1246                     }
1247                 }
1248                 return true;
1249             } catch (CharacterCodingException ignore) {
1250                 return false;
1251             }
1252         }
1253     }
1254 
1255     /**
1256      * Aborts on a byte which is not a valid ASCII character.
1257      */
1258     private static final ByteProcessor FIND_NON_ASCII = new ByteProcessor() {
1259         @Override
1260         public boolean process(byte value) {
1261             return value >= 0;
1262         }
1263     };
1264 
1265     /**
1266      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1267      * ASCII text, otherwise return {@code false}.
1268      *
1269      * @param buf    The given {@link ByteBuf}.
1270      * @param index  The start index of the specified buffer.
1271      * @param length The length of the specified buffer.
1272      */
1273     private static boolean isAscii(ByteBuf buf, int index, int length) {
1274         return buf.forEachByte(index, length, FIND_NON_ASCII) == -1;
1275     }
1276 
1277     /**
1278      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1279      * UTF8 text, otherwise return {@code false}.
1280      *
1281      * @param buf The given {@link ByteBuf}.
1282      * @param index The start index of the specified buffer.
1283      * @param length The length of the specified buffer.
1284      *
1285      * @see
1286      * <a href=http://www.ietf.org/rfc/rfc3629.txt>UTF-8 Definition</a>
1287      *
1288      * <pre>
1289      * 1. Bytes format of UTF-8
1290      *
1291      * The table below summarizes the format of these different octet types.
1292      * The letter x indicates bits available for encoding bits of the character number.
1293      *
1294      * Char. number range  |        UTF-8 octet sequence
1295      *    (hexadecimal)    |              (binary)
1296      * --------------------+---------------------------------------------
1297      * 0000 0000-0000 007F | 0xxxxxxx
1298      * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1299      * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1300      * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1301      * </pre>
1302      *
1303      * <pre>
1304      * 2. Syntax of UTF-8 Byte Sequences
1305      *
1306      * UTF8-octets = *( UTF8-char )
1307      * UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
1308      * UTF8-1      = %x00-7F
1309      * UTF8-2      = %xC2-DF UTF8-tail
1310      * UTF8-3      = %xE0 %xA0-BF UTF8-tail /
1311      *               %xE1-EC 2( UTF8-tail ) /
1312      *               %xED %x80-9F UTF8-tail /
1313      *               %xEE-EF 2( UTF8-tail )
1314      * UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) /
1315      *               %xF1-F3 3( UTF8-tail ) /
1316      *               %xF4 %x80-8F 2( UTF8-tail )
1317      * UTF8-tail   = %x80-BF
1318      * </pre>
1319      */
1320     private static boolean isUtf8(ByteBuf buf, int index, int length) {
1321         final int endIndex = index + length;
1322         while (index < endIndex) {
1323             byte b1 = buf.getByte(index++);
1324             byte b2, b3, b4;
1325             if ((b1 & 0x80) == 0) {
1326                 // 1 byte
1327                 continue;
1328             }
1329             if ((b1 & 0xE0) == 0xC0) {
1330                 // 2 bytes
1331                 //
1332                 // Bit/Byte pattern
1333                 // 110xxxxx    10xxxxxx
1334                 // C2..DF      80..BF
1335                 if (index >= endIndex) { // no enough bytes
1336                     return false;
1337                 }
1338                 b2 = buf.getByte(index++);
1339                 if ((b2 & 0xC0) != 0x80) { // 2nd byte not starts with 10
1340                     return false;
1341                 }
1342                 if ((b1 & 0xFF) < 0xC2) { // out of lower bound
1343                     return false;
1344                 }
1345             } else if ((b1 & 0xF0) == 0xE0) {
1346                 // 3 bytes
1347                 //
1348                 // Bit/Byte pattern
1349                 // 1110xxxx    10xxxxxx    10xxxxxx
1350                 // E0          A0..BF      80..BF
1351                 // E1..EC      80..BF      80..BF
1352                 // ED          80..9F      80..BF
1353                 // E1..EF      80..BF      80..BF
1354                 if (index > endIndex - 2) { // no enough bytes
1355                     return false;
1356                 }
1357                 b2 = buf.getByte(index++);
1358                 b3 = buf.getByte(index++);
1359                 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { // 2nd or 3rd bytes not start with 10
1360                     return false;
1361                 }
1362                 if ((b1 & 0x0F) == 0x00 && (b2 & 0xFF) < 0xA0) { // out of lower bound
1363                     return false;
1364                 }
1365                 if ((b1 & 0x0F) == 0x0D && (b2 & 0xFF) > 0x9F) { // out of upper bound
1366                     return false;
1367                 }
1368             } else if ((b1 & 0xF8) == 0xF0) {
1369                 // 4 bytes
1370                 //
1371                 // Bit/Byte pattern
1372                 // 11110xxx    10xxxxxx    10xxxxxx    10xxxxxx
1373                 // F0          90..BF      80..BF      80..BF
1374                 // F1..F3      80..BF      80..BF      80..BF
1375                 // F4          80..8F      80..BF      80..BF
1376                 if (index > endIndex - 3) { // no enough bytes
1377                     return false;
1378                 }
1379                 b2 = buf.getByte(index++);
1380                 b3 = buf.getByte(index++);
1381                 b4 = buf.getByte(index++);
1382                 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80) {
1383                     // 2nd, 3rd or 4th bytes not start with 10
1384                     return false;
1385                 }
1386                 if ((b1 & 0xFF) > 0xF4 // b1 invalid
1387                         || (b1 & 0xFF) == 0xF0 && (b2 & 0xFF) < 0x90    // b2 out of lower bound
1388                         || (b1 & 0xFF) == 0xF4 && (b2 & 0xFF) > 0x8F) { // b2 out of upper bound
1389                     return false;
1390                 }
1391             } else {
1392                 return false;
1393             }
1394         }
1395         return true;
1396     }
1397 
1398     /**
1399      * Read bytes from the given {@link ByteBuffer} into the given {@link OutputStream} using the {@code position} and
1400      * {@code length}. The position and limit of the given {@link ByteBuffer} may be adjusted.
1401      */
1402     static void readBytes(ByteBufAllocator allocator, ByteBuffer buffer, int position, int length, OutputStream out)
1403             throws IOException {
1404         if (buffer.hasArray()) {
1405             out.write(buffer.array(), position + buffer.arrayOffset(), length);
1406         } else {
1407             int chunkLen = Math.min(length, WRITE_CHUNK_SIZE);
1408             buffer.clear().position(position);
1409 
1410             if (allocator.isDirectBufferPooled()) {
1411                 // if direct buffers are pooled chances are good that heap buffers are pooled as well.
1412                 ByteBuf tmpBuf = allocator.heapBuffer(chunkLen);
1413                 try {
1414                     byte[] tmp = tmpBuf.array();
1415                     int offset = tmpBuf.arrayOffset();
1416                     getBytes(buffer, tmp, offset, chunkLen, out, length);
1417                 } finally {
1418                     tmpBuf.release();
1419                 }
1420             } else {
1421                 getBytes(buffer, new byte[chunkLen], 0, chunkLen, out, length);
1422             }
1423         }
1424     }
1425 
1426     private static void getBytes(ByteBuffer inBuffer, byte[] in, int inOffset, int inLen, OutputStream out, int outLen)
1427             throws IOException {
1428         do {
1429             int len = Math.min(inLen, outLen);
1430             inBuffer.get(in, inOffset, len);
1431             out.write(in, inOffset, len);
1432             outLen -= len;
1433         } while (outLen > 0);
1434     }
1435 
1436     private ByteBufUtil() { }
1437 }