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