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