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.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 byte to a buffer
393      * @param to Buffer is flush mode
394      * @param b bytes 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             out.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
468         else
469         {
470             byte[] bytes = new byte[TEMP_BUFFER_SIZE];
471             while(buffer.hasRemaining()){
472                 int byteCountToWrite = Math.min(buffer.remaining(), TEMP_BUFFER_SIZE);
473                 buffer.get(bytes, 0, byteCountToWrite);
474                 out.write(bytes,0 , byteCountToWrite);
475             }
476         }
477     }
478 
479     /* ------------------------------------------------------------ */
480     /** Convert the buffer to an ISO-8859-1 String
481      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
482      * @return The buffer as a string.
483      */
484     public static String toString(ByteBuffer buffer)
485     {
486         return toString(buffer, StandardCharsets.ISO_8859_1);
487     }
488 
489     /* ------------------------------------------------------------ */
490     /** Convert the buffer to an UTF-8 String
491      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
492      * @return The buffer as a string.
493      */
494     public static String toUTF8String(ByteBuffer buffer)
495     {
496         return toString(buffer, StandardCharsets.UTF_8);
497     }
498 
499     /* ------------------------------------------------------------ */
500     /** Convert the buffer to an ISO-8859-1 String
501      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
502      * @param charset The {@link Charset} to use to convert the bytes
503      * @return The buffer as a string.
504      */
505     public static String toString(ByteBuffer buffer, Charset charset)
506     {
507         if (buffer == null)
508             return null;
509         byte[] array = buffer.hasArray() ? buffer.array() : null;
510         if (array == null)
511         {
512             byte[] to = new byte[buffer.remaining()];
513             buffer.slice().get(to);
514             return new String(to, 0, to.length, charset);
515         }
516         return new String(array, buffer.arrayOffset() + buffer.position(), buffer.remaining(), charset);
517     }
518 
519     /* ------------------------------------------------------------ */
520     /** Convert a partial buffer to an ISO-8859-1 String
521      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
522      * @param charset The {@link Charset} to use to convert the bytes
523      * @return The buffer as a string.
524      */
525     public static String toString(ByteBuffer buffer, int position, int length, Charset charset)
526     {
527         if (buffer == null)
528             return null;
529         byte[] array = buffer.hasArray() ? buffer.array() : null;
530         if (array == null)
531         {
532             ByteBuffer ro = buffer.asReadOnlyBuffer();
533             ro.position(position);
534             ro.limit(position + length);
535             byte[] to = new byte[length];
536             ro.get(to);
537             return new String(to, 0, to.length, charset);
538         }
539         return new String(array, buffer.arrayOffset() + position, length, charset);
540     }
541 
542     /* ------------------------------------------------------------ */
543     /**
544      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
545      *
546      * @param buffer
547      *            A buffer containing an integer in flush mode. The position is not changed.
548      * @return an int
549      */
550     public static int toInt(ByteBuffer buffer)
551     {
552         int val = 0;
553         boolean started = false;
554         boolean minus = false;
555 
556         for (int i = buffer.position(); i < buffer.limit(); i++)
557         {
558             byte b = buffer.get(i);
559             if (b <= SPACE)
560             {
561                 if (started)
562                     break;
563             }
564             else if (b >= '0' && b <= '9')
565             {
566                 val = val * 10 + (b - '0');
567                 started = true;
568             }
569             else if (b == MINUS && !started)
570             {
571                 minus = true;
572             }
573             else
574                 break;
575         }
576 
577         if (started)
578             return minus ? (-val) : val;
579         throw new NumberFormatException(toString(buffer));
580     }
581     
582     /* ------------------------------------------------------------ */
583     /**
584      * Convert buffer to an integer. 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 updated.
588      * @return an int
589      */
590     public static int takeInt(ByteBuffer buffer)
591     {
592         int val = 0;
593         boolean started = false;
594         boolean minus = false;
595         int i;
596         for (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 * 10 + (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         {
619             buffer.position(i);
620             return minus ? (-val) : val;
621         }
622         throw new NumberFormatException(toString(buffer));
623     }
624 
625     /**
626      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
627      *
628      * @param buffer
629      *            A buffer containing an integer in flush mode. The position is not changed.
630      * @return an int
631      */
632     public static long toLong(ByteBuffer buffer)
633     {
634         long val = 0;
635         boolean started = false;
636         boolean minus = false;
637 
638         for (int i = buffer.position(); i < buffer.limit(); i++)
639         {
640             byte b = buffer.get(i);
641             if (b <= SPACE)
642             {
643                 if (started)
644                     break;
645             }
646             else if (b >= '0' && b <= '9')
647             {
648                 val = val * 10L + (b - '0');
649                 started = true;
650             }
651             else if (b == MINUS && !started)
652             {
653                 minus = true;
654             }
655             else
656                 break;
657         }
658 
659         if (started)
660             return minus ? (-val) : val;
661         throw new NumberFormatException(toString(buffer));
662     }
663 
664     public static void putHexInt(ByteBuffer buffer, int n)
665     {
666         if (n < 0)
667         {
668             buffer.put((byte)'-');
669 
670             if (n == Integer.MIN_VALUE)
671             {
672                 buffer.put((byte)(0x7f & '8'));
673                 buffer.put((byte)(0x7f & '0'));
674                 buffer.put((byte)(0x7f & '0'));
675                 buffer.put((byte)(0x7f & '0'));
676                 buffer.put((byte)(0x7f & '0'));
677                 buffer.put((byte)(0x7f & '0'));
678                 buffer.put((byte)(0x7f & '0'));
679                 buffer.put((byte)(0x7f & '0'));
680 
681                 return;
682             }
683             n = -n;
684         }
685 
686         if (n < 0x10)
687         {
688             buffer.put(DIGIT[n]);
689         }
690         else
691         {
692             boolean started = false;
693             // This assumes constant time int arithmatic
694             for (int hexDivisor : hexDivisors)
695             {
696                 if (n < hexDivisor)
697                 {
698                     if (started)
699                         buffer.put((byte)'0');
700                     continue;
701                 }
702 
703                 started = true;
704                 int d = n / hexDivisor;
705                 buffer.put(DIGIT[d]);
706                 n = n - d * hexDivisor;
707             }
708         }
709     }
710 
711     /* ------------------------------------------------------------ */
712     public static void putDecInt(ByteBuffer buffer, int n)
713     {
714         if (n < 0)
715         {
716             buffer.put((byte)'-');
717 
718             if (n == Integer.MIN_VALUE)
719             {
720                 buffer.put((byte)'2');
721                 n = 147483648;
722             }
723             else
724                 n = -n;
725         }
726 
727         if (n < 10)
728         {
729             buffer.put(DIGIT[n]);
730         }
731         else
732         {
733             boolean started = false;
734             // This assumes constant time int arithmatic
735             for (int decDivisor : decDivisors)
736             {
737                 if (n < decDivisor)
738                 {
739                     if (started)
740                         buffer.put((byte)'0');
741                     continue;
742                 }
743 
744                 started = true;
745                 int d = n / decDivisor;
746                 buffer.put(DIGIT[d]);
747                 n = n - d * decDivisor;
748             }
749         }
750     }
751 
752     public static void putDecLong(ByteBuffer buffer, long n)
753     {
754         if (n < 0)
755         {
756             buffer.put((byte)'-');
757 
758             if (n == Long.MIN_VALUE)
759             {
760                 buffer.put((byte)'9');
761                 n = 223372036854775808L;
762             }
763             else
764                 n = -n;
765         }
766 
767         if (n < 10)
768         {
769             buffer.put(DIGIT[(int)n]);
770         }
771         else
772         {
773             boolean started = false;
774             // This assumes constant time int arithmatic
775             for (long aDecDivisorsL : decDivisorsL)
776             {
777                 if (n < aDecDivisorsL)
778                 {
779                     if (started)
780                         buffer.put((byte)'0');
781                     continue;
782                 }
783 
784                 started = true;
785                 long d = n / aDecDivisorsL;
786                 buffer.put(DIGIT[(int)d]);
787                 n = n - d * aDecDivisorsL;
788             }
789         }
790     }
791 
792     public static ByteBuffer toBuffer(int value)
793     {
794         ByteBuffer buf = ByteBuffer.allocate(32);
795         putDecInt(buf, value);
796         return buf;
797     }
798 
799     public static ByteBuffer toBuffer(long value)
800     {
801         ByteBuffer buf = ByteBuffer.allocate(32);
802         putDecLong(buf, value);
803         return buf;
804     }
805 
806     public static ByteBuffer toBuffer(String s)
807     {
808         return ByteBuffer.wrap(s.getBytes(StandardCharsets.ISO_8859_1));
809     }
810 
811     public static ByteBuffer toDirectBuffer(String s)
812     {
813         byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
814         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
815         buf.put(bytes);
816         buf.flip();
817         return buf;
818     }
819 
820     public static ByteBuffer toBuffer(String s, Charset charset)
821     {
822         return ByteBuffer.wrap(s.getBytes(charset));
823     }
824 
825     public static ByteBuffer toDirectBuffer(String s, Charset charset)
826     {
827         byte[] bytes = s.getBytes(charset);
828         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
829         buf.put(bytes);
830         buf.flip();
831         return buf;
832     }
833 
834     /**
835      * Create a new ByteBuffer using provided byte array.
836      *
837      * @param array
838      *            the byte array to back buffer with.
839      * @return ByteBuffer with provided byte array, in flush mode
840      */
841     public static ByteBuffer toBuffer(byte array[])
842     {
843         return ByteBuffer.wrap(array);
844     }
845 
846     /**
847      * Create a new ByteBuffer using the provided byte array.
848      *
849      * @param array
850      *            the byte array to use.
851      * @param offset
852      *            the offset within the byte array to use from
853      * @param length
854      *            the length in bytes of the array to use
855      * @return ByteBuffer with provided byte array, in flush mode
856      */
857     public static ByteBuffer toBuffer(byte array[], int offset, int length)
858     {
859         return ByteBuffer.wrap(array, offset, length);
860     }
861 
862     public static ByteBuffer toMappedBuffer(File file) throws IOException
863     {
864         try (RandomAccessFile raf = new RandomAccessFile(file, "r"))
865         {
866             return raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
867         }
868     }
869 
870     public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
871     {
872         int len=(int)resource.length();
873         if (len<0)
874             throw new IllegalArgumentException("invalid resource: "+String.valueOf(resource)+" len="+len);
875         
876         ByteBuffer buffer = direct?BufferUtil.allocateDirect(len):BufferUtil.allocate(len);
877 
878         int pos=BufferUtil.flipToFill(buffer);
879         if (resource.getFile()!=null)
880             BufferUtil.readFrom(resource.getFile(),buffer);
881         else
882         {
883             try (InputStream is = resource.getInputStream();)
884             {
885                 BufferUtil.readFrom(is,len,buffer);
886             }
887         }
888         BufferUtil.flipToFlush(buffer,pos);
889         
890         return buffer;
891     }
892 
893     public static String toSummaryString(ByteBuffer buffer)
894     {
895         if (buffer == null)
896             return "null";
897         StringBuilder buf = new StringBuilder();
898         buf.append("[p=");
899         buf.append(buffer.position());
900         buf.append(",l=");
901         buf.append(buffer.limit());
902         buf.append(",c=");
903         buf.append(buffer.capacity());
904         buf.append(",r=");
905         buf.append(buffer.remaining());
906         buf.append("]");
907         return buf.toString();
908     }
909 
910     public static String toDetailString(ByteBuffer[] buffer)
911     {
912         StringBuilder builder = new StringBuilder();
913         builder.append('[');
914         for (int i = 0; i < buffer.length; i++)
915         {
916             if (i > 0) builder.append(',');
917             builder.append(toDetailString(buffer[i]));
918         }
919         builder.append(']');
920         return builder.toString();
921     }
922 
923     /* ------------------------------------------------------------ */
924     /** Convert Buffer to a detail debug string of pointers and content
925      * @param buffer
926      * @return A string showing the pointers and content of the buffer
927      */
928     public static String toDetailString(ByteBuffer buffer)
929     {
930         if (buffer == null)
931             return "null";
932 
933         StringBuilder buf = new StringBuilder();
934         buf.append(buffer.getClass().getSimpleName());
935         buf.append("@");
936         if (buffer.hasArray())
937             buf.append(Integer.toHexString(Arrays.hashCode(buffer.array())));
938         else
939             buf.append(Integer.toHexString(buf.hashCode()));
940         buf.append("[p=");
941         buf.append(buffer.position());
942         buf.append(",l=");
943         buf.append(buffer.limit());
944         buf.append(",c=");
945         buf.append(buffer.capacity());
946         buf.append(",r=");
947         buf.append(buffer.remaining());
948         buf.append("]={");
949 
950         appendDebugString(buf,buffer);
951 
952         buf.append("}");
953 
954         return buf.toString();
955     }
956 
957     /* ------------------------------------------------------------ */
958     /** Convert buffer to a Debug String.
959      * @param buffer
960      * @return A string showing the escaped content of the buffer around the
961      * position and limit (marked with &lt;&lt;&lt; and &gt;&gt;&gt;)
962      */
963     public static String toDebugString(ByteBuffer buffer)
964     {
965         if (buffer == null)
966             return "null";
967         StringBuilder buf = new StringBuilder();
968         appendDebugString(buf,buffer);
969         return buf.toString();
970     }
971     
972     private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
973     {
974         for (int i = 0; i < buffer.position(); i++)
975         {
976             appendContentChar(buf,buffer.get(i));
977             if (i == 16 && buffer.position() > 32)
978             {
979                 buf.append("...");
980                 i = buffer.position() - 16;
981             }
982         }
983         buf.append("<<<");
984         for (int i = buffer.position(); i < buffer.limit(); i++)
985         {
986             appendContentChar(buf,buffer.get(i));
987             if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
988             {
989                 buf.append("...");
990                 i = buffer.limit() - 16;
991             }
992         }
993         buf.append(">>>");
994         int limit = buffer.limit();
995         buffer.limit(buffer.capacity());
996         for (int i = limit; i < buffer.capacity(); i++)
997         {
998             appendContentChar(buf,buffer.get(i));
999             if (i == limit + 16 && buffer.capacity() > limit + 32)
1000             {
1001                 buf.append("...");
1002                 i = buffer.capacity() - 16;
1003             }
1004         }
1005         buffer.limit(limit);
1006     }
1007 
1008     private static void appendContentChar(StringBuilder buf, byte b)
1009     {
1010         if (b == '\\')
1011             buf.append("\\\\");   
1012         else if (b >= ' ')
1013             buf.append((char)b);
1014         else if (b == '\r')
1015             buf.append("\\r");
1016         else if (b == '\n')
1017             buf.append("\\n");
1018         else if (b == '\t')
1019             buf.append("\\t");
1020         else
1021             buf.append("\\x").append(TypeUtil.toHexString(b));
1022     }
1023 
1024     private final static int[] decDivisors =
1025             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1026 
1027     private final static int[] hexDivisors =
1028             {0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1};
1029 
1030     private final static long[] decDivisorsL =
1031             {1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
1032                     10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L};
1033 
1034     public static void putCRLF(ByteBuffer buffer)
1035     {
1036         buffer.put((byte)13);
1037         buffer.put((byte)10);
1038     }
1039 
1040     public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
1041     {
1042         if (prefix.remaining() > buffer.remaining())
1043             return false;
1044         int bi = buffer.position();
1045         for (int i = prefix.position(); i < prefix.limit(); i++)
1046             if (prefix.get(i) != buffer.get(bi++))
1047                 return false;
1048         return true;
1049     }
1050 
1051     public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
1052     {
1053         if (buffer==null)
1054             return allocate(capacity);
1055         
1056         if (buffer.capacity()>=capacity)
1057             return buffer;
1058         
1059         if (buffer.hasArray())
1060             return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
1061         
1062         throw new UnsupportedOperationException();
1063     }
1064 
1065 
1066 
1067 }