View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.io.RandomAccessFile;
26  import java.nio.Buffer;
27  import java.nio.ByteBuffer;
28  import java.nio.MappedByteBuffer;
29  import java.nio.channels.FileChannel;
30  import java.nio.channels.FileChannel.MapMode;
31  import java.nio.charset.Charset;
32  
33  
34  /* ------------------------------------------------------------------------------- */
35  /**
36   * Buffer utility methods.
37   *
38   * These utility methods facilitate the usage of NIO {@link ByteBuffer}'s in a more flexible way.
39   * The standard {@link ByteBuffer#flip()} assumes that once flipped to flush a buffer,
40   * that it will be completely emptied before being cleared ready to be filled again.
41   * The {@link #flipToFill(ByteBuffer)} and {@link #flipToFlush(ByteBuffer, int)} methods provided here
42   * do not assume that the buffer is empty and will preserve content when flipped.
43   * <p>
44   * ByteBuffers can be considered in one of two modes: Flush mode where valid content is contained between
45   * position and limit which is consumed by advancing the position; and Fill mode where empty space is between
46   * the position and limit, which is filled by advancing the position.   In fill mode, there may be valid data
47   * in the buffer before the position and the start of this data is given by the return value of {@link #flipToFill(ByteBuffer)}
48   * <p>
49   * A typical pattern for using the buffers in this style is:
50   * <blockquote><pre>
51   *    ByteBuffer buf = BufferUtil.allocate(4096);
52   *    while(in.isOpen())
53   *    {
54   *        int pos=BufferUtil.flipToFill(buf);
55   *        if (in.read(buf)<0)
56   *          break;
57   *        BufferUtil.flipToFlush(buf,pos);
58   *        out.write(buf);
59   *    }</pre></blockquote>
60   */
61  public class BufferUtil
62  {
63      static final byte SPACE = 0x20;
64      static final byte MINUS = '-';
65      static final byte[] DIGIT =
66      { (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',
67              (byte)'E', (byte)'F' };
68  
69      public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
70  
71      /* ------------------------------------------------------------ */
72      /** Allocate ByteBuffer in flush mode.
73       * The position and limit will both be zero, indicating that the buffer is
74       * empty and must be flipped before any data is put to it.
75       * @param capacity
76       * @return Buffer
77       */
78      public static ByteBuffer allocate(int capacity)
79      {
80          ByteBuffer buf = ByteBuffer.allocate(capacity);
81          buf.limit(0);
82          return buf;
83      }
84  
85      /* ------------------------------------------------------------ */
86      /** Allocate ByteBuffer in flush mode.
87       * The position and limit will both be zero, indicating that the buffer is
88       * empty and must be flipped before any data is put to it.
89       * @param capacity
90       * @return Buffer
91       */
92      public static ByteBuffer allocateDirect(int capacity)
93      {
94          ByteBuffer buf = ByteBuffer.allocateDirect(capacity);
95          buf.limit(0);
96          return buf;
97      }
98  
99  
100     /* ------------------------------------------------------------ */
101     /** Clear the buffer to be empty in flush mode.
102      * The position and limit are set to 0;
103      * @param buffer The buffer to clear.
104      */
105     public static void clear(ByteBuffer buffer)
106     {
107         if (buffer!=null)
108         {
109             buffer.position(0);
110             buffer.limit(0);
111         }
112     }
113 
114     /* ------------------------------------------------------------ */
115     /** Clear the buffer to be empty in fill mode.
116      * The position is set to 0 and the limit is set to the capacity.
117      * @param buffer The buffer to clear.
118      */
119     public static void clearToFill(ByteBuffer buffer)
120     {
121         if (buffer!=null)
122         {
123             buffer.position(0);
124             buffer.limit(buffer.capacity());
125         }
126     }
127 
128     /* ------------------------------------------------------------ */
129     /** Flip the buffer to fill mode.
130      * The position is set to the first unused position in the buffer
131      * (the old limit) and the limit is set to the capacity.
132      * If the buffer is empty, then this call is effectively {@link #clearToFill(ByteBuffer)}.
133      * If there is no unused space to fill, a {@link ByteBuffer#compact()} is done to attempt
134      * to create space.
135      * <p>
136      * This method is used as a replacement to {@link ByteBuffer#compact()}.
137      *
138      * @param buffer The buffer to flip
139      * @return The position of the valid data before the flipped position. This value should be
140      * passed to a subsequent call to {@link #flipToFlush(ByteBuffer, int)}
141      */
142     public static int flipToFill(ByteBuffer buffer)
143     {
144         int position=buffer.position();
145         int limit=buffer.limit();
146         if (position==limit)
147         {
148             buffer.position(0);
149             buffer.limit(buffer.capacity());
150             return 0;
151         }
152 
153         int capacity=buffer.capacity();
154         if (limit==capacity)
155         {
156             buffer.compact();
157             return 0;
158         }
159 
160         buffer.position(limit);
161         buffer.limit(capacity);
162         return position;
163     }
164 
165 
166     /* ------------------------------------------------------------ */
167     /** Flip the buffer to Flush mode.
168      * The limit is set to the first unused byte(the old position) and
169      * the position is set to the passed position.
170      * <p>
171      * This method is used as a replacement of {@link Buffer#flip()}.
172      * @param buffer the buffer to be flipped
173      * @param position The position of valid data to flip to. This should
174      * be the return value of the previous call to {@link #flipToFill(ByteBuffer)}
175      */
176     public static void flipToFlush(ByteBuffer buffer,int position)
177     {
178         buffer.limit(buffer.position());
179         buffer.position(position);
180     }
181 
182 
183     /* ------------------------------------------------------------ */
184     /** Convert a ByteBuffer to a byte array.
185      * @param buffer The buffer to convert in flush mode. The buffer is not altered.
186      * @return An array of bytes duplicated from the buffer.
187      */
188     public static byte[] toArray(ByteBuffer buffer)
189     {
190         byte[] to = new byte[buffer.remaining()];
191         if (buffer.hasArray())
192         {
193             byte[] array = buffer.array();
194             System.arraycopy(array,buffer.arrayOffset()+buffer.position(),to,0,to.length);
195         }
196         else
197             buffer.slice().get(to);
198         return to;
199     }
200 
201     /* ------------------------------------------------------------ */
202     /** Check for an empty or null buffer.
203      * @param buf the buffer to check
204      * @return true if the buffer is null or empty.
205      */
206     public static boolean isEmpty(ByteBuffer buf)
207     {
208         return buf==null || buf.remaining()==0;
209     }
210 
211     /* ------------------------------------------------------------ */
212     /** Check for a non null and non empty buffer.
213      * @param buf the buffer to check
214      * @return true if the buffer is not null and not empty.
215      */
216     public static boolean hasContent(ByteBuffer buf)
217     {
218         return buf!=null && buf.remaining()>0;
219     }
220 
221     /* ------------------------------------------------------------ */
222     /** Check for a non null and full buffer.
223      * @param buf the buffer to check
224      * @return true if the buffer is not null and the limit equals the capacity.
225      */
226     public static boolean isFull(ByteBuffer buf)
227     {
228         return buf!=null && buf.limit()==buf.capacity();
229     }
230 
231     /* ------------------------------------------------------------ */
232     /** Get remaining from null checked buffer
233      * @param buffer The buffer to get the remaining from, in flush mode.
234      * @return 0 if the buffer is null, else the bytes remaining in the buffer.
235      */
236     public static int length(ByteBuffer buffer)
237     {
238         return buffer==null?0:buffer.remaining();
239     }
240 
241     /* ------------------------------------------------------------ */
242     /** Get the space from the limit to the capacity
243      * @param buffer
244      * @return space
245      */
246     public static int space(ByteBuffer buffer)
247     {
248         if (buffer==null)
249             return 0;
250         return buffer.capacity()-buffer.limit();
251     }
252 
253     /* ------------------------------------------------------------ */
254     /** Compact the buffer
255      * @param buffer
256      * @return true if the compact made a full buffer have space
257      */
258     public static boolean compact(ByteBuffer buffer)
259     {
260         boolean full=buffer.limit()==buffer.capacity();
261         buffer.compact().flip();
262         return full && buffer.limit()<buffer.capacity();
263     }
264 
265     /* ------------------------------------------------------------ */
266     /**
267      * Put data from one buffer into another, avoiding over/under flows
268      * @param from Buffer to take bytes from in flush mode
269      * @param to Buffer to put bytes to in fill mode.
270      * @return number of bytes moved
271      */
272     public static int put(ByteBuffer from, ByteBuffer to)
273     {
274         int put;
275         int remaining=from.remaining();
276         if (remaining>0)
277         {
278             if (remaining<=to.remaining())
279             {
280                 to.put(from);
281                 put=remaining;
282                 from.position(0);
283                 from.limit(0);
284             }
285             else if (from.hasArray())
286             {
287                 put=to.remaining();
288                 to.put(from.array(),from.arrayOffset()+from.position(),put);
289                 from.position(from.position()+put);
290             }
291             else
292             {
293                 put=to.remaining();
294                 ByteBuffer slice=from.slice();
295                 slice.limit(put);
296                 to.put(slice);
297                 from.position(from.position()+put);
298             }
299         }
300         else
301             put=0;
302 
303         return put;
304     }
305 
306     /* ------------------------------------------------------------ */
307     /**
308      * Put data from one buffer into another, avoiding over/under flows
309      * @param from Buffer to take bytes from in flush mode
310      * @param to Buffer to put bytes to in flush mode. The buffer is flipToFill before the put and flipToFlush after.
311      * @return number of bytes moved
312      */
313     public static int flipPutFlip(ByteBuffer from, ByteBuffer to)
314     {
315         int pos= flipToFill(to);
316         try
317         {
318             return put(from,to);
319         }
320         finally
321         {
322             flipToFlush(to,pos);
323         }
324     }
325 
326     /* ------------------------------------------------------------ */
327     /**
328      */
329     public static void append(ByteBuffer to, byte[] b,int off,int len)
330     {
331         int pos= flipToFill(to);
332         try
333         {
334             to.put(b,off,len);
335         }
336         finally
337         {
338             flipToFlush(to,pos);
339         }
340     }
341 
342     /* ------------------------------------------------------------ */
343     /**
344      */
345     public static void append(ByteBuffer to, byte b)
346     {
347         int limit=to.limit();
348         to.limit(limit+1);
349         to.put(limit,b);
350     }
351 
352     /* ------------------------------------------------------------ */
353     public static void readFrom(File file, ByteBuffer buffer) throws IOException
354     {
355         RandomAccessFile raf = new RandomAccessFile(file,"r");
356         FileChannel channel = raf.getChannel();
357         long needed=raf.length();
358 
359         while (needed>0 && buffer.hasRemaining())
360             needed=needed-channel.read(buffer);
361     }
362 
363     /* ------------------------------------------------------------ */
364     public static void readFrom(InputStream is, int needed, ByteBuffer buffer) throws IOException
365     {
366         ByteBuffer tmp = allocate(8192);
367 
368         while (needed>0 && buffer.hasRemaining())
369         {
370             int l = is.read(tmp.array(),0,8192);
371             if (l<0)
372                 break;
373             tmp.position(0);
374             tmp.limit(l);
375             buffer.put(tmp);
376         }
377     }
378 
379     /* ------------------------------------------------------------ */
380     public static void writeTo(ByteBuffer buffer, OutputStream out) throws IOException
381     {
382         if (buffer.hasArray())
383             out.write(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.remaining());
384         else
385         {
386             // TODO this is horribly inefficient
387             for (int i=buffer.position();i<buffer.limit();i++)
388                 out.write(buffer.get(i));
389         }
390     }
391 
392     /* ------------------------------------------------------------ */
393     /** Convert the buffer to an ISO-8859-1 String
394      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
395      * @return The buffer as a string.
396      */
397     public static String toString(ByteBuffer buffer)
398     {
399         return toString(buffer,StringUtil.__ISO_8859_1_CHARSET);
400     }
401 
402     /* ------------------------------------------------------------ */
403     /** Convert the buffer to an UTF-8 String
404      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
405      * @return The buffer as a string.
406      */
407     public static String toUTF8String(ByteBuffer buffer)
408     {
409         return toString(buffer,StringUtil.__UTF8_CHARSET);
410     }
411 
412     /* ------------------------------------------------------------ */
413     /** Convert the buffer to an ISO-8859-1 String
414      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
415      * @param charset The {@link Charset} to use to convert the bytes
416      * @return The buffer as a string.
417      */
418     public static String toString(ByteBuffer buffer, Charset charset)
419     {
420         if (buffer == null)
421             return null;
422         byte[] array = buffer.hasArray()?buffer.array():null;
423         if (array == null)
424         {
425             byte[] to = new byte[buffer.remaining()];
426             buffer.slice().get(to);
427             return new String(to,0,to.length,charset);
428         }
429         return new String(array,buffer.arrayOffset()+buffer.position(),buffer.remaining(),charset);
430     }
431 
432     /* ------------------------------------------------------------ */
433     /** Convert a partial buffer to an ISO-8859-1 String
434      * @param buffer The buffer to convert in flush mode. The buffer is unchanged
435      * @param charset The {@link Charset} to use to convert the bytes
436      * @return The buffer as a string.
437      */
438     public static String toString(ByteBuffer buffer, int position, int length, Charset charset)
439     {
440         if (buffer == null)
441             return null;
442         byte[] array = buffer.hasArray()?buffer.array():null;
443         if (array == null)
444         {
445             ByteBuffer ro=buffer.asReadOnlyBuffer();
446             ro.position(position);
447             ro.limit(position+length);
448             byte[] to = new byte[length];
449             ro.get(to);
450             return new String(to,0,to.length,charset);
451         }
452         return new String(array,buffer.arrayOffset()+position,length,charset);
453     }
454 
455     /* ------------------------------------------------------------ */
456     /**
457      * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
458      *
459      * @param buffer
460      *            A buffer containing an integer in flush mode. The position is not changed.
461      * @return an int
462      */
463     public static int toInt(ByteBuffer buffer)
464     {
465         int val = 0;
466         boolean started = false;
467         boolean minus = false;
468 
469         for (int i = buffer.position(); i < buffer.limit(); i++)
470         {
471             byte b = buffer.get(i);
472             if (b <= SPACE)
473             {
474                 if (started)
475                     break;
476             }
477             else if (b >= '0' && b <= '9')
478             {
479                 val = val * 10 + (b - '0');
480                 started = true;
481             }
482             else if (b == MINUS && !started)
483             {
484                 minus = true;
485             }
486             else
487                 break;
488         }
489 
490         if (started)
491             return minus?(-val):val;
492         throw new NumberFormatException(toString(buffer));
493     }
494 
495     /**
496      * Convert buffer to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
497      *
498      * @param buffer
499      *            A buffer containing an integer in flush mode. The position is not changed.
500      * @return an int
501      */
502     public static long toLong(ByteBuffer buffer)
503     {
504         long val = 0;
505         boolean started = false;
506         boolean minus = false;
507 
508         for (int i = buffer.position(); i < buffer.limit(); i++)
509         {
510             byte b = buffer.get(i);
511             if (b <= SPACE)
512             {
513                 if (started)
514                     break;
515             }
516             else if (b >= '0' && b <= '9')
517             {
518                 val = val * 10L + (b - '0');
519                 started = true;
520             }
521             else if (b == MINUS && !started)
522             {
523                 minus = true;
524             }
525             else
526                 break;
527         }
528 
529         if (started)
530             return minus?(-val):val;
531         throw new NumberFormatException(toString(buffer));
532     }
533 
534     public static void putHexInt(ByteBuffer buffer, int n)
535     {
536         if (n < 0)
537         {
538             buffer.put((byte)'-');
539 
540             if (n == Integer.MIN_VALUE)
541             {
542                 buffer.put((byte)(0x7f & '8'));
543                 buffer.put((byte)(0x7f & '0'));
544                 buffer.put((byte)(0x7f & '0'));
545                 buffer.put((byte)(0x7f & '0'));
546                 buffer.put((byte)(0x7f & '0'));
547                 buffer.put((byte)(0x7f & '0'));
548                 buffer.put((byte)(0x7f & '0'));
549                 buffer.put((byte)(0x7f & '0'));
550 
551                 return;
552             }
553             n = -n;
554         }
555 
556         if (n < 0x10)
557         {
558             buffer.put(DIGIT[n]);
559         }
560         else
561         {
562             boolean started = false;
563             // This assumes constant time int arithmatic
564             for (int i = 0; i < hexDivisors.length; i++)
565             {
566                 if (n < hexDivisors[i])
567                 {
568                     if (started)
569                         buffer.put((byte)'0');
570                     continue;
571                 }
572 
573                 started = true;
574                 int d = n / hexDivisors[i];
575                 buffer.put(DIGIT[d]);
576                 n = n - d * hexDivisors[i];
577             }
578         }
579     }
580 
581     /* ------------------------------------------------------------ */
582     public static void putDecInt(ByteBuffer buffer, int n)
583     {
584         if (n < 0)
585         {
586             buffer.put((byte)'-');
587 
588             if (n == Integer.MIN_VALUE)
589             {
590                 buffer.put((byte)'2');
591                 n = 147483648;
592             }
593             else
594                 n = -n;
595         }
596 
597         if (n < 10)
598         {
599             buffer.put(DIGIT[n]);
600         }
601         else
602         {
603             boolean started = false;
604             // This assumes constant time int arithmatic
605             for (int i = 0; i < decDivisors.length; i++)
606             {
607                 if (n < decDivisors[i])
608                 {
609                     if (started)
610                         buffer.put((byte)'0');
611                     continue;
612                 }
613 
614                 started = true;
615                 int d = n / decDivisors[i];
616                 buffer.put(DIGIT[d]);
617                 n = n - d * decDivisors[i];
618             }
619         }
620     }
621 
622     public static void putDecLong(ByteBuffer buffer, long n)
623     {
624         if (n < 0)
625         {
626             buffer.put((byte)'-');
627 
628             if (n == Long.MIN_VALUE)
629             {
630                 buffer.put((byte)'9');
631                 n = 223372036854775808L;
632             }
633             else
634                 n = -n;
635         }
636 
637         if (n < 10)
638         {
639             buffer.put(DIGIT[(int)n]);
640         }
641         else
642         {
643             boolean started = false;
644             // This assumes constant time int arithmatic
645             for (int i = 0; i < decDivisorsL.length; i++)
646             {
647                 if (n < decDivisorsL[i])
648                 {
649                     if (started)
650                         buffer.put((byte)'0');
651                     continue;
652                 }
653 
654                 started = true;
655                 long d = n / decDivisorsL[i];
656                 buffer.put(DIGIT[(int)d]);
657                 n = n - d * decDivisorsL[i];
658             }
659         }
660     }
661 
662     public static ByteBuffer toBuffer(int value)
663     {
664         ByteBuffer buf = ByteBuffer.allocate(32);
665         putDecInt(buf,value);
666         return buf;
667     }
668 
669     public static ByteBuffer toBuffer(long value)
670     {
671         ByteBuffer buf = ByteBuffer.allocate(32);
672         putDecLong(buf,value);
673         return buf;
674     }
675 
676     public static ByteBuffer toBuffer(String s)
677     {
678         return ByteBuffer.wrap(s.getBytes(StringUtil.__ISO_8859_1_CHARSET));
679     }
680     
681     public static ByteBuffer toDirectBuffer(String s)
682     {
683         byte[] bytes=s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
684         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
685         buf.put(bytes);
686         buf.flip();
687         return buf;
688     }
689 
690     public static ByteBuffer toBuffer(String s, Charset charset)
691     {
692         return ByteBuffer.wrap(s.getBytes(charset));
693     }
694     
695     public static ByteBuffer toDirectBuffer(String s, Charset charset)
696     {
697         byte[] bytes=s.getBytes(charset);
698         ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
699         buf.put(bytes);
700         buf.flip();
701         return buf;
702     }
703 
704     /**
705      * Create a new ByteBuffer using provided byte array.
706      *
707      * @param array
708      *            the byte array to back buffer with.
709      * @return ByteBuffer with provided byte array, in flush mode
710      */
711     public static ByteBuffer toBuffer(byte array[])
712     {
713         return ByteBuffer.wrap(array);
714     }
715 
716     /**
717      * Create a new ByteBuffer using the provided byte array.
718      *
719      * @param array
720      *            the byte array to use.
721      * @param offset
722      *            the offset within the byte array to use from
723      * @param length
724      *            the length in bytes of the array to use
725      * @return ByteBuffer with provided byte array, in flush mode
726      */
727     public static ByteBuffer toBuffer(byte array[], int offset, int length)
728     {
729         return ByteBuffer.wrap(array,offset,length);
730     }
731 
732     public static ByteBuffer toBuffer(File file) throws IOException
733     {
734         RandomAccessFile raf = new RandomAccessFile(file,"r");
735         MappedByteBuffer buffer=raf.getChannel().map(MapMode.READ_ONLY,0,raf.length());
736         return buffer;
737     }
738 
739     public static String toSummaryString(ByteBuffer buffer)
740     {
741         if (buffer==null)
742             return "null";
743         StringBuilder buf = new StringBuilder();
744         buf.append("[p=");
745         buf.append(buffer.position());
746         buf.append(",l=");
747         buf.append(buffer.limit());
748         buf.append(",c=");
749         buf.append(buffer.capacity());
750         buf.append(",r=");
751         buf.append(buffer.remaining());
752         buf.append("]");
753         return buf.toString();
754     }
755 
756     public static String toDetailString(ByteBuffer[] buffer)
757     {
758         StringBuilder builder = new StringBuilder();
759         builder.append('[');
760         for (int i=0;i<buffer.length;i++)
761         {
762             if (i>0) builder.append(',');
763             builder.append(toDetailString(buffer[i]));
764         }
765         builder.append(']');
766         return builder.toString();
767     }
768 
769     public static String toDetailString(ByteBuffer buffer)
770     {
771         if (buffer==null)
772             return "null";
773 
774         StringBuilder buf = new StringBuilder();
775         buf.append(buffer.getClass().getSimpleName());
776         buf.append("@");
777         if (buffer.hasArray())
778             buf.append(Integer.toHexString(((Object)buffer.array()).hashCode()));
779         else
780             buf.append(Integer.toHexString(buf.hashCode()));
781         buf.append("[p=");
782         buf.append(buffer.position());
783         buf.append(",l=");
784         buf.append(buffer.limit());
785         buf.append(",c=");
786         buf.append(buffer.capacity());
787         buf.append(",r=");
788         buf.append(buffer.remaining());
789         buf.append("]={");
790 
791         for (int i=0;i<buffer.position();i++)
792         {
793             char c=(char)buffer.get(i);
794             if (c>=' ' && c<=127)
795                 buf.append(c);
796             else if (c=='\r'||c=='\n')
797                 buf.append('|');
798             else
799                 buf.append('\ufffd');
800             if (i==16&&buffer.position()>32)
801             {
802                 buf.append("...");
803                 i=buffer.position()-16;
804             }
805         }
806         buf.append("<<<");
807         for (int i=buffer.position();i<buffer.limit();i++)
808         {
809             char c=(char)buffer.get(i);
810             if (c>=' ' && c<=127)
811                 buf.append(c);
812             else if (c=='\r'||c=='\n')
813                 buf.append('|');
814             else
815                 buf.append('\ufffd');
816             if (i==buffer.position()+16&&buffer.limit()>buffer.position()+32)
817             {
818                 buf.append("...");
819                 i=buffer.limit()-16;
820             }
821         }
822         buf.append(">>>");
823         int limit=buffer.limit();
824         buffer.limit(buffer.capacity());
825         for (int i=limit;i<buffer.capacity();i++)
826         {
827             char c=(char)buffer.get(i);
828             if (c>=' ' && c<=127)
829                 buf.append(c);
830             else if (c=='\r'||c=='\n')
831                 buf.append('|');
832             else
833                 buf.append('\ufffd');
834             if (i==limit+16&&buffer.capacity()>limit+32)
835             {
836                 buf.append("...");
837                 i=buffer.capacity()-16;
838             }
839         }
840         buffer.limit(limit);
841         buf.append("}");
842 
843         return buf.toString();
844     }
845 
846 
847     private final static int[] decDivisors =
848     { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
849 
850     private final static int[] hexDivisors =
851     { 0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1 };
852 
853     private final static long[] decDivisorsL =
854     { 1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L,
855             10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L };
856 
857     public static void putCRLF(ByteBuffer buffer)
858     {
859         buffer.put((byte)13);
860         buffer.put((byte)10);
861     }
862 
863     public static boolean isPrefix(ByteBuffer prefix, ByteBuffer buffer)
864     {
865         if (prefix.remaining() > buffer.remaining())
866             return false;
867         int bi = buffer.position();
868         for (int i = prefix.position(); i < prefix.limit(); i++)
869             if (prefix.get(i) != buffer.get(bi++))
870                 return false;
871         return true;
872     }
873 
874 
875 
876 }