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.Buffer;
27  import java.nio.BufferOverflowException;
28  import java.nio.ByteBuffer;
29  import java.nio.channels.FileChannel;
30  import java.nio.channels.FileChannel.MapMode;
31  import java.nio.charset.Charset;
32  import java.nio.charset.StandardCharsets;
33  import java.util.Arrays;
34  
35  import org.eclipse.jetty.util.resource.Resource;
36  
37  
38  /* ------------------------------------------------------------------------------- */
39  /**
40   * Buffer utility methods.
41   * <p>The standard JVM {@link ByteBuffer} can exist in two modes: In fill mode the valid
42   * data is between 0 and pos; In flush mode the valid data is between the pos and the limit.
43   * The various ByteBuffer methods assume a mode and some of them will switch or enforce a mode:
44   * Allocate and clear set fill mode; flip and compact switch modes; read and write assume fill 
45   * and flush modes.    This duality can result in confusing code such as:
46   * </p>
47   * <pre>
48   *     buffer.clear();
49   *     channel.write(buffer);
50   * </pre>
51   * <p>
52   * Which looks as if it should write no data, but in fact writes the buffer worth of garbage.
53   * </p>
54   * <p>
55   * The BufferUtil class provides a set of utilities that operate on the convention that ByteBuffers
56   * will always be left, passed in an API or returned from a method in the flush mode - ie with
57   * valid data between the pos and limit.    This convention is adopted so as to avoid confusion as to
58   * what state a buffer is in and to avoid excessive copying of data that can result with the usage 
59   * of compress.</p> 
60   * <p>
61   * Thus this class provides alternate implementations of {@link #allocate(int)}, 
62   * {@link #allocateDirect(int)} and {@link #clear(ByteBuffer)} that leave the buffer
63   * in flush mode.   Thus the following tests will pass:
64   * </p>
65   * <pre>
66   *     ByteBuffer buffer = BufferUtil.allocate(1024);
67   *     assert(buffer.remaining()==0);
68   *     BufferUtil.clear(buffer);
69   *     assert(buffer.remaining()==0);
70   * </pre>
71   * <p>If the BufferUtil methods {@link #fill(ByteBuffer, byte[], int, int)}, 
72   * {@link #append(ByteBuffer, byte[], int, int)} or {@link #put(ByteBuffer, ByteBuffer)} are used,
73   * then the caller does not need to explicitly switch the buffer to fill mode.    
74   * If the caller wishes to use other ByteBuffer bases libraries to fill a buffer, 
75   * then they can use explicit calls of #flipToFill(ByteBuffer) and #flipToFlush(ByteBuffer, int)
76   * to change modes.  Note because this convention attempts to avoid the copies of compact, the position
77   * is not set to zero on each fill cycle and so its value must be remembered:
78   * </p>
79   * <pre>
80   *      int pos = BufferUtil.flipToFill(buffer);
81   *      try
82   *      {
83   *          buffer.put(data);
84   *      }
85   *      finally
86   *      {
87   *          flipToFlush(buffer, pos);
88   *      }
89   * </pre>
90   * <p>
91   * The flipToFill method will effectively clear the buffer if it is empty and will compact the buffer if there is no space.
92   * </p>
93   */
94  public class BufferUtil
95  {
96      static final int TEMP_BUFFER_SIZE = 4096;
97      static final byte SPACE = 0x20;
98      static final byte MINUS = '-';
99      static final byte[] DIGIT =
100             {(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',
101                     (byte)'E', (byte)'F'};
102 
103     public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
104 
105     /* ------------------------------------------------------------ */
106     /** Allocate ByteBuffer in flush mode.
107      * The position and limit will both be zero, indicating that the buffer is
108      * empty and must be flipped before any data is put to it.
109      * @param capacity capacity of the allocated ByteBuffer
110      * @return Buffer
111      */
112     public static ByteBuffer allocate(int capacity)
113     {
114         ByteBuffer buf = ByteBuffer.allocate(capacity);
115         buf.limit(0);
116         return buf;
117     }
118 
119     /* ------------------------------------------------------------ */
120     /** Allocate ByteBuffer in flush mode.
121      * The position and limit will both be zero, indicating that the buffer is
122      * empty and in flush mode.
123      * @param capacity capacity of the allocated ByteBuffer
124      * @return Buffer
125      */
126     public static ByteBuffer allocateDirect(int capacity)
127     {
128         ByteBuffer buf = ByteBuffer.allocateDirect(capacity);
129         buf.limit(0);
130         return buf;
131     }
132 
133 
134     /* ------------------------------------------------------------ */
135     /** Clear the buffer to be empty in flush mode.
136      * The position and limit are set to 0;
137      * @param buffer The buffer to clear.
138      */
139     public static void clear(ByteBuffer buffer)
140     {
141         if (buffer != null)
142         {
143             buffer.position(0);
144             buffer.limit(0);
145         }
146     }
147 
148     /* ------------------------------------------------------------ */
149     /** Clear the buffer to be empty in fill mode.
150      * The position is set to 0 and the limit is set to the capacity.
151      * @param buffer The buffer to clear.
152      */
153     public static void clearToFill(ByteBuffer buffer)
154     {
155         if (buffer != null)
156         {
157             buffer.position(0);
158             buffer.limit(buffer.capacity());
159         }
160     }
161 
162     /* ------------------------------------------------------------ */
163     /** Flip the buffer to fill mode.
164      * The position is set to the first unused position in the buffer
165      * (the old limit) and the limit is set to the capacity.
166      * If the buffer is empty, then this call is effectively {@link #clearToFill(ByteBuffer)}.
167      * If there is no unused space to fill, a {@link ByteBuffer#compact()} is done to attempt
168      * to create space.
169      * <p>
170      * This method is used as a replacement to {@link ByteBuffer#compact()}.
171      *
172      * @param buffer The buffer to flip
173      * @return The position of the valid data before the flipped position. This value should be
174      * passed to a subsequent call to {@link #flipToFlush(ByteBuffer, int)}
175      */
176     public static int flipToFill(ByteBuffer buffer)
177     {
178         int position = buffer.position();
179         int limit = buffer.limit();
180         if (position == limit)
181         {
182             buffer.position(0);
183             buffer.limit(buffer.capacity());
184             return 0;
185         }
186 
187         int capacity = buffer.capacity();
188         if (limit == capacity)
189         {
190             buffer.compact();
191             return 0;
192         }
193 
194         buffer.position(limit);
195         buffer.limit(capacity);
196         return position;
197     }
198 
199 
200     /* ------------------------------------------------------------ */
201     /** Flip the buffer to Flush mode.
202      * The limit is set to the first unused byte(the old position) and
203      * the position is set to the passed position.
204      * <p>
205      * This method is used as a replacement of {@link Buffer#flip()}.
206      * @param buffer   the buffer to be flipped
207      * @param position The position of valid data to flip to. This should
208      * be the return value of the previous call to {@link #flipToFill(ByteBuffer)}
209      */
210     public static void flipToFlush(ByteBuffer buffer, int position)
211     {
212         buffer.limit(buffer.position());
213         buffer.position(position);
214     }
215 
216 
217     /* ------------------------------------------------------------ */
218     /** Convert a ByteBuffer to a byte array.
219      * @param buffer The buffer to convert in flush mode. The buffer is not altered.
220      * @return An array of bytes duplicated from the buffer.
221      */
222     public static byte[] toArray(ByteBuffer buffer)
223     {
224         if (buffer.hasArray())
225         {
226             byte[] array = buffer.array();
227             int from=buffer.arrayOffset() + buffer.position();
228             return Arrays.copyOfRange(array,from,from+buffer.remaining());
229         }
230         else
231         {
232             byte[] to = new byte[buffer.remaining()];
233             buffer.slice().get(to);
234             return to;
235         }
236     }
237 
238     /* ------------------------------------------------------------ */
239     /** Check for an empty or null buffer.
240      * @param buf the buffer to check
241      * @return true if the buffer is null or empty.
242      */
243     public static boolean isEmpty(ByteBuffer buf)
244     {
245         return buf == null || buf.remaining() == 0;
246     }
247 
248     /* ------------------------------------------------------------ */
249     /** Check for a non null and non empty buffer.
250      * @param buf the buffer to check
251      * @return true if the buffer is not null and not empty.
252      */
253     public static boolean hasContent(ByteBuffer buf)
254     {
255         return buf != null && buf.remaining() > 0;
256     }
257 
258     /* ------------------------------------------------------------ */
259     /** Check for a non null and full buffer.
260      * @param buf the buffer to check
261      * @return true if the buffer is not null and the limit equals the capacity.
262      */
263     public static boolean isFull(ByteBuffer buf)
264     {
265         return buf != null && buf.limit() == buf.capacity();
266     }
267 
268     /* ------------------------------------------------------------ */
269     /** Get remaining from null checked buffer
270      * @param buffer The buffer to get the remaining from, in flush mode.
271      * @return 0 if the buffer is null, else the bytes remaining in the buffer.
272      */
273     public static int length(ByteBuffer buffer)
274     {
275         return buffer == null ? 0 : buffer.remaining();
276     }
277 
278     /* ------------------------------------------------------------ */
279     /** Get the space from the limit to the capacity
280      * @param buffer the buffer to get the space from
281      * @return space
282      */
283     public static int space(ByteBuffer buffer)
284     {
285         if (buffer == null)
286             return 0;
287         return buffer.capacity() - buffer.limit();
288     }
289 
290     /* ------------------------------------------------------------ */
291     /** Compact the buffer
292      * @param buffer the buffer to compact
293      * @return true if the compact made a full buffer have space
294      */
295     public static boolean compact(ByteBuffer buffer)
296     {
297         if (buffer.position()==0)
298             return false;
299         boolean full = buffer.limit() == buffer.capacity();
300         buffer.compact().flip();
301         return full && buffer.limit() < buffer.capacity();
302     }
303 
304     /* ------------------------------------------------------------ */
305     /**
306      * Put data from one buffer into another, avoiding over/under flows
307      * @param from Buffer to take bytes from in flush mode
308      * @param to   Buffer to put bytes to in fill mode.
309      * @return number of bytes moved
310      */
311     public static int put(ByteBuffer from, ByteBuffer to)
312     {
313         int put;
314         int remaining = from.remaining();
315         if (remaining > 0)
316         {
317             if (remaining <= to.remaining())
318             {
319                 to.put(from);
320                 put = remaining;
321                 from.position(from.limit());
322             }
323             else if (from.hasArray())
324             {
325                 put = to.remaining();
326                 to.put(from.array(), from.arrayOffset() + from.position(), put);
327                 from.position(from.position() + put);
328             }
329             else
330             {
331                 put = to.remaining();
332                 ByteBuffer slice = from.slice();
333                 slice.limit(put);
334                 to.put(slice);
335                 from.position(from.position() + put);
336             }
337         }
338         else
339             put = 0;
340 
341         return put;
342     }
343 
344     /* ------------------------------------------------------------ */
345     /**
346      * Put data from one buffer into another, avoiding over/under flows
347      * @param from Buffer to take bytes from in flush mode
348      * @param to   Buffer to put bytes to in flush mode. The buffer is flipToFill before the put and flipToFlush after.
349      * @return number of bytes moved
350      * @deprecated use {@link #append(ByteBuffer, ByteBuffer)}
351      */
352     public static int flipPutFlip(ByteBuffer from, ByteBuffer to)
353     {
354         return append(to,from);
355     }
356 
357     /* ------------------------------------------------------------ */
358     /** Append bytes to a buffer.
359      * @param to Buffer is flush mode
360      * @param b bytes to append
361      * @param off offset into byte
362      * @param len length to append
363      * @throws BufferOverflowException if unable to append buffer due to space limits
364      */
365     public static void append(ByteBuffer to, byte[] b, int off, int len) throws BufferOverflowException
366     {
367         int pos = flipToFill(to);
368         try
369         {
370             to.put(b, off, len);
371         }
372         finally
373         {
374             flipToFlush(to, pos);
375         }
376     }
377 
378     /* ------------------------------------------------------------ */
379     /** Appends a byte to a buffer
380      * @param to Buffer is flush mode
381      * @param b byte to append
382      */
383     public static void append(ByteBuffer to, byte b)
384     {
385         int pos = flipToFill(to);
386         try
387         {
388             to.put(b);
389         }
390         finally
391         {
392             flipToFlush(to, pos);
393         }
394     }
395 
396     /* ------------------------------------------------------------ */
397     /** Appends a buffer to a buffer
398      * @param to Buffer is flush mode
399      * @param b buffer to append
400      * @return The position of the valid data before the flipped position.
401      */
402     public static int append(ByteBuffer to, ByteBuffer b)
403     {
404         int pos = flipToFill(to);
405         try
406         {
407             return put(b, to);
408         }
409         finally
410         {
411             flipToFlush(to, pos);
412         }
413     }
414 
415     /* ------------------------------------------------------------ */
416     /**
417      * Like append, but does not throw {@link BufferOverflowException}
418      * @param to Buffer is flush mode
419      * @param b bytes to fill
420      * @param off offset into byte
421      * @param len length to fill
422      * @return The position of the valid data before the flipped position.
423      */
424     public static int fill(ByteBuffer to, byte[] b, int off, int len)
425     {
426         int pos = flipToFill(to);
427         try
428         {
429             int remaining = to.remaining();
430             int take = remaining < len ? remaining : len;
431             to.put(b, off, take);
432             return take;
433         }
434         finally
435         {
436             flipToFlush(to, pos);
437         }
438     }
439 
440 
441     /* ------------------------------------------------------------ */
442     public static void readFrom(File file, ByteBuffer buffer) throws IOException
443     {
444         try(RandomAccessFile raf = new RandomAccessFile(file,"r"))
445         {
446             FileChannel channel = raf.getChannel();
447             long needed=raf.length();
448 
449             while (needed>0 && buffer.hasRemaining())
450                 needed=needed-channel.read(buffer);
451         }
452     }
453 
454     /* ------------------------------------------------------------ */
455     public static void readFrom(InputStream is, int needed, ByteBuffer buffer) throws IOException
456     {
457         ByteBuffer tmp = allocate(8192);
458 
459         while (needed > 0 && buffer.hasRemaining())
460         {
461             int l = is.read(tmp.array(), 0, 8192);
462             if (l < 0)
463                 break;
464             tmp.position(0);
465             tmp.limit(l);
466             buffer.put(tmp);
467         }
468     }
469 
470     /* ------------------------------------------------------------ */
471     public static void writeTo(ByteBuffer buffer, OutputStream out) throws IOException
472     {
473         if (buffer.hasArray())
474         {
475             out.write(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining());
476             // update buffer position, in way similar to non-array version of writeTo
477             buffer.position(buffer.position() + buffer.remaining());
478         }
479         else
480         {
481             byte[] bytes = new byte[TEMP_BUFFER_SIZE];
482             while(buffer.hasRemaining()){
483                 int byteCountToWrite = Math.min(buffer.remaining(), TEMP_BUFFER_SIZE);
484                 buffer.get(bytes, 0, byteCountToWrite);
485                 out.write(bytes,0 , byteCountToWrite);
486             }
487         }
488     }
489 
490     /* ------------------------------------------------------------ */
491     /** Convert the buffer to an ISO-8859-1 String
492      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
493      * @return The buffer as a string.
494      */
495     public static String toString(ByteBuffer buffer)
496     {
497         return toString(buffer, StandardCharsets.ISO_8859_1);
498     }
499 
500     /* ------------------------------------------------------------ */
501     /** Convert the buffer to an UTF-8 String
502      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
503      * @return The buffer as a string.
504      */
505     public static String toUTF8String(ByteBuffer buffer)
506     {
507         return toString(buffer, StandardCharsets.UTF_8);
508     }
509 
510     /* ------------------------------------------------------------ */
511     /** Convert the buffer to an ISO-8859-1 String
512      * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
513      * @param charset The {@link Charset} to use to convert the bytes
514      * @return The buffer as a string.
515      */
516     public static String toString(ByteBuffer buffer, Charset charset)
517     {
518         if (buffer == null)
519             return null;
520         byte[] array = buffer.hasArray() ? buffer.array() : null;
521         if (array == null)
522         {
523             byte[] to = new byte[buffer.remaining()];
524             buffer.slice().get(to);
525             return new String(to, 0, to.length, charset);
526         }
527         return new String(array, buffer.arrayOffset() + buffer.position(), buffer.remaining(), charset);
528     }
529 
530     /* ------------------------------------------------------------ */
531     /** Convert a partial buffer to a String.
532      * 
533      * @param buffer the buffer to convert 
534      * @param position The position in the buffer to start the string from
535      * @param length The length of the buffer
536      * @param charset The {@link Charset} to use to convert the bytes
537      * @return  The buffer as a string.
538      */
539     public static String toString(ByteBuffer buffer, int position, int length, Charset charset)
540     {
541         if (buffer == null)
542             return null;
543         byte[] array = buffer.hasArray() ? buffer.array() : null;
544         if (array == null)
545         {
546             ByteBuffer ro = buffer.asReadOnlyBuffer();
547             ro.position(position);
548             ro.limit(position + length);
549             byte[] to = new byte[length];
550             ro.get(to);
551             return new String(to, 0, to.length, charset);
552         }
553         return new String(array, buffer.arrayOffset() + position, length, charset);
554     }
555 
556     /* ------------------------------------------------------------ */
557     /**
558      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
559      *
560      * @param buffer
561      *            A buffer containing an integer in flush mode. The position is not changed.
562      * @return an int
563      */
564     public static int toInt(ByteBuffer buffer)
565     {
566         return toInt(buffer,buffer.position(),buffer.remaining());
567     }
568 
569     /* ------------------------------------------------------------ */
570     /**
571      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an
572      * IllegalArgumentException is thrown
573      *
574      * @param buffer
575      *            A buffer containing an integer in flush mode. The position is not changed.
576      * @param position
577      *            the position in the buffer to start reading from
578      * @param length
579      *            the length of the buffer to use for conversion
580      * @return an int of the buffer bytes
581      */
582     public static int toInt(ByteBuffer buffer, int position, int length)
583     {
584         int val = 0;
585         boolean started = false;
586         boolean minus = false;
587 
588         int limit = position+length;
589         
590         if (length<=0)
591             throw new NumberFormatException(toString(buffer,position,length,StandardCharsets.UTF_8));
592         
593         for (int i = position; i < limit; i++)
594         {
595             byte b = buffer.get(i);
596             if (b <= SPACE)
597             {
598                 if (started)
599                     break;
600             }
601             else if (b >= '0' && b <= '9')
602             {
603                 val = val * 10 + (b - '0');
604                 started = true;
605             }
606             else if (b == MINUS && !started)
607             {
608                 minus = true;
609             }
610             else
611                 break;
612         }
613 
614         if (started)
615             return minus ? (-val) : val;
616         throw new NumberFormatException(toString(buffer));
617     }
618     
619     /* ------------------------------------------------------------ */
620     /**
621      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
622      *
623      * @param buffer
624      *            A buffer containing an integer in flush mode. The position is updated.
625      * @return an int
626      */
627     public static int takeInt(ByteBuffer buffer)
628     {
629         int val = 0;
630         boolean started = false;
631         boolean minus = false;
632         int i;
633         for (i = buffer.position(); i < buffer.limit(); i++)
634         {
635             byte b = buffer.get(i);
636             if (b <= SPACE)
637             {
638                 if (started)
639                     break;
640             }
641             else if (b >= '0' && b <= '9')
642             {
643                 val = val * 10 + (b - '0');
644                 started = true;
645             }
646             else if (b == MINUS && !started)
647             {
648                 minus = true;
649             }
650             else
651                 break;
652         }
653 
654         if (started)
655         {
656             buffer.position(i);
657             return minus ? (-val) : val;
658         }
659         throw new NumberFormatException(toString(buffer));
660     }
661 
662     /**
663      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
664      *
665      * @param buffer
666      *            A buffer containing an integer in flush mode. The position is not changed.
667      * @return an int
668      */
669     public static long toLong(ByteBuffer buffer)
670     {
671         long val = 0;
672         boolean started = false;
673         boolean minus = false;
674 
675         for (int i = buffer.position(); i < buffer.limit(); i++)
676         {
677             byte b = buffer.get(i);
678             if (b <= SPACE)
679             {
680                 if (started)
681                     break;
682             }
683             else if (b >= '0' && b <= '9')
684             {
685                 val = val * 10L + (b - '0');
686                 started = true;
687             }
688             else if (b == MINUS && !started)
689             {
690                 minus = true;
691             }
692             else
693                 break;
694         }
695 
696         if (started)
697             return minus ? (-val) : val;
698         throw new NumberFormatException(toString(buffer));
699     }
700 
701     public static void putHexInt(ByteBuffer buffer, int n)
702     {
703         if (n < 0)
704         {
705             buffer.put((byte)'-');
706 
707             if (n == Integer.MIN_VALUE)
708             {
709                 buffer.put((byte)(0x7f & '8'));
710                 buffer.put((byte)(0x7f & '0'));
711                 buffer.put((byte)(0x7f & '0'));
712                 buffer.put((byte)(0x7f & '0'));
713                 buffer.put((byte)(0x7f & '0'));
714                 buffer.put((byte)(0x7f & '0'));
715                 buffer.put((byte)(0x7f & '0'));
716                 buffer.put((byte)(0x7f & '0'));
717 
718                 return;
719             }
720             n = -n;
721         }
722 
723         if (n < 0x10)
724         {
725             buffer.put(DIGIT[n]);
726         }
727         else
728         {
729             boolean started = false;
730             // This assumes constant time int arithmatic
731             for (int hexDivisor : hexDivisors)
732             {
733                 if (n < hexDivisor)
734                 {
735                     if (started)
736                         buffer.put((byte)'0');
737                     continue;
738                 }
739 
740                 started = true;
741                 int d = n / hexDivisor;
742                 buffer.put(DIGIT[d]);
743                 n = n - d * hexDivisor;
744             }
745         }
746     }
747 
748     /* ------------------------------------------------------------ */
749     public static void putDecInt(ByteBuffer buffer, int n)
750     {
751         if (n < 0)
752         {
753             buffer.put((byte)'-');
754 
755             if (n == Integer.MIN_VALUE)
756             {
757                 buffer.put((byte)'2');
758                 n = 147483648;
759             }
760             else
761                 n = -n;
762         }
763 
764         if (n < 10)
765         {
766             buffer.put(DIGIT[n]);
767         }
768         else
769         {
770             boolean started = false;
771             // This assumes constant time int arithmatic
772             for (int decDivisor : decDivisors)
773             {
774                 if (n < decDivisor)
775                 {
776                     if (started)
777                         buffer.put((byte)'0');
778                     continue;
779                 }
780 
781                 started = true;
782                 int d = n / decDivisor;
783                 buffer.put(DIGIT[d]);
784                 n = n - d * decDivisor;
785             }
786         }
787     }
788 
789     public static void putDecLong(ByteBuffer buffer, long n)
790     {
791         if (n < 0)
792         {
793             buffer.put((byte)'-');
794 
795             if (n == Long.MIN_VALUE)
796             {
797                 buffer.put((byte)'9');
798                 n = 223372036854775808L;
799             }
800             else
801                 n = -n;
802         }
803 
804         if (n < 10)
805         {
806             buffer.put(DIGIT[(int)n]);
807         }
808         else
809         {
810             boolean started = false;
811             // This assumes constant time int arithmatic
812             for (long aDecDivisorsL : decDivisorsL)
813             {
814                 if (n < aDecDivisorsL)
815                 {
816                     if (started)
817                         buffer.put((byte)'0');
818                     continue;
819                 }
820 
821                 started = true;
822                 long d = n / aDecDivisorsL;
823                 buffer.put(DIGIT[(int)d]);
824                 n = n - d * aDecDivisorsL;
825             }
826         }
827     }
828 
829     public static ByteBuffer toBuffer(int value)
830     {
831         ByteBuffer buf = ByteBuffer.allocate(32);
832         putDecInt(buf, value);
833         return buf;
834     }
835 
836     public static ByteBuffer toBuffer(long value)
837     {
838         ByteBuffer buf = ByteBuffer.allocate(32);
839         putDecLong(buf, value);
840         return buf;
841     }
842 
843     public static ByteBuffer toBuffer(String s)
844     {
845         return toBuffer(s, StandardCharsets.ISO_8859_1);
846     }
847 
848     public static ByteBuffer toBuffer(String s, Charset charset)
849     {
850         if (s == null)
851             return EMPTY_BUFFER;
852         return toBuffer(s.getBytes(charset));
853     }
854 
855     /**
856      * Create a new ByteBuffer using provided byte array.
857      *
858      * @param array
859      *            the byte array to back buffer with.
860      * @return ByteBuffer with provided byte array, in flush mode
861      */
862     public static ByteBuffer toBuffer(byte[] array)
863     {
864         if (array == null)
865             return EMPTY_BUFFER;
866         return toBuffer(array, 0, array.length);
867     }
868 
869     /**
870      * Create a new ByteBuffer using the provided byte array.
871      *
872      * @param array
873      *            the byte array to use.
874      * @param offset
875      *            the offset within the byte array to use from
876      * @param length
877      *            the length in bytes of the array to use
878      * @return ByteBuffer with provided byte array, in flush mode
879      */
880     public static ByteBuffer toBuffer(byte array[], int offset, int length)
881     {
882         if (array == null)
883             return EMPTY_BUFFER;
884         return ByteBuffer.wrap(array, offset, length);
885     }
886 
887     public static ByteBuffer toDirectBuffer(String s)
888     {
889         return toDirectBuffer(s, StandardCharsets.ISO_8859_1);
890     }
891 
892     public static ByteBuffer toDirectBuffer(String s, Charset charset)
893     {
894         if (s == null)
895             return EMPTY_BUFFER;
896         byte[] bytes = s.getBytes(charset);
897         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
898         buf.put(bytes);
899         buf.flip();
900         return buf;
901     }
902 
903     public static ByteBuffer toMappedBuffer(File file) throws IOException
904     {
905         try (RandomAccessFile raf = new RandomAccessFile(file, "r"))
906         {
907             return raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
908         }
909     }
910 
911     public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
912     {
913         int len=(int)resource.length();
914         if (len<0)
915             throw new IllegalArgumentException("invalid resource: "+String.valueOf(resource)+" len="+len);
916         
917         ByteBuffer buffer = direct?BufferUtil.allocateDirect(len):BufferUtil.allocate(len);
918 
919         int pos=BufferUtil.flipToFill(buffer);
920         if (resource.getFile()!=null)
921             BufferUtil.readFrom(resource.getFile(),buffer);
922         else
923         {
924             try (InputStream is = resource.getInputStream();)
925             {
926                 BufferUtil.readFrom(is,len,buffer);
927             }
928         }
929         BufferUtil.flipToFlush(buffer,pos);
930         
931         return buffer;
932     }
933 
934     public static String toSummaryString(ByteBuffer buffer)
935     {
936         if (buffer == null)
937             return "null";
938         StringBuilder buf = new StringBuilder();
939         buf.append("[p=");
940         buf.append(buffer.position());
941         buf.append(",l=");
942         buf.append(buffer.limit());
943         buf.append(",c=");
944         buf.append(buffer.capacity());
945         buf.append(",r=");
946         buf.append(buffer.remaining());
947         buf.append("]");
948         return buf.toString();
949     }
950 
951     public static String toDetailString(ByteBuffer[] buffer)
952     {
953         StringBuilder builder = new StringBuilder();
954         builder.append('[');
955         for (int i = 0; i < buffer.length; i++)
956         {
957             if (i > 0) builder.append(',');
958             builder.append(toDetailString(buffer[i]));
959         }
960         builder.append(']');
961         return builder.toString();
962     }
963 
964 
965     
966     /* ------------------------------------------------------------ */
967     /** Convert Buffer to string ID independent of content
968      */
969     private static void idString(ByteBuffer buffer, StringBuilder out) 
970     {
971         out.append(buffer.getClass().getSimpleName());
972         out.append("@");
973         if (buffer.hasArray() && buffer.arrayOffset()==4)
974         {
975             out.append('T');
976             byte[] array = buffer.array();
977             TypeUtil.toHex(array[0],out);
978             TypeUtil.toHex(array[1],out);
979             TypeUtil.toHex(array[2],out);
980             TypeUtil.toHex(array[3],out);
981         }
982         else
983             out.append(Integer.toHexString(System.identityHashCode(buffer)));
984     }
985     
986     /* ------------------------------------------------------------ */
987     /** Convert Buffer to string ID independent of content
988      * @param buffer the buffet to generate a string ID from
989      * @return A string showing the buffer ID
990      */
991     public static String toIDString(ByteBuffer buffer)
992     {
993         StringBuilder buf = new StringBuilder();
994         idString(buffer,buf);
995         return buf.toString();
996     }
997     
998     
999     /* ------------------------------------------------------------ */
1000     /** Convert Buffer to a detail debug string of pointers and content
1001      * @param buffer the buffer to generate a detail string from
1002      * @return A string showing the pointers and content of the buffer
1003      */
1004     public static String toDetailString(ByteBuffer buffer)
1005     {
1006         if (buffer == null)
1007             return "null";
1008 
1009         StringBuilder buf = new StringBuilder();
1010         idString(buffer,buf);
1011         buf.append("[p=");
1012         buf.append(buffer.position());
1013         buf.append(",l=");
1014         buf.append(buffer.limit());
1015         buf.append(",c=");
1016         buf.append(buffer.capacity());
1017         buf.append(",r=");
1018         buf.append(buffer.remaining());
1019         buf.append("]={");
1020 
1021         appendDebugString(buf,buffer);
1022 
1023         buf.append("}");
1024 
1025         return buf.toString();
1026     }
1027 
1028     private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
1029     {
1030         for (int i = 0; i < buffer.position(); i++)
1031         {
1032             appendContentChar(buf,buffer.get(i));
1033             if (i == 16 && buffer.position() > 32)
1034             {
1035                 buf.append("...");
1036                 i = buffer.position() - 16;
1037             }
1038         }
1039         buf.append("<<<");
1040         for (int i = buffer.position(); i < buffer.limit(); i++)
1041         {
1042             appendContentChar(buf,buffer.get(i));
1043             if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
1044             {
1045                 buf.append("...");
1046                 i = buffer.limit() - 16;
1047             }
1048         }
1049         buf.append(">>>");
1050         int limit = buffer.limit();
1051         buffer.limit(buffer.capacity());
1052         for (int i = limit; i < buffer.capacity(); i++)
1053         {
1054             appendContentChar(buf,buffer.get(i));
1055             if (i == limit + 16 && buffer.capacity() > limit + 32)
1056             {
1057                 buf.append("...");
1058                 i = buffer.capacity() - 16;
1059             }
1060         }
1061         buffer.limit(limit);
1062     }
1063 
1064     private static void appendContentChar(StringBuilder buf, byte b)
1065     {
1066         if (b == '\\')
1067             buf.append("\\\\");   
1068         else if (b >= ' ')
1069             buf.append((char)b);
1070         else if (b == '\r')
1071             buf.append("\\r");
1072         else if (b == '\n')
1073             buf.append("\\n");
1074         else if (b == '\t')
1075             buf.append("\\t");
1076         else
1077             buf.append("\\x").append(TypeUtil.toHexString(b));
1078     }
1079     
1080 
1081     /* ------------------------------------------------------------ */
1082     /** Convert buffer to a Hex Summary String.
1083      * @param buffer the buffer to generate a hex byte summary from
1084      * @return A string showing the escaped content of the buffer around the
1085      * position and limit (marked with &lt;&lt;&lt; and &gt;&gt;&gt;)
1086      */
1087     public static String toHexSummary(ByteBuffer buffer)
1088     {
1089         if (buffer == null)
1090             return "null";
1091         StringBuilder buf = new StringBuilder();
1092         
1093         buf.append("b[").append(buffer.remaining()).append("]=");
1094         for (int i = buffer.position(); i < buffer.limit(); i++)
1095         {
1096             TypeUtil.toHex(buffer.get(i),buf);
1097             if (i == buffer.position() + 24 && buffer.limit() > buffer.position() + 32)
1098             {
1099                 buf.append("...");
1100                 i = buffer.limit() - 8;
1101             }
1102         }
1103         return buf.toString();
1104     }
1105 
1106 
1107     private final static int[] decDivisors =
1108             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1109 
1110     private final static int[] hexDivisors =
1111             {0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1};
1112 
1113     private final static long[] decDivisorsL =
1114             {1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
1115                     10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L};
1116 
1117     public static void putCRLF(ByteBuffer buffer)
1118     {
1119         buffer.put((byte)13);
1120         buffer.put((byte)10);
1121     }
1122 
1123     public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
1124     {
1125         if (prefix.remaining() > buffer.remaining())
1126             return false;
1127         int bi = buffer.position();
1128         for (int i = prefix.position(); i < prefix.limit(); i++)
1129             if (prefix.get(i) != buffer.get(bi++))
1130                 return false;
1131         return true;
1132     }
1133 
1134     public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
1135     {
1136         if (buffer==null)
1137             return allocate(capacity);
1138         
1139         if (buffer.capacity()>=capacity)
1140             return buffer;
1141         
1142         if (buffer.hasArray())
1143             return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
1144         
1145         throw new UnsupportedOperationException();
1146     }
1147 
1148 
1149 
1150 }