1   // ========================================================================
2   // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.io;
16  
17  import java.io.UnsupportedEncodingException;
18  
19  import org.mortbay.io.BufferCache.CachedBuffer;
20  import org.mortbay.util.StringUtil;
21  
22  /* ------------------------------------------------------------------------------- */
23  /** Buffer utility methods.
24   * 
25   * @author gregw
26   */
27  public class BufferUtil
28  {
29      static final byte SPACE= 0x20;
30      static final byte MINUS= '-';
31      static final byte[] DIGIT=
32      {(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',(byte)'E',(byte)'F'};
33  
34      /**
35       * Convert buffer to an integer.
36       * Parses up to the first non-numeric character. If no number is found an
37       * IllegalArgumentException is thrown
38       * @param buffer A buffer containing an integer. The position is not changed.
39       * @return an int 
40       */
41      public static int toInt(Buffer buffer)
42      {
43          int val= 0;
44          boolean started= false;
45          boolean minus= false;
46          for (int i= buffer.getIndex(); i < buffer.putIndex(); i++)
47          {
48              byte b= buffer.peek(i);
49              if (b <= SPACE)
50              {
51                  if (started)
52                      break;
53              }
54              else if (b >= '0' && b <= '9')
55              {
56                  val= val * 10 + (b - '0');
57                  started= true;
58              }
59              else if (b == MINUS && !started)
60              {
61                  minus= true;
62              }
63              else
64                  break;
65          }
66  
67          if (started)
68              return minus ? (-val) : val;
69          throw new NumberFormatException(buffer.toString());
70      }
71      
72      /**
73       * Convert buffer to an long.
74       * Parses up to the first non-numeric character. If no number is found an
75       * IllegalArgumentException is thrown
76       * @param buffer A buffer containing an integer. The position is not changed.
77       * @return an int 
78       */
79      public static long toLong(Buffer buffer)
80      {
81          long val= 0;
82          boolean started= false;
83          boolean minus= false;
84          for (int i= buffer.getIndex(); i < buffer.putIndex(); i++)
85          {
86              byte b= buffer.peek(i);
87              if (b <= SPACE)
88              {
89                  if (started)
90                      break;
91              }
92              else if (b >= '0' && b <= '9')
93              {
94                  val= val * 10L + (b - '0');
95                  started= true;
96              }
97              else if (b == MINUS && !started)
98              {
99                  minus= true;
100             }
101             else
102                 break;
103         }
104 
105         if (started)
106             return minus ? (-val) : val;
107         throw new NumberFormatException(buffer.toString());
108     }
109 
110     public static void putHexInt(Buffer buffer, int n)
111     {
112 
113         if (n < 0)
114         {
115             buffer.put((byte)'-');
116 
117             if (n == Integer.MIN_VALUE)
118             {
119                 buffer.put((byte)(0x7f&'8'));
120                 buffer.put((byte)(0x7f&'0'));
121                 buffer.put((byte)(0x7f&'0'));
122                 buffer.put((byte)(0x7f&'0'));
123                 buffer.put((byte)(0x7f&'0'));
124                 buffer.put((byte)(0x7f&'0'));
125                 buffer.put((byte)(0x7f&'0'));
126                 buffer.put((byte)(0x7f&'0'));
127                 
128                 return;
129             }
130             n= -n;
131         }
132 
133         if (n < 0x10)
134         {
135             buffer.put(DIGIT[n]);
136         }
137         else
138         {
139             boolean started= false;
140             // This assumes constant time int arithmatic
141             for (int i= 0; i < hexDivisors.length; i++)
142             {
143                 if (n < hexDivisors[i])
144                 {
145                     if (started)
146                         buffer.put((byte)'0');
147                     continue;
148                 }
149 
150                 started= true;
151                 int d= n / hexDivisors[i];
152                 buffer.put(DIGIT[d]);
153                 n= n - d * hexDivisors[i];
154             }
155         }
156     }
157 
158     /* ------------------------------------------------------------ */
159     /**
160      * Add hex integer BEFORE current getIndex.
161      * @param buffer
162      * @param n
163      */
164     public static void prependHexInt(Buffer buffer, int n)
165     {
166         if (n==0)
167         {
168             int gi=buffer.getIndex();
169             buffer.poke(--gi,(byte)'0');
170             buffer.setGetIndex(gi);
171         }
172         else
173         {
174             boolean minus=false;
175             if (n<0)
176             {
177                 minus=true;
178                 n=-n;
179             }
180 
181             int gi=buffer.getIndex();
182             while(n>0)
183             {
184                 int d = 0xf&n;
185                 n=n>>4;
186                 buffer.poke(--gi,DIGIT[d]);
187             }
188             
189             if (minus)
190                 buffer.poke(--gi,(byte)'-');
191             buffer.setGetIndex(gi);
192         }
193     }
194     
195 
196     /* ------------------------------------------------------------ */
197     public static void putDecInt(Buffer buffer, int n)
198     {
199         if (n < 0)
200         {
201             buffer.put((byte)'-');
202 
203             if (n == Integer.MIN_VALUE)
204             {
205                 buffer.put((byte)'2');
206                 n= 147483648;
207             }
208             else
209                 n= -n;
210         }
211 
212         if (n < 10)
213         {
214             buffer.put(DIGIT[n]);
215         }
216         else
217         {
218             boolean started= false;
219             // This assumes constant time int arithmatic
220             for (int i= 0; i < decDivisors.length; i++)
221             {
222                 if (n < decDivisors[i])
223                 {
224                     if (started)
225                         buffer.put((byte)'0');
226                     continue;
227                 }
228 
229                 started= true;
230                 int d= n / decDivisors[i];
231                 buffer.put(DIGIT[d]);
232                 n= n - d * decDivisors[i];
233             }
234         }
235     }
236     
237     public static void putDecLong(Buffer buffer, long n)
238     {
239         if (n < 0)
240         {
241             buffer.put((byte)'-');
242 
243             if (n == Long.MIN_VALUE)
244             {
245                 buffer.put((byte)'9');
246                 n= 223372036854775808L;
247             }
248             else
249                 n= -n;
250         }
251 
252         if (n < 10)
253         {
254             buffer.put(DIGIT[(int)n]);
255         }
256         else
257         {
258             boolean started= false;
259             // This assumes constant time int arithmatic
260             for (int i= 0; i < decDivisors.length; i++)
261             {
262                 if (n < decDivisors[i])
263                 {
264                     if (started)
265                         buffer.put((byte)'0');
266                     continue;
267                 }
268 
269                 started= true;
270                 long d= n / decDivisors[i];
271                 buffer.put(DIGIT[(int)d]);
272                 n= n - d * decDivisors[i];
273             }
274         }
275     }
276     
277     public static Buffer toBuffer(long value)
278     {
279         ByteArrayBuffer buf=new ByteArrayBuffer(16);
280         putDecLong(buf, value);
281         return buf;
282     }
283 
284     private static int[] decDivisors=
285         { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
286 
287     private static int[] hexDivisors=
288         { 0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 1 };
289 
290 
291     public static void putCRLF(Buffer buffer)
292     {
293         buffer.put((byte)13);
294         buffer.put((byte)10);
295     }
296     
297     public static boolean isPrefix(Buffer prefix,Buffer buffer)
298     {
299         if (prefix.length()>buffer.length())
300             return false;
301         int bi=buffer.getIndex();
302         for (int i=prefix.getIndex(); i<prefix.putIndex();i++)
303             if (prefix.peek(i)!=buffer.peek(bi++))
304                 return false;
305         return true;
306     }
307 
308     public static String to8859_1_String(Buffer buffer)
309     {
310         if (buffer instanceof CachedBuffer)
311             return buffer.toString();
312         return buffer.toString(StringUtil.__ISO_8859_1);
313     }
314 }