1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.io.RandomAccessFile;
26 import java.nio.Buffer;
27 import java.nio.BufferOverflowException;
28 import java.nio.ByteBuffer;
29 import java.nio.channels.FileChannel;
30 import java.nio.channels.FileChannel.MapMode;
31 import java.nio.charset.Charset;
32 import java.nio.charset.StandardCharsets;
33 import java.util.Arrays;
34
35 import org.eclipse.jetty.util.resource.Resource;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public class BufferUtil
95 {
96 static final int TEMP_BUFFER_SIZE = 4096;
97 static final byte SPACE = 0x20;
98 static final byte MINUS = '-';
99 static final byte[] DIGIT =
100 {(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D',
101 (byte)'E', (byte)'F'};
102
103 public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
104
105
106
107
108
109
110
111
112 public static ByteBuffer allocate(int capacity)
113 {
114 ByteBuffer buf = ByteBuffer.allocate(capacity);
115 buf.limit(0);
116 return buf;
117 }
118
119
120
121
122
123
124
125
126 public static ByteBuffer allocateDirect(int capacity)
127 {
128 ByteBuffer buf = ByteBuffer.allocateDirect(capacity);
129 buf.limit(0);
130 return buf;
131 }
132
133
134
135
136
137
138
139 public static void clear(ByteBuffer buffer)
140 {
141 if (buffer != null)
142 {
143 buffer.position(0);
144 buffer.limit(0);
145 }
146 }
147
148
149
150
151
152
153 public static void clearToFill(ByteBuffer buffer)
154 {
155 if (buffer != null)
156 {
157 buffer.position(0);
158 buffer.limit(buffer.capacity());
159 }
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public static int flipToFill(ByteBuffer buffer)
177 {
178 int position = buffer.position();
179 int limit = buffer.limit();
180 if (position == limit)
181 {
182 buffer.position(0);
183 buffer.limit(buffer.capacity());
184 return 0;
185 }
186
187 int capacity = buffer.capacity();
188 if (limit == capacity)
189 {
190 buffer.compact();
191 return 0;
192 }
193
194 buffer.position(limit);
195 buffer.limit(capacity);
196 return position;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210 public static void flipToFlush(ByteBuffer buffer, int position)
211 {
212 buffer.limit(buffer.position());
213 buffer.position(position);
214 }
215
216
217
218
219
220
221
222 public static byte[] toArray(ByteBuffer buffer)
223 {
224 if (buffer.hasArray())
225 {
226 byte[] array = buffer.array();
227 int from=buffer.arrayOffset() + buffer.position();
228 return Arrays.copyOfRange(array,from,from+buffer.remaining());
229 }
230 else
231 {
232 byte[] to = new byte[buffer.remaining()];
233 buffer.slice().get(to);
234 return to;
235 }
236 }
237
238
239
240
241
242
243 public static boolean isEmpty(ByteBuffer buf)
244 {
245 return buf == null || buf.remaining() == 0;
246 }
247
248
249
250
251
252
253 public static boolean hasContent(ByteBuffer buf)
254 {
255 return buf != null && buf.remaining() > 0;
256 }
257
258
259
260
261
262
263 public static boolean isFull(ByteBuffer buf)
264 {
265 return buf != null && buf.limit() == buf.capacity();
266 }
267
268
269
270
271
272
273 public static int length(ByteBuffer buffer)
274 {
275 return buffer == null ? 0 : buffer.remaining();
276 }
277
278
279
280
281
282
283 public static int space(ByteBuffer buffer)
284 {
285 if (buffer == null)
286 return 0;
287 return buffer.capacity() - buffer.limit();
288 }
289
290
291
292
293
294
295 public static boolean compact(ByteBuffer buffer)
296 {
297 if (buffer.position()==0)
298 return false;
299 boolean full = buffer.limit() == buffer.capacity();
300 buffer.compact().flip();
301 return full && buffer.limit() < buffer.capacity();
302 }
303
304
305
306
307
308
309
310
311 public static int put(ByteBuffer from, ByteBuffer to)
312 {
313 int put;
314 int remaining = from.remaining();
315 if (remaining > 0)
316 {
317 if (remaining <= to.remaining())
318 {
319 to.put(from);
320 put = remaining;
321 from.position(from.limit());
322 }
323 else if (from.hasArray())
324 {
325 put = to.remaining();
326 to.put(from.array(), from.arrayOffset() + from.position(), put);
327 from.position(from.position() + put);
328 }
329 else
330 {
331 put = to.remaining();
332 ByteBuffer slice = from.slice();
333 slice.limit(put);
334 to.put(slice);
335 from.position(from.position() + put);
336 }
337 }
338 else
339 put = 0;
340
341 return put;
342 }
343
344
345
346
347
348
349
350
351
352 public static int flipPutFlip(ByteBuffer from, ByteBuffer to)
353 {
354 return append(to,from);
355 }
356
357
358
359
360
361
362
363
364
365 public static void append(ByteBuffer to, byte[] b, int off, int len) throws BufferOverflowException
366 {
367 int pos = flipToFill(to);
368 try
369 {
370 to.put(b, off, len);
371 }
372 finally
373 {
374 flipToFlush(to, pos);
375 }
376 }
377
378
379
380
381
382
383 public static void append(ByteBuffer to, byte b)
384 {
385 int pos = flipToFill(to);
386 try
387 {
388 to.put(b);
389 }
390 finally
391 {
392 flipToFlush(to, pos);
393 }
394 }
395
396
397
398
399
400
401
402 public static int append(ByteBuffer to, ByteBuffer b)
403 {
404 int pos = flipToFill(to);
405 try
406 {
407 return put(b, to);
408 }
409 finally
410 {
411 flipToFlush(to, pos);
412 }
413 }
414
415
416
417
418
419
420
421
422
423
424 public static int fill(ByteBuffer to, byte[] b, int off, int len)
425 {
426 int pos = flipToFill(to);
427 try
428 {
429 int remaining = to.remaining();
430 int take = remaining < len ? remaining : len;
431 to.put(b, off, take);
432 return take;
433 }
434 finally
435 {
436 flipToFlush(to, pos);
437 }
438 }
439
440
441
442 public static void readFrom(File file, ByteBuffer buffer) throws IOException
443 {
444 try(RandomAccessFile raf = new RandomAccessFile(file,"r"))
445 {
446 FileChannel channel = raf.getChannel();
447 long needed=raf.length();
448
449 while (needed>0 && buffer.hasRemaining())
450 needed=needed-channel.read(buffer);
451 }
452 }
453
454
455 public static void readFrom(InputStream is, int needed, ByteBuffer buffer) throws IOException
456 {
457 ByteBuffer tmp = allocate(8192);
458
459 while (needed > 0 && buffer.hasRemaining())
460 {
461 int l = is.read(tmp.array(), 0, 8192);
462 if (l < 0)
463 break;
464 tmp.position(0);
465 tmp.limit(l);
466 buffer.put(tmp);
467 }
468 }
469
470
471 public static void writeTo(ByteBuffer buffer, OutputStream out) throws IOException
472 {
473 if (buffer.hasArray())
474 {
475 out.write(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining());
476
477 buffer.position(buffer.position() + buffer.remaining());
478 }
479 else
480 {
481 byte[] bytes = new byte[TEMP_BUFFER_SIZE];
482 while(buffer.hasRemaining()){
483 int byteCountToWrite = Math.min(buffer.remaining(), TEMP_BUFFER_SIZE);
484 buffer.get(bytes, 0, byteCountToWrite);
485 out.write(bytes,0 , byteCountToWrite);
486 }
487 }
488 }
489
490
491
492
493
494
495 public static String toString(ByteBuffer buffer)
496 {
497 return toString(buffer, StandardCharsets.ISO_8859_1);
498 }
499
500
501
502
503
504
505 public static String toUTF8String(ByteBuffer buffer)
506 {
507 return toString(buffer, StandardCharsets.UTF_8);
508 }
509
510
511
512
513
514
515
516 public static String toString(ByteBuffer buffer, Charset charset)
517 {
518 if (buffer == null)
519 return null;
520 byte[] array = buffer.hasArray() ? buffer.array() : null;
521 if (array == null)
522 {
523 byte[] to = new byte[buffer.remaining()];
524 buffer.slice().get(to);
525 return new String(to, 0, to.length, charset);
526 }
527 return new String(array, buffer.arrayOffset() + buffer.position(), buffer.remaining(), charset);
528 }
529
530
531
532
533
534
535
536
537
538
539 public static String toString(ByteBuffer buffer, int position, int length, Charset charset)
540 {
541 if (buffer == null)
542 return null;
543 byte[] array = buffer.hasArray() ? buffer.array() : null;
544 if (array == null)
545 {
546 ByteBuffer ro = buffer.asReadOnlyBuffer();
547 ro.position(position);
548 ro.limit(position + length);
549 byte[] to = new byte[length];
550 ro.get(to);
551 return new String(to, 0, to.length, charset);
552 }
553 return new String(array, buffer.arrayOffset() + position, length, charset);
554 }
555
556
557
558
559
560
561
562
563
564 public static int toInt(ByteBuffer buffer)
565 {
566 return toInt(buffer,buffer.position(),buffer.remaining());
567 }
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582 public static int toInt(ByteBuffer buffer, int position, int length)
583 {
584 int val = 0;
585 boolean started = false;
586 boolean minus = false;
587
588 int limit = position+length;
589
590 if (length<=0)
591 throw new NumberFormatException(toString(buffer,position,length,StandardCharsets.UTF_8));
592
593 for (int i = position; i < limit; i++)
594 {
595 byte b = buffer.get(i);
596 if (b <= SPACE)
597 {
598 if (started)
599 break;
600 }
601 else if (b >= '0' && b <= '9')
602 {
603 val = val * 10 + (b - '0');
604 started = true;
605 }
606 else if (b == MINUS && !started)
607 {
608 minus = true;
609 }
610 else
611 break;
612 }
613
614 if (started)
615 return minus ? (-val) : val;
616 throw new NumberFormatException(toString(buffer));
617 }
618
619
620
621
622
623
624
625
626
627 public static int takeInt(ByteBuffer buffer)
628 {
629 int val = 0;
630 boolean started = false;
631 boolean minus = false;
632 int i;
633 for (i = buffer.position(); i < buffer.limit(); i++)
634 {
635 byte b = buffer.get(i);
636 if (b <= SPACE)
637 {
638 if (started)
639 break;
640 }
641 else if (b >= '0' && b <= '9')
642 {
643 val = val * 10 + (b - '0');
644 started = true;
645 }
646 else if (b == MINUS && !started)
647 {
648 minus = true;
649 }
650 else
651 break;
652 }
653
654 if (started)
655 {
656 buffer.position(i);
657 return minus ? (-val) : val;
658 }
659 throw new NumberFormatException(toString(buffer));
660 }
661
662
663
664
665
666
667
668
669 public static long toLong(ByteBuffer buffer)
670 {
671 long val = 0;
672 boolean started = false;
673 boolean minus = false;
674
675 for (int i = buffer.position(); i < buffer.limit(); i++)
676 {
677 byte b = buffer.get(i);
678 if (b <= SPACE)
679 {
680 if (started)
681 break;
682 }
683 else if (b >= '0' && b <= '9')
684 {
685 val = val * 10L + (b - '0');
686 started = true;
687 }
688 else if (b == MINUS && !started)
689 {
690 minus = true;
691 }
692 else
693 break;
694 }
695
696 if (started)
697 return minus ? (-val) : val;
698 throw new NumberFormatException(toString(buffer));
699 }
700
701 public static void putHexInt(ByteBuffer buffer, int n)
702 {
703 if (n < 0)
704 {
705 buffer.put((byte)'-');
706
707 if (n == Integer.MIN_VALUE)
708 {
709 buffer.put((byte)(0x7f & '8'));
710 buffer.put((byte)(0x7f & '0'));
711 buffer.put((byte)(0x7f & '0'));
712 buffer.put((byte)(0x7f & '0'));
713 buffer.put((byte)(0x7f & '0'));
714 buffer.put((byte)(0x7f & '0'));
715 buffer.put((byte)(0x7f & '0'));
716 buffer.put((byte)(0x7f & '0'));
717
718 return;
719 }
720 n = -n;
721 }
722
723 if (n < 0x10)
724 {
725 buffer.put(DIGIT[n]);
726 }
727 else
728 {
729 boolean started = false;
730
731 for (int hexDivisor : hexDivisors)
732 {
733 if (n < hexDivisor)
734 {
735 if (started)
736 buffer.put((byte)'0');
737 continue;
738 }
739
740 started = true;
741 int d = n / hexDivisor;
742 buffer.put(DIGIT[d]);
743 n = n - d * hexDivisor;
744 }
745 }
746 }
747
748
749 public static void putDecInt(ByteBuffer buffer, int n)
750 {
751 if (n < 0)
752 {
753 buffer.put((byte)'-');
754
755 if (n == Integer.MIN_VALUE)
756 {
757 buffer.put((byte)'2');
758 n = 147483648;
759 }
760 else
761 n = -n;
762 }
763
764 if (n < 10)
765 {
766 buffer.put(DIGIT[n]);
767 }
768 else
769 {
770 boolean started = false;
771
772 for (int decDivisor : decDivisors)
773 {
774 if (n < decDivisor)
775 {
776 if (started)
777 buffer.put((byte)'0');
778 continue;
779 }
780
781 started = true;
782 int d = n / decDivisor;
783 buffer.put(DIGIT[d]);
784 n = n - d * decDivisor;
785 }
786 }
787 }
788
789 public static void putDecLong(ByteBuffer buffer, long n)
790 {
791 if (n < 0)
792 {
793 buffer.put((byte)'-');
794
795 if (n == Long.MIN_VALUE)
796 {
797 buffer.put((byte)'9');
798 n = 223372036854775808L;
799 }
800 else
801 n = -n;
802 }
803
804 if (n < 10)
805 {
806 buffer.put(DIGIT[(int)n]);
807 }
808 else
809 {
810 boolean started = false;
811
812 for (long aDecDivisorsL : decDivisorsL)
813 {
814 if (n < aDecDivisorsL)
815 {
816 if (started)
817 buffer.put((byte)'0');
818 continue;
819 }
820
821 started = true;
822 long d = n / aDecDivisorsL;
823 buffer.put(DIGIT[(int)d]);
824 n = n - d * aDecDivisorsL;
825 }
826 }
827 }
828
829 public static ByteBuffer toBuffer(int value)
830 {
831 ByteBuffer buf = ByteBuffer.allocate(32);
832 putDecInt(buf, value);
833 return buf;
834 }
835
836 public static ByteBuffer toBuffer(long value)
837 {
838 ByteBuffer buf = ByteBuffer.allocate(32);
839 putDecLong(buf, value);
840 return buf;
841 }
842
843 public static ByteBuffer toBuffer(String s)
844 {
845 return toBuffer(s, StandardCharsets.ISO_8859_1);
846 }
847
848 public static ByteBuffer toBuffer(String s, Charset charset)
849 {
850 if (s == null)
851 return EMPTY_BUFFER;
852 return toBuffer(s.getBytes(charset));
853 }
854
855
856
857
858
859
860
861
862 public static ByteBuffer toBuffer(byte[] array)
863 {
864 if (array == null)
865 return EMPTY_BUFFER;
866 return toBuffer(array, 0, array.length);
867 }
868
869
870
871
872
873
874
875
876
877
878
879
880 public static ByteBuffer toBuffer(byte array[], int offset, int length)
881 {
882 if (array == null)
883 return EMPTY_BUFFER;
884 return ByteBuffer.wrap(array, offset, length);
885 }
886
887 public static ByteBuffer toDirectBuffer(String s)
888 {
889 return toDirectBuffer(s, StandardCharsets.ISO_8859_1);
890 }
891
892 public static ByteBuffer toDirectBuffer(String s, Charset charset)
893 {
894 if (s == null)
895 return EMPTY_BUFFER;
896 byte[] bytes = s.getBytes(charset);
897 ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
898 buf.put(bytes);
899 buf.flip();
900 return buf;
901 }
902
903 public static ByteBuffer toMappedBuffer(File file) throws IOException
904 {
905 try (RandomAccessFile raf = new RandomAccessFile(file, "r"))
906 {
907 return raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
908 }
909 }
910
911 public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
912 {
913 int len=(int)resource.length();
914 if (len<0)
915 throw new IllegalArgumentException("invalid resource: "+String.valueOf(resource)+" len="+len);
916
917 ByteBuffer buffer = direct?BufferUtil.allocateDirect(len):BufferUtil.allocate(len);
918
919 int pos=BufferUtil.flipToFill(buffer);
920 if (resource.getFile()!=null)
921 BufferUtil.readFrom(resource.getFile(),buffer);
922 else
923 {
924 try (InputStream is = resource.getInputStream();)
925 {
926 BufferUtil.readFrom(is,len,buffer);
927 }
928 }
929 BufferUtil.flipToFlush(buffer,pos);
930
931 return buffer;
932 }
933
934 public static String toSummaryString(ByteBuffer buffer)
935 {
936 if (buffer == null)
937 return "null";
938 StringBuilder buf = new StringBuilder();
939 buf.append("[p=");
940 buf.append(buffer.position());
941 buf.append(",l=");
942 buf.append(buffer.limit());
943 buf.append(",c=");
944 buf.append(buffer.capacity());
945 buf.append(",r=");
946 buf.append(buffer.remaining());
947 buf.append("]");
948 return buf.toString();
949 }
950
951 public static String toDetailString(ByteBuffer[] buffer)
952 {
953 StringBuilder builder = new StringBuilder();
954 builder.append('[');
955 for (int i = 0; i < buffer.length; i++)
956 {
957 if (i > 0) builder.append(',');
958 builder.append(toDetailString(buffer[i]));
959 }
960 builder.append(']');
961 return builder.toString();
962 }
963
964
965
966
967
968
969 private static void idString(ByteBuffer buffer, StringBuilder out)
970 {
971 out.append(buffer.getClass().getSimpleName());
972 out.append("@");
973 if (buffer.hasArray() && buffer.arrayOffset()==4)
974 {
975 out.append('T');
976 byte[] array = buffer.array();
977 TypeUtil.toHex(array[0],out);
978 TypeUtil.toHex(array[1],out);
979 TypeUtil.toHex(array[2],out);
980 TypeUtil.toHex(array[3],out);
981 }
982 else
983 out.append(Integer.toHexString(System.identityHashCode(buffer)));
984 }
985
986
987
988
989
990
991 public static String toIDString(ByteBuffer buffer)
992 {
993 StringBuilder buf = new StringBuilder();
994 idString(buffer,buf);
995 return buf.toString();
996 }
997
998
999
1000
1001
1002
1003
1004 public static String toDetailString(ByteBuffer buffer)
1005 {
1006 if (buffer == null)
1007 return "null";
1008
1009 StringBuilder buf = new StringBuilder();
1010 idString(buffer,buf);
1011 buf.append("[p=");
1012 buf.append(buffer.position());
1013 buf.append(",l=");
1014 buf.append(buffer.limit());
1015 buf.append(",c=");
1016 buf.append(buffer.capacity());
1017 buf.append(",r=");
1018 buf.append(buffer.remaining());
1019 buf.append("]={");
1020
1021 appendDebugString(buf,buffer);
1022
1023 buf.append("}");
1024
1025 return buf.toString();
1026 }
1027
1028 private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
1029 {
1030 for (int i = 0; i < buffer.position(); i++)
1031 {
1032 appendContentChar(buf,buffer.get(i));
1033 if (i == 16 && buffer.position() > 32)
1034 {
1035 buf.append("...");
1036 i = buffer.position() - 16;
1037 }
1038 }
1039 buf.append("<<<");
1040 for (int i = buffer.position(); i < buffer.limit(); i++)
1041 {
1042 appendContentChar(buf,buffer.get(i));
1043 if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
1044 {
1045 buf.append("...");
1046 i = buffer.limit() - 16;
1047 }
1048 }
1049 buf.append(">>>");
1050 int limit = buffer.limit();
1051 buffer.limit(buffer.capacity());
1052 for (int i = limit; i < buffer.capacity(); i++)
1053 {
1054 appendContentChar(buf,buffer.get(i));
1055 if (i == limit + 16 && buffer.capacity() > limit + 32)
1056 {
1057 buf.append("...");
1058 i = buffer.capacity() - 16;
1059 }
1060 }
1061 buffer.limit(limit);
1062 }
1063
1064 private static void appendContentChar(StringBuilder buf, byte b)
1065 {
1066 if (b == '\\')
1067 buf.append("\\\\");
1068 else if (b >= ' ')
1069 buf.append((char)b);
1070 else if (b == '\r')
1071 buf.append("\\r");
1072 else if (b == '\n')
1073 buf.append("\\n");
1074 else if (b == '\t')
1075 buf.append("\\t");
1076 else
1077 buf.append("\\x").append(TypeUtil.toHexString(b));
1078 }
1079
1080
1081
1082
1083
1084
1085
1086
1087 public static String toHexSummary(ByteBuffer buffer)
1088 {
1089 if (buffer == null)
1090 return "null";
1091 StringBuilder buf = new StringBuilder();
1092
1093 buf.append("b[").append(buffer.remaining()).append("]=");
1094 for (int i = buffer.position(); i < buffer.limit(); i++)
1095 {
1096 TypeUtil.toHex(buffer.get(i),buf);
1097 if (i == buffer.position() + 24 && buffer.limit() > buffer.position() + 32)
1098 {
1099 buf.append("...");
1100 i = buffer.limit() - 8;
1101 }
1102 }
1103 return buf.toString();
1104 }
1105
1106
1107 private final static int[] decDivisors =
1108 {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1109
1110 private final static int[] hexDivisors =
1111 {0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1};
1112
1113 private final static long[] decDivisorsL =
1114 {1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
1115 10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L};
1116
1117 public static void putCRLF(ByteBuffer buffer)
1118 {
1119 buffer.put((byte)13);
1120 buffer.put((byte)10);
1121 }
1122
1123 public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
1124 {
1125 if (prefix.remaining() > buffer.remaining())
1126 return false;
1127 int bi = buffer.position();
1128 for (int i = prefix.position(); i < prefix.limit(); i++)
1129 if (prefix.get(i) != buffer.get(bi++))
1130 return false;
1131 return true;
1132 }
1133
1134 public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
1135 {
1136 if (buffer==null)
1137 return allocate(capacity);
1138
1139 if (buffer.capacity()>=capacity)
1140 return buffer;
1141
1142 if (buffer.hasArray())
1143 return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
1144
1145 throw new UnsupportedOperationException();
1146 }
1147
1148
1149
1150 }