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