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;
23 import io.netty.util.Recycler.EnhancedHandle;
24 import io.netty.util.ResourceLeakDetector;
25 import io.netty.util.concurrent.FastThreadLocal;
26 import io.netty.util.concurrent.FastThreadLocalThread;
27 import io.netty.util.internal.MathUtil;
28 import io.netty.util.internal.ObjectPool.Handle;
29 import io.netty.util.internal.PlatformDependent;
30 import io.netty.util.internal.SWARUtil;
31 import io.netty.util.internal.StringUtil;
32 import io.netty.util.internal.SystemPropertyUtil;
33 import io.netty.util.internal.logging.InternalLogger;
34 import io.netty.util.internal.logging.InternalLoggerFactory;
35
36 import java.io.IOException;
37 import java.io.OutputStream;
38 import java.nio.ByteBuffer;
39 import java.nio.ByteOrder;
40 import java.nio.CharBuffer;
41 import java.nio.charset.CharacterCodingException;
42 import java.nio.charset.Charset;
43 import java.nio.charset.CharsetDecoder;
44 import java.nio.charset.CharsetEncoder;
45 import java.nio.charset.CoderResult;
46 import java.nio.charset.CodingErrorAction;
47 import java.util.Arrays;
48
49 import static io.netty.util.internal.MathUtil.isOutOfBounds;
50 import static io.netty.util.internal.ObjectUtil.checkNotNull;
51 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
52 import static io.netty.util.internal.StringUtil.NEWLINE;
53 import static io.netty.util.internal.StringUtil.isSurrogate;
54
55
56
57
58
59 public final class ByteBufUtil {
60
61 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ByteBufUtil.class);
62 private static final FastThreadLocal<byte[]> BYTE_ARRAYS = new FastThreadLocal<byte[]>() {
63 @Override
64 protected byte[] initialValue() throws Exception {
65 return PlatformDependent.allocateUninitializedArray(MAX_TL_ARRAY_LEN);
66 }
67 };
68
69 private static final byte WRITE_UTF_UNKNOWN = (byte) '?';
70 private static final int MAX_CHAR_BUFFER_SIZE;
71 private static final int THREAD_LOCAL_BUFFER_SIZE;
72 private static final int MAX_BYTES_PER_CHAR_UTF8 =
73 (int) CharsetUtil.encoder(CharsetUtil.UTF_8).maxBytesPerChar();
74
75 static final int WRITE_CHUNK_SIZE = 8192;
76 static final ByteBufAllocator DEFAULT_ALLOCATOR;
77 private static final boolean SWAR_UNALIGNED = PlatformDependent.canUnalignedAccess();
78
79 static {
80 String allocType = SystemPropertyUtil.get(
81 "io.netty.allocator.type", "adaptive");
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 && FastThreadLocalThread.currentThreadHasFastThreadLocal()) {
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 (!SWAR_UNALIGNED) {
582 return linearFirstIndexOf(buffer, fromIndex, toIndex, value);
583 }
584 assert SWAR_UNALIGNED;
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 (!SWAR_UNALIGNED) {
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() && buffer.nioBufferCount() == 1) {
929 final ByteBuffer internalDirectBuffer = buffer.internalNioBuffer(writerIndex, reservedBytes);
930 final int bufferPosition = internalDirectBuffer.position();
931 return safeDirectWriteUtf8(internalDirectBuffer, bufferPosition, seq, start, end);
932 }
933 }
934 return safeWriteUtf8(buffer, writerIndex, seq, start, end);
935 }
936
937
938 static void writeAsciiString(AbstractByteBuf buffer, int writerIndex, AsciiString seq, int start, int end) {
939 final int begin = seq.arrayOffset() + start;
940 final int length = end - start;
941 if (PlatformDependent.hasUnsafe()) {
942 if (buffer.hasArray()) {
943 PlatformDependent.copyMemory(seq.array(), begin,
944 buffer.array(), buffer.arrayOffset() + writerIndex, length);
945 return;
946 }
947 if (buffer.hasMemoryAddress()) {
948 PlatformDependent.copyMemory(seq.array(), begin, buffer.memoryAddress() + writerIndex, length);
949 return;
950 }
951 }
952 if (buffer.hasArray()) {
953 System.arraycopy(seq.array(), begin, buffer.array(), buffer.arrayOffset() + writerIndex, length);
954 return;
955 }
956 buffer.setBytes(writerIndex, seq.array(), begin, length);
957 }
958
959
960 private static int safeDirectWriteUtf8(ByteBuffer buffer, int writerIndex, CharSequence seq, int start, int end) {
961 assert !(seq instanceof AsciiString);
962 int oldWriterIndex = writerIndex;
963
964
965
966 for (int i = start; i < end; i++) {
967 char c = seq.charAt(i);
968 if (c < 0x80) {
969 buffer.put(writerIndex++, (byte) c);
970 } else if (c < 0x800) {
971 buffer.put(writerIndex++, (byte) (0xc0 | (c >> 6)));
972 buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
973 } else if (isSurrogate(c)) {
974 if (!Character.isHighSurrogate(c)) {
975 buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
976 continue;
977 }
978
979 if (++i == end) {
980 buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
981 break;
982 }
983
984
985 char c2 = seq.charAt(i);
986 if (!Character.isLowSurrogate(c2)) {
987 buffer.put(writerIndex++, WRITE_UTF_UNKNOWN);
988 buffer.put(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : (byte) c2);
989 } else {
990 int codePoint = Character.toCodePoint(c, c2);
991
992 buffer.put(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
993 buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
994 buffer.put(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
995 buffer.put(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
996 }
997 } else {
998 buffer.put(writerIndex++, (byte) (0xe0 | (c >> 12)));
999 buffer.put(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
1000 buffer.put(writerIndex++, (byte) (0x80 | (c & 0x3f)));
1001 }
1002 }
1003 return writerIndex - oldWriterIndex;
1004 }
1005
1006
1007 private static int safeWriteUtf8(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int start, int end) {
1008 assert !(seq instanceof AsciiString);
1009 int oldWriterIndex = writerIndex;
1010
1011
1012
1013 for (int i = start; i < end; i++) {
1014 char c = seq.charAt(i);
1015 if (c < 0x80) {
1016 buffer._setByte(writerIndex++, (byte) c);
1017 } else if (c < 0x800) {
1018 buffer._setByte(writerIndex++, (byte) (0xc0 | (c >> 6)));
1019 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
1020 } else if (isSurrogate(c)) {
1021 if (!Character.isHighSurrogate(c)) {
1022 buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
1023 continue;
1024 }
1025
1026 if (++i == end) {
1027 buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
1028 break;
1029 }
1030
1031
1032 char c2 = seq.charAt(i);
1033 if (!Character.isLowSurrogate(c2)) {
1034 buffer._setByte(writerIndex++, WRITE_UTF_UNKNOWN);
1035 buffer._setByte(writerIndex++, Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
1036 } else {
1037 int codePoint = Character.toCodePoint(c, c2);
1038
1039 buffer._setByte(writerIndex++, (byte) (0xf0 | (codePoint >> 18)));
1040 buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
1041 buffer._setByte(writerIndex++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
1042 buffer._setByte(writerIndex++, (byte) (0x80 | (codePoint & 0x3f)));
1043 }
1044 } else {
1045 buffer._setByte(writerIndex++, (byte) (0xe0 | (c >> 12)));
1046 buffer._setByte(writerIndex++, (byte) (0x80 | ((c >> 6) & 0x3f)));
1047 buffer._setByte(writerIndex++, (byte) (0x80 | (c & 0x3f)));
1048 }
1049 }
1050 return writerIndex - oldWriterIndex;
1051 }
1052
1053
1054 private static int safeArrayWriteUtf8(byte[] buffer, int writerIndex, CharSequence seq, int start, int end) {
1055 int oldWriterIndex = writerIndex;
1056 for (int i = start; i < end; i++) {
1057 char c = seq.charAt(i);
1058 if (c < 0x80) {
1059 buffer[writerIndex++] = (byte) c;
1060 } else if (c < 0x800) {
1061 buffer[writerIndex++] = (byte) (0xc0 | (c >> 6));
1062 buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
1063 } else if (isSurrogate(c)) {
1064 if (!Character.isHighSurrogate(c)) {
1065 buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
1066 continue;
1067 }
1068
1069 if (++i == end) {
1070 buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
1071 break;
1072 }
1073 char c2 = seq.charAt(i);
1074
1075
1076 if (!Character.isLowSurrogate(c2)) {
1077 buffer[writerIndex++] = WRITE_UTF_UNKNOWN;
1078 buffer[writerIndex++] = (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2);
1079 } else {
1080 int codePoint = Character.toCodePoint(c, c2);
1081
1082 buffer[writerIndex++] = (byte) (0xf0 | (codePoint >> 18));
1083 buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 12) & 0x3f));
1084 buffer[writerIndex++] = (byte) (0x80 | ((codePoint >> 6) & 0x3f));
1085 buffer[writerIndex++] = (byte) (0x80 | (codePoint & 0x3f));
1086 }
1087 } else {
1088 buffer[writerIndex++] = (byte) (0xe0 | (c >> 12));
1089 buffer[writerIndex++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1090 buffer[writerIndex++] = (byte) (0x80 | (c & 0x3f));
1091 }
1092 }
1093 return writerIndex - oldWriterIndex;
1094 }
1095
1096
1097 private static int unsafeWriteUtf8(byte[] buffer, long memoryOffset, int writerIndex,
1098 CharSequence seq, int start, int end) {
1099 assert !(seq instanceof AsciiString);
1100 long writerOffset = memoryOffset + writerIndex;
1101 final long oldWriterOffset = writerOffset;
1102 for (int i = start; i < end; i++) {
1103 char c = seq.charAt(i);
1104 if (c < 0x80) {
1105 PlatformDependent.putByte(buffer, writerOffset++, (byte) c);
1106 } else if (c < 0x800) {
1107 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xc0 | (c >> 6)));
1108 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
1109 } else if (isSurrogate(c)) {
1110 if (!Character.isHighSurrogate(c)) {
1111 PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1112 continue;
1113 }
1114
1115 if (++i == end) {
1116 PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1117 break;
1118 }
1119 char c2 = seq.charAt(i);
1120
1121
1122 if (!Character.isLowSurrogate(c2)) {
1123 PlatformDependent.putByte(buffer, writerOffset++, WRITE_UTF_UNKNOWN);
1124 PlatformDependent.putByte(buffer, writerOffset++,
1125 (byte) (Character.isHighSurrogate(c2)? WRITE_UTF_UNKNOWN : c2));
1126 } else {
1127 int codePoint = Character.toCodePoint(c, c2);
1128
1129 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xf0 | (codePoint >> 18)));
1130 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 12) & 0x3f)));
1131 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((codePoint >> 6) & 0x3f)));
1132 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (codePoint & 0x3f)));
1133 }
1134 } else {
1135 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0xe0 | (c >> 12)));
1136 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | ((c >> 6) & 0x3f)));
1137 PlatformDependent.putByte(buffer, writerOffset++, (byte) (0x80 | (c & 0x3f)));
1138 }
1139 }
1140 return (int) (writerOffset - oldWriterOffset);
1141 }
1142
1143
1144
1145
1146 public static int utf8MaxBytes(final int seqLength) {
1147 return seqLength * MAX_BYTES_PER_CHAR_UTF8;
1148 }
1149
1150
1151
1152
1153
1154
1155 public static int utf8MaxBytes(CharSequence seq) {
1156 if (seq instanceof AsciiString) {
1157 return seq.length();
1158 }
1159 return utf8MaxBytes(seq.length());
1160 }
1161
1162
1163
1164
1165
1166
1167 public static int utf8Bytes(final CharSequence seq) {
1168 return utf8ByteCount(seq, 0, seq.length());
1169 }
1170
1171
1172
1173
1174
1175
1176
1177 public static int utf8Bytes(final CharSequence seq, int start, int end) {
1178 return utf8ByteCount(checkCharSequenceBounds(seq, start, end), start, end);
1179 }
1180
1181 private static int utf8ByteCount(final CharSequence seq, int start, int end) {
1182 if (seq instanceof AsciiString) {
1183 return end - start;
1184 }
1185 int i = start;
1186
1187 while (i < end && seq.charAt(i) < 0x80) {
1188 ++i;
1189 }
1190
1191 return i < end ? (i - start) + utf8BytesNonAscii(seq, i, end) : i - start;
1192 }
1193
1194 private static int utf8BytesNonAscii(final CharSequence seq, final int start, final int end) {
1195 int encodedLength = 0;
1196 for (int i = start; i < end; i++) {
1197 final char c = seq.charAt(i);
1198
1199 if (c < 0x800) {
1200
1201 encodedLength += ((0x7f - c) >>> 31) + 1;
1202 } else if (isSurrogate(c)) {
1203 if (!Character.isHighSurrogate(c)) {
1204 encodedLength++;
1205
1206 continue;
1207 }
1208
1209 if (++i == end) {
1210 encodedLength++;
1211
1212 break;
1213 }
1214 if (!Character.isLowSurrogate(seq.charAt(i))) {
1215
1216 encodedLength += 2;
1217 continue;
1218 }
1219
1220 encodedLength += 4;
1221 } else {
1222 encodedLength += 3;
1223 }
1224 }
1225 return encodedLength;
1226 }
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236 public static ByteBuf writeAscii(ByteBufAllocator alloc, CharSequence seq) {
1237
1238 ByteBuf buf = alloc.buffer(seq.length());
1239 writeAscii(buf, seq);
1240 return buf;
1241 }
1242
1243
1244
1245
1246
1247
1248
1249 public static int writeAscii(ByteBuf buf, CharSequence seq) {
1250
1251 for (;;) {
1252 if (buf instanceof WrappedCompositeByteBuf) {
1253
1254 buf = buf.unwrap();
1255 } else if (buf instanceof AbstractByteBuf) {
1256 final int len = seq.length();
1257 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
1258 byteBuf.ensureWritable0(len);
1259 if (seq instanceof AsciiString) {
1260 writeAsciiString(byteBuf, byteBuf.writerIndex, (AsciiString) seq, 0, len);
1261 } else {
1262 final int written = writeAscii(byteBuf, byteBuf.writerIndex, seq, len);
1263 assert written == len;
1264 }
1265 byteBuf.writerIndex += len;
1266 return len;
1267 } else if (buf instanceof WrappedByteBuf) {
1268
1269 buf = buf.unwrap();
1270 } else {
1271 byte[] bytes = seq.toString().getBytes(CharsetUtil.US_ASCII);
1272 buf.writeBytes(bytes);
1273 return bytes.length;
1274 }
1275 }
1276 }
1277
1278 static int writeAscii(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
1279 if (seq instanceof AsciiString) {
1280 writeAsciiString(buffer, writerIndex, (AsciiString) seq, 0, len);
1281 } else {
1282 writeAsciiCharSequence(buffer, writerIndex, seq, len);
1283 }
1284 return len;
1285 }
1286
1287 private static int writeAsciiCharSequence(AbstractByteBuf buffer, int writerIndex, CharSequence seq, int len) {
1288
1289
1290 for (int i = 0; i < len; i++) {
1291 buffer._setByte(writerIndex++, AsciiString.c2b(seq.charAt(i)));
1292 }
1293 return len;
1294 }
1295
1296
1297
1298
1299
1300 public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset) {
1301 return encodeString0(alloc, false, src, charset, 0);
1302 }
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313 public static ByteBuf encodeString(ByteBufAllocator alloc, CharBuffer src, Charset charset, int extraCapacity) {
1314 return encodeString0(alloc, false, src, charset, extraCapacity);
1315 }
1316
1317 static ByteBuf encodeString0(ByteBufAllocator alloc, boolean enforceHeap, CharBuffer src, Charset charset,
1318 int extraCapacity) {
1319 final CharsetEncoder encoder = CharsetUtil.encoder(charset);
1320 int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar()) + extraCapacity;
1321 boolean release = true;
1322 final ByteBuf dst;
1323 if (enforceHeap) {
1324 dst = alloc.heapBuffer(length);
1325 } else {
1326 dst = alloc.buffer(length);
1327 }
1328 try {
1329 final ByteBuffer dstBuf = dst.internalNioBuffer(dst.readerIndex(), length);
1330 final int pos = dstBuf.position();
1331 CoderResult cr = encoder.encode(src, dstBuf, true);
1332 if (!cr.isUnderflow()) {
1333 cr.throwException();
1334 }
1335 cr = encoder.flush(dstBuf);
1336 if (!cr.isUnderflow()) {
1337 cr.throwException();
1338 }
1339 dst.writerIndex(dst.writerIndex() + dstBuf.position() - pos);
1340 release = false;
1341 return dst;
1342 } catch (CharacterCodingException x) {
1343 throw new IllegalStateException(x);
1344 } finally {
1345 if (release) {
1346 dst.release();
1347 }
1348 }
1349 }
1350
1351 @SuppressWarnings("deprecation")
1352 static String decodeString(ByteBuf src, int readerIndex, int len, Charset charset) {
1353 if (len == 0) {
1354 return StringUtil.EMPTY_STRING;
1355 }
1356 final byte[] array;
1357 final int offset;
1358
1359 if (src.hasArray()) {
1360 array = src.array();
1361 offset = src.arrayOffset() + readerIndex;
1362 } else {
1363 array = threadLocalTempArray(len);
1364 offset = 0;
1365 src.getBytes(readerIndex, array, 0, len);
1366 }
1367 if (CharsetUtil.US_ASCII.equals(charset)) {
1368
1369 return new String(array, 0, offset, len);
1370 }
1371 return new String(array, offset, len, charset);
1372 }
1373
1374
1375
1376
1377
1378
1379 public static ByteBuf threadLocalDirectBuffer() {
1380 if (THREAD_LOCAL_BUFFER_SIZE <= 0) {
1381 return null;
1382 }
1383
1384 if (PlatformDependent.hasUnsafe()) {
1385 return ThreadLocalUnsafeDirectByteBuf.newInstance();
1386 } else {
1387 return ThreadLocalDirectByteBuf.newInstance();
1388 }
1389 }
1390
1391
1392
1393
1394
1395 public static byte[] getBytes(ByteBuf buf) {
1396 return getBytes(buf, buf.readerIndex(), buf.readableBytes());
1397 }
1398
1399
1400
1401
1402
1403 public static byte[] getBytes(ByteBuf buf, int start, int length) {
1404 return getBytes(buf, start, length, true);
1405 }
1406
1407
1408
1409
1410
1411
1412
1413 public static byte[] getBytes(ByteBuf buf, int start, int length, boolean copy) {
1414 int capacity = buf.capacity();
1415 if (isOutOfBounds(start, length, capacity)) {
1416 throw new IndexOutOfBoundsException("expected: " + "0 <= start(" + start + ") <= start + length(" + length
1417 + ") <= " + "buf.capacity(" + capacity + ')');
1418 }
1419
1420 if (buf.hasArray()) {
1421 int baseOffset = buf.arrayOffset() + start;
1422 byte[] bytes = buf.array();
1423 if (copy || baseOffset != 0 || length != bytes.length) {
1424 return Arrays.copyOfRange(bytes, baseOffset, baseOffset + length);
1425 } else {
1426 return bytes;
1427 }
1428 }
1429
1430 byte[] bytes = PlatformDependent.allocateUninitializedArray(length);
1431 buf.getBytes(start, bytes);
1432 return bytes;
1433 }
1434
1435
1436
1437
1438
1439
1440
1441 public static void copy(AsciiString src, ByteBuf dst) {
1442 copy(src, 0, dst, src.length());
1443 }
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456 public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int dstIdx, int length) {
1457 if (isOutOfBounds(srcIdx, length, src.length())) {
1458 throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
1459 + length + ") <= srcLen(" + src.length() + ')');
1460 }
1461
1462 checkNotNull(dst, "dst").setBytes(dstIdx, src.array(), srcIdx + src.arrayOffset(), length);
1463 }
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473 public static void copy(AsciiString src, int srcIdx, ByteBuf dst, int length) {
1474 if (isOutOfBounds(srcIdx, length, src.length())) {
1475 throw new IndexOutOfBoundsException("expected: " + "0 <= srcIdx(" + srcIdx + ") <= srcIdx + length("
1476 + length + ") <= srcLen(" + src.length() + ')');
1477 }
1478
1479 checkNotNull(dst, "dst").writeBytes(src.array(), srcIdx + src.arrayOffset(), length);
1480 }
1481
1482
1483
1484
1485 public static String prettyHexDump(ByteBuf buffer) {
1486 return prettyHexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
1487 }
1488
1489
1490
1491
1492
1493 public static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1494 return HexUtil.prettyHexDump(buffer, offset, length);
1495 }
1496
1497
1498
1499
1500
1501 public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf) {
1502 appendPrettyHexDump(dump, buf, buf.readerIndex(), buf.readableBytes());
1503 }
1504
1505
1506
1507
1508
1509
1510 public static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1511 HexUtil.appendPrettyHexDump(dump, buf, offset, length);
1512 }
1513
1514
1515 private static final class HexUtil {
1516
1517 private static final char[] BYTE2CHAR = new char[256];
1518 private static final char[] HEXDUMP_TABLE = new char[256 * 2];
1519 private static final String[] HEXPADDING = new String[16];
1520 private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4];
1521 private static final String[] BYTE2HEX = new String[256];
1522 private static final String[] BYTEPADDING = new String[16];
1523
1524 static {
1525 final char[] DIGITS = "0123456789abcdef".toCharArray();
1526 for (int i = 0; i < 256; i ++) {
1527 HEXDUMP_TABLE[ i << 1 ] = DIGITS[i >>> 4 & 0x0F];
1528 HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F];
1529 }
1530
1531 int i;
1532
1533
1534 for (i = 0; i < HEXPADDING.length; i ++) {
1535 int padding = HEXPADDING.length - i;
1536 StringBuilder buf = new StringBuilder(padding * 3);
1537 for (int j = 0; j < padding; j ++) {
1538 buf.append(" ");
1539 }
1540 HEXPADDING[i] = buf.toString();
1541 }
1542
1543
1544 for (i = 0; i < HEXDUMP_ROWPREFIXES.length; i ++) {
1545 StringBuilder buf = new StringBuilder(12);
1546 buf.append(NEWLINE);
1547 buf.append(Long.toHexString(i << 4 & 0xFFFFFFFFL | 0x100000000L));
1548 buf.setCharAt(buf.length() - 9, '|');
1549 buf.append('|');
1550 HEXDUMP_ROWPREFIXES[i] = buf.toString();
1551 }
1552
1553
1554 for (i = 0; i < BYTE2HEX.length; i ++) {
1555 BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i);
1556 }
1557
1558
1559 for (i = 0; i < BYTEPADDING.length; i ++) {
1560 int padding = BYTEPADDING.length - i;
1561 StringBuilder buf = new StringBuilder(padding);
1562 for (int j = 0; j < padding; j ++) {
1563 buf.append(' ');
1564 }
1565 BYTEPADDING[i] = buf.toString();
1566 }
1567
1568
1569 for (i = 0; i < BYTE2CHAR.length; i ++) {
1570 if (i <= 0x1f || i >= 0x7f) {
1571 BYTE2CHAR[i] = '.';
1572 } else {
1573 BYTE2CHAR[i] = (char) i;
1574 }
1575 }
1576 }
1577
1578 private static String hexDump(ByteBuf buffer, int fromIndex, int length) {
1579 checkPositiveOrZero(length, "length");
1580 if (length == 0) {
1581 return "";
1582 }
1583
1584 int endIndex = fromIndex + length;
1585 char[] buf = new char[length << 1];
1586
1587 int srcIdx = fromIndex;
1588 int dstIdx = 0;
1589 for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1590 System.arraycopy(
1591 HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1,
1592 buf, dstIdx, 2);
1593 }
1594
1595 return new String(buf);
1596 }
1597
1598 private static String hexDump(byte[] array, int fromIndex, int length) {
1599 checkPositiveOrZero(length, "length");
1600 if (length == 0) {
1601 return "";
1602 }
1603
1604 int endIndex = fromIndex + length;
1605 char[] buf = new char[length << 1];
1606
1607 int srcIdx = fromIndex;
1608 int dstIdx = 0;
1609 for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) {
1610 System.arraycopy(
1611 HEXDUMP_TABLE, (array[srcIdx] & 0xFF) << 1,
1612 buf, dstIdx, 2);
1613 }
1614
1615 return new String(buf);
1616 }
1617
1618 private static String prettyHexDump(ByteBuf buffer, int offset, int length) {
1619 if (length == 0) {
1620 return StringUtil.EMPTY_STRING;
1621 } else {
1622 int rows = length / 16 + ((length & 15) == 0? 0 : 1) + 4;
1623 StringBuilder buf = new StringBuilder(rows * 80);
1624 appendPrettyHexDump(buf, buffer, offset, length);
1625 return buf.toString();
1626 }
1627 }
1628
1629 private static void appendPrettyHexDump(StringBuilder dump, ByteBuf buf, int offset, int length) {
1630 if (isOutOfBounds(offset, length, buf.capacity())) {
1631 throw new IndexOutOfBoundsException(
1632 "expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length
1633 + ") <= " + "buf.capacity(" + buf.capacity() + ')');
1634 }
1635 if (length == 0) {
1636 return;
1637 }
1638 dump.append(
1639 " +-------------------------------------------------+" +
1640 NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" +
1641 NEWLINE + "+--------+-------------------------------------------------+----------------+");
1642
1643 final int fullRows = length >>> 4;
1644 final int remainder = length & 0xF;
1645
1646
1647 for (int row = 0; row < fullRows; row ++) {
1648 int rowStartIndex = (row << 4) + offset;
1649
1650
1651 appendHexDumpRowPrefix(dump, row, rowStartIndex);
1652
1653
1654 int rowEndIndex = rowStartIndex + 16;
1655 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1656 dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1657 }
1658 dump.append(" |");
1659
1660
1661 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1662 dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1663 }
1664 dump.append('|');
1665 }
1666
1667
1668 if (remainder != 0) {
1669 int rowStartIndex = (fullRows << 4) + offset;
1670 appendHexDumpRowPrefix(dump, fullRows, rowStartIndex);
1671
1672
1673 int rowEndIndex = rowStartIndex + remainder;
1674 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1675 dump.append(BYTE2HEX[buf.getUnsignedByte(j)]);
1676 }
1677 dump.append(HEXPADDING[remainder]);
1678 dump.append(" |");
1679
1680
1681 for (int j = rowStartIndex; j < rowEndIndex; j ++) {
1682 dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
1683 }
1684 dump.append(BYTEPADDING[remainder]);
1685 dump.append('|');
1686 }
1687
1688 dump.append(NEWLINE +
1689 "+--------+-------------------------------------------------+----------------+");
1690 }
1691
1692 private static void appendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartIndex) {
1693 if (row < HEXDUMP_ROWPREFIXES.length) {
1694 dump.append(HEXDUMP_ROWPREFIXES[row]);
1695 } else {
1696 dump.append(NEWLINE);
1697 dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L));
1698 dump.setCharAt(dump.length() - 9, '|');
1699 dump.append('|');
1700 }
1701 }
1702 }
1703
1704 static final class ThreadLocalUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
1705
1706 private static final Recycler<ThreadLocalUnsafeDirectByteBuf> RECYCLER =
1707 new Recycler<ThreadLocalUnsafeDirectByteBuf>() {
1708 @Override
1709 protected ThreadLocalUnsafeDirectByteBuf newObject(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1710 return new ThreadLocalUnsafeDirectByteBuf(handle);
1711 }
1712 };
1713
1714 static ThreadLocalUnsafeDirectByteBuf newInstance() {
1715 ThreadLocalUnsafeDirectByteBuf buf = RECYCLER.get();
1716 buf.resetRefCnt();
1717 return buf;
1718 }
1719
1720 private final EnhancedHandle<ThreadLocalUnsafeDirectByteBuf> handle;
1721
1722 private ThreadLocalUnsafeDirectByteBuf(Handle<ThreadLocalUnsafeDirectByteBuf> handle) {
1723 super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1724 this.handle = (EnhancedHandle<ThreadLocalUnsafeDirectByteBuf>) handle;
1725 }
1726
1727 @Override
1728 protected void deallocate() {
1729 if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1730 super.deallocate();
1731 } else {
1732 clear();
1733 handle.unguardedRecycle(this);
1734 }
1735 }
1736 }
1737
1738 static final class ThreadLocalDirectByteBuf extends UnpooledDirectByteBuf {
1739
1740 private static final Recycler<ThreadLocalDirectByteBuf> RECYCLER = new Recycler<ThreadLocalDirectByteBuf>() {
1741 @Override
1742 protected ThreadLocalDirectByteBuf newObject(Handle<ThreadLocalDirectByteBuf> handle) {
1743 return new ThreadLocalDirectByteBuf(handle);
1744 }
1745 };
1746
1747 static ThreadLocalDirectByteBuf newInstance() {
1748 ThreadLocalDirectByteBuf buf = RECYCLER.get();
1749 buf.resetRefCnt();
1750 return buf;
1751 }
1752
1753 private final EnhancedHandle<ThreadLocalDirectByteBuf> handle;
1754
1755 private ThreadLocalDirectByteBuf(Handle<ThreadLocalDirectByteBuf> handle) {
1756 super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1757 this.handle = (EnhancedHandle<ThreadLocalDirectByteBuf>) handle;
1758 }
1759
1760 @Override
1761 protected void deallocate() {
1762 if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1763 super.deallocate();
1764 } else {
1765 clear();
1766 handle.unguardedRecycle(this);
1767 }
1768 }
1769 }
1770
1771
1772
1773
1774
1775
1776
1777
1778 public static boolean isText(ByteBuf buf, Charset charset) {
1779 return isText(buf, buf.readerIndex(), buf.readableBytes(), charset);
1780 }
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793 public static boolean isText(ByteBuf buf, int index, int length, Charset charset) {
1794 checkNotNull(buf, "buf");
1795 checkNotNull(charset, "charset");
1796 final int maxIndex = buf.readerIndex() + buf.readableBytes();
1797 if (index < 0 || length < 0 || index > maxIndex - length) {
1798 throw new IndexOutOfBoundsException("index: " + index + " length: " + length);
1799 }
1800 if (charset.equals(CharsetUtil.UTF_8)) {
1801 return isUtf8(buf, index, length);
1802 } else if (charset.equals(CharsetUtil.US_ASCII)) {
1803 return isAscii(buf, index, length);
1804 } else {
1805 CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
1806 try {
1807 if (buf.nioBufferCount() == 1) {
1808 decoder.decode(buf.nioBuffer(index, length));
1809 } else {
1810 ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
1811 try {
1812 heapBuffer.writeBytes(buf, index, length);
1813 decoder.decode(heapBuffer.internalNioBuffer(heapBuffer.readerIndex(), length));
1814 } finally {
1815 heapBuffer.release();
1816 }
1817 }
1818 return true;
1819 } catch (CharacterCodingException ignore) {
1820 return false;
1821 }
1822 }
1823 }
1824
1825
1826
1827
1828 private static final ByteProcessor FIND_NON_ASCII = new ByteProcessor() {
1829 @Override
1830 public boolean process(byte value) {
1831 return value >= 0;
1832 }
1833 };
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843 private static boolean isAscii(ByteBuf buf, int index, int length) {
1844 return buf.forEachByte(index, length, FIND_NON_ASCII) == -1;
1845 }
1846
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 private static boolean isUtf8(ByteBuf buf, int index, int length) {
1891 final int endIndex = index + length;
1892 while (index < endIndex) {
1893 byte b1 = buf.getByte(index++);
1894 byte b2, b3, b4;
1895 if ((b1 & 0x80) == 0) {
1896
1897 continue;
1898 }
1899 if ((b1 & 0xE0) == 0xC0) {
1900
1901
1902
1903
1904
1905 if (index >= endIndex) {
1906 return false;
1907 }
1908 b2 = buf.getByte(index++);
1909 if ((b2 & 0xC0) != 0x80) {
1910 return false;
1911 }
1912 if ((b1 & 0xFF) < 0xC2) {
1913 return false;
1914 }
1915 } else if ((b1 & 0xF0) == 0xE0) {
1916
1917
1918
1919
1920
1921
1922
1923
1924 if (index > endIndex - 2) {
1925 return false;
1926 }
1927 b2 = buf.getByte(index++);
1928 b3 = buf.getByte(index++);
1929 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
1930 return false;
1931 }
1932 if ((b1 & 0x0F) == 0x00 && (b2 & 0xFF) < 0xA0) {
1933 return false;
1934 }
1935 if ((b1 & 0x0F) == 0x0D && (b2 & 0xFF) > 0x9F) {
1936 return false;
1937 }
1938 } else if ((b1 & 0xF8) == 0xF0) {
1939
1940
1941
1942
1943
1944
1945
1946 if (index > endIndex - 3) {
1947 return false;
1948 }
1949 b2 = buf.getByte(index++);
1950 b3 = buf.getByte(index++);
1951 b4 = buf.getByte(index++);
1952 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80) {
1953
1954 return false;
1955 }
1956 if ((b1 & 0xFF) > 0xF4
1957 || (b1 & 0xFF) == 0xF0 && (b2 & 0xFF) < 0x90
1958 || (b1 & 0xFF) == 0xF4 && (b2 & 0xFF) > 0x8F) {
1959 return false;
1960 }
1961 } else {
1962 return false;
1963 }
1964 }
1965 return true;
1966 }
1967
1968
1969
1970
1971
1972 static void readBytes(ByteBufAllocator allocator, ByteBuffer buffer, int position, int length, OutputStream out)
1973 throws IOException {
1974 if (buffer.hasArray()) {
1975 out.write(buffer.array(), position + buffer.arrayOffset(), length);
1976 } else {
1977 int chunkLen = Math.min(length, WRITE_CHUNK_SIZE);
1978 buffer.clear().position(position).limit(position + length);
1979
1980 if (length <= MAX_TL_ARRAY_LEN || !allocator.isDirectBufferPooled()) {
1981 getBytes(buffer, threadLocalTempArray(chunkLen), 0, chunkLen, out, length);
1982 } else {
1983
1984 ByteBuf tmpBuf = allocator.heapBuffer(chunkLen);
1985 try {
1986 byte[] tmp = tmpBuf.array();
1987 int offset = tmpBuf.arrayOffset();
1988 getBytes(buffer, tmp, offset, chunkLen, out, length);
1989 } finally {
1990 tmpBuf.release();
1991 }
1992 }
1993 }
1994 }
1995
1996 private static void getBytes(ByteBuffer inBuffer, byte[] in, int inOffset, int inLen, OutputStream out, int outLen)
1997 throws IOException {
1998 do {
1999 int len = Math.min(inLen, outLen);
2000 inBuffer.get(in, inOffset, len);
2001 out.write(in, inOffset, len);
2002 outLen -= len;
2003 } while (outLen > 0);
2004 }
2005
2006
2007
2008
2009
2010
2011 public static void setLeakListener(ResourceLeakDetector.LeakListener leakListener) {
2012 AbstractByteBuf.leakDetector.setLeakListener(leakListener);
2013 }
2014
2015 private ByteBufUtil() { }
2016 }