]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/BufferUtil.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / util / BufferUtil.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
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  * Buffer utility methods.
41  * <p>The standard JVM {@link ByteBuffer} can exist in two modes: In fill mode the valid
42  * data is between 0 and pos; In flush mode the valid data is between the pos and the limit.
43  * The various ByteBuffer methods assume a mode and some of them will switch or enforce a mode:
44  * Allocate and clear set fill mode; flip and compact switch modes; read and write assume fill 
45  * and flush modes.    This duality can result in confusing code such as:
46  * <pre>
47  *     buffer.clear();
48  *     channel.write(buffer);
49  * </pre>
50  * Which looks as if it should write no data, but in fact writes the buffer worth of garbage.
51  * </p>
52  * <p>
53  * The BufferUtil class provides a set of utilities that operate on the convention that ByteBuffers
54  * will always be left, passed in an API or returned from a method in the flush mode - ie with
55  * valid data between the pos and limit.    This convention is adopted so as to avoid confusion as to
56  * what state a buffer is in and to avoid excessive copying of data that can result with the usage 
57  * of compress.</p> 
58  * <p>
59  * Thus this class provides alternate implementations of {@link #allocate(int)}, 
60  * {@link #allocateDirect(int)} and {@link #clear(ByteBuffer)} that leave the buffer
61  * in flush mode.   Thus the following tests will pass:<pre>
62  *     ByteBuffer buffer = BufferUtil.allocate(1024);
63  *     assert(buffer.remaining()==0);
64  *     BufferUtil.clear(buffer);
65  *     assert(buffer.remaining()==0);
66  * </pre>
67  * </p>
68  * <p>If the BufferUtil methods {@link #fill(ByteBuffer, byte[], int, int)}, 
69  * {@link #append(ByteBuffer, byte[], int, int)} or {@link #put(ByteBuffer, ByteBuffer)} are used,
70  * then the caller does not need to explicitly switch the buffer to fill mode.    
71  * If the caller wishes to use other ByteBuffer bases libraries to fill a buffer, 
72  * then they can use explicit calls of #flipToFill(ByteBuffer) and #flipToFlush(ByteBuffer, int)
73  * to change modes.  Note because this convention attempts to avoid the copies of compact, the position
74  * is not set to zero on each fill cycle and so its value must be remembered:
75  * <pre>
76  *      int pos = BufferUtil.flipToFill(buffer);
77  *      try
78  *      {
79  *          buffer.put(data);
80  *      }
81  *      finally
82  *      {
83  *          flipToFlush(buffer, pos);
84  *      }
85  * </pre>
86  * The flipToFill method will effectively clear the buffer if it is emtpy and will compact the buffer if there is no space.
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     /** Allocate ByteBuffer in flush mode.
102      * The position and limit will both be zero, indicating that the buffer is
103      * empty and must be flipped before any data is put to it.
104      * @param capacity capacity of the allocated ByteBuffer
105      * @return Buffer
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     /** Allocate ByteBuffer in flush mode.
116      * The position and limit will both be zero, indicating that the buffer is
117      * empty and in flush mode.
118      * @param capacity capacity of the allocated ByteBuffer
119      * @return Buffer
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     /** Clear the buffer to be empty in flush mode.
131      * The position and limit are set to 0;
132      * @param buffer The buffer to clear.
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     /** Clear the buffer to be empty in fill mode.
145      * The position is set to 0 and the limit is set to the capacity.
146      * @param buffer The buffer to clear.
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     /** Flip the buffer to fill mode.
159      * The position is set to the first unused position in the buffer
160      * (the old limit) and the limit is set to the capacity.
161      * If the buffer is empty, then this call is effectively {@link #clearToFill(ByteBuffer)}.
162      * If there is no unused space to fill, a {@link ByteBuffer#compact()} is done to attempt
163      * to create space.
164      * <p>
165      * This method is used as a replacement to {@link ByteBuffer#compact()}.
166      *
167      * @param buffer The buffer to flip
168      * @return The position of the valid data before the flipped position. This value should be
169      * passed to a subsequent call to {@link #flipToFlush(ByteBuffer, int)}
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     /** Flip the buffer to Flush mode.
197      * The limit is set to the first unused byte(the old position) and
198      * the position is set to the passed position.
199      * <p>
200      * This method is used as a replacement of {@link Buffer#flip()}.
201      * @param buffer   the buffer to be flipped
202      * @param position The position of valid data to flip to. This should
203      * be the return value of the previous call to {@link #flipToFill(ByteBuffer)}
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     /** Convert a ByteBuffer to a byte array.
214      * @param buffer The buffer to convert in flush mode. The buffer is not altered.
215      * @return An array of bytes duplicated from the buffer.
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     /** Check for an empty or null buffer.
235      * @param buf the buffer to check
236      * @return true if the buffer is null or empty.
237      */
238     public static boolean isEmpty(ByteBuffer buf)
239     {
240         return buf == null || buf.remaining() == 0;
241     }
242
243     /* ------------------------------------------------------------ */
244     /** Check for a non null and non empty buffer.
245      * @param buf the buffer to check
246      * @return true if the buffer is not null and not empty.
247      */
248     public static boolean hasContent(ByteBuffer buf)
249     {
250         return buf != null && buf.remaining() > 0;
251     }
252
253     /* ------------------------------------------------------------ */
254     /** Check for a non null and full buffer.
255      * @param buf the buffer to check
256      * @return true if the buffer is not null and the limit equals the capacity.
257      */
258     public static boolean isFull(ByteBuffer buf)
259     {
260         return buf != null && buf.limit() == buf.capacity();
261     }
262
263     /* ------------------------------------------------------------ */
264     /** Get remaining from null checked buffer
265      * @param buffer The buffer to get the remaining from, in flush mode.
266      * @return 0 if the buffer is null, else the bytes remaining in the buffer.
267      */
268     public static int length(ByteBuffer buffer)
269     {
270         return buffer == null ? 0 : buffer.remaining();
271     }
272
273     /* ------------------------------------------------------------ */
274     /** Get the space from the limit to the capacity
275      * @param buffer the buffer to get the space from
276      * @return space
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     /** Compact the buffer
287      * @param buffer the buffer to compact
288      * @return true if the compact made a full buffer have space
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      * Put data from one buffer into another, avoiding over/under flows
302      * @param from Buffer to take bytes from in flush mode
303      * @param to   Buffer to put bytes to in fill mode.
304      * @return number of bytes moved
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      * Put data from one buffer into another, avoiding over/under flows
343      * @param from Buffer to take bytes from in flush mode
344      * @param to   Buffer to put bytes to in flush mode. The buffer is flipToFill before the put and flipToFlush after.
345      * @return number of bytes moved
346      * @deprecated use {@link #append(ByteBuffer, ByteBuffer)}
347      */
348     public static int flipPutFlip(ByteBuffer from, ByteBuffer to)
349     {
350         return append(to,from);
351     }
352
353     /* ------------------------------------------------------------ */
354     /** Append bytes to a buffer.
355      * @param to Buffer is flush mode
356      * @param b bytes to append
357      * @param off offset into byte
358      * @param len length to append
359      * @throws BufferOverflowException
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     /** Appends a byte to a buffer
376      * @param to Buffer is flush mode
377      * @param b byte to append
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     /** Appends a byte to a buffer
394      * @param to Buffer is flush mode
395      * @param b bytes to append
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      * Like append, but does not throw {@link BufferOverflowException}
413      * @param to Buffer is flush mode
414      * @param b bytes to fill
415      * @param off offset into byte
416      * @param len length to fill
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     /** Convert the buffer to an ISO-8859-1 String
482      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
483      * @return The buffer as a string.
484      */
485     public static String toString(ByteBuffer buffer)
486     {
487         return toString(buffer, StandardCharsets.ISO_8859_1);
488     }
489
490     /* ------------------------------------------------------------ */
491     /** Convert the buffer to an UTF-8 String
492      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
493      * @return The buffer as a string.
494      */
495     public static String toUTF8String(ByteBuffer buffer)
496     {
497         return toString(buffer, StandardCharsets.UTF_8);
498     }
499
500     /* ------------------------------------------------------------ */
501     /** Convert the buffer to an ISO-8859-1 String
502      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
503      * @param charset The {@link Charset} to use to convert the bytes
504      * @return The buffer as a string.
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     /** Convert a partial buffer to an ISO-8859-1 String
522      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
523      * @param charset The {@link Charset} to use to convert the bytes
524      * @return The buffer as a string.
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      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
546      *
547      * @param buffer
548      *            A buffer containing an integer in flush mode. The position is not changed.
549      * @return an int
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      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
586      *
587      * @param buffer
588      *            A buffer containing an integer in flush mode. The position is updated.
589      * @return an int
590      */
591     public static int takeInt(ByteBuffer buffer)
592     {
593         int val = 0;
594         boolean started = false;
595         boolean minus = false;
596         int i;
597         for (i = buffer.position(); i < buffer.limit(); i++)
598         {
599             byte b = buffer.get(i);
600             if (b <= SPACE)
601             {
602                 if (started)
603                     break;
604             }
605             else if (b >= '0' && b <= '9')
606             {
607                 val = val * 10 + (b - '0');
608                 started = true;
609             }
610             else if (b == MINUS && !started)
611             {
612                 minus = true;
613             }
614             else
615                 break;
616         }
617
618         if (started)
619         {
620             buffer.position(i);
621             return minus ? (-val) : val;
622         }
623         throw new NumberFormatException(toString(buffer));
624     }
625
626     /**
627      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
628      *
629      * @param buffer
630      *            A buffer containing an integer in flush mode. The position is not changed.
631      * @return an int
632      */
633     public static long toLong(ByteBuffer buffer)
634     {
635         long val = 0;
636         boolean started = false;
637         boolean minus = false;
638
639         for (int i = buffer.position(); i < buffer.limit(); i++)
640         {
641             byte b = buffer.get(i);
642             if (b <= SPACE)
643             {
644                 if (started)
645                     break;
646             }
647             else if (b >= '0' && b <= '9')
648             {
649                 val = val * 10L + (b - '0');
650                 started = true;
651             }
652             else if (b == MINUS && !started)
653             {
654                 minus = true;
655             }
656             else
657                 break;
658         }
659
660         if (started)
661             return minus ? (-val) : val;
662         throw new NumberFormatException(toString(buffer));
663     }
664
665     public static void putHexInt(ByteBuffer buffer, int n)
666     {
667         if (n < 0)
668         {
669             buffer.put((byte)'-');
670
671             if (n == Integer.MIN_VALUE)
672             {
673                 buffer.put((byte)(0x7f & '8'));
674                 buffer.put((byte)(0x7f & '0'));
675                 buffer.put((byte)(0x7f & '0'));
676                 buffer.put((byte)(0x7f & '0'));
677                 buffer.put((byte)(0x7f & '0'));
678                 buffer.put((byte)(0x7f & '0'));
679                 buffer.put((byte)(0x7f & '0'));
680                 buffer.put((byte)(0x7f & '0'));
681
682                 return;
683             }
684             n = -n;
685         }
686
687         if (n < 0x10)
688         {
689             buffer.put(DIGIT[n]);
690         }
691         else
692         {
693             boolean started = false;
694             // This assumes constant time int arithmatic
695             for (int hexDivisor : hexDivisors)
696             {
697                 if (n < hexDivisor)
698                 {
699                     if (started)
700                         buffer.put((byte)'0');
701                     continue;
702                 }
703
704                 started = true;
705                 int d = n / hexDivisor;
706                 buffer.put(DIGIT[d]);
707                 n = n - d * hexDivisor;
708             }
709         }
710     }
711
712     /* ------------------------------------------------------------ */
713     public static void putDecInt(ByteBuffer buffer, int n)
714     {
715         if (n < 0)
716         {
717             buffer.put((byte)'-');
718
719             if (n == Integer.MIN_VALUE)
720             {
721                 buffer.put((byte)'2');
722                 n = 147483648;
723             }
724             else
725                 n = -n;
726         }
727
728         if (n < 10)
729         {
730             buffer.put(DIGIT[n]);
731         }
732         else
733         {
734             boolean started = false;
735             // This assumes constant time int arithmatic
736             for (int decDivisor : decDivisors)
737             {
738                 if (n < decDivisor)
739                 {
740                     if (started)
741                         buffer.put((byte)'0');
742                     continue;
743                 }
744
745                 started = true;
746                 int d = n / decDivisor;
747                 buffer.put(DIGIT[d]);
748                 n = n - d * decDivisor;
749             }
750         }
751     }
752
753     public static void putDecLong(ByteBuffer buffer, long n)
754     {
755         if (n < 0)
756         {
757             buffer.put((byte)'-');
758
759             if (n == Long.MIN_VALUE)
760             {
761                 buffer.put((byte)'9');
762                 n = 223372036854775808L;
763             }
764             else
765                 n = -n;
766         }
767
768         if (n < 10)
769         {
770             buffer.put(DIGIT[(int)n]);
771         }
772         else
773         {
774             boolean started = false;
775             // This assumes constant time int arithmatic
776             for (long aDecDivisorsL : decDivisorsL)
777             {
778                 if (n < aDecDivisorsL)
779                 {
780                     if (started)
781                         buffer.put((byte)'0');
782                     continue;
783                 }
784
785                 started = true;
786                 long d = n / aDecDivisorsL;
787                 buffer.put(DIGIT[(int)d]);
788                 n = n - d * aDecDivisorsL;
789             }
790         }
791     }
792
793     public static ByteBuffer toBuffer(int value)
794     {
795         ByteBuffer buf = ByteBuffer.allocate(32);
796         putDecInt(buf, value);
797         return buf;
798     }
799
800     public static ByteBuffer toBuffer(long value)
801     {
802         ByteBuffer buf = ByteBuffer.allocate(32);
803         putDecLong(buf, value);
804         return buf;
805     }
806
807     public static ByteBuffer toBuffer(String s)
808     {
809         return ByteBuffer.wrap(s.getBytes(StandardCharsets.ISO_8859_1));
810     }
811
812     public static ByteBuffer toDirectBuffer(String s)
813     {
814         byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
815         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
816         buf.put(bytes);
817         buf.flip();
818         return buf;
819     }
820
821     public static ByteBuffer toBuffer(String s, Charset charset)
822     {
823         return ByteBuffer.wrap(s.getBytes(charset));
824     }
825
826     public static ByteBuffer toDirectBuffer(String s, Charset charset)
827     {
828         byte[] bytes = s.getBytes(charset);
829         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
830         buf.put(bytes);
831         buf.flip();
832         return buf;
833     }
834
835     /**
836      * Create a new ByteBuffer using provided byte array.
837      *
838      * @param array
839      *            the byte array to back buffer with.
840      * @return ByteBuffer with provided byte array, in flush mode
841      */
842     public static ByteBuffer toBuffer(byte array[])
843     {
844         return ByteBuffer.wrap(array);
845     }
846
847     /**
848      * Create a new ByteBuffer using the provided byte array.
849      *
850      * @param array
851      *            the byte array to use.
852      * @param offset
853      *            the offset within the byte array to use from
854      * @param length
855      *            the length in bytes of the array to use
856      * @return ByteBuffer with provided byte array, in flush mode
857      */
858     public static ByteBuffer toBuffer(byte array[], int offset, int length)
859     {
860         return ByteBuffer.wrap(array, offset, length);
861     }
862
863     public static ByteBuffer toMappedBuffer(File file) throws IOException
864     {
865         try (RandomAccessFile raf = new RandomAccessFile(file, "r"))
866         {
867             return raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
868         }
869     }
870
871     public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
872     {
873         int len=(int)resource.length();
874         if (len<0)
875             throw new IllegalArgumentException("invalid resource: "+String.valueOf(resource)+" len="+len);
876         
877         ByteBuffer buffer = direct?BufferUtil.allocateDirect(len):BufferUtil.allocate(len);
878
879         int pos=BufferUtil.flipToFill(buffer);
880         if (resource.getFile()!=null)
881             BufferUtil.readFrom(resource.getFile(),buffer);
882         else
883         {
884             try (InputStream is = resource.getInputStream();)
885             {
886                 BufferUtil.readFrom(is,len,buffer);
887             }
888         }
889         BufferUtil.flipToFlush(buffer,pos);
890         
891         return buffer;
892     }
893
894     public static String toSummaryString(ByteBuffer buffer)
895     {
896         if (buffer == null)
897             return "null";
898         StringBuilder buf = new StringBuilder();
899         buf.append("[p=");
900         buf.append(buffer.position());
901         buf.append(",l=");
902         buf.append(buffer.limit());
903         buf.append(",c=");
904         buf.append(buffer.capacity());
905         buf.append(",r=");
906         buf.append(buffer.remaining());
907         buf.append("]");
908         return buf.toString();
909     }
910
911     public static String toDetailString(ByteBuffer[] buffer)
912     {
913         StringBuilder builder = new StringBuilder();
914         builder.append('[');
915         for (int i = 0; i < buffer.length; i++)
916         {
917             if (i > 0) builder.append(',');
918             builder.append(toDetailString(buffer[i]));
919         }
920         builder.append(']');
921         return builder.toString();
922     }
923
924     public static String toDetailString(ByteBuffer buffer)
925     {
926         if (buffer == null)
927             return "null";
928
929         StringBuilder buf = new StringBuilder();
930         buf.append(buffer.getClass().getSimpleName());
931         buf.append("@");
932         if (buffer.hasArray())
933             buf.append(Integer.toHexString(((Object)buffer.array()).hashCode()));
934         else
935             buf.append(Integer.toHexString(buf.hashCode()));
936         buf.append("[p=");
937         buf.append(buffer.position());
938         buf.append(",l=");
939         buf.append(buffer.limit());
940         buf.append(",c=");
941         buf.append(buffer.capacity());
942         buf.append(",r=");
943         buf.append(buffer.remaining());
944         buf.append("]={");
945
946         for (int i = 0; i < buffer.position(); i++)
947         {
948             char c = (char)buffer.get(i);
949             if (c >= ' ' && c <= 127)
950                 buf.append(c);
951             else if (c == '\r' || c == '\n')
952                 buf.append('|');
953             else
954                 buf.append('\ufffd');
955             if (i == 16 && buffer.position() > 32)
956             {
957                 buf.append("...");
958                 i = buffer.position() - 16;
959             }
960         }
961         buf.append("<<<");
962         for (int i = buffer.position(); i < buffer.limit(); i++)
963         {
964             char c = (char)buffer.get(i);
965             if (c >= ' ' && c <= 127)
966                 buf.append(c);
967             else if (c == '\r' || c == '\n')
968                 buf.append('|');
969             else
970                 buf.append('\ufffd');
971             if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
972             {
973                 buf.append("...");
974                 i = buffer.limit() - 16;
975             }
976         }
977         buf.append(">>>");
978         int limit = buffer.limit();
979         buffer.limit(buffer.capacity());
980         for (int i = limit; i < buffer.capacity(); i++)
981         {
982             char c = (char)buffer.get(i);
983             if (c >= ' ' && c <= 127)
984                 buf.append(c);
985             else if (c == '\r' || c == '\n')
986                 buf.append('|');
987             else
988                 buf.append('\ufffd');
989             if (i == limit + 16 && buffer.capacity() > limit + 32)
990             {
991                 buf.append("...");
992                 i = buffer.capacity() - 16;
993             }
994         }
995         buffer.limit(limit);
996         buf.append("}");
997
998         return buf.toString();
999     }
1000
1001
1002     private final static int[] decDivisors =
1003             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1004
1005     private final static int[] hexDivisors =
1006             {0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1};
1007
1008     private final static long[] decDivisorsL =
1009             {1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
1010                     10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L};
1011
1012     public static void putCRLF(ByteBuffer buffer)
1013     {
1014         buffer.put((byte)13);
1015         buffer.put((byte)10);
1016     }
1017
1018     public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
1019     {
1020         if (prefix.remaining() > buffer.remaining())
1021             return false;
1022         int bi = buffer.position();
1023         for (int i = prefix.position(); i < prefix.limit(); i++)
1024             if (prefix.get(i) != buffer.get(bi++))
1025                 return false;
1026         return true;
1027     }
1028
1029     public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
1030     {
1031         if (buffer==null)
1032             return allocate(capacity);
1033         
1034         if (buffer.capacity()>=capacity)
1035             return buffer;
1036         
1037         if (buffer.hasArray())
1038             return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
1039         
1040         throw new UnsupportedOperationException();
1041     }
1042
1043
1044
1045 }