View Javadoc

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      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
585      *
586      * @param buffer
587      *            A buffer containing an integer in flush mode. The position is not changed.
588      * @return an int
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             // This assumes constant time int arithmatic
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             // This assumes constant time int arithmatic
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             // This assumes constant time int arithmatic
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      * Create a new ByteBuffer using provided byte array.
794      *
795      * @param array
796      *            the byte array to back buffer with.
797      * @return ByteBuffer with provided byte array, in flush mode
798      */
799     public static ByteBuffer toBuffer(byte array[])
800     {
801         return ByteBuffer.wrap(array);
802     }
803 
804     /**
805      * Create a new ByteBuffer using the provided byte array.
806      *
807      * @param array
808      *            the byte array to use.
809      * @param offset
810      *            the offset within the byte array to use from
811      * @param length
812      *            the length in bytes of the array to use
813      * @return ByteBuffer with provided byte array, in flush mode
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 }