View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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.BufferOverflowException;
27  import java.nio.ByteBuffer;
28  import java.nio.channels.FileChannel;
29  import java.nio.channels.FileChannel.MapMode;
30  import java.nio.charset.Charset;
31  import java.nio.charset.StandardCharsets;
32  import java.util.Arrays;
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         if (buffer.hasArray())
219         {
220             byte[] array = buffer.array();
221             int from=buffer.arrayOffset() + buffer.position();
222             return Arrays.copyOfRange(array,from,from+buffer.remaining());
223         }
224         else
225         {
226             byte[] to = new byte[buffer.remaining()];
227             buffer.slice().get(to);
228             return to;
229         }
230     }
231 
232     /* ------------------------------------------------------------ */
233     /** Check for an empty or null buffer.
234      * @param buf the buffer to check
235      * @return true if the buffer is null or empty.
236      */
237     public static boolean isEmpty(ByteBuffer buf)
238     {
239         return buf == null || buf.remaining() == 0;
240     }
241 
242     /* ------------------------------------------------------------ */
243     /** Check for a non null and non empty buffer.
244      * @param buf the buffer to check
245      * @return true if the buffer is not null and not empty.
246      */
247     public static boolean hasContent(ByteBuffer buf)
248     {
249         return buf != null && buf.remaining() > 0;
250     }
251 
252     /* ------------------------------------------------------------ */
253     /** Check for a non null and full buffer.
254      * @param buf the buffer to check
255      * @return true if the buffer is not null and the limit equals the capacity.
256      */
257     public static boolean isFull(ByteBuffer buf)
258     {
259         return buf != null && buf.limit() == buf.capacity();
260     }
261 
262     /* ------------------------------------------------------------ */
263     /** Get remaining from null checked buffer
264      * @param buffer The buffer to get the remaining from, in flush mode.
265      * @return 0 if the buffer is null, else the bytes remaining in the buffer.
266      */
267     public static int length(ByteBuffer buffer)
268     {
269         return buffer == null ? 0 : buffer.remaining();
270     }
271 
272     /* ------------------------------------------------------------ */
273     /** Get the space from the limit to the capacity
274      * @param buffer the buffer to get the space from
275      * @return space
276      */
277     public static int space(ByteBuffer buffer)
278     {
279         if (buffer == null)
280             return 0;
281         return buffer.capacity() - buffer.limit();
282     }
283 
284     /* ------------------------------------------------------------ */
285     /** Compact the buffer
286      * @param buffer the buffer to compact
287      * @return true if the compact made a full buffer have space
288      */
289     public static boolean compact(ByteBuffer buffer)
290     {
291         if (buffer.position()==0)
292             return false;
293         boolean full = buffer.limit() == buffer.capacity();
294         buffer.compact().flip();
295         return full && buffer.limit() < buffer.capacity();
296     }
297 
298     /* ------------------------------------------------------------ */
299     /**
300      * Put data from one buffer into another, avoiding over/under flows
301      * @param from Buffer to take bytes from in flush mode
302      * @param to   Buffer to put bytes to in fill mode.
303      * @return number of bytes moved
304      */
305     public static int put(ByteBuffer from, ByteBuffer to)
306     {
307         int put;
308         int remaining = from.remaining();
309         if (remaining > 0)
310         {
311             if (remaining <= to.remaining())
312             {
313                 to.put(from);
314                 put = remaining;
315                 from.position(0);
316                 from.limit(0);
317             }
318             else if (from.hasArray())
319             {
320                 put = to.remaining();
321                 to.put(from.array(), from.arrayOffset() + from.position(), put);
322                 from.position(from.position() + put);
323             }
324             else
325             {
326                 put = to.remaining();
327                 ByteBuffer slice = from.slice();
328                 slice.limit(put);
329                 to.put(slice);
330                 from.position(from.position() + put);
331             }
332         }
333         else
334             put = 0;
335 
336         return put;
337     }
338 
339     /* ------------------------------------------------------------ */
340     /**
341      * Put data from one buffer into another, avoiding over/under flows
342      * @param from Buffer to take bytes from in flush mode
343      * @param to   Buffer to put bytes to in flush mode. The buffer is flipToFill before the put and flipToFlush after.
344      * @return number of bytes moved
345      * @deprecated use {@link #append(ByteBuffer, ByteBuffer)}
346      */
347     public static int flipPutFlip(ByteBuffer from, ByteBuffer to)
348     {
349         return append(to,from);
350     }
351 
352     /* ------------------------------------------------------------ */
353     /** Append bytes to a buffer.
354      * @param to Buffer is flush mode
355      * @param b bytes to append
356      * @param off offset into byte
357      * @param len length to append
358      * @throws BufferOverflowException
359      */
360     public static void append(ByteBuffer to, byte[] b, int off, int len) throws BufferOverflowException
361     {
362         int pos = flipToFill(to);
363         try
364         {
365             to.put(b, off, len);
366         }
367         finally
368         {
369             flipToFlush(to, pos);
370         }
371     }
372 
373     /* ------------------------------------------------------------ */
374     /** Appends a byte to a buffer
375      * @param to Buffer is flush mode
376      * @param b byte to append
377      */
378     public static void append(ByteBuffer to, byte b)
379     {
380         int pos = flipToFill(to);
381         try
382         {
383             to.put(b);
384         }
385         finally
386         {
387             flipToFlush(to, pos);
388         }
389     }
390 
391     /* ------------------------------------------------------------ */
392     /** Appends a buffer to a buffer
393      * @param to Buffer is flush mode
394      * @param b buffer to append
395      */
396     public static int append(ByteBuffer to, ByteBuffer b)
397     {
398         int pos = flipToFill(to);
399         try
400         {
401             return put(b, to);
402         }
403         finally
404         {
405             flipToFlush(to, pos);
406         }
407     }
408 
409     /* ------------------------------------------------------------ */
410     /**
411      * Like append, but does not throw {@link BufferOverflowException}
412      * @param to Buffer is flush mode
413      * @param b bytes to fill
414      * @param off offset into byte
415      * @param len length to fill
416      */
417     public static int fill(ByteBuffer to, byte[] b, int off, int len)
418     {
419         int pos = flipToFill(to);
420         try
421         {
422             int remaining = to.remaining();
423             int take = remaining < len ? remaining : len;
424             to.put(b, off, take);
425             return take;
426         }
427         finally
428         {
429             flipToFlush(to, pos);
430         }
431     }
432 
433 
434     /* ------------------------------------------------------------ */
435     public static void readFrom(File file, ByteBuffer buffer) throws IOException
436     {
437         try(RandomAccessFile raf = new RandomAccessFile(file,"r"))
438         {
439             FileChannel channel = raf.getChannel();
440             long needed=raf.length();
441 
442             while (needed>0 && buffer.hasRemaining())
443                 needed=needed-channel.read(buffer);
444         }
445     }
446 
447     /* ------------------------------------------------------------ */
448     public static void readFrom(InputStream is, int needed, ByteBuffer buffer) throws IOException
449     {
450         ByteBuffer tmp = allocate(8192);
451 
452         while (needed > 0 && buffer.hasRemaining())
453         {
454             int l = is.read(tmp.array(), 0, 8192);
455             if (l < 0)
456                 break;
457             tmp.position(0);
458             tmp.limit(l);
459             buffer.put(tmp);
460         }
461     }
462 
463     /* ------------------------------------------------------------ */
464     public static void writeTo(ByteBuffer buffer, OutputStream out) throws IOException
465     {
466         if (buffer.hasArray())
467         {
468             out.write(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining());
469             // update buffer position, in way similar to non-array version of writeTo
470             buffer.position(buffer.position() + buffer.remaining());
471         }
472         else
473         {
474             byte[] bytes = new byte[TEMP_BUFFER_SIZE];
475             while(buffer.hasRemaining()){
476                 int byteCountToWrite = Math.min(buffer.remaining(), TEMP_BUFFER_SIZE);
477                 buffer.get(bytes, 0, byteCountToWrite);
478                 out.write(bytes,0 , byteCountToWrite);
479             }
480         }
481     }
482 
483     /* ------------------------------------------------------------ */
484     /** Convert the buffer to an ISO-8859-1 String
485      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
486      * @return The buffer as a string.
487      */
488     public static String toString(ByteBuffer buffer)
489     {
490         return toString(buffer, StandardCharsets.ISO_8859_1);
491     }
492 
493     /* ------------------------------------------------------------ */
494     /** Convert the buffer to an UTF-8 String
495      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
496      * @return The buffer as a string.
497      */
498     public static String toUTF8String(ByteBuffer buffer)
499     {
500         return toString(buffer, StandardCharsets.UTF_8);
501     }
502 
503     /* ------------------------------------------------------------ */
504     /** Convert the buffer to an ISO-8859-1 String
505      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
506      * @param charset The {@link Charset} to use to convert the bytes
507      * @return The buffer as a string.
508      */
509     public static String toString(ByteBuffer buffer, Charset charset)
510     {
511         if (buffer == null)
512             return null;
513         byte[] array = buffer.hasArray() ? buffer.array() : null;
514         if (array == null)
515         {
516             byte[] to = new byte[buffer.remaining()];
517             buffer.slice().get(to);
518             return new String(to, 0, to.length, charset);
519         }
520         return new String(array, buffer.arrayOffset() + buffer.position(), buffer.remaining(), charset);
521     }
522 
523     /* ------------------------------------------------------------ */
524     /** Convert a partial buffer to an ISO-8859-1 String
525      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
526      * @param charset The {@link Charset} to use to convert the bytes
527      * @return The buffer as a string.
528      */
529     public static String toString(ByteBuffer buffer, int position, int length, Charset charset)
530     {
531         if (buffer == null)
532             return null;
533         byte[] array = buffer.hasArray() ? buffer.array() : null;
534         if (array == null)
535         {
536             ByteBuffer ro = buffer.asReadOnlyBuffer();
537             ro.position(position);
538             ro.limit(position + length);
539             byte[] to = new byte[length];
540             ro.get(to);
541             return new String(to, 0, to.length, charset);
542         }
543         return new String(array, buffer.arrayOffset() + position, length, charset);
544     }
545 
546     /* ------------------------------------------------------------ */
547     /**
548      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
549      *
550      * @param buffer
551      *            A buffer containing an integer in flush mode. The position is not changed.
552      * @return an int
553      */
554     public static int toInt(ByteBuffer buffer)
555     {
556         int val = 0;
557         boolean started = false;
558         boolean minus = false;
559 
560         for (int i = buffer.position(); i < buffer.limit(); i++)
561         {
562             byte b = buffer.get(i);
563             if (b <= SPACE)
564             {
565                 if (started)
566                     break;
567             }
568             else if (b >= '0' && b <= '9')
569             {
570                 val = val * 10 + (b - '0');
571                 started = true;
572             }
573             else if (b == MINUS && !started)
574             {
575                 minus = true;
576             }
577             else
578                 break;
579         }
580 
581         if (started)
582             return minus ? (-val) : val;
583         throw new NumberFormatException(toString(buffer));
584     }
585     
586     /* ------------------------------------------------------------ */
587     /**
588      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
589      *
590      * @param buffer
591      *            A buffer containing an integer in flush mode. The position is updated.
592      * @return an int
593      */
594     public static int takeInt(ByteBuffer buffer)
595     {
596         int val = 0;
597         boolean started = false;
598         boolean minus = false;
599         int i;
600         for (i = buffer.position(); i < buffer.limit(); i++)
601         {
602             byte b = buffer.get(i);
603             if (b <= SPACE)
604             {
605                 if (started)
606                     break;
607             }
608             else if (b >= '0' && b <= '9')
609             {
610                 val = val * 10 + (b - '0');
611                 started = true;
612             }
613             else if (b == MINUS && !started)
614             {
615                 minus = true;
616             }
617             else
618                 break;
619         }
620 
621         if (started)
622         {
623             buffer.position(i);
624             return minus ? (-val) : val;
625         }
626         throw new NumberFormatException(toString(buffer));
627     }
628 
629     /**
630      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
631      *
632      * @param buffer
633      *            A buffer containing an integer in flush mode. The position is not changed.
634      * @return an int
635      */
636     public static long toLong(ByteBuffer buffer)
637     {
638         long val = 0;
639         boolean started = false;
640         boolean minus = false;
641 
642         for (int i = buffer.position(); i < buffer.limit(); i++)
643         {
644             byte b = buffer.get(i);
645             if (b <= SPACE)
646             {
647                 if (started)
648                     break;
649             }
650             else if (b >= '0' && b <= '9')
651             {
652                 val = val * 10L + (b - '0');
653                 started = true;
654             }
655             else if (b == MINUS && !started)
656             {
657                 minus = true;
658             }
659             else
660                 break;
661         }
662 
663         if (started)
664             return minus ? (-val) : val;
665         throw new NumberFormatException(toString(buffer));
666     }
667 
668     public static void putHexInt(ByteBuffer buffer, int n)
669     {
670         if (n < 0)
671         {
672             buffer.put((byte)'-');
673 
674             if (n == Integer.MIN_VALUE)
675             {
676                 buffer.put((byte)(0x7f & '8'));
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                 buffer.put((byte)(0x7f & '0'));
682                 buffer.put((byte)(0x7f & '0'));
683                 buffer.put((byte)(0x7f & '0'));
684 
685                 return;
686             }
687             n = -n;
688         }
689 
690         if (n < 0x10)
691         {
692             buffer.put(DIGIT[n]);
693         }
694         else
695         {
696             boolean started = false;
697             // This assumes constant time int arithmatic
698             for (int hexDivisor : hexDivisors)
699             {
700                 if (n < hexDivisor)
701                 {
702                     if (started)
703                         buffer.put((byte)'0');
704                     continue;
705                 }
706 
707                 started = true;
708                 int d = n / hexDivisor;
709                 buffer.put(DIGIT[d]);
710                 n = n - d * hexDivisor;
711             }
712         }
713     }
714 
715     /* ------------------------------------------------------------ */
716     public static void putDecInt(ByteBuffer buffer, int n)
717     {
718         if (n < 0)
719         {
720             buffer.put((byte)'-');
721 
722             if (n == Integer.MIN_VALUE)
723             {
724                 buffer.put((byte)'2');
725                 n = 147483648;
726             }
727             else
728                 n = -n;
729         }
730 
731         if (n < 10)
732         {
733             buffer.put(DIGIT[n]);
734         }
735         else
736         {
737             boolean started = false;
738             // This assumes constant time int arithmatic
739             for (int decDivisor : decDivisors)
740             {
741                 if (n < decDivisor)
742                 {
743                     if (started)
744                         buffer.put((byte)'0');
745                     continue;
746                 }
747 
748                 started = true;
749                 int d = n / decDivisor;
750                 buffer.put(DIGIT[d]);
751                 n = n - d * decDivisor;
752             }
753         }
754     }
755 
756     public static void putDecLong(ByteBuffer buffer, long n)
757     {
758         if (n < 0)
759         {
760             buffer.put((byte)'-');
761 
762             if (n == Long.MIN_VALUE)
763             {
764                 buffer.put((byte)'9');
765                 n = 223372036854775808L;
766             }
767             else
768                 n = -n;
769         }
770 
771         if (n < 10)
772         {
773             buffer.put(DIGIT[(int)n]);
774         }
775         else
776         {
777             boolean started = false;
778             // This assumes constant time int arithmatic
779             for (long aDecDivisorsL : decDivisorsL)
780             {
781                 if (n < aDecDivisorsL)
782                 {
783                     if (started)
784                         buffer.put((byte)'0');
785                     continue;
786                 }
787 
788                 started = true;
789                 long d = n / aDecDivisorsL;
790                 buffer.put(DIGIT[(int)d]);
791                 n = n - d * aDecDivisorsL;
792             }
793         }
794     }
795 
796     public static ByteBuffer toBuffer(int value)
797     {
798         ByteBuffer buf = ByteBuffer.allocate(32);
799         putDecInt(buf, value);
800         return buf;
801     }
802 
803     public static ByteBuffer toBuffer(long value)
804     {
805         ByteBuffer buf = ByteBuffer.allocate(32);
806         putDecLong(buf, value);
807         return buf;
808     }
809 
810     public static ByteBuffer toBuffer(String s)
811     {
812         return ByteBuffer.wrap(s.getBytes(StandardCharsets.ISO_8859_1));
813     }
814 
815     public static ByteBuffer toDirectBuffer(String s)
816     {
817         byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
818         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
819         buf.put(bytes);
820         buf.flip();
821         return buf;
822     }
823 
824     public static ByteBuffer toBuffer(String s, Charset charset)
825     {
826         return ByteBuffer.wrap(s.getBytes(charset));
827     }
828 
829     public static ByteBuffer toDirectBuffer(String s, Charset charset)
830     {
831         byte[] bytes = s.getBytes(charset);
832         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
833         buf.put(bytes);
834         buf.flip();
835         return buf;
836     }
837 
838     /**
839      * Create a new ByteBuffer using provided byte array.
840      *
841      * @param array
842      *            the byte array to back buffer with.
843      * @return ByteBuffer with provided byte array, in flush mode
844      */
845     public static ByteBuffer toBuffer(byte array[])
846     {
847         return ByteBuffer.wrap(array);
848     }
849 
850     /**
851      * Create a new ByteBuffer using the provided byte array.
852      *
853      * @param array
854      *            the byte array to use.
855      * @param offset
856      *            the offset within the byte array to use from
857      * @param length
858      *            the length in bytes of the array to use
859      * @return ByteBuffer with provided byte array, in flush mode
860      */
861     public static ByteBuffer toBuffer(byte array[], int offset, int length)
862     {
863         return ByteBuffer.wrap(array, offset, length);
864     }
865 
866     public static ByteBuffer toMappedBuffer(File file) throws IOException
867     {
868         try (RandomAccessFile raf = new RandomAccessFile(file, "r"))
869         {
870             return raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
871         }
872     }
873 
874     public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
875     {
876         int len=(int)resource.length();
877         if (len<0)
878             throw new IllegalArgumentException("invalid resource: "+String.valueOf(resource)+" len="+len);
879         
880         ByteBuffer buffer = direct?BufferUtil.allocateDirect(len):BufferUtil.allocate(len);
881 
882         int pos=BufferUtil.flipToFill(buffer);
883         if (resource.getFile()!=null)
884             BufferUtil.readFrom(resource.getFile(),buffer);
885         else
886         {
887             try (InputStream is = resource.getInputStream();)
888             {
889                 BufferUtil.readFrom(is,len,buffer);
890             }
891         }
892         BufferUtil.flipToFlush(buffer,pos);
893         
894         return buffer;
895     }
896 
897     public static String toSummaryString(ByteBuffer buffer)
898     {
899         if (buffer == null)
900             return "null";
901         StringBuilder buf = new StringBuilder();
902         buf.append("[p=");
903         buf.append(buffer.position());
904         buf.append(",l=");
905         buf.append(buffer.limit());
906         buf.append(",c=");
907         buf.append(buffer.capacity());
908         buf.append(",r=");
909         buf.append(buffer.remaining());
910         buf.append("]");
911         return buf.toString();
912     }
913 
914     public static String toDetailString(ByteBuffer[] buffer)
915     {
916         StringBuilder builder = new StringBuilder();
917         builder.append('[');
918         for (int i = 0; i < buffer.length; i++)
919         {
920             if (i > 0) builder.append(',');
921             builder.append(toDetailString(buffer[i]));
922         }
923         builder.append(']');
924         return builder.toString();
925     }
926 
927 
928     
929     /* ------------------------------------------------------------ */
930     /** Convert Buffer to string ID independent of content
931      * @param buffer
932      * @return A string showing the buffer ID
933      */
934     private static void idString(ByteBuffer buffer, StringBuilder out) 
935     {
936         out.append(buffer.getClass().getSimpleName());
937         out.append("@");
938         if (buffer.hasArray() && buffer.arrayOffset()==4)
939         {
940             out.append('T');
941             byte[] array = buffer.array();
942             TypeUtil.toHex(array[0],out);
943             TypeUtil.toHex(array[1],out);
944             TypeUtil.toHex(array[2],out);
945             TypeUtil.toHex(array[3],out);
946         }
947         else
948             out.append(Integer.toHexString(System.identityHashCode(buffer)));
949     }
950     
951     /* ------------------------------------------------------------ */
952     /** Convert Buffer to string ID independent of content
953      * @param buffer
954      * @return A string showing the buffer ID
955      */
956     public static String toIDString(ByteBuffer buffer)
957     {
958         StringBuilder buf = new StringBuilder();
959         idString(buffer,buf);
960         return buf.toString();
961     }
962     
963     
964     /* ------------------------------------------------------------ */
965     /** Convert Buffer to a detail debug string of pointers and content
966      * @param buffer
967      * @return A string showing the pointers and content of the buffer
968      */
969     public static String toDetailString(ByteBuffer buffer)
970     {
971         if (buffer == null)
972             return "null";
973 
974         StringBuilder buf = new StringBuilder();
975         idString(buffer,buf);
976         buf.append("[p=");
977         buf.append(buffer.position());
978         buf.append(",l=");
979         buf.append(buffer.limit());
980         buf.append(",c=");
981         buf.append(buffer.capacity());
982         buf.append(",r=");
983         buf.append(buffer.remaining());
984         buf.append("]={");
985 
986         appendDebugString(buf,buffer);
987 
988         buf.append("}");
989 
990         return buf.toString();
991     }
992 
993     private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
994     {
995         for (int i = 0; i < buffer.position(); i++)
996         {
997             appendContentChar(buf,buffer.get(i));
998             if (i == 16 && buffer.position() > 32)
999             {
1000                 buf.append("...");
1001                 i = buffer.position() - 16;
1002             }
1003         }
1004         buf.append("<<<");
1005         for (int i = buffer.position(); i < buffer.limit(); i++)
1006         {
1007             appendContentChar(buf,buffer.get(i));
1008             if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
1009             {
1010                 buf.append("...");
1011                 i = buffer.limit() - 16;
1012             }
1013         }
1014         buf.append(">>>");
1015         int limit = buffer.limit();
1016         buffer.limit(buffer.capacity());
1017         for (int i = limit; i < buffer.capacity(); i++)
1018         {
1019             appendContentChar(buf,buffer.get(i));
1020             if (i == limit + 16 && buffer.capacity() > limit + 32)
1021             {
1022                 buf.append("...");
1023                 i = buffer.capacity() - 16;
1024             }
1025         }
1026         buffer.limit(limit);
1027     }
1028 
1029     private static void appendContentChar(StringBuilder buf, byte b)
1030     {
1031         if (b == '\\')
1032             buf.append("\\\\");   
1033         else if (b >= ' ')
1034             buf.append((char)b);
1035         else if (b == '\r')
1036             buf.append("\\r");
1037         else if (b == '\n')
1038             buf.append("\\n");
1039         else if (b == '\t')
1040             buf.append("\\t");
1041         else
1042             buf.append("\\x").append(TypeUtil.toHexString(b));
1043     }
1044 
1045     private final static int[] decDivisors =
1046             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1047 
1048     private final static int[] hexDivisors =
1049             {0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1};
1050 
1051     private final static long[] decDivisorsL =
1052             {1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
1053                     10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L};
1054 
1055     public static void putCRLF(ByteBuffer buffer)
1056     {
1057         buffer.put((byte)13);
1058         buffer.put((byte)10);
1059     }
1060 
1061     public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
1062     {
1063         if (prefix.remaining() > buffer.remaining())
1064             return false;
1065         int bi = buffer.position();
1066         for (int i = prefix.position(); i < prefix.limit(); i++)
1067             if (prefix.get(i) != buffer.get(bi++))
1068                 return false;
1069         return true;
1070     }
1071 
1072     public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
1073     {
1074         if (buffer==null)
1075             return allocate(capacity);
1076         
1077         if (buffer.capacity()>=capacity)
1078             return buffer;
1079         
1080         if (buffer.hasArray())
1081             return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
1082         
1083         throw new UnsupportedOperationException();
1084     }
1085 
1086 
1087 
1088 }