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    *   https://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.IllegalReferenceCountException;
22  import io.netty.util.concurrent.FastThreadLocal;
23  import io.netty.util.internal.MathUtil;
24  import io.netty.util.internal.ObjectPool;
25  import io.netty.util.internal.ObjectPool.Handle;
26  import io.netty.util.internal.ObjectPool.ObjectCreator;
27  import io.netty.util.internal.PlatformDependent;
28  import io.netty.util.internal.StringUtil;
29  import io.netty.util.internal.SystemPropertyUtil;
30  import io.netty.util.internal.logging.InternalLogger;
31  import io.netty.util.internal.logging.InternalLoggerFactory;
32  
33  import java.io.IOException;
34  import java.io.OutputStream;
35  import java.nio.ByteBuffer;
36  import java.nio.ByteOrder;
37  import java.nio.CharBuffer;
38  import java.nio.charset.CharacterCodingException;
39  import java.nio.charset.Charset;
40  import java.nio.charset.CharsetDecoder;
41  import java.nio.charset.CharsetEncoder;
42  import java.nio.charset.CoderResult;
43  import java.nio.charset.CodingErrorAction;
44  import java.util.Arrays;
45  import java.util.Locale;
46  
47  import static io.netty.util.internal.MathUtil.isOutOfBounds;
48  import static io.netty.util.internal.ObjectUtil.checkNotNull;
49  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
50  import static io.netty.util.internal.StringUtil.NEWLINE;
51  import static io.netty.util.internal.StringUtil.isSurrogate;
52  
53  /**
54   * A collection of utility methods that is related with handling {@link ByteBuf},
55   * such as the generation of hex dump and swapping an integer's byte order.
56   */
57  public final class ByteBufUtil {
58  
59      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ByteBufUtil.class);
60      private static final FastThreadLocal<byte[]> BYTE_ARRAYS = new FastThreadLocal<byte[]>() {
61          @Override
62          protected byte[] initialValue() throws Exception {
63              return PlatformDependent.allocateUninitializedArray(MAX_TL_ARRAY_LEN);
64          }
65      };
66  
67      private static final byte WRITE_UTF_UNKNOWN = (byte) '?';
68      private static final int MAX_CHAR_BUFFER_SIZE;
69      private static final int THREAD_LOCAL_BUFFER_SIZE;
70      private static final int MAX_BYTES_PER_CHAR_UTF8 =
71              (int) CharsetUtil.encoder(CharsetUtil.UTF_8).maxBytesPerChar();
72  
73      static final int WRITE_CHUNK_SIZE = 8192;
74      static final ByteBufAllocator DEFAULT_ALLOCATOR;
75  
76      static {
77          String allocType = SystemPropertyUtil.get(
78                  "io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
79          allocType = allocType.toLowerCase(Locale.US).trim();
80  
81          ByteBufAllocator alloc;
82          if ("unpooled".equals(allocType)) {
83              alloc = UnpooledByteBufAllocator.DEFAULT;
84              logger.debug("-Dio.netty.allocator.type: {}", allocType);
85          } else if ("pooled".equals(allocType)) {
86              alloc = PooledByteBufAllocator.DEFAULT;
87              logger.debug("-Dio.netty.allocator.type: {}", allocType);
88          } else {
89              alloc = PooledByteBufAllocator.DEFAULT;
90              logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
91          }
92  
93          DEFAULT_ALLOCATOR = alloc;
94  
95          THREAD_LOCAL_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalDirectBufferSize", 0);
96          logger.debug("-Dio.netty.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE);
97  
98          MAX_CHAR_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.maxThreadLocalCharBufferSize", 16 * 1024);
99          logger.debug("-Dio.netty.maxThreadLocalCharBufferSize: {}", MAX_CHAR_BUFFER_SIZE);
100     }
101 
102     static final int MAX_TL_ARRAY_LEN = 1024;
103 
104     /**
105      * Allocates a new array if minLength > {@link ByteBufUtil#MAX_TL_ARRAY_LEN}
106      */
107     static byte[] threadLocalTempArray(int minLength) {
108         return minLength <= MAX_TL_ARRAY_LEN ? BYTE_ARRAYS.get()
109             : PlatformDependent.allocateUninitializedArray(minLength);
110     }
111 
112     /**
113      * @return whether the specified buffer has a nonzero ref count
114      */
115     public static boolean isAccessible(ByteBuf buffer) {
116         return buffer.isAccessible();
117     }
118 
119     /**
120      * @throws IllegalReferenceCountException if the buffer has a zero ref count
121      * @return the passed in buffer
122      */
123     public static ByteBuf ensureAccessible(ByteBuf buffer) {
124         if (!buffer.isAccessible()) {
125             throw new IllegalReferenceCountException(buffer.refCnt());
126         }
127         return buffer;
128     }
129 
130     /**
131      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
132      * of the specified buffer's readable bytes.
133      */
134     public static String hexDump(ByteBuf buffer) {
135         return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
136     }
137 
138     /**
139      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
140      * of the specified buffer's sub-region.
141      */
142     public static String hexDump(ByteBuf buffer, int fromIndex, int length) {
143         return HexUtil.hexDump(buffer, fromIndex, length);
144     }
145 
146     /**
147      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
148      * of the specified byte array.
149      */
150     public static String hexDump(byte[] array) {
151         return hexDump(array, 0, array.length);
152     }
153 
154     /**
155      * Returns a <a href="https://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
156      * of the specified byte array's sub-region.
157      */
158     public static String hexDump(byte[] array, int fromIndex, int length) {
159         return HexUtil.hexDump(array, fromIndex, length);
160     }
161 
162     /**
163      * Decode a 2-digit hex byte from within a string.
164      */
165     public static byte decodeHexByte(CharSequence s, int pos) {
166         return StringUtil.decodeHexByte(s, pos);
167     }
168 
169     /**
170      * Decodes a string generated by {@link #hexDump(byte[])}
171      */
172     public static byte[] decodeHexDump(CharSequence hexDump) {
173         return StringUtil.decodeHexDump(hexDump, 0, hexDump.length());
174     }
175 
176     /**
177      * Decodes part of a string generated by {@link #hexDump(byte[])}
178      */
179     public static byte[] decodeHexDump(CharSequence hexDump, int fromIndex, int length) {
180         return StringUtil.decodeHexDump(hexDump, fromIndex, length);
181     }
182 
183     /**
184      * Used to determine if the return value of {@link ByteBuf#ensureWritable(int, boolean)} means that there is
185      * adequate space and a write operation will succeed.
186      * @param ensureWritableResult The return value from {@link ByteBuf#ensureWritable(int, boolean)}.
187      * @return {@code true} if {@code ensureWritableResult} means that there is adequate space and a write operation
188      * will succeed.
189      */
190     public static boolean ensureWritableSuccess(int ensureWritableResult) {
191         return ensureWritableResult == 0 || ensureWritableResult == 2;
192     }
193 
194     /**
195      * Calculates the hash code of the specified buffer.  This method is
196      * useful when implementing a new buffer type.
197      */
198     public static int hashCode(ByteBuf buffer) {
199         final int aLen = buffer.readableBytes();
200         final int intCount = aLen >>> 2;
201         final int byteCount = aLen & 3;
202 
203         int hashCode = EmptyByteBuf.EMPTY_BYTE_BUF_HASH_CODE;
204         int arrayIndex = buffer.readerIndex();
205         if (buffer.order() == ByteOrder.BIG_ENDIAN) {
206             for (int i = intCount; i > 0; i --) {
207                 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
208                 arrayIndex += 4;
209             }
210         } else {
211             for (int i = intCount; i > 0; i --) {
212                 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
213                 arrayIndex += 4;
214             }
215         }
216 
217         for (int i = byteCount; i > 0; i --) {
218             hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
219         }
220 
221         if (hashCode == 0) {
222             hashCode = 1;
223         }
224 
225         return hashCode;
226     }
227 
228     /**
229      * Returns the reader index of needle in haystack, or -1 if needle is not in haystack.
230      * This method uses the <a href="https://en.wikipedia.org/wiki/Two-way_string-matching_algorithm">Two-Way
231      * string matching algorithm</a>, which yields O(1) space complexity and excellent performance.
232      */
233     public static int indexOf(ByteBuf needle, ByteBuf haystack) {
234         if (haystack == null || needle == null) {
235             return -1;
236         }
237 
238         if (needle.readableBytes() > haystack.readableBytes()) {
239             return -1;
240         }
241 
242         int n = haystack.readableBytes();
243         int m = needle.readableBytes();
244         if (m == 0) {
245             return 0;
246         }
247 
248         // When the needle has only one byte that can be read,
249         // the ByteBuf.indexOf() can be used
250         if (m == 1) {
251             return haystack.indexOf(haystack.readerIndex(), haystack.writerIndex(),
252                           needle.getByte(needle.readerIndex()));
253         }
254 
255         int i;
256         int j = 0;
257         int aStartIndex = needle.readerIndex();
258         int bStartIndex = haystack.readerIndex();
259         long suffixes =  maxSuf(needle, m, aStartIndex, true);
260         long prefixes = maxSuf(needle, m, aStartIndex, false);
261         int ell = Math.max((int) (suffixes >> 32), (int) (prefixes >> 32));
262         int per = Math.max((int) suffixes, (int) prefixes);
263         int memory;
264         int length = Math.min(m - per, ell + 1);
265 
266         if (equals(needle, aStartIndex, needle, aStartIndex + per,  length)) {
267             memory = -1;
268             while (j <= n - m) {
269                 i = Math.max(ell, memory) + 1;
270                 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
271                     ++i;
272                 }
273                 if (i > n) {
274                     return -1;
275                 }
276                 if (i >= m) {
277                     i = ell;
278                     while (i > memory && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
279                         --i;
280                     }
281                     if (i <= memory) {
282                         return j + bStartIndex;
283                     }
284                     j += per;
285                     memory = m - per - 1;
286                 } else {
287                     j += i - ell;
288                     memory = -1;
289                 }
290             }
291         } else {
292             per = Math.max(ell + 1, m - ell - 1) + 1;
293             while (j <= n - m) {
294                 i = ell + 1;
295                 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
296                     ++i;
297                 }
298                 if (i > n) {
299                     return -1;
300                 }
301                 if (i >= m) {
302                     i = ell;
303                     while (i >= 0 && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
304                         --i;
305                     }
306                     if (i < 0) {
307                         return j + bStartIndex;
308                     }
309                     j += per;
310                 } else {
311                     j += i - ell;
312                 }
313             }
314         }
315         return -1;
316     }
317 
318     private static long maxSuf(ByteBuf x, int m, int start, boolean isSuffix) {
319         int p = 1;
320         int ms = -1;
321         int j = start;
322         int k = 1;
323         byte a;
324         byte b;
325         while (j + k < m) {
326             a = x.getByte(j + k);
327             b = x.getByte(ms + k);
328             boolean suffix = isSuffix ? a < b : a > b;
329             if (suffix) {
330                 j += k;
331                 k = 1;
332                 p = j - ms;
333             } else if (a == b) {
334                 if (k != p) {
335                     ++k;
336                 } else {
337                     j += p;
338                     k = 1;
339                 }
340             } else {
341                 ms = j;
342                 j = ms + 1;
343                 k = p = 1;
344             }
345         }
346         return ((long) ms << 32) + p;
347     }
348 
349     /**
350      * Returns {@code true} if and only if the two specified buffers are
351      * identical to each other for {@code length} bytes starting at {@code aStartIndex}
352      * index for the {@code a} buffer and {@code bStartIndex} index for the {@code b} buffer.
353      * A more compact way to express this is:
354      * <p>
355      * {@code a[aStartIndex : aStartIndex + length] == b[bStartIndex : bStartIndex + length]}
356      */
357     public static boolean equals(ByteBuf a, int aStartIndex, ByteBuf b, int bStartIndex, int length) {
358         checkNotNull(a, "a");
359         checkNotNull(b, "b");
360         // All indexes and lengths must be non-negative
361         checkPositiveOrZero(aStartIndex, "aStartIndex");
362         checkPositiveOrZero(bStartIndex, "bStartIndex");
363         checkPositiveOrZero(length, "length");
364 
365         if (a.writerIndex() - length < aStartIndex || b.writerIndex() - length < bStartIndex) {
366             return false;
367         }
368 
369         final int longCount = length >>> 3;
370         final int byteCount = length & 7;
371 
372         if (a.order() == b.order()) {
373             for (int i = longCount; i > 0; i --) {
374                 if (a.getLong(aStartIndex) != b.getLong(bStartIndex)) {
375                     return false;
376                 }
377                 aStartIndex += 8;
378                 bStartIndex += 8;
379             }
380         } else {
381             for (int i = longCount; i > 0; i --) {
382                 if (a.getLong(aStartIndex) != swapLong(b.getLong(bStartIndex))) {
383                     return false;
384                 }
385                 aStartIndex += 8;
386                 bStartIndex += 8;
387             }
388         }
389 
390         for (int i = byteCount; i > 0; i --) {
391             if (a.getByte(aStartIndex) != b.getByte(bStartIndex)) {
392                 return false;
393             }
394             aStartIndex ++;
395             bStartIndex ++;
396         }
397 
398         return true;
399     }
400 
401     /**
402      * Returns {@code true} if and only if the two specified buffers are
403      * identical to each other as described in {@link ByteBuf#equals(Object)}.
404      * This method is useful when implementing a new buffer type.
405      */
406     public static boolean equals(ByteBuf bufferA, ByteBuf bufferB) {
407         if (bufferA == bufferB) {
408             return true;
409         }
410         final int aLen = bufferA.readableBytes();
411         if (aLen != bufferB.readableBytes()) {
412             return false;
413         }
414         return equals(bufferA, bufferA.readerIndex(), bufferB, bufferB.readerIndex(), aLen);
415     }
416 
417     /**
418      * Compares the two specified buffers as described in {@link ByteBuf#compareTo(ByteBuf)}.
419      * This method is useful when implementing a new buffer type.
420      */
421     public static int compare(ByteBuf bufferA, ByteBuf bufferB) {
422         if (bufferA == bufferB) {
423             return 0;
424         }
425         final int aLen = bufferA.readableBytes();
426         final int bLen = bufferB.readableBytes();
427         final int minLength = Math.min(aLen, bLen);
428         final int uintCount = minLength >>> 2;
429         final int byteCount = minLength & 3;
430         int aIndex = bufferA.readerIndex();
431         int bIndex = bufferB.readerIndex();
432 
433         if (uintCount > 0) {
434             boolean bufferAIsBigEndian = bufferA.order() == ByteOrder.BIG_ENDIAN;
435             final long res;
436             int uintCountIncrement = uintCount << 2;
437 
438             if (bufferA.order() == bufferB.order()) {
439                 res = bufferAIsBigEndian ? compareUintBigEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
440                         compareUintLittleEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
441             } else {
442                 res = bufferAIsBigEndian ? compareUintBigEndianA(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
443                         compareUintBigEndianB(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
444             }
445             if (res != 0) {
446                 // Ensure we not overflow when cast
447                 return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, res));
448             }
449             aIndex += uintCountIncrement;
450             bIndex += uintCountIncrement;
451         }
452 
453         for (int aEnd = aIndex + byteCount; aIndex < aEnd; ++aIndex, ++bIndex) {
454             int comp = bufferA.getUnsignedByte(aIndex) - bufferB.getUnsignedByte(bIndex);
455             if (comp != 0) {
456                 return comp;
457             }
458         }
459 
460         return aLen - bLen;
461     }
462 
463     private static long compareUintBigEndian(
464             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
465         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
466             long comp = bufferA.getUnsignedInt(aIndex) - bufferB.getUnsignedInt(bIndex);
467             if (comp != 0) {
468                 return comp;
469             }
470         }
471         return 0;
472     }
473 
474     private static long compareUintLittleEndian(
475             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
476         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
477             long comp = uintFromLE(bufferA.getUnsignedIntLE(aIndex)) - uintFromLE(bufferB.getUnsignedIntLE(bIndex));
478             if (comp != 0) {
479                 return comp;
480             }
481         }
482         return 0;
483     }
484 
485     private static long compareUintBigEndianA(
486             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
487         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
488             long a = bufferA.getUnsignedInt(aIndex);
489             long b = uintFromLE(bufferB.getUnsignedIntLE(bIndex));
490             long comp =  a - b;
491             if (comp != 0) {
492                 return comp;
493             }
494         }
495         return 0;
496     }
497 
498     private static long compareUintBigEndianB(
499             ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
500         for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
501             long a = uintFromLE(bufferA.getUnsignedIntLE(aIndex));
502             long b = bufferB.getUnsignedInt(bIndex);
503             long comp =  a - b;
504             if (comp != 0) {
505                 return comp;
506             }
507         }
508         return 0;
509     }
510 
511     private static long uintFromLE(long value) {
512         return Long.reverseBytes(value) >>> Integer.SIZE;
513     }
514 
515     private static final class SWARByteSearch {
516 
517         private static long compilePattern(byte byteToFind) {
518             return (byteToFind & 0xFFL) * 0x101010101010101L;
519         }
520 
521         private static int firstAnyPattern(long word, long pattern, boolean leading) {
522             long input = word ^ pattern;
523             long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;
524             tmp = ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);
525             final int binaryPosition = leading? Long.numberOfLeadingZeros(tmp) : Long.numberOfTrailingZeros(tmp);
526             return binaryPosition >>> 3;
527         }
528     }
529 
530     private static int unrolledFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int byteCount, byte value) {
531         assert byteCount > 0 && byteCount < 8;
532         if (buffer._getByte(fromIndex) == value) {
533             return fromIndex;
534         }
535         if (byteCount == 1) {
536             return -1;
537         }
538         if (buffer._getByte(fromIndex + 1) == value) {
539             return fromIndex + 1;
540         }
541         if (byteCount == 2) {
542             return -1;
543         }
544         if (buffer._getByte(fromIndex + 2) == value) {
545             return fromIndex + 2;
546         }
547         if (byteCount == 3) {
548             return -1;
549         }
550         if (buffer._getByte(fromIndex + 3) == value) {
551             return fromIndex + 3;
552         }
553         if (byteCount == 4) {
554             return -1;
555         }
556         if (buffer._getByte(fromIndex + 4) == value) {
557             return fromIndex + 4;
558         }
559         if (byteCount == 5) {
560             return -1;
561         }
562         if (buffer._getByte(fromIndex + 5) == value) {
563             return fromIndex + 5;
564         }
565         if (byteCount == 6) {
566             return -1;
567         }
568         if (buffer._getByte(fromIndex + 6) == value) {
569             return fromIndex + 6;
570         }
571         return -1;
572     }
573 
574     /**
575      * This is using a SWAR (SIMD Within A Register) batch read technique to minimize bound-checks and improve memory
576      * usage while searching for {@code value}.
577      */
578     static int firstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
579         fromIndex = Math.max(fromIndex, 0);
580         if (fromIndex >= toIndex || buffer.capacity() == 0) {
581             return -1;
582         }
583         final int length = toIndex - fromIndex;
584         buffer.checkIndex(fromIndex, length);
585         if (!PlatformDependent.isUnaligned()) {
586             return linearFirstIndexOf(buffer, fromIndex, toIndex, value);
587         }
588         assert PlatformDependent.isUnaligned();
589         int offset = fromIndex;
590         final int byteCount = length & 7;
591         if (byteCount > 0) {
592             final int index = unrolledFirstIndexOf(buffer, fromIndex, byteCount, value);
593             if (index != -1) {
594                 return index;
595             }
596             offset += byteCount;
597             if (offset == toIndex) {
598                 return -1;
599             }
600         }
601         final int longCount = length >>> 3;
602         final ByteOrder nativeOrder = ByteOrder.nativeOrder();
603         final boolean isNative = nativeOrder == buffer.order();
604         final boolean useLE = nativeOrder == ByteOrder.LITTLE_ENDIAN;
605         final long pattern = SWARByteSearch.compilePattern(value);
606         for (int i = 0; i < longCount; i++) {
607             // use the faster available getLong
608             final long word = useLE? buffer._getLongLE(offset) : buffer._getLong(offset);
609             int index = SWARByteSearch.firstAnyPattern(word, pattern, isNative);
610             if (index < Long.BYTES) {
611                 return offset + index;
612             }
613             offset += Long.BYTES;
614         }
615         return -1;
616     }
617 
618     private static int linearFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
619         for (int i = fromIndex; i < toIndex; i++) {
620             if (buffer._getByte(i) == value) {
621                 return i;
622             }
623         }
624         return -1;
625     }
626 
627     /**
628      * The default implementation of {@link ByteBuf#indexOf(int, int, byte)}.
629      * This method is useful when implementing a new buffer type.
630      */
631     public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value) {
632         return buffer.indexOf(fromIndex, toIndex, value);
633     }
634 
635     /**
636      * Toggles the endianness of the specified 16-bit short integer.
637      */
638     public static short swapShort(short value) {
639         return Short.reverseBytes(value);
640     }
641 
642     /**
643      * Toggles the endianness of the specified 24-bit medium integer.
644      */
645     public static int swapMedium(int value) {
646         int swapped = value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff;
647         if ((swapped & 0x800000) != 0) {
648             swapped |= 0xff000000;
649         }
650         return swapped;
651     }
652 
653     /**
654      * Toggles the endianness of the specified 32-bit integer.
655      */
656     public static int swapInt(int value) {
657         return Integer.reverseBytes(value);
658     }
659 
660     /**
661      * Toggles the endianness of the specified 64-bit long integer.
662      */
663     public static long swapLong(long value) {
664         return Long.reverseBytes(value);
665     }
666 
667     /**
668      * Writes a big-endian 16-bit short integer to the buffer.
669      */
670     @SuppressWarnings("deprecation")
671     public static ByteBuf writeShortBE(ByteBuf buf, int shortValue) {
672         return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeShort(shortValue) :
673                 buf.writeShort(swapShort((short) shortValue));
674     }
675 
676     /**
677      * Sets a big-endian 16-bit short integer to the buffer.
678      */
679     @SuppressWarnings("deprecation")
680     public static ByteBuf setShortBE(ByteBuf buf, int index, int shortValue) {
681         return buf.order() == ByteOrder.BIG_ENDIAN? buf.setShort(index, shortValue) :
682                 buf.setShort(index, swapShort((short) shortValue));
683     }
684 
685     /**
686      * Writes a big-endian 24-bit medium integer to the buffer.
687      */
688     @SuppressWarnings("deprecation")
689     public static ByteBuf writeMediumBE(ByteBuf buf, int mediumValue) {
690         return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeMedium(mediumValue) :
691                 buf.writeMedium(swapMedium(mediumValue));
692     }
693 
694     /**
695      * Read the given amount of bytes into a new {@link ByteBuf} that is allocated from the {@link ByteBufAllocator}.
696      */
697     public static ByteBuf readBytes(ByteBufAllocator alloc, ByteBuf buffer, int length) {
698         boolean release = true;
699         ByteBuf dst = alloc.buffer(length);
700         try {
701             buffer.readBytes(dst);
702             release = false;
703             return dst;
704         } finally {
705             if (release) {
706                 dst.release();
707             }
708         }
709     }
710 
711     static int lastIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
712         assert fromIndex > toIndex;
713         final int capacity = buffer.capacity();
714         fromIndex = Math.min(fromIndex, capacity);
715         if (fromIndex < 0 || capacity == 0) {
716             return -1;
717         }
718         buffer.checkIndex(toIndex, fromIndex - toIndex);
719         for (int i = fromIndex - 1; i >= toIndex; i--) {
720             if (buffer._getByte(i) == value) {
721                 return i;
722             }
723         }
724 
725         return -1;
726     }
727 
728     private static CharSequence checkCharSequenceBounds(CharSequence seq, int start, int end) {
729         if (MathUtil.isOutOfBounds(start, end - start, seq.length())) {
730             throw new IndexOutOfBoundsException("expected: 0 <= start(" + start + ") <= end (" + end
731                     + ") <= seq.length(" + seq.length() + ')');
732         }
733         return seq;
734     }
735 
736     /**
737      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
738      * it to a {@link ByteBuf} allocated with {@code alloc}.
739      * @param alloc The allocator used to allocate a new {@link ByteBuf}.
740      * @param seq The characters to write into a buffer.
741      * @return The {@link ByteBuf} which contains the <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoded
742      * result.
743      */
744     public static ByteBuf writeUtf8(ByteBufAllocator alloc, CharSequence seq) {
745         // UTF-8 uses max. 3 bytes per char, so calculate the worst case.
746         ByteBuf buf = alloc.buffer(utf8MaxBytes(seq));
747         writeUtf8(buf, seq);
748         return buf;
749     }
750 
751     /**
752      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
753      * it to a {@link ByteBuf}.
754      * <p>
755      * It behaves like {@link #reserveAndWriteUtf8(ByteBuf, CharSequence, int)} with {@code reserveBytes}
756      * computed by {@link #utf8MaxBytes(CharSequence)}.<br>
757      * This method returns the actual number of bytes written.
758      */
759     public static int writeUtf8(ByteBuf buf, CharSequence seq) {
760         int seqLength = seq.length();
761         return reserveAndWriteUtf8Seq(buf, seq, 0, seqLength, utf8MaxBytes(seqLength));
762     }
763 
764     /**
765      * Equivalent to <code>{@link #writeUtf8(ByteBuf, CharSequence) writeUtf8(buf, seq.subSequence(start, end))}</code>
766      * but avoids subsequence object allocation.
767      */
768     public static int writeUtf8(ByteBuf buf, CharSequence seq, int start, int end) {
769         checkCharSequenceBounds(seq, start, end);
770         return reserveAndWriteUtf8Seq(buf, seq, start, end, utf8MaxBytes(end - start));
771     }
772 
773     /**
774      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> and write
775      * it into {@code reserveBytes} of a {@link ByteBuf}.
776      * <p>
777      * The {@code reserveBytes} must be computed (ie eagerly using {@link #utf8MaxBytes(CharSequence)}
778      * or exactly with {@link #utf8Bytes(CharSequence)}) to ensure this method to not fail: for performance reasons
779      * the index checks will be performed using just {@code reserveBytes}.<br>
780      * This method returns the actual number of bytes written.
781      */
782     public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int reserveBytes) {
783         return reserveAndWriteUtf8Seq(buf, seq, 0, seq.length(), reserveBytes);
784     }
785 
786     /**
787      * Equivalent to <code>{@link #reserveAndWriteUtf8(ByteBuf, CharSequence, int)
788      * reserveAndWriteUtf8(buf, seq.subSequence(start, end), reserveBytes)}</code> but avoids
789      * subsequence object allocation if possible.
790      *
791      * @return actual number of bytes written
792      */
793     public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int start, int end, int reserveBytes) {
794         return reserveAndWriteUtf8Seq(buf, checkCharSequenceBounds(seq, start, end), start, end, reserveBytes);
795     }
796 
797     private static int reserveAndWriteUtf8Seq(ByteBuf buf, CharSequence seq, int start, int end, int reserveBytes) {
798         for (;;) {
799             if (buf instanceof WrappedCompositeByteBuf) {
800                 // WrappedCompositeByteBuf is a sub-class of AbstractByteBuf so it needs special handling.
801                 buf = buf.unwrap();
802             } else if (buf instanceof AbstractByteBuf) {
803                 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
804                 byteBuf.ensureWritable0(reserveBytes);
805                 int written = writeUtf8(byteBuf, byteBuf.writerIndex, reserveBytes, seq, start, end);
806                 byteBuf.writerIndex += written;
807                 return written;
808             } else if (buf instanceof WrappedByteBuf) {
809                 // Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
810                 buf = buf.unwrap();
811             } else {
812                 byte[] bytes = seq.subSequence(start, end).toString().getBytes(CharsetUtil.UTF_8);
813                 buf.writeBytes(bytes);
814                 return bytes.length;
815             }
816         }
817     }
818 
819     static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes, CharSequence seq, int len) {
820         return writeUtf8(buffer, writerIndex, reservedBytes, seq, 0, len);
821     }
822 
823     // Fast-Path implementation
824     static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes,
825                          CharSequence seq, int start, int end) {
826         if (seq instanceof AsciiString) {
827             writeAsciiString(buffer, writerIndex, (AsciiString) seq, start, end);
828             return end - start;
829         }
830         if (PlatformDependent.hasUnsafe()) {
831             if (buffer.hasArray()) {
832                 return unsafeWriteUtf8(buffer.array(), PlatformDependent.byteArrayBaseOffset(),
833                                        buffer.arrayOffset() + writerIndex, seq, start, end);
834             }
835             if (buffer.hasMemoryAddress()) {
836                 return unsafeWriteUtf8(null, buffer.memoryAddress(), writerIndex, seq, start, end);
837             }
838         } else {
839             if (buffer.hasArray()) {
840                 return safeArrayWriteUtf8(buffer.array(), buffer.arrayOffset() + writerIndex, seq, start, end);
841             }
842             if (buffer.isDirect()) {
843                 assert buffer.nioBufferCount() == 1;
844                 final ByteBuffer internalDirectBuffer = buffer.internalNioBuffer(writerIndex, reservedBytes);
845                 final int bufferPosition = internalDirectBuffer.position();
846                 return safeDirectWriteUtf8(internalDirectBuffer, bufferPosition, seq, start, end);
847             }
848         }
849         return safeWriteUtf8(buffer, writerIndex, seq, start, end);
850     }
851 
852     // AsciiString Fast-Path implementation - no explicit bound-checks
853     static void writeAsciiString(AbstractByteBuf buffer, int writerIndex, AsciiString seq, int start, int end) {
854         final int begin = seq.arrayOffset() + start;
855         final int length = end - start;
856         if (PlatformDependent.hasUnsafe()) {
857             if (buffer.hasArray()) {
858                 PlatformDependent.copyMemory(seq.array(), begin,
859                                              buffer.array(), buffer.arrayOffset() + writerIndex, length);
860                 return;
861             }
862             if (buffer.hasMemoryAddress()) {
863                 PlatformDependent.copyMemory(seq.array(), begin, buffer.memoryAddress() + writerIndex, length);
864                 return;
865             }
866         }
867         if (buffer.hasArray()) {
868             System.arraycopy(seq.array(), begin, buffer.array(), buffer.arrayOffset() + writerIndex, length);
869             return;
870         }
871         buffer.setBytes(writerIndex, seq.array(), begin, length);
872     }
873 
874     // Safe off-heap Fast-Path implementation
875     private static int safeDirectWriteUtf8(ByteBuffer buffer, int writerIndex, CharSequence seq, int start, int end) {
876         assert !(seq instanceof AsciiString);
877         int oldWriterIndex = writerIndex;
878 
879         // We can use the _set methods as these not need to do any index checks and reference checks.
880         // This is possible as we called ensureWritable(...) before.
881         for (int i = start; i < end; i++) {
882             char c = seq.charAt(i);
883             if (c < 0x80) {
884                 buffer.put(writerIndex++, (byte) c);
885             } else if (c < 0x800) {
886                 buffer.put(writerIndex++, (byte) (0xc0 | (c >> 6)));
887                 buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
888             } else if (isSurrogate(c)) {
889                 if (!Character.isHighSurrogate(c)) {
890                     buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
891                     continue;
892                 }
893                 // Surrogate Pair consumes 2 characters.
894                 if (++i == end) {
895                     buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
896                     break;
897                 }
898                 // Extra method is copied here to NOT allow inlining of writeUtf8
899                 // and increase the chance to inline CharSequence::charAt instead
900                 char c2 = seq.charAt(i);
901                 if (!Character.isLowSurrogate(c2)) {
902                     buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
903                     buffer.put(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : (byte) c2);
904                 } else {
905                     int codePoint = Character.toCodePoint(c, c2);
906                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
907                     buffer.put(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
908                     buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
909                     buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
910                     buffer.put(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
911                 }
912             } else {
913                 buffer.put(writerIndex++, (byte) (0xe0 | (c >> 12)));
914                 buffer.put(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
915                 buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
916             }
917         }
918         return writerIndex - oldWriterIndex;
919     }
920 
921     // Safe off-heap Fast-Path implementation
922     private static int safeWriteUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int start, int end) {
923         assert !(seq instanceof AsciiString);
924         int oldWriterIndex = writerIndex;
925 
926         // We can use the _set methods as these not need to do any index checks and reference checks.
927         // This is possible as we called ensureWritable(...) before.
928         for (int i = start; i < end; i++) {
929             char c = seq.charAt(i);
930             if (c < 0x80) {
931                 buffer._setByte(writerIndex++, (byte) c);
932             } else if (c < 0x800) {
933                 buffer._setByte(writerIndex++, (byte) (0xc0 | (c >> 6)));
934                 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
935             } else if (isSurrogate(c)) {
936                 if (!Character.isHighSurrogate(c)) {
937                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
938                     continue;
939                 }
940                 // Surrogate Pair consumes 2 characters.
941                 if (++i == end) {
942                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
943                     break;
944                 }
945                 // Extra method is copied here to NOT allow inlining of writeUtf8
946                 // and increase the chance to inline CharSequence::charAt instead
947                 char c2 = seq.charAt(i);
948                 if (!Character.isLowSurrogate(c2)) {
949                     buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
950                     buffer._setByte(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
951                 } else {
952                     int codePoint = Character.toCodePoint(c, c2);
953                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
954                     buffer._setByte(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
955                     buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
956                     buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
957                     buffer._setByte(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
958                 }
959             } else {
960                 buffer._setByte(writerIndex++, (byte) (0xe0 | (c >> 12)));
961                 buffer._setByte(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
962                 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
963             }
964         }
965         return writerIndex - oldWriterIndex;
966     }
967 
968     // safe byte[] Fast-Path implementation
969     private static int safeArrayWriteUtf8(byte[] buffer, int writerIndex, CharSequence seq, int start, int end) {
970         int oldWriterIndex = writerIndex;
971         for (int i = start; i < end; i++) {
972             char c = seq.charAt(i);
973             if (c < 0x80) {
974                 buffer[writerIndex++] = (byte) c;
975             } else if (c < 0x800) {
976                 buffer[writerIndex++] = (byte) (0xc0 | (c >> 6));
977                 buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
978             } else if (isSurrogate(c)) {
979                 if (!Character.isHighSurrogate(c)) {
980                     buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
981                     continue;
982                 }
983                 // Surrogate Pair consumes 2 characters.
984                 if (++i == end) {
985                     buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
986                     break;
987                 }
988                 char c2 = seq.charAt(i);
989                 // Extra method is copied here to NOT allow inlining of writeUtf8
990                 // and increase the chance to inline CharSequence::charAt instead
991                 if (!Character.isLowSurrogate(c2)) {
992                     buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
993                     buffer[writerIndex++] = (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
994                 } else {
995                     int codePoint = Character.toCodePoint(c, c2);
996                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
997                     buffer[writerIndex++] = (byte) (0xf0 | (codePoint >> 18));
998                     buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 12) & 0x3f));
999                     buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 6) & 0x3f));
1000                     buffer[writerIndex++] = (byte) (0x80 | (codePoint & 0x3f));
1001                 }
1002             } else {
1003                 buffer[writerIndex++] = (byte) (0xe0 | (c >> 12));
1004                 buffer[writerIndex++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1005                 buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
1006             }
1007         }
1008         return writerIndex - oldWriterIndex;
1009     }
1010 
1011     // unsafe Fast-Path implementation
1012     private static int unsafeWriteUtf8(byte[] buffer, long memoryOffset, int writerIndex,
1013                                        CharSequence seq, int start, int end) {
1014         assert !(seq instanceof AsciiString);
1015         long writerOffset = memoryOffset + writerIndex;
1016         final long oldWriterOffset = writerOffset;
1017         for (int i = start; i < end; i++) {
1018             char c = seq.charAt(i);
1019             if (c < 0x80) {
1020                 PlatformDependent.putByte(buffer, writerOffset++, (byte) c);
1021             } else if (c < 0x800) {
1022                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xc0 | (c >> 6)));
1023                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
1024             } else if (isSurrogate(c)) {
1025                 if (!Character.isHighSurrogate(c)) {
1026                     PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1027                     continue;
1028                 }
1029                 // Surrogate Pair consumes 2 characters.
1030                 if (++i == end) {
1031                     PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1032                     break;
1033                 }
1034                 char c2 = seq.charAt(i);
1035                 // Extra method is copied here to NOT allow inlining of writeUtf8
1036                 // and increase the chance to inline CharSequence::charAt instead
1037                 if (!Character.isLowSurrogate(c2)) {
1038                     PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1039                     PlatformDependent.putByte(buffer, writerOffset++,
1040                                               (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2));
1041                 } else {
1042                     int codePoint = Character.toCodePoint(c, c2);
1043                     // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
1044                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xf0 | (codePoint >> 18)));
1045                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
1046                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
1047                     PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (codePoint & 0x3f)));
1048                 }
1049             } else {
1050                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xe0 | (c >> 12)));
1051                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((c >> 6) & 0x3f)));
1052                 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
1053             }
1054         }
1055         return (int) (writerOffset - oldWriterOffset);
1056     }
1057 
1058     /**
1059      * Returns max bytes length of UTF8 character sequence of the given length.
1060      */
1061     public static int utf8MaxBytes(final int seqLength) {
1062         return seqLength * MAX_BYTES_PER_CHAR_UTF8;
1063     }
1064 
1065     /**
1066      * Returns max bytes length of UTF8 character sequence.
1067      * <p>
1068      * It behaves like {@link #utf8MaxBytes(int)} applied to {@code seq} {@link CharSequence#length()}.
1069      */
1070     public static int utf8MaxBytes(CharSequence seq) {
1071         return utf8MaxBytes(seq.length());
1072     }
1073 
1074     /**
1075      * Returns the exact bytes length of UTF8 character sequence.
1076      * <p>
1077      * This method is producing the exact length according to {@link #writeUtf8(ByteBuf, CharSequence)}.
1078      */
1079     public static int utf8Bytes(final CharSequence seq) {
1080         return utf8ByteCount(seq, 0, seq.length());
1081     }
1082 
1083     /**
1084      * Equivalent to <code>{@link #utf8Bytes(CharSequence) utf8Bytes(seq.subSequence(start, end))}</code>
1085      * but avoids subsequence object allocation.
1086      * <p>
1087      * This method is producing the exact length according to {@link #writeUtf8(ByteBuf, CharSequence, int, int)}.
1088      */
1089     public static int utf8Bytes(final CharSequence seq, int start, int end) {
1090         return utf8ByteCount(checkCharSequenceBounds(seq, start, end), start, end);
1091     }
1092 
1093     private static int utf8ByteCount(final CharSequence seq, int start, int end) {
1094         if (seq instanceof AsciiString) {
1095             return end - start;
1096         }
1097         int i = start;
1098         // ASCII fast path
1099         while (i < end && seq.charAt(i) < 0x80) {
1100             ++i;
1101         }
1102         // !ASCII is packed in a separate method to let the ASCII case be smaller
1103         return i < end ? (i - start) + utf8BytesNonAscii(seq, i, end) : i - start;
1104     }
1105 
1106     private static int utf8BytesNonAscii(final CharSequence seq, final int start, final int end) {
1107         int encodedLength = 0;
1108         for (int i = start; i < end; i++) {
1109             final char c = seq.charAt(i);
1110             // making it 100% branchless isn't rewarding due to the many bit operations necessary!
1111             if (c < 0x800) {
1112                 // branchless version of: (c <= 127 ? 0:1) + 1
1113                 encodedLength += ((0x7f - c) >>> 31) + 1;
1114             } else if (isSurrogate(c)) {
1115                 if (!Character.isHighSurrogate(c)) {
1116                     encodedLength++;
1117                     // WRITE_UTF_UNKNOWN
1118                     continue;
1119                 }
1120                 // Surrogate Pair consumes 2 characters.
1121                 if (++i == end) {
1122                     encodedLength++;
1123                     // WRITE_UTF_UNKNOWN
1124                     break;
1125                 }
1126                 if (!Character.isLowSurrogate(seq.charAt(i))) {
1127                     // WRITE_UTF_UNKNOWN + (Character.isHighSurrogate(c2) ? WRITE_UTF_UNKNOWN : c2)
1128                     encodedLength += 2;
1129                     continue;
1130                 }
1131                 // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G2630.
1132                 encodedLength += 4;
1133             } else {
1134                 encodedLength += 3;
1135             }
1136         }
1137         return encodedLength;
1138     }
1139 
1140     /**
1141      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> and write
1142      * it to a {@link ByteBuf} allocated with {@code alloc}.
1143      * @param alloc The allocator used to allocate a new {@link ByteBuf}.
1144      * @param seq The characters to write into a buffer.
1145      * @return The {@link ByteBuf} which contains the <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> encoded
1146      * result.
1147      */
1148     public static ByteBuf writeAscii(ByteBufAllocator alloc, CharSequence seq) {
1149         // ASCII uses 1 byte per char
1150         ByteBuf buf = alloc.buffer(seq.length());
1151         writeAscii(buf, seq);
1152         return buf;
1153     }
1154 
1155     /**
1156      * Encode a {@link CharSequence} in <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> and write it
1157      * to a {@link ByteBuf}.
1158      *
1159      * This method returns the actual number of bytes written.
1160      */
1161     public static int writeAscii(ByteBuf buf, CharSequence seq) {
1162         // ASCII uses 1 byte per char
1163         for (;;) {
1164             if (buf instanceof WrappedCompositeByteBuf) {
1165                 // WrappedCompositeByteBuf is a sub-class of AbstractByteBuf so it needs special handling.
1166                 buf = buf.unwrap();
1167             } else if (buf instanceof AbstractByteBuf) {
1168                 final int len = seq.length();
1169                 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
1170                 byteBuf.ensureWritable0(len);
1171                 if (seq instanceof AsciiString) {
1172                     writeAsciiString(byteBuf, byteBuf.writerIndex, (AsciiString) seq, 0, len);
1173                 } else {
1174                     final int written = writeAscii(byteBuf, byteBuf.writerIndex, seq, len);
1175                     assert written == len;
1176                 }
1177                 byteBuf.writerIndex += len;
1178                 return len;
1179             } else if (buf instanceof WrappedByteBuf) {
1180                 // Unwrap as the wrapped buffer may be an AbstractByteBuf and so we can use fast-path.
1181                 buf = buf.unwrap();
1182             } else {
1183                 byte[] bytes = seq.toString().getBytes(CharsetUtil.US_ASCII);
1184                 buf.writeBytes(bytes);
1185                 return bytes.length;
1186             }
1187         }
1188     }
1189 
1190     // Fast-Path implementation
1191     static int writeAscii(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
1192 
1193         // We can use the _set methods as these not need to do any index checks and reference checks.
1194         // This is possible as we called ensureWritable(...) before.
1195         for (int i = 0; i < len; i++) {
1196             buffer._setByte(writerIndex++, AsciiString.c2b(seq.charAt(i)));
1197         }
1198         return len;
1199     }
1200 
1201     /**
1202      * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which
1203      * is allocated via the {@link ByteBufAllocator}.
1204      */
1205     public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset) {
1206         return encodeString0(alloc, false, src, charset, 0);
1207     }
1208 
1209     /**
1210      * Encode the given {@link CharBuffer} using the given {@link Charset} into a new {@link ByteBuf} which
1211      * is allocated via the {@link ByteBufAllocator}.
1212      *
1213      * @param alloc The {@link ByteBufAllocator} to allocate {@link ByteBuf}.
1214      * @param src The {@link CharBuffer} to encode.
1215      * @param charset The specified {@link Charset}.
1216      * @param extraCapacity the extra capacity to alloc except the space for decoding.
1217      */
1218     public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset, int extraCapacity) {
1219         return encodeString0(alloc, false, src, charset, extraCapacity);
1220     }
1221 
1222     static ByteBuf encodeString0(ByteBufAllocator alloc, boolean enforceHeap, CharBuffer src, Charset charset,
1223                                  int extraCapacity) {
1224         final CharsetEncoder encoder = CharsetUtil.encoder(charset);
1225         int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar()) + extraCapacity;
1226         boolean release = true;
1227         final ByteBuf dst;
1228         if (enforceHeap) {
1229             dst = alloc.heapBuffer(length);
1230         } else {
1231             dst = alloc.buffer(length);
1232         }
1233         try {
1234             final ByteBuffer dstBuf = dst.internalNioBuffer(dst.readerIndex(), length);
1235             final int pos = dstBuf.position();
1236             CoderResult cr = encoder.encode(src, dstBuf, true);
1237             if (!cr.isUnderflow()) {
1238                 cr.throwException();
1239             }
1240             cr = encoder.flush(dstBuf);
1241             if (!cr.isUnderflow()) {
1242                 cr.throwException();
1243             }
1244             dst.writerIndex(dst.writerIndex() + dstBuf.position() - pos);
1245             release = false;
1246             return dst;
1247         } catch (CharacterCodingException x) {
1248             throw new IllegalStateException(x);
1249         } finally {
1250             if (release) {
1251                 dst.release();
1252             }
1253         }
1254     }
1255 
1256     @SuppressWarnings("deprecation")
1257     static String decodeString(ByteBuf src, int readerIndex, int len, Charset charset) {
1258         if (len == 0) {
1259             return StringUtil.EMPTY_STRING;
1260         }
1261         final byte[] array;
1262         final int offset;
1263 
1264         if (src.hasArray()) {
1265             array = src.array();
1266             offset = src.arrayOffset() + readerIndex;
1267         } else {
1268             array = threadLocalTempArray(len);
1269             offset = 0;
1270             src.getBytes(readerIndex, array, 0, len);
1271         }
1272         if (CharsetUtil.US_ASCII.equals(charset)) {
1273             // Fast-path for US-ASCII which is used frequently.
1274             return new String(array, 0, offset, len);
1275         }
1276         return new String(array, offset, len, charset);
1277     }
1278 
1279     /**
1280      * Returns a cached thread-local direct buffer, if available.
1281      *
1282      * @return a cached thread-local direct buffer, if available.  {@code null} otherwise.
1283      */
1284     public static ByteBuf threadLocalDirectBuffer() {
1285         if (THREAD_LOCAL_BUFFER_SIZE <= 0) {
1286             return null;
1287         }
1288 
1289         if (PlatformDependent.hasUnsafe()) {
1290             return ThreadLocalUnsafeDirectByteBuf.newInstance();
1291         } else {
1292             return ThreadLocalDirectByteBuf.newInstance();
1293         }
1294     }
1295 
1296     /**
1297      * Create a copy of the underlying storage from {@code buf} into a byte array.
1298      * The copy will start at {@link ByteBuf#readerIndex()} and copy {@link ByteBuf#readableBytes()} bytes.
1299      */
1300     public static byte[] getBytes(ByteBuf buf) {
1301         return getBytes(buf,  buf.readerIndex(), buf.readableBytes());
1302     }
1303 
1304     /**
1305      * Create a copy of the underlying storage from {@code buf} into a byte array.
1306      * The copy will start at {@code start} and copy {@code length} bytes.
1307      */
1308     public static byte[] getBytes(ByteBuf buf, int start, int length) {
1309         return getBytes(buf, start, length, true);
1310     }
1311 
1312     /**
1313      * Return an array of the underlying storage from {@code buf} into a byte array.
1314      * The copy will start at {@code start} and copy {@code length} bytes.
1315      * If {@code copy} is true a copy will be made of the memory.
1316      * If {@code copy} is false the underlying storage will be shared, if possible.
1317      */
1318     public static byte[] getBytes(ByteBuf buf, int start, int length, boolean copy) {
1319         int capacity = buf.capacity();
1320         if (isOutOfBounds(start, length, capacity)) {
1321             throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
1322                     + ") <= " + "buf.capacity(" + capacity + ')');
1323         }
1324 
1325         if (buf.hasArray()) {
1326             int baseOffset = buf.arrayOffset() + start;
1327             byte[] bytes = buf.array();
1328             if (copy || baseOffset != 0 || length != bytes.length) {
1329                 return Arrays.copyOfRange(bytes, baseOffset, baseOffset + length);
1330             } else {
1331                 return bytes;
1332             }
1333         }
1334 
1335         byte[] bytes = PlatformDependent.allocateUninitializedArray(length);
1336         buf.getBytes(start, bytes);
1337         return bytes;
1338     }
1339 
1340     /**
1341      * Copies the all content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
1342      *
1343      * @param src the source string to copy
1344      * @param dst the destination buffer
1345      */
1346     public static void copy(AsciiString src, ByteBuf dst) {
1347         copy(src, 0, dst, src.length());
1348     }
1349 
1350     /**
1351      * Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#setBytes(int, byte[], int, int)}.
1352      * Unlike the {@link #copy(AsciiString, ByteBuf)} and {@link #copy(AsciiString, int, ByteBuf, int)} methods,
1353      * this method do not increase a {@code writerIndex} of {@code dst} buffer.
1354      *
1355      * @param src the source string to copy
1356      * @param srcIdx the starting offset of characters to copy
1357      * @param dst the destination buffer
1358      * @param dstIdx the starting offset in the destination buffer
1359      * @param length the number of characters to copy
1360      */
1361     public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int dstIdx, int length) {
1362         if (isOutOfBounds(srcIdx, length, src.length())) {
1363             throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
1364                             + length + ") <= srcLen(" + src.length() + ')');
1365         }
1366 
1367         checkNotNull(dst, "dst").setBytes(dstIdx, src.array(), srcIdx + src.arrayOffset(), length);
1368     }
1369 
1370     /**
1371      * Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
1372      *
1373      * @param src the source string to copy
1374      * @param srcIdx the starting offset of characters to copy
1375      * @param dst the destination buffer
1376      * @param length the number of characters to copy
1377      */
1378     public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int length) {
1379         if (isOutOfBounds(srcIdx, length, src.length())) {
1380             throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
1381                             + length + ") <= srcLen(" + src.length() + ')');
1382         }
1383 
1384         checkNotNull(dst, "dst").writeBytes(src.array(), srcIdx + src.arrayOffset(), length);
1385     }
1386 
1387     /**
1388      * Returns a multi-line hexadecimal dump of the specified {@link ByteBuf} that is easy to read by humans.
1389      */
1390     public static String prettyHexDump(ByteBuf buffer) {
1391         return prettyHexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
1392     }
1393 
1394     /**
1395      * Returns a multi-line hexadecimal dump of the specified {@link ByteBuf} that is easy to read by humans,
1396      * starting at the given {@code offset} using the given {@code length}.
1397      */
1398     public static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1399         return HexUtil.prettyHexDump(buffer, offset, length);
1400     }
1401 
1402     /**
1403      * Appends the prettified multi-line hexadecimal dump of the specified {@link ByteBuf} to the specified
1404      * {@link StringBuilder} that is easy to read by humans.
1405      */
1406     public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf) {
1407         appendPrettyHexDump(dump, buf, buf.readerIndex(), buf.readableBytes());
1408     }
1409 
1410     /**
1411      * Appends the prettified multi-line hexadecimal dump of the specified {@link ByteBuf} to the specified
1412      * {@link StringBuilder} that is easy to read by humans, starting at the given {@code offset} using
1413      * the given {@code length}.
1414      */
1415     public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1416         HexUtil.appendPrettyHexDump(dump, buf, offset, length);
1417     }
1418 
1419     /* Separate class so that the expensive static initialization is only done when needed */
1420     private static final class HexUtil {
1421 
1422         private static final char[] BYTE2CHAR = new char[256];
1423         private static final char[] HEXDUMP_TABLE = new char[256 * 4];
1424         private static final String[] HEXPADDING = new String[16];
1425         private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4];
1426         private static final String[] BYTE2HEX = new String[256];
1427         private static final String[] BYTEPADDING = new String[16];
1428 
1429         static {
1430             final char[] DIGITS = "0123456789abcdef".toCharArray();
1431             for (int i = 0; i < 256; i ++) {
1432                 HEXDUMP_TABLE[ i << 1     ] = DIGITS[i >>> 4 & 0x0F];
1433                 HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i       & 0x0F];
1434             }
1435 
1436             int i;
1437 
1438             // Generate the lookup table for hex dump paddings
1439             for (i = 0; i < HEXPADDING.length; i ++) {
1440                 int padding = HEXPADDING.length - i;
1441                 StringBuilder buf = new StringBuilder(padding * 3);
1442                 for (int j = 0; j < padding; j ++) {
1443                     buf.append("   ");
1444                 }
1445                 HEXPADDING[i] = buf.toString();
1446             }
1447 
1448             // Generate the lookup table for the start-offset header in each row (up to 64KiB).
1449             for (i = 0; i < HEXDUMP_ROWPREFIXES.length; i ++) {
1450                 StringBuilder buf = new StringBuilder(12);
1451                 buf.append(NEWLINE);
1452                 buf.append(Long.toHexString(i << 4 & 0xFFFFFFFFL | 0x100000000L));
1453                 buf.setCharAt(buf.length() - 9, '|');
1454                 buf.append('|');
1455                 HEXDUMP_ROWPREFIXES[i] = buf.toString();
1456             }
1457 
1458             // Generate the lookup table for byte-to-hex-dump conversion
1459             for (i = 0; i < BYTE2HEX.length; i ++) {
1460                 BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i);
1461             }
1462 
1463             // Generate the lookup table for byte dump paddings
1464             for (i = 0; i < BYTEPADDING.length; i ++) {
1465                 int padding = BYTEPADDING.length - i;
1466                 StringBuilder buf = new StringBuilder(padding);
1467                 for (int j = 0; j < padding; j ++) {
1468                     buf.append(' ');
1469                 }
1470                 BYTEPADDING[i] = buf.toString();
1471             }
1472 
1473             // Generate the lookup table for byte-to-char conversion
1474             for (i = 0; i < BYTE2CHAR.length; i ++) {
1475                 if (i <= 0x1f || i >= 0x7f) {
1476                     BYTE2CHAR[i] = '.';
1477                 } else {
1478                     BYTE2CHAR[i] = (char) i;
1479                 }
1480             }
1481         }
1482 
1483         private static String hexDump(ByteBuf buffer, int fromIndex, int length) {
1484             checkPositiveOrZero(length, "length");
1485             if (length == 0) {
1486               return "";
1487             }
1488 
1489             int endIndex = fromIndex + length;
1490             char[] buf = new char[length << 1];
1491 
1492             int srcIdx = fromIndex;
1493             int dstIdx = 0;
1494             for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1495               System.arraycopy(
1496                   HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1,
1497                   buf, dstIdx, 2);
1498             }
1499 
1500             return new String(buf);
1501         }
1502 
1503         private static String hexDump(byte[] array, int fromIndex, int length) {
1504             checkPositiveOrZero(length, "length");
1505             if (length == 0) {
1506                 return "";
1507             }
1508 
1509             int endIndex = fromIndex + length;
1510             char[] buf = new char[length << 1];
1511 
1512             int srcIdx = fromIndex;
1513             int dstIdx = 0;
1514             for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1515                 System.arraycopy(
1516                     HEXDUMP_TABLE, (array[srcIdx] & 0xFF) << 1,
1517                     buf, dstIdx, 2);
1518             }
1519 
1520             return new String(buf);
1521         }
1522 
1523         private static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1524             if (length == 0) {
1525               return StringUtil.EMPTY_STRING;
1526             } else {
1527                 int rows = length / 16 + ((length & 15) == 0? 0 : 1) + 4;
1528                 StringBuilder buf = new StringBuilder(rows * 80);
1529                 appendPrettyHexDump(buf, buffer, offset, length);
1530                 return buf.toString();
1531             }
1532         }
1533 
1534         private static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1535             if (isOutOfBounds(offset, length, buf.capacity())) {
1536                 throw new IndexOutOfBoundsException(
1537                         "expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length
1538                                                     + ") <= " + "buf.capacity(" + buf.capacity() + ')');
1539             }
1540             if (length == 0) {
1541                 return;
1542             }
1543             dump.append(
1544                               "         +-------------------------------------------------+" +
1545                     NEWLINE + "         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |" +
1546                     NEWLINE + "+--------+-------------------------------------------------+----------------+");
1547 
1548             final int fullRows = length >>> 4;
1549             final int remainder = length & 0xF;
1550 
1551             // Dump the rows which have 16 bytes.
1552             for (int row = 0; row < fullRows; row ++) {
1553                 int rowStartIndex = (row << 4) + offset;
1554 
1555                 // Per-row prefix.
1556                 appendHexDumpRowPrefix(dump, row, rowStartIndex);
1557 
1558                 // Hex dump
1559                 int rowEndIndex = rowStartIndex + 16;
1560                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1561                     dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1562                 }
1563                 dump.append(" |");
1564 
1565                 // ASCII dump
1566                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1567                     dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1568                 }
1569                 dump.append('|');
1570             }
1571 
1572             // Dump the last row which has less than 16 bytes.
1573             if (remainder != 0) {
1574                 int rowStartIndex = (fullRows << 4) + offset;
1575                 appendHexDumpRowPrefix(dump, fullRows, rowStartIndex);
1576 
1577                 // Hex dump
1578                 int rowEndIndex = rowStartIndex + remainder;
1579                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1580                     dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1581                 }
1582                 dump.append(HEXPADDING[remainder]);
1583                 dump.append(" |");
1584 
1585                 // Ascii dump
1586                 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1587                     dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1588                 }
1589                 dump.append(BYTEPADDING[remainder]);
1590                 dump.append('|');
1591             }
1592 
1593             dump.append(NEWLINE +
1594                         "+--------+-------------------------------------------------+----------------+");
1595         }
1596 
1597         private static void appendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartIndex) {
1598             if (row < HEXDUMP_ROWPREFIXES.length) {
1599                 dump.append(HEXDUMP_ROWPREFIXES[row]);
1600             } else {
1601                 dump.append(NEWLINE);
1602                 dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L));
1603                 dump.setCharAt(dump.length() - 9, '|');
1604                 dump.append('|');
1605             }
1606         }
1607     }
1608 
1609     static final class ThreadLocalUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
1610 
1611         private static final ObjectPool<ThreadLocalUnsafeDirectByteBuf> RECYCLER =
1612                 ObjectPool.newPool(new ObjectCreator<ThreadLocalUnsafeDirectByteBuf>() {
1613                     @Override
1614                     public ThreadLocalUnsafeDirectByteBuf newObject(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1615                         return new ThreadLocalUnsafeDirectByteBuf(handle);
1616                     }
1617                 });
1618 
1619         static ThreadLocalUnsafeDirectByteBuf newInstance() {
1620             ThreadLocalUnsafeDirectByteBuf buf = RECYCLER.get();
1621             buf.resetRefCnt();
1622             return buf;
1623         }
1624 
1625         private final Handle<ThreadLocalUnsafeDirectByteBuf> handle;
1626 
1627         private ThreadLocalUnsafeDirectByteBuf(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1628             super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1629             this.handle = handle;
1630         }
1631 
1632         @Override
1633         protected void deallocate() {
1634             if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1635                 super.deallocate();
1636             } else {
1637                 clear();
1638                 handle.recycle(this);
1639             }
1640         }
1641     }
1642 
1643     static final class ThreadLocalDirectByteBuf extends UnpooledDirectByteBuf {
1644 
1645         private static final ObjectPool<ThreadLocalDirectByteBuf> RECYCLER = ObjectPool.newPool(
1646                 new ObjectCreator<ThreadLocalDirectByteBuf>() {
1647             @Override
1648             public ThreadLocalDirectByteBuf newObject(Handle<ThreadLocalDirectByteBuf> handle) {
1649                 return new ThreadLocalDirectByteBuf(handle);
1650             }
1651         });
1652 
1653         static ThreadLocalDirectByteBuf newInstance() {
1654             ThreadLocalDirectByteBuf buf = RECYCLER.get();
1655             buf.resetRefCnt();
1656             return buf;
1657         }
1658 
1659         private final Handle<ThreadLocalDirectByteBuf> handle;
1660 
1661         private ThreadLocalDirectByteBuf(Handle<ThreadLocalDirectByteBuf> handle) {
1662             super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1663             this.handle = handle;
1664         }
1665 
1666         @Override
1667         protected void deallocate() {
1668             if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1669                 super.deallocate();
1670             } else {
1671                 clear();
1672                 handle.recycle(this);
1673             }
1674         }
1675     }
1676 
1677     /**
1678      * Returns {@code true} if the given {@link ByteBuf} is valid text using the given {@link Charset},
1679      * otherwise return {@code false}.
1680      *
1681      * @param buf The given {@link ByteBuf}.
1682      * @param charset The specified {@link Charset}.
1683      */
1684     public static boolean isText(ByteBuf buf, Charset charset) {
1685         return isText(buf, buf.readerIndex(), buf.readableBytes(), charset);
1686     }
1687 
1688     /**
1689      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1690      * text using the given {@link Charset}, otherwise return {@code false}.
1691      *
1692      * @param buf The given {@link ByteBuf}.
1693      * @param index The start index of the specified buffer.
1694      * @param length The length of the specified buffer.
1695      * @param charset The specified {@link Charset}.
1696      *
1697      * @throws IndexOutOfBoundsException if {@code index} + {@code length} is greater than {@code buf.readableBytes}
1698      */
1699     public static boolean isText(ByteBuf buf, int index, int length, Charset charset) {
1700         checkNotNull(buf, "buf");
1701         checkNotNull(charset, "charset");
1702         final int maxIndex = buf.readerIndex() + buf.readableBytes();
1703         if (index < 0 || length < 0 || index > maxIndex - length) {
1704             throw new IndexOutOfBoundsException("index: " + index + " length: " + length);
1705         }
1706         if (charset.equals(CharsetUtil.UTF_8)) {
1707             return isUtf8(buf, index, length);
1708         } else if (charset.equals(CharsetUtil.US_ASCII)) {
1709             return isAscii(buf, index, length);
1710         } else {
1711             CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
1712             try {
1713                 if (buf.nioBufferCount() == 1) {
1714                     decoder.decode(buf.nioBuffer(index, length));
1715                 } else {
1716                     ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
1717                     try {
1718                         heapBuffer.writeBytes(buf, index, length);
1719                         decoder.decode(heapBuffer.internalNioBuffer(heapBuffer.readerIndex(), length));
1720                     } finally {
1721                         heapBuffer.release();
1722                     }
1723                 }
1724                 return true;
1725             } catch (CharacterCodingException ignore) {
1726                 return false;
1727             }
1728         }
1729     }
1730 
1731     /**
1732      * Aborts on a byte which is not a valid ASCII character.
1733      */
1734     private static final ByteProcessor FIND_NON_ASCII = new ByteProcessor() {
1735         @Override
1736         public boolean process(byte value) {
1737             return value >= 0;
1738         }
1739     };
1740 
1741     /**
1742      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1743      * ASCII text, otherwise return {@code false}.
1744      *
1745      * @param buf    The given {@link ByteBuf}.
1746      * @param index  The start index of the specified buffer.
1747      * @param length The length of the specified buffer.
1748      */
1749     private static boolean isAscii(ByteBuf buf, int index, int length) {
1750         return buf.forEachByte(index, length, FIND_NON_ASCII) == -1;
1751     }
1752 
1753     /**
1754      * Returns {@code true} if the specified {@link ByteBuf} starting at {@code index} with {@code length} is valid
1755      * UTF8 text, otherwise return {@code false}.
1756      *
1757      * @param buf The given {@link ByteBuf}.
1758      * @param index The start index of the specified buffer.
1759      * @param length The length of the specified buffer.
1760      *
1761      * @see
1762      * <a href=https://www.ietf.org/rfc/rfc3629.txt>UTF-8 Definition</a>
1763      *
1764      * <pre>
1765      * 1. Bytes format of UTF-8
1766      *
1767      * The table below summarizes the format of these different octet types.
1768      * The letter x indicates bits available for encoding bits of the character number.
1769      *
1770      * Char. number range  |        UTF-8 octet sequence
1771      *    (hexadecimal)    |              (binary)
1772      * --------------------+---------------------------------------------
1773      * 0000 0000-0000 007F | 0xxxxxxx
1774      * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1775      * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1776      * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1777      * </pre>
1778      *
1779      * <pre>
1780      * 2. Syntax of UTF-8 Byte Sequences
1781      *
1782      * UTF8-octets = *( UTF8-char )
1783      * UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
1784      * UTF8-1      = %x00-7F
1785      * UTF8-2      = %xC2-DF UTF8-tail
1786      * UTF8-3      = %xE0 %xA0-BF UTF8-tail /
1787      *               %xE1-EC 2( UTF8-tail ) /
1788      *               %xED %x80-9F UTF8-tail /
1789      *               %xEE-EF 2( UTF8-tail )
1790      * UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) /
1791      *               %xF1-F3 3( UTF8-tail ) /
1792      *               %xF4 %x80-8F 2( UTF8-tail )
1793      * UTF8-tail   = %x80-BF
1794      * </pre>
1795      */
1796     private static boolean isUtf8(ByteBuf buf, int index, int length) {
1797         final int endIndex = index + length;
1798         while (index < endIndex) {
1799             byte b1 = buf.getByte(index++);
1800             byte b2, b3, b4;
1801             if ((b1 & 0x80) == 0) {
1802                 // 1 byte
1803                 continue;
1804             }
1805             if ((b1 & 0xE0) == 0xC0) {
1806                 // 2 bytes
1807                 //
1808                 // Bit/Byte pattern
1809                 // 110xxxxx    10xxxxxx
1810                 // C2..DF      80..BF
1811                 if (index >= endIndex) { // no enough bytes
1812                     return false;
1813                 }
1814                 b2 = buf.getByte(index++);
1815                 if ((b2 & 0xC0) != 0x80) { // 2nd byte not starts with 10
1816                     return false;
1817                 }
1818                 if ((b1 & 0xFF) < 0xC2) { // out of lower bound
1819                     return false;
1820                 }
1821             } else if ((b1 & 0xF0) == 0xE0) {
1822                 // 3 bytes
1823                 //
1824                 // Bit/Byte pattern
1825                 // 1110xxxx    10xxxxxx    10xxxxxx
1826                 // E0          A0..BF      80..BF
1827                 // E1..EC      80..BF      80..BF
1828                 // ED          80..9F      80..BF
1829                 // E1..EF      80..BF      80..BF
1830                 if (index > endIndex - 2) { // no enough bytes
1831                     return false;
1832                 }
1833                 b2 = buf.getByte(index++);
1834                 b3 = buf.getByte(index++);
1835                 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { // 2nd or 3rd bytes not start with 10
1836                     return false;
1837                 }
1838                 if ((b1 & 0x0F) == 0x00 && (b2 & 0xFF) < 0xA0) { // out of lower bound
1839                     return false;
1840                 }
1841                 if ((b1 & 0x0F) == 0x0D && (b2 & 0xFF) > 0x9F) { // out of upper bound
1842                     return false;
1843                 }
1844             } else if ((b1 & 0xF8) == 0xF0) {
1845                 // 4 bytes
1846                 //
1847                 // Bit/Byte pattern
1848                 // 11110xxx    10xxxxxx    10xxxxxx    10xxxxxx
1849                 // F0          90..BF      80..BF      80..BF
1850                 // F1..F3      80..BF      80..BF      80..BF
1851                 // F4          80..8F      80..BF      80..BF
1852                 if (index > endIndex - 3) { // no enough bytes
1853                     return false;
1854                 }
1855                 b2 = buf.getByte(index++);
1856                 b3 = buf.getByte(index++);
1857                 b4 = buf.getByte(index++);
1858                 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80) {
1859                     // 2nd, 3rd or 4th bytes not start with 10
1860                     return false;
1861                 }
1862                 if ((b1 & 0xFF) > 0xF4 // b1 invalid
1863                         || (b1 & 0xFF) == 0xF0 && (b2 & 0xFF) < 0x90    // b2 out of lower bound
1864                         || (b1 & 0xFF) == 0xF4 && (b2 & 0xFF) > 0x8F) { // b2 out of upper bound
1865                     return false;
1866                 }
1867             } else {
1868                 return false;
1869             }
1870         }
1871         return true;
1872     }
1873 
1874     /**
1875      * Read bytes from the given {@link ByteBuffer} into the given {@link OutputStream} using the {@code position} and
1876      * {@code length}. The position and limit of the given {@link ByteBuffer} may be adjusted.
1877      */
1878     static void readBytes(ByteBufAllocator allocator, ByteBuffer buffer, int position, int length, OutputStream out)
1879             throws IOException {
1880         if (buffer.hasArray()) {
1881             out.write(buffer.array(), position + buffer.arrayOffset(), length);
1882         } else {
1883             int chunkLen = Math.min(length, WRITE_CHUNK_SIZE);
1884             buffer.clear().position(position);
1885 
1886             if (length <= MAX_TL_ARRAY_LEN || !allocator.isDirectBufferPooled()) {
1887                 getBytes(buffer, threadLocalTempArray(chunkLen), 0, chunkLen, out, length);
1888             } else {
1889                 // if direct buffers are pooled chances are good that heap buffers are pooled as well.
1890                 ByteBuf tmpBuf = allocator.heapBuffer(chunkLen);
1891                 try {
1892                     byte[] tmp = tmpBuf.array();
1893                     int offset = tmpBuf.arrayOffset();
1894                     getBytes(buffer, tmp, offset, chunkLen, out, length);
1895                 } finally {
1896                     tmpBuf.release();
1897                 }
1898             }
1899         }
1900     }
1901 
1902     private static void getBytes(ByteBuffer inBuffer, byte[] in, int inOffset, int inLen, OutputStream out, int outLen)
1903             throws IOException {
1904         do {
1905             int len = Math.min(inLen, outLen);
1906             inBuffer.get(in, inOffset, len);
1907             out.write(in, inOffset, len);
1908             outLen -= len;
1909         } while (outLen > 0);
1910     }
1911 
1912     private ByteBufUtil() { }
1913 }