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