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
78 static {
79 String allocType = SystemPropertyUtil.get(
80 "io.netty.allocator.type", "adaptive");
81
82 ByteBufAllocator alloc;
83 if ("unpooled".equals(allocType)) {
84 alloc = UnpooledByteBufAllocator.DEFAULT;
85 logger.debug("-Dio.netty.allocator.type: {}", allocType);
86 } else if ("pooled".equals(allocType)) {
87 alloc = PooledByteBufAllocator.DEFAULT;
88 logger.debug("-Dio.netty.allocator.type: {}", allocType);
89 } else if ("adaptive".equals(allocType)) {
90 alloc = new AdaptiveByteBufAllocator();
91 logger.debug("-Dio.netty.allocator.type: {}", allocType);
92 } else {
93 alloc = PooledByteBufAllocator.DEFAULT;
94 logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
95 }
96
97 DEFAULT_ALLOCATOR = alloc;
98
99 THREAD_LOCAL_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalDirectBufferSize", 0);
100 logger.debug("-Dio.netty.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE);
101
102 MAX_CHAR_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.maxThreadLocalCharBufferSize", 16 * 1024);
103 logger.debug("-Dio.netty.maxThreadLocalCharBufferSize: {}", MAX_CHAR_BUFFER_SIZE);
104 }
105
106 static final int MAX_TL_ARRAY_LEN = 1024;
107
108
109
110
111 static byte[] threadLocalTempArray(int minLength) {
112
113
114
115 if (minLength <= MAX_TL_ARRAY_LEN && FastThreadLocalThread.currentThreadHasFastThreadLocal()) {
116 return BYTE_ARRAYS.get();
117 }
118 return PlatformDependent.allocateUninitializedArray(minLength);
119 }
120
121
122
123
124 public static boolean isAccessible(ByteBuf buffer) {
125 return buffer.isAccessible();
126 }
127
128
129
130
131
132 public static ByteBuf ensureAccessible(ByteBuf buffer) {
133 if (!buffer.isAccessible()) {
134 throw new IllegalReferenceCountException(buffer.refCnt());
135 }
136 return buffer;
137 }
138
139
140
141
142
143 public static String hexDump(ByteBuf buffer) {
144 return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
145 }
146
147
148
149
150
151 public static String hexDump(ByteBuf buffer, int fromIndex, int length) {
152 return HexUtil.hexDump(buffer, fromIndex, length);
153 }
154
155
156
157
158
159 public static String hexDump(byte[] array) {
160 return hexDump(array, 0, array.length);
161 }
162
163
164
165
166
167 public static String hexDump(byte[] array, int fromIndex, int length) {
168 return HexUtil.hexDump(array, fromIndex, length);
169 }
170
171
172
173
174 public static byte decodeHexByte(CharSequence s, int pos) {
175 return StringUtil.decodeHexByte(s, pos);
176 }
177
178
179
180
181 public static byte[] decodeHexDump(CharSequence hexDump) {
182 return StringUtil.decodeHexDump(hexDump, 0, hexDump.length());
183 }
184
185
186
187
188 public static byte[] decodeHexDump(CharSequence hexDump, int fromIndex, int length) {
189 return StringUtil.decodeHexDump(hexDump, fromIndex, length);
190 }
191
192
193
194
195
196
197
198
199 public static boolean ensureWritableSuccess(int ensureWritableResult) {
200 return ensureWritableResult == 0 || ensureWritableResult == 2;
201 }
202
203
204
205
206
207 public static int hashCode(ByteBuf buffer) {
208 final int aLen = buffer.readableBytes();
209 final int intCount = aLen >>> 2;
210 final int byteCount = aLen & 3;
211
212 int hashCode = EmptyByteBuf.EMPTY_BYTE_BUF_HASH_CODE;
213 int arrayIndex = buffer.readerIndex();
214 if (buffer.order() == ByteOrder.BIG_ENDIAN) {
215 for (int i = intCount; i > 0; i --) {
216 hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
217 arrayIndex += 4;
218 }
219 } else {
220 for (int i = intCount; i > 0; i --) {
221 hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
222 arrayIndex += 4;
223 }
224 }
225
226 for (int i = byteCount; i > 0; i --) {
227 hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
228 }
229
230 if (hashCode == 0) {
231 hashCode = 1;
232 }
233
234 return hashCode;
235 }
236
237
238
239
240
241
242 public static int indexOf(ByteBuf needle, ByteBuf haystack) {
243 if (haystack == null || needle == null) {
244 return -1;
245 }
246
247 if (needle.readableBytes() > haystack.readableBytes()) {
248 return -1;
249 }
250
251 int n = haystack.readableBytes();
252 int m = needle.readableBytes();
253 if (m == 0) {
254 return 0;
255 }
256
257
258
259 if (m == 1) {
260 return haystack.indexOf(haystack.readerIndex(), haystack.writerIndex(),
261 needle.getByte(needle.readerIndex()));
262 }
263
264 int i;
265 int j = 0;
266 int aStartIndex = needle.readerIndex();
267 int bStartIndex = haystack.readerIndex();
268 long suffixes = maxSuf(needle, m, aStartIndex, true);
269 long prefixes = maxSuf(needle, m, aStartIndex, false);
270 int ell = Math.max((int) (suffixes >> 32), (int) (prefixes >> 32));
271 int per = Math.max((int) suffixes, (int) prefixes);
272 int memory;
273 int length = Math.min(m - per, ell + 1);
274
275 if (equals(needle, aStartIndex, needle, aStartIndex + per, length)) {
276 memory = -1;
277 while (j <= n - m) {
278 i = Math.max(ell, memory) + 1;
279 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
280 ++i;
281 }
282 if (i > n) {
283 return -1;
284 }
285 if (i >= m) {
286 i = ell;
287 while (i > memory && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
288 --i;
289 }
290 if (i <= memory) {
291 return j + bStartIndex;
292 }
293 j += per;
294 memory = m - per - 1;
295 } else {
296 j += i - ell;
297 memory = -1;
298 }
299 }
300 } else {
301 per = Math.max(ell + 1, m - ell - 1) + 1;
302 while (j <= n - m) {
303 i = ell + 1;
304 while (i < m && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
305 ++i;
306 }
307 if (i > n) {
308 return -1;
309 }
310 if (i >= m) {
311 i = ell;
312 while (i >= 0 && needle.getByte(i + aStartIndex) == haystack.getByte(i + j + bStartIndex)) {
313 --i;
314 }
315 if (i < 0) {
316 return j + bStartIndex;
317 }
318 j += per;
319 } else {
320 j += i - ell;
321 }
322 }
323 }
324 return -1;
325 }
326
327 private static long maxSuf(ByteBuf x, int m, int start, boolean isSuffix) {
328 int p = 1;
329 int ms = -1;
330 int j = start;
331 int k = 1;
332 byte a;
333 byte b;
334 while (j + k < m) {
335 a = x.getByte(j + k);
336 b = x.getByte(ms + k);
337 boolean suffix = isSuffix ? a < b : a > b;
338 if (suffix) {
339 j += k;
340 k = 1;
341 p = j - ms;
342 } else if (a == b) {
343 if (k != p) {
344 ++k;
345 } else {
346 j += p;
347 k = 1;
348 }
349 } else {
350 ms = j;
351 j = ms + 1;
352 k = p = 1;
353 }
354 }
355 return ((long) ms << 32) + p;
356 }
357
358
359
360
361
362
363
364
365
366 public static boolean equals(ByteBuf a, int aStartIndex, ByteBuf b, int bStartIndex, int length) {
367 checkNotNull(a, "a");
368 checkNotNull(b, "b");
369
370 checkPositiveOrZero(aStartIndex, "aStartIndex");
371 checkPositiveOrZero(bStartIndex, "bStartIndex");
372 checkPositiveOrZero(length, "length");
373
374 if (a.writerIndex() - length < aStartIndex || b.writerIndex() - length < bStartIndex) {
375 return false;
376 }
377
378 final int longCount = length >>> 3;
379 final int byteCount = length & 7;
380
381 if (a.order() == b.order()) {
382 for (int i = longCount; i > 0; i --) {
383 if (a.getLong(aStartIndex) != b.getLong(bStartIndex)) {
384 return false;
385 }
386 aStartIndex += 8;
387 bStartIndex += 8;
388 }
389 } else {
390 for (int i = longCount; i > 0; i --) {
391 if (a.getLong(aStartIndex) != swapLong(b.getLong(bStartIndex))) {
392 return false;
393 }
394 aStartIndex += 8;
395 bStartIndex += 8;
396 }
397 }
398
399 for (int i = byteCount; i > 0; i --) {
400 if (a.getByte(aStartIndex) != b.getByte(bStartIndex)) {
401 return false;
402 }
403 aStartIndex ++;
404 bStartIndex ++;
405 }
406
407 return true;
408 }
409
410
411
412
413
414
415 public static boolean equals(ByteBuf bufferA, ByteBuf bufferB) {
416 if (bufferA == bufferB) {
417 return true;
418 }
419 final int aLen = bufferA.readableBytes();
420 if (aLen != bufferB.readableBytes()) {
421 return false;
422 }
423 return equals(bufferA, bufferA.readerIndex(), bufferB, bufferB.readerIndex(), aLen);
424 }
425
426
427
428
429
430 public static int compare(ByteBuf bufferA, ByteBuf bufferB) {
431 if (bufferA == bufferB) {
432 return 0;
433 }
434 final int aLen = bufferA.readableBytes();
435 final int bLen = bufferB.readableBytes();
436 final int minLength = Math.min(aLen, bLen);
437 final int uintCount = minLength >>> 2;
438 final int byteCount = minLength & 3;
439 int aIndex = bufferA.readerIndex();
440 int bIndex = bufferB.readerIndex();
441
442 if (uintCount > 0) {
443 boolean bufferAIsBigEndian = bufferA.order() == ByteOrder.BIG_ENDIAN;
444 final long res;
445 int uintCountIncrement = uintCount << 2;
446
447 if (bufferA.order() == bufferB.order()) {
448 res = bufferAIsBigEndian ? compareUintBigEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
449 compareUintLittleEndian(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
450 } else {
451 res = bufferAIsBigEndian ? compareUintBigEndianA(bufferA, bufferB, aIndex, bIndex, uintCountIncrement) :
452 compareUintBigEndianB(bufferA, bufferB, aIndex, bIndex, uintCountIncrement);
453 }
454 if (res != 0) {
455
456 return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, res));
457 }
458 aIndex += uintCountIncrement;
459 bIndex += uintCountIncrement;
460 }
461
462 for (int aEnd = aIndex + byteCount; aIndex < aEnd; ++aIndex, ++bIndex) {
463 int comp = bufferA.getUnsignedByte(aIndex) - bufferB.getUnsignedByte(bIndex);
464 if (comp != 0) {
465 return comp;
466 }
467 }
468
469 return aLen - bLen;
470 }
471
472 private static long compareUintBigEndian(
473 ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
474 for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
475 long comp = bufferA.getUnsignedInt(aIndex) - bufferB.getUnsignedInt(bIndex);
476 if (comp != 0) {
477 return comp;
478 }
479 }
480 return 0;
481 }
482
483 private static long compareUintLittleEndian(
484 ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
485 for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
486 long comp = uintFromLE(bufferA.getUnsignedIntLE(aIndex)) - uintFromLE(bufferB.getUnsignedIntLE(bIndex));
487 if (comp != 0) {
488 return comp;
489 }
490 }
491 return 0;
492 }
493
494 private static long compareUintBigEndianA(
495 ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
496 for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
497 long a = bufferA.getUnsignedInt(aIndex);
498 long b = uintFromLE(bufferB.getUnsignedIntLE(bIndex));
499 long comp = a - b;
500 if (comp != 0) {
501 return comp;
502 }
503 }
504 return 0;
505 }
506
507 private static long compareUintBigEndianB(
508 ByteBuf bufferA, ByteBuf bufferB, int aIndex, int bIndex, int uintCountIncrement) {
509 for (int aEnd = aIndex + uintCountIncrement; aIndex < aEnd; aIndex += 4, bIndex += 4) {
510 long a = uintFromLE(bufferA.getUnsignedIntLE(aIndex));
511 long b = bufferB.getUnsignedInt(bIndex);
512 long comp = a - b;
513 if (comp != 0) {
514 return comp;
515 }
516 }
517 return 0;
518 }
519
520 private static long uintFromLE(long value) {
521 return Long.reverseBytes(value) >>> Integer.SIZE;
522 }
523
524 private static int unrolledFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int byteCount, byte value) {
525 assert byteCount > 0 && byteCount < 8;
526 if (buffer._getByte(fromIndex) == value) {
527 return fromIndex;
528 }
529 if (byteCount == 1) {
530 return -1;
531 }
532 if (buffer._getByte(fromIndex + 1) == value) {
533 return fromIndex + 1;
534 }
535 if (byteCount == 2) {
536 return -1;
537 }
538 if (buffer._getByte(fromIndex + 2) == value) {
539 return fromIndex + 2;
540 }
541 if (byteCount == 3) {
542 return -1;
543 }
544 if (buffer._getByte(fromIndex + 3) == value) {
545 return fromIndex + 3;
546 }
547 if (byteCount == 4) {
548 return -1;
549 }
550 if (buffer._getByte(fromIndex + 4) == value) {
551 return fromIndex + 4;
552 }
553 if (byteCount == 5) {
554 return -1;
555 }
556 if (buffer._getByte(fromIndex + 5) == value) {
557 return fromIndex + 5;
558 }
559 if (byteCount == 6) {
560 return -1;
561 }
562 if (buffer._getByte(fromIndex + 6) == value) {
563 return fromIndex + 6;
564 }
565 return -1;
566 }
567
568
569
570
571
572 static int firstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
573 fromIndex = Math.max(fromIndex, 0);
574 if (fromIndex >= toIndex || buffer.capacity() == 0) {
575 return -1;
576 }
577 final int length = toIndex - fromIndex;
578 buffer.checkIndex(fromIndex, length);
579 if (!PlatformDependent.isUnaligned()) {
580 return linearFirstIndexOf(buffer, fromIndex, toIndex, value);
581 }
582 assert PlatformDependent.isUnaligned();
583 int offset = fromIndex;
584 final int byteCount = length & 7;
585 if (byteCount > 0) {
586 final int index = unrolledFirstIndexOf(buffer, fromIndex, byteCount, value);
587 if (index != -1) {
588 return index;
589 }
590 offset += byteCount;
591 if (offset == toIndex) {
592 return -1;
593 }
594 }
595 final int longCount = length >>> 3;
596 final ByteOrder nativeOrder = ByteOrder.nativeOrder();
597 final boolean isNative = nativeOrder == buffer.order();
598 final boolean useLE = nativeOrder == ByteOrder.LITTLE_ENDIAN;
599 final long pattern = SWARUtil.compilePattern(value);
600 for (int i = 0; i < longCount; i++) {
601
602 final long word = useLE? buffer._getLongLE(offset) : buffer._getLong(offset);
603 final long result = SWARUtil.applyPattern(word, pattern);
604 if (result != 0) {
605 return offset + SWARUtil.getIndex(result, isNative);
606 }
607 offset += Long.BYTES;
608 }
609 return -1;
610 }
611
612 private static int linearFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte value) {
613 for (int i = fromIndex; i < toIndex; i++) {
614 if (buffer._getByte(i) == value) {
615 return i;
616 }
617 }
618 return -1;
619 }
620
621
622
623
624
625 public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value) {
626 return buffer.indexOf(fromIndex, toIndex, value);
627 }
628
629
630
631
632 public static short swapShort(short value) {
633 return Short.reverseBytes(value);
634 }
635
636
637
638
639 public static int swapMedium(int value) {
640 int swapped = value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff;
641 if ((swapped & 0x800000) != 0) {
642 swapped |= 0xff000000;
643 }
644 return swapped;
645 }
646
647
648
649
650 public static int swapInt(int value) {
651 return Integer.reverseBytes(value);
652 }
653
654
655
656
657 public static long swapLong(long value) {
658 return Long.reverseBytes(value);
659 }
660
661
662
663
664 @SuppressWarnings("deprecation")
665 public static ByteBuf writeShortBE(ByteBuf buf, int shortValue) {
666 return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeShort(shortValue) :
667 buf.writeShort(swapShort((short) shortValue));
668 }
669
670
671
672
673 @SuppressWarnings("deprecation")
674 public static ByteBuf setShortBE(ByteBuf buf, int index, int shortValue) {
675 return buf.order() == ByteOrder.BIG_ENDIAN? buf.setShort(index, shortValue) :
676 buf.setShort(index, swapShort((short) shortValue));
677 }
678
679
680
681
682 @SuppressWarnings("deprecation")
683 public static ByteBuf writeMediumBE(ByteBuf buf, int mediumValue) {
684 return buf.order() == ByteOrder.BIG_ENDIAN? buf.writeMedium(mediumValue) :
685 buf.writeMedium(swapMedium(mediumValue));
686 }
687
688
689
690
691 @SuppressWarnings("deprecation")
692 public static int readUnsignedShortBE(ByteBuf buf) {
693 return buf.order() == ByteOrder.BIG_ENDIAN? buf.readUnsignedShort() :
694 swapShort((short) buf.readUnsignedShort()) & 0xFFFF;
695 }
696
697
698
699
700 @SuppressWarnings("deprecation")
701 public static int readIntBE(ByteBuf buf) {
702 return buf.order() == ByteOrder.BIG_ENDIAN? buf.readInt() :
703 swapInt(buf.readInt());
704 }
705
706
707
708
709 public static ByteBuf readBytes(ByteBufAllocator alloc, ByteBuf buffer, int length) {
710 boolean release = true;
711 ByteBuf dst = alloc.buffer(length);
712 try {
713 buffer.readBytes(dst);
714 release = false;
715 return dst;
716 } finally {
717 if (release) {
718 dst.release();
719 }
720 }
721 }
722
723 static int lastIndexOf(final AbstractByteBuf buffer, int fromIndex, final int toIndex, final byte value) {
724 assert fromIndex > toIndex;
725 final int capacity = buffer.capacity();
726 fromIndex = Math.min(fromIndex, capacity);
727 if (fromIndex <= 0) {
728 return -1;
729 }
730 final int length = fromIndex - toIndex;
731 buffer.checkIndex(toIndex, length);
732 if (!PlatformDependent.isUnaligned()) {
733 return linearLastIndexOf(buffer, fromIndex, toIndex, value);
734 }
735 final int longCount = length >>> 3;
736 if (longCount > 0) {
737 final ByteOrder nativeOrder = ByteOrder.nativeOrder();
738 final boolean isNative = nativeOrder == buffer.order();
739 final boolean useLE = nativeOrder == ByteOrder.LITTLE_ENDIAN;
740 final long pattern = SWARUtil.compilePattern(value);
741 for (int i = 0, offset = fromIndex - Long.BYTES; i < longCount; i++, offset -= Long.BYTES) {
742
743 final long word = useLE? buffer._getLongLE(offset) : buffer._getLong(offset);
744 final long result = SWARUtil.applyPattern(word, pattern);
745 if (result != 0) {
746
747 return offset + Long.BYTES - 1 - SWARUtil.getIndex(result, !isNative);
748 }
749 }
750 }
751 return unrolledLastIndexOf(buffer, fromIndex - (longCount << 3), length & 7, value);
752 }
753
754 private static int linearLastIndexOf(final AbstractByteBuf buffer, final int fromIndex, final int toIndex,
755 final byte value) {
756 for (int i = fromIndex - 1; i >= toIndex; i--) {
757 if (buffer._getByte(i) == value) {
758 return i;
759 }
760 }
761 return -1;
762 }
763
764 private static int unrolledLastIndexOf(final AbstractByteBuf buffer, final int fromIndex, final int byteCount,
765 final byte value) {
766 assert byteCount >= 0 && byteCount < 8;
767 if (byteCount == 0) {
768 return -1;
769 }
770 if (buffer._getByte(fromIndex - 1) == value) {
771 return fromIndex - 1;
772 }
773 if (byteCount == 1) {
774 return -1;
775 }
776 if (buffer._getByte(fromIndex - 2) == value) {
777 return fromIndex - 2;
778 }
779 if (byteCount == 2) {
780 return -1;
781 }
782 if (buffer._getByte(fromIndex - 3) == value) {
783 return fromIndex - 3;
784 }
785 if (byteCount == 3) {
786 return -1;
787 }
788 if (buffer._getByte(fromIndex - 4) == value) {
789 return fromIndex - 4;
790 }
791 if (byteCount == 4) {
792 return -1;
793 }
794 if (buffer._getByte(fromIndex - 5) == value) {
795 return fromIndex - 5;
796 }
797 if (byteCount == 5) {
798 return -1;
799 }
800 if (buffer._getByte(fromIndex - 6) == value) {
801 return fromIndex - 6;
802 }
803 if (byteCount == 6) {
804 return -1;
805 }
806 if (buffer._getByte(fromIndex - 7) == value) {
807 return fromIndex - 7;
808 }
809 return -1;
810 }
811
812 private static CharSequence checkCharSequenceBounds(CharSequence seq, int start, int end) {
813 if (MathUtil.isOutOfBounds(start, end - start, seq.length())) {
814 throw new IndexOutOfBoundsException("expected: 0 <= start(" + start + ") <= end (" + end
815 + ") <= seq.length(" + seq.length() + ')');
816 }
817 return seq;
818 }
819
820
821
822
823
824
825
826
827
828 public static ByteBuf writeUtf8(ByteBufAllocator alloc, CharSequence seq) {
829
830 ByteBuf buf = alloc.buffer(utf8MaxBytes(seq));
831 writeUtf8(buf, seq);
832 return buf;
833 }
834
835
836
837
838
839
840
841
842
843 public static int writeUtf8(ByteBuf buf, CharSequence seq) {
844 int seqLength = seq.length();
845 return reserveAndWriteUtf8Seq(buf, seq, 0, seqLength, utf8MaxBytes(seqLength));
846 }
847
848
849
850
851
852 public static int writeUtf8(ByteBuf buf, CharSequence seq, int start, int end) {
853 checkCharSequenceBounds(seq, start, end);
854 return reserveAndWriteUtf8Seq(buf, seq, start, end, utf8MaxBytes(end - start));
855 }
856
857
858
859
860
861
862
863
864
865
866 public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int reserveBytes) {
867 return reserveAndWriteUtf8Seq(buf, seq, 0, seq.length(), reserveBytes);
868 }
869
870
871
872
873
874
875
876
877 public static int reserveAndWriteUtf8(ByteBuf buf, CharSequence seq, int start, int end, int reserveBytes) {
878 return reserveAndWriteUtf8Seq(buf, checkCharSequenceBounds(seq, start, end), start, end, reserveBytes);
879 }
880
881 private static int reserveAndWriteUtf8Seq(ByteBuf buf, CharSequence seq, int start, int end, int reserveBytes) {
882 for (;;) {
883 if (buf instanceof WrappedCompositeByteBuf) {
884
885 buf = buf.unwrap();
886 } else if (buf instanceof AbstractByteBuf) {
887 AbstractByteBuf byteBuf = (AbstractByteBuf) buf;
888 byteBuf.ensureWritable0(reserveBytes);
889 int written = writeUtf8(byteBuf, byteBuf.writerIndex, reserveBytes, seq, start, end);
890 byteBuf.writerIndex += written;
891 return written;
892 } else if (buf instanceof WrappedByteBuf) {
893
894 buf = buf.unwrap();
895 } else {
896 byte[] bytes = seq.subSequence(start, end).toString().getBytes(CharsetUtil.UTF_8);
897 buf.writeBytes(bytes);
898 return bytes.length;
899 }
900 }
901 }
902
903 static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes, CharSequence seq, int len) {
904 return writeUtf8(buffer, writerIndex, reservedBytes, seq, 0, len);
905 }
906
907
908 static int writeUtf8(AbstractByteBuf buffer, int writerIndex, int reservedBytes,
909 CharSequence seq, int start, int end) {
910 if (seq instanceof AsciiString) {
911 writeAsciiString(buffer, writerIndex, (AsciiString) seq, start, end);
912 return end - start;
913 }
914 if (PlatformDependent.hasUnsafe()) {
915 if (buffer.hasArray()) {
916 return unsafeWriteUtf8(buffer.array(), PlatformDependent.byteArrayBaseOffset(),
917 buffer.arrayOffset() + writerIndex, seq, start, end);
918 }
919 if (buffer.hasMemoryAddress()) {
920 return unsafeWriteUtf8(null, buffer.memoryAddress(), writerIndex, seq, start, end);
921 }
922 } else {
923 if (buffer.hasArray()) {
924 return safeArrayWriteUtf8(buffer.array(), buffer.arrayOffset() + writerIndex, seq, start, end);
925 }
926 if (buffer.isDirect()) {
927 assert 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 }