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