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