View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
34  import org.eclipse.jetty.util.resource.Resource;
35  
36  
37  /* ------------------------------------------------------------------------------- */
38  /**
39   * Buffer utility methods.
40   * <p>The standard JVM {@link ByteBuffer} can exist in two modes: In fill mode the valid
41   * data is between 0 and pos; In flush mode the valid data is between the pos and the limit.
42   * The various ByteBuffer methods assume a mode and some of them will switch or enforce a mode:
43   * Allocate and clear set fill mode; flip and compact switch modes; read and write assume fill 
44   * and flush modes.    This duality can result in confusing code such as:
45   * <pre>
46   *     buffer.clear();
47   *     channel.write(buffer);
48   * </pre>
49   * Which looks as if it should write no data, but in fact writes the buffer worth of garbage.
50   * </p>
51   * <p>
52   * The BufferUtil class provides a set of utilities that operate on the convention that ByteBuffers
53   * will always be left, passed in an API or returned from a method in the flush mode - ie with
54   * valid data between the pos and limit.    This convention is adopted so as to avoid confusion as to
55   * what state a buffer is in and to avoid excessive copying of data that can result with the usage 
56   * of compress.</p> 
57   * <p>
58   * Thus this class provides alternate implementations of {@link #allocate(int)}, 
59   * {@link #allocateDirect(int)} and {@link #clear(ByteBuffer)} that leave the buffer
60   * in flush mode.   Thus the following tests will pass:<pre>
61   *     ByteBuffer buffer = BufferUtil.allocate(1024);
62   *     assert(buffer.remaining()==0);
63   *     BufferUtil.clear(buffer);
64   *     assert(buffer.remaining()==0);
65   * </pre>
66   * </p>
67   * <p>If the BufferUtil methods {@link #fill(ByteBuffer, byte[], int, int)}, 
68   * {@link #append(ByteBuffer, byte[], int, int)} or {@link #put(ByteBuffer, ByteBuffer)} are used,
69   * then the caller does not need to explicitly switch the buffer to fill mode.    
70   * If the caller wishes to use other ByteBuffer bases libraries to fill a buffer, 
71   * then they can use explicit calls of #flipToFill(ByteBuffer) and #flipToFlush(ByteBuffer, int)
72   * to change modes.  Note because this convention attempts to avoid the copies of compact, the position
73   * is not set to zero on each fill cycle and so its value must be remembered:
74   * <pre>
75   *      int pos = BufferUtil.flipToFill(buffer);
76   *      try
77   *      {
78   *          buffer.put(data);
79   *      }
80   *      finally
81   *      {
82   *          flipToFlush(buffer, pos);
83   *      }
84   * </pre>
85   * The flipToFill method will effectively clear the buffer if it is emtpy and will compact the buffer if there is no space.
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     /** Allocate ByteBuffer in flush mode.
101      * The position and limit will both be zero, indicating that the buffer is
102      * empty and must be flipped before any data is put to it.
103      * @param capacity capacity of the allocated ByteBuffer
104      * @return Buffer
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     /** Allocate ByteBuffer in flush mode.
115      * The position and limit will both be zero, indicating that the buffer is
116      * empty and in flush mode.
117      * @param capacity capacity of the allocated ByteBuffer
118      * @return Buffer
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     /** Clear the buffer to be empty in flush mode.
130      * The position and limit are set to 0;
131      * @param buffer The buffer to clear.
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     /** Clear the buffer to be empty in fill mode.
144      * The position is set to 0 and the limit is set to the capacity.
145      * @param buffer The buffer to clear.
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     /** Flip the buffer to fill mode.
158      * The position is set to the first unused position in the buffer
159      * (the old limit) and the limit is set to the capacity.
160      * If the buffer is empty, then this call is effectively {@link #clearToFill(ByteBuffer)}.
161      * If there is no unused space to fill, a {@link ByteBuffer#compact()} is done to attempt
162      * to create space.
163      * <p>
164      * This method is used as a replacement to {@link ByteBuffer#compact()}.
165      *
166      * @param buffer The buffer to flip
167      * @return The position of the valid data before the flipped position. This value should be
168      * passed to a subsequent call to {@link #flipToFlush(ByteBuffer, int)}
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     /** Flip the buffer to Flush mode.
196      * The limit is set to the first unused byte(the old position) and
197      * the position is set to the passed position.
198      * <p>
199      * This method is used as a replacement of {@link Buffer#flip()}.
200      * @param buffer   the buffer to be flipped
201      * @param position The position of valid data to flip to. This should
202      * be the return value of the previous call to {@link #flipToFill(ByteBuffer)}
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     /** Convert a ByteBuffer to a byte array.
213      * @param buffer The buffer to convert in flush mode. The buffer is not altered.
214      * @return An array of bytes duplicated from the buffer.
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     /** Check for an empty or null buffer.
231      * @param buf the buffer to check
232      * @return true if the buffer is null or empty.
233      */
234     public static boolean isEmpty(ByteBuffer buf)
235     {
236         return buf == null || buf.remaining() == 0;
237     }
238 
239     /* ------------------------------------------------------------ */
240     /** Check for a non null and non empty buffer.
241      * @param buf the buffer to check
242      * @return true if the buffer is not null and not empty.
243      */
244     public static boolean hasContent(ByteBuffer buf)
245     {
246         return buf != null && buf.remaining() > 0;
247     }
248 
249     /* ------------------------------------------------------------ */
250     /** Check for a non null and full buffer.
251      * @param buf the buffer to check
252      * @return true if the buffer is not null and the limit equals the capacity.
253      */
254     public static boolean isFull(ByteBuffer buf)
255     {
256         return buf != null && buf.limit() == buf.capacity();
257     }
258 
259     /* ------------------------------------------------------------ */
260     /** Get remaining from null checked buffer
261      * @param buffer The buffer to get the remaining from, in flush mode.
262      * @return 0 if the buffer is null, else the bytes remaining in the buffer.
263      */
264     public static int length(ByteBuffer buffer)
265     {
266         return buffer == null ? 0 : buffer.remaining();
267     }
268 
269     /* ------------------------------------------------------------ */
270     /** Get the space from the limit to the capacity
271      * @param buffer the buffer to get the space from
272      * @return space
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     /** Compact the buffer
283      * @param buffer the buffer to compact
284      * @return true if the compact made a full buffer have space
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      * Put data from one buffer into another, avoiding over/under flows
296      * @param from Buffer to take bytes from in flush mode
297      * @param to   Buffer to put bytes to in fill mode.
298      * @return number of bytes moved
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      * Put data from one buffer into another, avoiding over/under flows
337      * @param from Buffer to take bytes from in flush mode
338      * @param to   Buffer to put bytes to in flush mode. The buffer is flipToFill before the put and flipToFlush after.
339      * @return number of bytes moved
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     /** Append bytes to a buffer.
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     /** Appends a byte to a buffer
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      * Like append, but does not throw {@link BufferOverflowException}
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     /** Convert the buffer to an ISO-8859-1 String
455      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
456      * @return The buffer as a string.
457      */
458     public static String toString(ByteBuffer buffer)
459     {
460         return toString(buffer, StandardCharsets.ISO_8859_1);
461     }
462 
463     /* ------------------------------------------------------------ */
464     /** Convert the buffer to an UTF-8 String
465      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
466      * @return The buffer as a string.
467      */
468     public static String toUTF8String(ByteBuffer buffer)
469     {
470         return toString(buffer, StandardCharsets.UTF_8);
471     }
472 
473     /* ------------------------------------------------------------ */
474     /** Convert the buffer to an ISO-8859-1 String
475      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
476      * @param charset The {@link Charset} to use to convert the bytes
477      * @return The buffer as a string.
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     /** Convert a partial buffer to an ISO-8859-1 String
495      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
496      * @param charset The {@link Charset} to use to convert the bytes
497      * @return The buffer as a string.
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      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
519      *
520      * @param buffer
521      *            A buffer containing an integer in flush mode. The position is not changed.
522      * @return an int
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      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
558      *
559      * @param buffer
560      *            A buffer containing an integer in flush mode. The position is not changed.
561      * @return an int
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             // This assumes constant time int arithmatic
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             // This assumes constant time int arithmatic
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             // This assumes constant time int arithmatic
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      * Create a new ByteBuffer using provided byte array.
767      *
768      * @param array
769      *            the byte array to back buffer with.
770      * @return ByteBuffer with provided byte array, in flush mode
771      */
772     public static ByteBuffer toBuffer(byte array[])
773     {
774         return ByteBuffer.wrap(array);
775     }
776 
777     /**
778      * Create a new ByteBuffer using the provided byte array.
779      *
780      * @param array
781      *            the byte array to use.
782      * @param offset
783      *            the offset within the byte array to use from
784      * @param length
785      *            the length in bytes of the array to use
786      * @return ByteBuffer with provided byte array, in flush mode
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 }