]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/BufferUtil.java
Merge "Update notes about password security"
[gigi.git] / lib / jetty / org / eclipse / jetty / util / BufferUtil.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 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      */
933     private static void idString(ByteBuffer buffer, StringBuilder out) 
934     {
935         out.append(buffer.getClass().getSimpleName());
936         out.append("@");
937         if (buffer.hasArray() && buffer.arrayOffset()==4)
938         {
939             out.append('T');
940             byte[] array = buffer.array();
941             TypeUtil.toHex(array[0],out);
942             TypeUtil.toHex(array[1],out);
943             TypeUtil.toHex(array[2],out);
944             TypeUtil.toHex(array[3],out);
945         }
946         else
947             out.append(Integer.toHexString(System.identityHashCode(buffer)));
948     }
949     
950     /* ------------------------------------------------------------ */
951     /** Convert Buffer to string ID independent of content
952      * @param buffer
953      * @return A string showing the buffer ID
954      */
955     public static String toIDString(ByteBuffer buffer)
956     {
957         StringBuilder buf = new StringBuilder();
958         idString(buffer,buf);
959         return buf.toString();
960     }
961     
962     
963     /* ------------------------------------------------------------ */
964     /** Convert Buffer to a detail debug string of pointers and content
965      * @param buffer
966      * @return A string showing the pointers and content of the buffer
967      */
968     public static String toDetailString(ByteBuffer buffer)
969     {
970         if (buffer == null)
971             return "null";
972
973         StringBuilder buf = new StringBuilder();
974         idString(buffer,buf);
975         buf.append("[p=");
976         buf.append(buffer.position());
977         buf.append(",l=");
978         buf.append(buffer.limit());
979         buf.append(",c=");
980         buf.append(buffer.capacity());
981         buf.append(",r=");
982         buf.append(buffer.remaining());
983         buf.append("]={");
984
985         appendDebugString(buf,buffer);
986
987         buf.append("}");
988
989         return buf.toString();
990     }
991
992     private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
993     {
994         for (int i = 0; i < buffer.position(); i++)
995         {
996             appendContentChar(buf,buffer.get(i));
997             if (i == 16 && buffer.position() > 32)
998             {
999                 buf.append("...");
1000                 i = buffer.position() - 16;
1001             }
1002         }
1003         buf.append("<<<");
1004         for (int i = buffer.position(); i < buffer.limit(); i++)
1005         {
1006             appendContentChar(buf,buffer.get(i));
1007             if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
1008             {
1009                 buf.append("...");
1010                 i = buffer.limit() - 16;
1011             }
1012         }
1013         buf.append(">>>");
1014         int limit = buffer.limit();
1015         buffer.limit(buffer.capacity());
1016         for (int i = limit; i < buffer.capacity(); i++)
1017         {
1018             appendContentChar(buf,buffer.get(i));
1019             if (i == limit + 16 && buffer.capacity() > limit + 32)
1020             {
1021                 buf.append("...");
1022                 i = buffer.capacity() - 16;
1023             }
1024         }
1025         buffer.limit(limit);
1026     }
1027
1028     private static void appendContentChar(StringBuilder buf, byte b)
1029     {
1030         if (b == '\\')
1031             buf.append("\\\\");   
1032         else if (b >= ' ')
1033             buf.append((char)b);
1034         else if (b == '\r')
1035             buf.append("\\r");
1036         else if (b == '\n')
1037             buf.append("\\n");
1038         else if (b == '\t')
1039             buf.append("\\t");
1040         else
1041             buf.append("\\x").append(TypeUtil.toHexString(b));
1042     }
1043
1044     private final static int[] decDivisors =
1045             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1046
1047     private final static int[] hexDivisors =
1048             {0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1};
1049
1050     private final static long[] decDivisorsL =
1051             {1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
1052                     10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L};
1053
1054     public static void putCRLF(ByteBuffer buffer)
1055     {
1056         buffer.put((byte)13);
1057         buffer.put((byte)10);
1058     }
1059
1060     public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
1061     {
1062         if (prefix.remaining() > buffer.remaining())
1063             return false;
1064         int bi = buffer.position();
1065         for (int i = prefix.position(); i < prefix.limit(); i++)
1066             if (prefix.get(i) != buffer.get(bi++))
1067                 return false;
1068         return true;
1069     }
1070
1071     public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
1072     {
1073         if (buffer==null)
1074             return allocate(capacity);
1075         
1076         if (buffer.capacity()>=capacity)
1077             return buffer;
1078         
1079         if (buffer.hasArray())
1080             return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
1081         
1082         throw new UnsupportedOperationException();
1083     }
1084
1085
1086
1087 }