1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.buffer;
17
18 import io.netty.util.AsciiString;
19 import io.netty.util.ByteProcessor;
20 import io.netty.util.CharsetUtil;
21 import io.netty.util.IllegalReferenceCountException;
22 import io.netty.util.Recycler.EnhancedHandle;
23 import io.netty.util.ResourceLeakDetector;
24 import io.netty.util.concurrent.FastThreadLocal;
25 import io.netty.util.concurrent.FastThreadLocalThread;
26 import io.netty.util.internal.MathUtil;
27 import io.netty.util.internal.ObjectPool;
28 import io.netty.util.internal.ObjectPool.Handle;
29 import io.netty.util.internal.ObjectPool.ObjectCreator;
30 import io.netty.util.internal.PlatformDependent;
31 import io.netty.util.internal.SWARUtil;
32 import io.netty.util.internal.StringUtil;
33 import io.netty.util.internal.SystemPropertyUtil;
34 import io.netty.util.internal.logging.InternalLogger;
35 import io.netty.util.internal.logging.InternalLoggerFactory;
36
37 import java.io.IOException;
38 import java.io.OutputStream;
39 import java.nio.ByteBuffer;
40 import java.nio.ByteOrder;
41 import java.nio.CharBuffer;
42 import java.nio.charset.CharacterCodingException;
43 import java.nio.charset.Charset;
44 import java.nio.charset.CharsetDecoder;
45 import java.nio.charset.CharsetEncoder;
46 import java.nio.charset.CoderResult;
47 import java.nio.charset.CodingErrorAction;
48 import java.util.Arrays;
49
50 import static io.netty.util.internal.MathUtil.isOutOfBounds;
51 import static io.netty.util.internal.ObjectUtil.checkNotNull;
52 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
53 import static io.netty.util.internal.StringUtil.NEWLINE;
54 import static io.netty.util.internal.StringUtil.isSurrogate;
55
56
57
58
59
60 public final class ByteBufUtil {
61
62 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ByteBufUtil.class);
63 private static final FastThreadLocal<byte[]> BYTE_ARRAYS = new FastThreadLocal<byte[]>() {
64 @Override
65 protected byte[] initialValue() throws Exception {
66 return PlatformDependent.allocateUninitializedArray(MAX_TL_ARRAY_LEN);
67 }
68 };
69
70 private static final byte WRITE_UTF_UNKNOWN = (byte) '?';
71 private static final int MAX_CHAR_BUFFER_SIZE;
72 private static final int THREAD_LOCAL_BUFFER_SIZE;
73 private static final int MAX_BYTES_PER_CHAR_UTF8 =
74 (int) CharsetUtil.encoder(CharsetUtil.UTF_8).maxBytesPerChar();
75
76 static final int WRITE_CHUNK_SIZE = 8192;
77 static final ByteBufAllocator DEFAULT_ALLOCATOR;
78
79 static {
80 String allocType = SystemPropertyUtil.get(
81 "io.netty.allocator.type", "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 && Thread.currentThread() instanceof FastThreadLocalThread) {
117 return BYTE_ARRAYS.get();
118 }
119 return PlatformDependent.allocateUninitializedArray(minLength);
120 }
121
122
123
124
125 public static boolean isAccessible(ByteBuf buffer) {
126 return buffer.isAccessible();
127 }
128
129
130
131
132
133 public static ByteBuf ensureAccessible(ByteBuf buffer) {
134 if (!buffer.isAccessible()) {
135 throw new IllegalReferenceCountException(buffer.refCnt());
136 }
137 return buffer;
138 }
139
140
141
142
143
144 public static String hexDump(ByteBuf buffer) {
145 return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
146 }
147
148
149
150
151
152 public static String hexDump(ByteBuf buffer, int fromIndex, int length) {
153 return HexUtil.hexDump(buffer, fromIndex, length);
154 }
155
156
157
158
159
160 public static String hexDump(byte[] array) {
161 return hexDump(array, 0, array.length);
162 }
163
164
165
166
167
168 public static String hexDump(byte[] array, int fromIndex, int length) {
169 return HexUtil.hexDump(array, fromIndex, length);
170 }
171
172
173
174
175 public static byte decodeHexByte(CharSequence s, int pos) {
176 return StringUtil.decodeHexByte(s, pos);
177 }
178
179
180
181
182 public static byte[] decodeHexDump(CharSequence hexDump) {
183 return StringUtil.decodeHexDump(hexDump, 0, hexDump.length());
184 }
185
186
187
188
189 public static byte[] decodeHexDump(CharSequence hexDump, int fromIndex, int length) {
190 return StringUtil.decodeHexDump(hexDump, fromIndex, length);
191 }
192
193
194
195
196
197
198
199
200 public static boolean ensureWritableSuccess(int ensureWritableResult) {
201 return ensureWritableResult == 0 || ensureWritableResult == 2;
202 }
203
204
205
206
207
208 public static int hashCode(ByteBuf buffer) {
209 final int aLen = buffer.readableBytes();
210 final int intCount = aLen >>> 2;
211 final int byteCount = aLen & 3;
212
213 int hashCode = EmptyByteBuf.EMPTY_BYTE_BUF_HASH_CODE;
214 int arrayIndex = buffer.readerIndex();
215 if (buffer.order() == ByteOrder.BIG_ENDIAN) {
216 for (int i = intCount; i > 0; i --) {
217 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
218 arrayIndex += 4;
219 }
220 } else {
221 for (int i = intCount; i > 0; i --) {
222 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
223 arrayIndex += 4;
224 }
225 }
226
227 for (int i = byteCount; i > 0; i --) {
228 hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
229 }
230
231 if (hashCode == 0) {
232 hashCode = 1;
233 }
234
235 return hashCode;
236 }
237
238
239
240
241
242
243 public static int indexOf(ByteBuf needle, ByteBuf haystack) {
244 if (haystack == null || needle == null) {
245 return -1;
246 }
247
248 if (needle.readableBytes() > haystack.readableBytes()) {
249 return -1;
250 }
251
252 int n = haystack.readableBytes();
253 int m = needle.readableBytes();
254 if (m == 0) {
255 return 0;
256 }
257
258
259
260 if (m == 1) {
261 return haystack.indexOf(haystack.readerIndex(), haystack.writerIndex(),
262 needle.getByte(needle.readerIndex()));
263 }
264
265 int i;
266 int j = 0;
267 int aStartIndex = needle.readerIndex();
268 int bStartIndex = haystack.readerIndex();
269 long suffixes = maxSuf(needle, m, aStartIndex, true);
270 long prefixes = maxSuf(needle, m, aStartIndex, false);
271 int ell = Math.max((int) (suffixes >> 32), (int) (prefixes >> 32));
272 int per = Math.max((int) suffixes, (int) prefixes);
273 int memory;
274 int length = Math.min(m - per, ell + 1);
275
276 if (equals(needle, aStartIndex, needle, aStartIndex + per, length)) {
277 memory = -1;
278 while (j <= n - m) {
279 i = Math.max(ell, memory) + 1;
280 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
281 ++i;
282 }
283 if (i > n) {
284 return -1;
285 }
286 if (i >= m) {
287 i = ell;
288 while (i > memory && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
289 --i;
290 }
291 if (i <= memory) {
292 return j + bStartIndex;
293 }
294 j += per;
295 memory = m - per - 1;
296 } else {
297 j += i - ell;
298 memory = -1;
299 }
300 }
301 } else {
302 per = Math.max(ell + 1, m - ell - 1) + 1;
303 while (j <= n - m) {
304 i = ell + 1;
305 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
306 ++i;
307 }
308 if (i > n) {
309 return -1;
310 }
311 if (i >= m) {
312 i = ell;
313 while (i >= 0 && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
314 --i;
315 }
316 if (i < 0) {
317 return j + bStartIndex;
318 }
319 j += per;
320 } else {
321 j += i - ell;
322 }
323 }
324 }
325 return -1;
326 }
327
328 private static long maxSuf(ByteBuf x, int m, int start, boolean isSuffix) {
329 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 (!PlatformDependent.isUnaligned()) {
581 return linearFirstIndexOf(buffer, fromIndex, toIndex, value);
582 }
583 assert PlatformDependent.isUnaligned();
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 (!PlatformDependent.isUnaligned()) {
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()) {
928 assert 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 * 4];
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 ObjectPool<ThreadLocalUnsafeDirectByteBuf> RECYCLER =
1707 ObjectPool.newPool(new ObjectCreator<ThreadLocalUnsafeDirectByteBuf>() {
1708 @Override
1709 public 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 ObjectPool<ThreadLocalDirectByteBuf> RECYCLER = ObjectPool.newPool(
1741 new ObjectCreator<ThreadLocalDirectByteBuf>() {
1742 @Override
1743 public ThreadLocalDirectByteBuf newObject(Handle<ThreadLocalDirectByteBuf> handle) {
1744 return new ThreadLocalDirectByteBuf(handle);
1745 }
1746 });
1747
1748 static ThreadLocalDirectByteBuf newInstance() {
1749 ThreadLocalDirectByteBuf buf = RECYCLER.get();
1750 buf.resetRefCnt();
1751 return buf;
1752 }
1753
1754 private final EnhancedHandle<ThreadLocalDirectByteBuf> handle;
1755
1756 private ThreadLocalDirectByteBuf(Handle<ThreadLocalDirectByteBuf> handle) {
1757 super(UnpooledByteBufAllocator.DEFAULT, 256, Integer.MAX_VALUE);
1758 this.handle = (EnhancedHandle<ThreadLocalDirectByteBuf>) handle;
1759 }
1760
1761 @Override
1762 protected void deallocate() {
1763 if (capacity() > THREAD_LOCAL_BUFFER_SIZE) {
1764 super.deallocate();
1765 } else {
1766 clear();
1767 handle.unguardedRecycle(this);
1768 }
1769 }
1770 }
1771
1772
1773
1774
1775
1776
1777
1778
1779 public static boolean isText(ByteBuf buf, Charset charset) {
1780 return isText(buf, buf.readerIndex(), buf.readableBytes(), charset);
1781 }
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794 public static boolean isText(ByteBuf buf, int index, int length, Charset charset) {
1795 checkNotNull(buf, "buf");
1796 checkNotNull(charset, "charset");
1797 final int maxIndex = buf.readerIndex() + buf.readableBytes();
1798 if (index < 0 || length < 0 || index > maxIndex - length) {
1799 throw new IndexOutOfBoundsException("index: " + index + " length: " + length);
1800 }
1801 if (charset.equals(CharsetUtil.UTF_8)) {
1802 return isUtf8(buf, index, length);
1803 } else if (charset.equals(CharsetUtil.US_ASCII)) {
1804 return isAscii(buf, index, length);
1805 } else {
1806 CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
1807 try {
1808 if (buf.nioBufferCount() == 1) {
1809 decoder.decode(buf.nioBuffer(index, length));
1810 } else {
1811 ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
1812 try {
1813 heapBuffer.writeBytes(buf, index, length);
1814 decoder.decode(heapBuffer.internalNioBuffer(heapBuffer.readerIndex(), length));
1815 } finally {
1816 heapBuffer.release();
1817 }
1818 }
1819 return true;
1820 } catch (CharacterCodingException ignore) {
1821 return false;
1822 }
1823 }
1824 }
1825
1826
1827
1828
1829 private static final ByteProcessor FIND_NON_ASCII = new ByteProcessor() {
1830 @Override
1831 public boolean process(byte value) {
1832 return value >= 0;
1833 }
1834 };
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844 private static boolean isAscii(ByteBuf buf, int index, int length) {
1845 return buf.forEachByte(index, length, FIND_NON_ASCII) == -1;
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
1891 private static boolean isUtf8(ByteBuf buf, int index, int length) {
1892 final int endIndex = index + length;
1893 while (index < endIndex) {
1894 byte b1 = buf.getByte(index++);
1895 byte b2, b3, b4;
1896 if ((b1 & 0x80) == 0) {
1897
1898 continue;
1899 }
1900 if ((b1 & 0xE0) == 0xC0) {
1901
1902
1903
1904
1905
1906 if (index >= endIndex) {
1907 return false;
1908 }
1909 b2 = buf.getByte(index++);
1910 if ((b2 & 0xC0) != 0x80) {
1911 return false;
1912 }
1913 if ((b1 & 0xFF) < 0xC2) {
1914 return false;
1915 }
1916 } else if ((b1 & 0xF0) == 0xE0) {
1917
1918
1919
1920
1921
1922
1923
1924
1925 if (index > endIndex - 2) {
1926 return false;
1927 }
1928 b2 = buf.getByte(index++);
1929 b3 = buf.getByte(index++);
1930 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
1931 return false;
1932 }
1933 if ((b1 & 0x0F) == 0x00 && (b2 & 0xFF) < 0xA0) {
1934 return false;
1935 }
1936 if ((b1 & 0x0F) == 0x0D && (b2 & 0xFF) > 0x9F) {
1937 return false;
1938 }
1939 } else if ((b1 & 0xF8) == 0xF0) {
1940
1941
1942
1943
1944
1945
1946
1947 if (index > endIndex - 3) {
1948 return false;
1949 }
1950 b2 = buf.getByte(index++);
1951 b3 = buf.getByte(index++);
1952 b4 = buf.getByte(index++);
1953 if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80) {
1954
1955 return false;
1956 }
1957 if ((b1 & 0xFF) > 0xF4
1958 || (b1 & 0xFF) == 0xF0 && (b2 & 0xFF) < 0x90
1959 || (b1 & 0xFF) == 0xF4 && (b2 & 0xFF) > 0x8F) {
1960 return false;
1961 }
1962 } else {
1963 return false;
1964 }
1965 }
1966 return true;
1967 }
1968
1969
1970
1971
1972
1973 static void readBytes(ByteBufAllocator allocator, ByteBuffer buffer, int position, int length, OutputStream out)
1974 throws IOException {
1975 if (buffer.hasArray()) {
1976 out.write(buffer.array(), position + buffer.arrayOffset(), length);
1977 } else {
1978 int chunkLen = Math.min(length, WRITE_CHUNK_SIZE);
1979 buffer.clear().position(position);
1980
1981 if (length <= MAX_TL_ARRAY_LEN || !allocator.isDirectBufferPooled()) {
1982 getBytes(buffer, threadLocalTempArray(chunkLen), 0, chunkLen, out, length);
1983 } else {
1984
1985 ByteBuf tmpBuf = allocator.heapBuffer(chunkLen);
1986 try {
1987 byte[] tmp = tmpBuf.array();
1988 int offset = tmpBuf.arrayOffset();
1989 getBytes(buffer, tmp, offset, chunkLen, out, length);
1990 } finally {
1991 tmpBuf.release();
1992 }
1993 }
1994 }
1995 }
1996
1997 private static void getBytes(ByteBuffer inBuffer, byte[] in, int inOffset, int inLen, OutputStream out, int outLen)
1998 throws IOException {
1999 do {
2000 int len = Math.min(inLen, outLen);
2001 inBuffer.get(in, inOffset, len);
2002 out.write(in, inOffset, len);
2003 outLen -= len;
2004 } while (outLen > 0);
2005 }
2006
2007
2008
2009
2010
2011
2012 public static void setLeakListener(ResourceLeakDetector.LeakListener leakListener) {
2013 AbstractByteBuf.leakDetector.setLeakListener(leakListener);
2014 }
2015
2016 private ByteBufUtil() { }
2017 }