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