View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.api.util;
21  
22  
23  import static org.apache.directory.api.util.Chars.isHex;
24  import static org.apache.directory.api.util.Hex.encodeHex;
25  import static org.apache.directory.api.util.Hex.getHexValue;
26  
27  import java.io.UnsupportedEncodingException;
28  import java.nio.charset.Charset;
29  import java.nio.charset.StandardCharsets;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.UUID;
35  
36  import org.apache.directory.api.i18n.I18n;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  
41  /**
42   * Various string manipulation methods that are more efficient then chaining
43   * string operations: all is done in the same buffer without creating a bunch of
44   * string objects.
45   *
46   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
47   */
48  public final class Strings
49  {
50      /** A logger for this class */
51      private static final Logger LOG = LoggerFactory.getLogger( Strings.class );
52  
53      /** Hex chars */
54      private static final byte[] HEX_CHAR = new byte[]
55          { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
56  
57      /** A table containing booleans when the corresponding char is printable */
58      private static final boolean[] IS_PRINTABLE_CHAR =
59          {
60              // ---, ---, ---, ---, ---, ---, ---, ---
61              false, false, false, false, false, false, false, false, 
62              // ---, ---, ---, ---, ---, ---, ---, ---
63              false, false, false, false, false, false, false, false, 
64              // ---, ---, ---, ---, ---, ---, ---, ---
65              false, false, false, false, false, false, false, false, 
66              // ---, ---, ---, ---, ---, ---, ---, ---
67              false, false, false, false, false, false, false, false, 
68              // ' ', ---, ---, ---, ---, ---, ---, "'"
69              true,  false, false, false, false, false, false, true,  
70              // '(', ')', ---, '+', ',', '-', '.', '/'
71              true,  true,  false, true,  true,  true,  true,  true,  
72              // '0', '1', '2', '3', '4', '5', '6', '7',
73              true,  true,  true,  true,  true,  true,  true,  true,  
74              // '8', '9', ':', ---, ---, '=', ---, '?'
75              true,  true,  true,  false, false, true,  false, true,  
76              // ---, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
77              false, true,  true,  true,  true,  true,  true,  true,  
78              // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
79              true,  true,  true,  true,  true,  true,  true,  true,  
80              // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'
81              true,  true,  true,  true,  true,  true,  true,  true,  
82              // 'X', 'Y', 'Z', ---, ---, ---, ---, ---
83              true,  true,  true,  false, false, false, false, false, 
84              // ---, 'a', 'b', 'c', 'd', 'e', 'f', 'g'
85              false, true,  true,  true,  true,  true,  true,  true,  
86              // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'
87              true,  true,  true,  true,  true,  true,  true,  true,  
88              // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w'
89              true,  true,  true,  true,  true,  true,  true,  true, 
90              // 'x', 'y', 'z', ---, ---, ---, ---, ---
91              true,  true,  true,  false, false, false, false, false 
92      };
93  
94      private static final char[] TO_LOWER_CASE =
95          {
96              0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
97              0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
98              0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
99              0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
100             ' ',  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, '\'',
101             '(',  ')',  0x2A, '+',  ',',  '-',  '.',  '/',
102             '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
103             '8',  '9',  ':',  0x3B, 0x3C, '=',  0x3E, '?',
104             0x40, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
105             'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
106             'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
107             'x',  'y',  'z',  0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
108             0x60, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
109             'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
110             'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
111             'x',  'y',  'z',  0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
112             0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
113             0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
114             0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
115             0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
116             0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
117             0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
118             0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
119             0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
120             0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
121             0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
122             0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
123             0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
124             0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
125             0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
126             0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
127             0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
128     };
129 
130     private static final byte[] TO_LOWER_CASE_BYTE =
131         {
132             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
133             0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
134             0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
135             0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
136             ' ',  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, '\'',
137             '(',  ')',  0x2A, '+',  ',',  '-',  '.',  '/',
138             '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
139             '8',  '9',  ':',  0x3B, 0x3C, '=',  0x3E, '?',
140             0x40, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
141             'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
142             'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
143             'x',  'y',  'z',  0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
144             0x60, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
145             'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
146             'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
147             'x',  'y',  'z',  0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
148             ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83,
149             ( byte ) 0x84, ( byte ) 0x85, ( byte ) 0x86, ( byte ) 0x87,
150             ( byte ) 0x88, ( byte ) 0x89, ( byte ) 0x8A, ( byte ) 0x8B,
151             ( byte ) 0x8C, ( byte ) 0x8D, ( byte ) 0x8E, ( byte ) 0x8F,
152             ( byte ) 0x90, ( byte ) 0x91, ( byte ) 0x92, ( byte ) 0x93,
153             ( byte ) 0x94, ( byte ) 0x95, ( byte ) 0x96, ( byte ) 0x97,
154             ( byte ) 0x98, ( byte ) 0x99, ( byte ) 0x9A, ( byte ) 0x9B,
155             ( byte ) 0x9C, ( byte ) 0x9D, ( byte ) 0x9E, ( byte ) 0x9F,
156             ( byte ) 0xA0, ( byte ) 0xA1, ( byte ) 0xA2, ( byte ) 0xA3,
157             ( byte ) 0xA4, ( byte ) 0xA5, ( byte ) 0xA6, ( byte ) 0xA7,
158             ( byte ) 0xA8, ( byte ) 0xA9, ( byte ) 0xAA, ( byte ) 0xAB,
159             ( byte ) 0xAC, ( byte ) 0xAD, ( byte ) 0xAE, ( byte ) 0xAF,
160             ( byte ) 0xB0, ( byte ) 0xB1, ( byte ) 0xB2, ( byte ) 0xB3,
161             ( byte ) 0xB4, ( byte ) 0xB5, ( byte ) 0xB6, ( byte ) 0xB7,
162             ( byte ) 0xB8, ( byte ) 0xB9, ( byte ) 0xBA, ( byte ) 0xBB,
163             ( byte ) 0xBC, ( byte ) 0xBD, ( byte ) 0xBE, ( byte ) 0xBF,
164             ( byte ) 0xC0, ( byte ) 0xC1, ( byte ) 0xC2, ( byte ) 0xC3,
165             ( byte ) 0xC4, ( byte ) 0xC5, ( byte ) 0xC6, ( byte ) 0xC7,
166             ( byte ) 0xC8, ( byte ) 0xC9, ( byte ) 0xCA, ( byte ) 0xCB,
167             ( byte ) 0xCC, ( byte ) 0xCD, ( byte ) 0xCE, ( byte ) 0xCF,
168             ( byte ) 0xD0, ( byte ) 0xD1, ( byte ) 0xD2, ( byte ) 0xD3,
169             ( byte ) 0xD4, ( byte ) 0xD5, ( byte ) 0xD6, ( byte ) 0xD7,
170             ( byte ) 0xD8, ( byte ) 0xD9, ( byte ) 0xDA, ( byte ) 0xDB,
171             ( byte ) 0xDC, ( byte ) 0xDD, ( byte ) 0xDE, ( byte ) 0xDF,
172             ( byte ) 0xE0, ( byte ) 0xE1, ( byte ) 0xE2, ( byte ) 0xE3,
173             ( byte ) 0xE4, ( byte ) 0xE5, ( byte ) 0xE6, ( byte ) 0xE7,
174             ( byte ) 0xE8, ( byte ) 0xE9, ( byte ) 0xEA, ( byte ) 0xEB,
175             ( byte ) 0xEC, ( byte ) 0xED, ( byte ) 0xEE, ( byte ) 0xEF,
176             ( byte ) 0xF0, ( byte ) 0xF1, ( byte ) 0xF2, ( byte ) 0xF3,
177             ( byte ) 0xF4, ( byte ) 0xF5, ( byte ) 0xF6, ( byte ) 0xF7,
178             ( byte ) 0xF8, ( byte ) 0xF9, ( byte ) 0xFA, ( byte ) 0xFB,
179             ( byte ) 0xFC, ( byte ) 0xFD, ( byte ) 0xFE, ( byte ) 0xFF
180     };
181 
182     /** upperCase = 'A' .. 'Z', '0'..'9', '-' */
183     private static final char[] UPPER_CASE =
184         {
185             0, 0, 0, 0, 0, 0, 0, 0,
186             0, 0, 0, 0, 0, 0, 0, 0,
187             0, 0, 0, 0, 0, 0, 0, 0,
188             0, 0, 0, 0, 0, 0, 0, 0,
189             0, 0, 0, 0, 0, 0, 0, 0,
190             0, 0, 0, 0, 0, '-', 0, 0,
191             '0', '1', '2', '3', '4', '5', '6', '7',
192             '8', '9', 0, 0, 0, 0, 0, 0,
193             0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
194             'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
195             'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
196             'X', 'Y', 'Z', 0, 0, 0, 0, 0,
197             0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
198             'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
199             'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
200             'X', 'Y', 'Z', 0, 0, 0, 0, 0,
201             0, 0, 0, 0, 0, 0, 0, 0,
202             0, 0, 0, 0, 0, 0, 0, 0,
203             0, 0, 0, 0, 0, 0, 0, 0,
204             0, 0, 0, 0, 0, 0, 0, 0,
205             0, 0, 0, 0, 0, 0, 0, 0,
206             0, 0, 0, 0, 0, 0, 0, 0,
207             0, 0, 0, 0, 0, 0, 0, 0,
208             0, 0, 0, 0, 0, 0, 0, 0
209     };
210     
211     private static final byte[] UTF8 = new byte[]
212         { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
213             0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
214             0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
215             0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
216             0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
217             0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
218             0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
219             0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F };
220 
221     /** An empty byte array */
222     public static final byte[] EMPTY_BYTES = new byte[0];
223     
224     /** An empty String */
225     public static final String EMPTY_STRING = "";
226     
227     /** An empty String array */
228     public static final String[] EMPTY_STRING_ARRAY = new String[]{};
229 
230 
231     /**
232      * Private constructor
233      */
234     private Strings()
235     {
236     }
237 
238 
239     /**
240      * Helper function that dump an array of bytes in hex form
241      *
242      * @param buffer The bytes array to dump
243      * @return A string representation of the array of bytes
244      */
245     public static String dumpBytes( byte[] buffer )
246     {
247         if ( buffer == null )
248         {
249             return "";
250         }
251 
252         StringBuilder sb = new StringBuilder();
253 
254         for ( int i = 0; i < buffer.length; i++ )
255         {
256             sb.append( "0x" ).append( ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] ) ).append(
257                 ( char ) ( HEX_CHAR[buffer[i] & 0x000F] ) ).append( " " );
258         }
259 
260         return sb.toString();
261     }
262 
263 
264     /**
265      * Helper function that dump a byte in hex form
266      *
267      * @param octet The byte to dump
268      * @return A string representation of the byte
269      */
270     public static String dumpByte( byte octet )
271     {
272         return Strings.utf8ToString( new byte[]
273             { '0', 'x', HEX_CHAR[( octet & 0x00F0 ) >> 4], HEX_CHAR[octet & 0x000F] } );
274     }
275 
276 
277     /**
278      * Helper function that returns a char from an hex
279      *
280      * @param hex The hex to dump
281      * @return A char representation of the hex
282      */
283     public static char dumpHex( byte hex )
284     {
285         return ( char ) HEX_CHAR[hex & 0x000F];
286     }
287 
288 
289     /**
290      * Helper function that dump an array of bytes in hex pair form,
291      * without '0x' and space chars
292      *
293      * @param buffer The bytes array to dump
294      * @return A string representation of the array of bytes
295      */
296     public static String dumpHexPairs( byte[] buffer )
297     {
298         if ( buffer == null )
299         {
300             return "";
301         }
302 
303         char[] str = new char[buffer.length << 1];
304         int pos = 0;
305 
306         for ( int i = 0; i < buffer.length; i++ )
307         {
308             str[pos++] = ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] );
309             str[pos++] = ( char ) ( HEX_CHAR[buffer[i] & 0x000F] );
310         }
311 
312         return new String( str );
313     }
314 
315 
316     /**
317      * Put common code to deepTrim(String) and deepTrimToLower here.
318      *
319      * @param str the string to deep trim
320      * @param toLowerCase how to normalize for case: upper or lower
321      * @return the deep trimmed string
322      * @see Strings#deepTrim( String )
323      */
324     public static String deepTrim( String str, boolean toLowerCase )
325     {
326         if ( ( null == str ) || ( str.length() == 0 ) )
327         {
328             return "";
329         }
330 
331         char ch;
332         int length = str.length();
333         char[] newbuf = new char[length];
334         boolean wsSeen = false;
335         boolean isStart = true;
336         int pos = 0;
337 
338         for ( int i = 0; i < length; i++ )
339         {
340             ch = str.charAt( i );
341 
342             // filter out all uppercase characters
343             if ( toLowerCase && Character.isUpperCase( ch ) )
344             {
345                 ch = Character.toLowerCase( ch );
346             }
347 
348             // Check to see if we should add space
349             if ( Character.isWhitespace( ch ) )
350             {
351                 // If the buffer has had characters added already check last
352                 // added character. Only append a spc if last character was
353                 // not whitespace.
354                 if ( wsSeen )
355                 {
356                     continue;
357                 }
358                 else
359                 {
360                     wsSeen = true;
361 
362                     if ( isStart )
363                     {
364                         isStart = false;
365                     }
366                     else
367                     {
368                         newbuf[pos++] = ch;
369                     }
370                 }
371             }
372             else
373             {
374                 // Add all non-whitespace
375                 wsSeen = false;
376                 isStart = false;
377                 newbuf[pos++] = ch;
378             }
379         }
380 
381         return pos == 0 ? "" : new String( newbuf, 0, wsSeen ? pos - 1 : pos );
382     }
383 
384 
385     /**
386      * This does the same thing as a trim but we also lowercase the string while
387      * performing the deep trim within the same buffer. This saves us from
388      * having to create multiple String and StringBuffer objects and is much
389      * more efficient.
390      *
391      * @see Strings#deepTrim( String )
392      * 
393      * @param string The String to modify
394      * @return The modified String
395      */
396     public static String deepTrimToLower( String string )
397     {
398         return deepTrim( string, true );
399     }
400 
401 
402     /**
403      * A deep trim of a string remove whitespace from the ends as well as
404      * excessive whitespace within the inside of the string between
405      * non-whitespace characters. A deep trim reduces internal whitespace down
406      * to a single space to preserve the whitespace separated tokenization order
407      * of the String.
408      *
409      * @param string the string to deep trim.
410      * @return the trimmed string.
411      */
412     public static String deepTrim( String string )
413     {
414         return deepTrim( string, false );
415     }
416 
417 
418     /**
419      * Trims several consecutive characters into one.
420      *
421      * @param str the string to trim consecutive characters of
422      * @param ch the character to trim down
423      * @return the newly trimmed down string
424      */
425     public static String trimConsecutiveToOne( String str, char ch )
426     {
427         if ( ( null == str ) || ( str.length() == 0 ) )
428         {
429             return "";
430         }
431 
432         char[] buffer = str.toCharArray();
433         char[] newbuf = new char[buffer.length];
434         int pos = 0;
435         boolean same = false;
436 
437         for ( int i = 0; i < buffer.length; i++ )
438         {
439             char car = buffer[i];
440 
441             if ( car == ch )
442             {
443                 if ( same )
444                 {
445                     continue;
446                 }
447                 else
448                 {
449                     same = true;
450                     newbuf[pos++] = car;
451                 }
452             }
453             else
454             {
455                 same = false;
456                 newbuf[pos++] = car;
457             }
458         }
459 
460         return new String( newbuf, 0, pos );
461     }
462 
463 
464     /**
465      * Truncates large Strings showing a portion of the String's head and tail
466      * with the center cut out and replaced with '...'. Also displays the total
467      * length of the truncated string so size of '...' can be interpreted.
468      * Useful for large strings in UIs or hex dumps to log files.
469      *
470      * @param str the string to truncate
471      * @param head the amount of the head to display
472      * @param tail the amount of the tail to display
473      * @return the center truncated string
474      */
475     public static String centerTrunc( String str, int head, int tail )
476     {
477         // Return as-is if String is smaller than or equal to the head plus the
478         // tail plus the number of characters added to the trunc representation
479         // plus the number of digits in the string length.
480         if ( str.length() <= ( head + tail + 7 + str.length() / 10 ) )
481         {
482             return str;
483         }
484 
485         StringBuilder buf = new StringBuilder();
486         buf.append( '[' ).append( str.length() ).append( "][" );
487         buf.append( str.substring( 0, head ) ).append( "..." );
488         buf.append( str.substring( str.length() - tail ) );
489         buf.append( ']' );
490         return buf.toString();
491     }
492 
493 
494     /**
495      * Gets a hex string from byte array.
496      *
497      * @param res the byte array
498      * @return the hex string representing the binary values in the array
499      */
500     public static String toHexString( byte[] res )
501     {
502         StringBuilder buf = new StringBuilder( res.length << 1 );
503 
504         for ( int ii = 0; ii < res.length; ii++ )
505         {
506             String digit = Integer.toHexString( 0xFF & res[ii] );
507 
508             if ( digit.length() == 1 )
509             {
510                 digit = '0' + digit;
511             }
512 
513             buf.append( digit );
514         }
515 
516         return upperCase( buf.toString() );
517     }
518 
519 
520     /**
521      * Get byte array from hex string
522      *
523      * @param hexString the hex string to convert to a byte array
524      * @return the byte form of the hex string.
525      */
526     public static byte[] toByteArray( String hexString )
527     {
528         int arrLength = hexString.length() >> 1;
529         byte[] buf = new byte[arrLength];
530 
531         for ( int ii = 0; ii < arrLength; ii++ )
532         {
533             int index = ii << 1;
534 
535             String digit = hexString.substring( index, index + 2 );
536             buf[ii] = ( byte ) Integer.parseInt( digit, 16 );
537         }
538 
539         return buf;
540     }
541 
542 
543     /**
544      * This method is used to insert HTML block dynamically
545      *
546      * @param source the HTML code to be processes
547      * @param replaceNl if true '\n' will be replaced by &lt;br@gt;
548      * @param replaceTag if true '&lt;' will be replaced by &lt; and '&gt;' will be replaced
549      *            by &gt;
550      * @param replaceQuote if true '\"' will be replaced by &quot;
551      * @return the formated html block
552      */
553     public static String formatHtml( String source, boolean replaceNl, boolean replaceTag,
554         boolean replaceQuote )
555     {
556         StringBuilder buf = new StringBuilder();
557         int len = source.length();
558 
559         for ( int i = 0; i < len; i++ )
560         {
561             char ch = source.charAt( i );
562 
563             switch ( ch )
564             {
565                 case '\"':
566                     if ( replaceQuote )
567                     {
568                         buf.append( "&quot;" );
569                     }
570                     else
571                     {
572                         buf.append( ch );
573                     }
574                     break;
575 
576                 case '<':
577                     if ( replaceTag )
578                     {
579                         buf.append( "&lt;" );
580                     }
581                     else
582                     {
583                         buf.append( ch );
584                     }
585                     break;
586 
587                 case '>':
588                     if ( replaceTag )
589                     {
590                         buf.append( "&gt;" );
591                     }
592                     else
593                     {
594                         buf.append( ch );
595                     }
596                     break;
597 
598                 case '\n':
599                     if ( replaceNl )
600                     {
601                         if ( replaceTag )
602                         {
603                             buf.append( "&lt;br&gt;" );
604                         }
605                         else
606                         {
607                             buf.append( "<br>" );
608                         }
609                     }
610                     else
611                     {
612                         buf.append( ch );
613                     }
614                     break;
615 
616                 case '\r':
617                     break;
618 
619                 case '&':
620                     buf.append( "&amp;" );
621                     break;
622 
623                 default:
624                     buf.append( ch );
625                     break;
626             }
627         }
628 
629         return buf.toString();
630     }
631 
632 
633     /**
634      * Check if a text is present at the current position in another string.
635      *
636      * @param string The string which contains the data
637      * @param index Current position in the string
638      * @param text The text we want to check
639      * @return <code>true</code> if the string contains the text.
640      */
641     public static boolean areEquals( String string, int index, String text )
642     {
643         if ( ( string == null ) || ( text == null ) )
644         {
645             return false;
646         }
647 
648         int length1 = string.length();
649         int length2 = text.length();
650 
651         if ( ( length1 == 0 ) || ( length1 <= index ) || ( index < 0 )
652             || ( length2 == 0 ) || ( length2 > ( length1 + index ) ) )
653         {
654             return false;
655         }
656         else
657         {
658             return string.substring( index ).startsWith( text );
659         }
660     }
661 
662 
663     /**
664      * Test if the current character is equal to a specific character. This
665      * function works only for character between 0 and 127, as it does compare a
666      * byte and a char (which is 16 bits wide)
667      *
668      * @param byteArray The buffer which contains the data
669      * @param index Current position in the buffer
670      * @param car The character we want to compare with the current buffer position
671      * @return <code>true</code> if the current character equals the given character.
672      */
673     public static boolean isCharASCII( byte[] byteArray, int index, char car )
674     {
675         if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) || ( index >= byteArray.length ) )
676         {
677             return false;
678         }
679         else
680         {
681             return ( byteArray[index] == car ) ? true : false;
682         }
683     }
684 
685 
686     /**
687      * Test if the current character is equal to a specific character.
688      *
689      * @param string The String which contains the data
690      * @param index Current position in the string
691      * @param car The character we want to compare with the current string position
692      * @return <code>true</code> if the current character equals the given character.
693      */
694     public static boolean isCharASCII( String string, int index, char car )
695     {
696         if ( string == null )
697         {
698             return false;
699         }
700 
701         int length = string.length();
702 
703         if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
704         {
705             return false;
706         }
707         else
708         {
709             return string.charAt( index ) == car;
710         }
711     }
712 
713     /**
714      * Return an UTF-8 encoded String
715      *
716      * @param bytes The byte array to be transformed to a String
717      * @return A String.
718      */
719     public static String utf8ToString( byte[] bytes )
720     {
721         if ( bytes == null )
722         {
723             return "";
724         }
725 
726         char[] chars = new char[bytes.length];
727         int pos = 0;
728 
729         try
730         {
731             for ( byte b : bytes )
732             {
733                 chars[pos++] = ( char ) UTF8[b];
734             }
735         }
736         catch ( ArrayIndexOutOfBoundsException aioobe )
737         {
738             return new String( bytes, StandardCharsets.UTF_8 );
739         }
740 
741         return new String( chars );
742     }
743 
744 
745     /**
746      * Return an UTF-8 encoded String
747      *
748      * @param bytes The byte array to be transformed to a String
749      * @param length The length of the byte array to be converted
750      * @return A String.
751      */
752     public static String utf8ToString( byte[] bytes, int length )
753     {
754         if ( bytes == null )
755         {
756             return "";
757         }
758 
759         return new String( bytes, 0, length, StandardCharsets.UTF_8 );
760     }
761 
762 
763     /**
764      * Return an UTF-8 encoded String
765      *
766      * @param bytes  The byte array to be transformed to a String
767      * @param start the starting position in the byte array
768      * @param length The length of the byte array to be converted
769      * @return A String.
770      */
771     public static String utf8ToString( byte[] bytes, int start, int length )
772     {
773         if ( bytes == null )
774         {
775             return "";
776         }
777 
778         return new String( bytes, start, length, StandardCharsets.UTF_8 );
779     }
780 
781 
782     /**
783      * Check if a text is present at the current position in a buffer.
784      *
785      * @param bytes The buffer which contains the data
786      * @param index Current position in the buffer
787      * @param text The text we want to check
788      * @return <code>true</code> if the buffer contains the text.
789      */
790     public static int areEquals( byte[] bytes, int index, String text )
791     {
792         if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) || ( index < 0 )
793             || ( text == null ) )
794         {
795             return StringConstants.NOT_EQUAL;
796         }
797         else
798         {
799             byte[] data = text.getBytes( StandardCharsets.UTF_8 );
800 
801             return areEquals( bytes, index, data );
802         }
803     }
804 
805 
806     /**
807      * Check if a text is present at the current position in a buffer.
808      *
809      * @param chars The buffer which contains the data
810      * @param index Current position in the buffer
811      * @param text The text we want to check
812      * @return <code>true</code> if the buffer contains the text.
813      */
814     public static int areEquals( char[] chars, int index, String text )
815     {
816         return areEquals( chars, index, text, true );
817     }
818 
819 
820     /**
821      * Check if a text is present at the current position in a buffer.
822      *
823      * @param chars The buffer which contains the data
824      * @param index Current position in the buffer
825      * @param text The text we want to check
826      * @param caseSensitive If the comparison is case-sensitive
827      * @return <code>true</code> if the buffer contains the text.
828      */
829     public static int areEquals( char[] chars, int index, String text, boolean caseSensitive )
830     {
831         if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) || ( index < 0 )
832             || ( text == null ) )
833         {
834             return StringConstants.NOT_EQUAL;
835         }
836         else
837         {
838             char[] data = text.toCharArray();
839 
840             return areEquals( chars, index, data, caseSensitive );
841         }
842     }
843 
844 
845     /**
846      * Check if a text is present at the current position in a buffer.
847      *
848      * @param chars The buffer which contains the data
849      * @param index Current position in the buffer
850      * @param chars2 The text we want to check
851      * @return <code>true</code> if the buffer contains the text.
852      */
853     public static int areEquals( char[] chars, int index, char[] chars2 )
854     {
855         return areEquals( chars, index, chars2, true );
856     }
857 
858 
859     /**
860      * Check if a text is present at the current position in a buffer.
861      *
862      * @param chars The buffer which contains the data
863      * @param index Current position in the buffer
864      * @param chars2 The text we want to check
865      * @param caseSensitive If the comparison is case-sensitive
866      * @return <code>true</code> if the buffer contains the text.
867      */
868     public static int areEquals( char[] chars, int index, char[] chars2, boolean caseSensitive )
869     {
870         if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) || ( index < 0 )
871             || ( chars2 == null ) || ( chars2.length == 0 )
872             || ( chars2.length > ( chars.length - index ) ) )
873         {
874             return StringConstants.NOT_EQUAL;
875         }
876         else
877         {
878             for ( int i = 0; i < chars2.length; i++ )
879             {
880                 char c1 = chars[index++];
881                 char c2 = chars2[i];
882 
883                 if ( !caseSensitive )
884                 {
885                     c1 = Character.toLowerCase( c1 );
886                     c2 = Character.toLowerCase( c2 );
887                 }
888 
889                 if ( c1 != c2 )
890                 {
891                     return StringConstants.NOT_EQUAL;
892                 }
893             }
894 
895             return index;
896         }
897     }
898 
899 
900     /**
901      * Check if a text is present at the current position in a buffer.
902      *
903      * @param bytes The buffer which contains the data
904      * @param index Current position in the buffer
905      * @param bytes2 The text we want to check
906      * @return <code>true</code> if the buffer contains the text.
907      */
908     public static int areEquals( byte[] bytes, int index, byte[] bytes2 )
909     {
910         if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) || ( index < 0 )
911             || ( bytes2 == null ) || ( bytes2.length == 0 )
912             || ( bytes2.length > ( bytes.length - index ) ) )
913         {
914             return StringConstants.NOT_EQUAL;
915         }
916         else
917         {
918             for ( int i = 0; i < bytes2.length; i++ )
919             {
920                 if ( bytes[index++] != bytes2[i] )
921                 {
922                     return StringConstants.NOT_EQUAL;
923                 }
924             }
925 
926             return index;
927         }
928     }
929 
930 
931     /**
932      * <p>
933      * Checks if a String is empty ("") or null.
934      * </p>
935      *
936      * <pre>
937      *  StringUtils.isEmpty(null)      = true
938      *  StringUtils.isEmpty(&quot;&quot;)        = true
939      *  StringUtils.isEmpty(&quot; &quot;)       = false
940      *  StringUtils.isEmpty(&quot;bob&quot;)     = false
941      *  StringUtils.isEmpty(&quot;  bob  &quot;) = false
942      * </pre>
943      *
944      * <p>
945      * NOTE: This method changed in Lang version 2.0. It no longer trims the
946      * String. That functionality is available in isBlank().
947      * </p>
948      *
949      * @param str the String to check, may be null
950      * @return <code>true</code> if the String is empty or null
951      */
952     public static boolean isEmpty( String str )
953     {
954         return ( str == null ) || ( str.length() == 0 );
955     }
956 
957 
958     /**
959      * Checks if a bytes array is empty or null.
960      *
961      * @param bytes The bytes array to check, may be null
962      * @return <code>true</code> if the bytes array is empty or null
963      */
964     public static boolean isEmpty( byte[] bytes )
965     {
966         return ( bytes == null ) || ( bytes.length == 0 );
967     }
968 
969 
970     /**
971      * <p>
972      * Removes spaces (char &lt;= 32) from both start and ends of this String,
973      * handling <code>null</code> by returning <code>null</code>.
974      * </p>
975      * Trim removes start and end characters &lt;= 32.
976      *
977      * <pre>
978      *  StringUtils.trim(null)          = null
979      *  StringUtils.trim(&quot;&quot;)            = &quot;&quot;
980      *  StringUtils.trim(&quot;     &quot;)       = &quot;&quot;
981      *  StringUtils.trim(&quot;abc&quot;)         = &quot;abc&quot;
982      *  StringUtils.trim(&quot;    abc    &quot;) = &quot;abc&quot;
983      * </pre>
984      *
985      * @param str the String to be trimmed, may be null
986      * @return the trimmed string, <code>null</code> if null String input
987      */
988     public static String trim( String str )
989     {
990         return isEmpty( str ) ? "" : str.trim();
991     }
992 
993 
994     /**
995      * <p>
996      * Removes spaces (char &lt;= 32) from both start and ends of this bytes
997      * array, handling <code>null</code> by returning <code>null</code>.
998      * </p>
999      * Trim removes start and end characters &lt;= 32.
1000      *
1001      * <pre>
1002      *  StringUtils.trim(null)          = null
1003      *  StringUtils.trim(&quot;&quot;)            = &quot;&quot;
1004      *  StringUtils.trim(&quot;     &quot;)       = &quot;&quot;
1005      *  StringUtils.trim(&quot;abc&quot;)         = &quot;abc&quot;
1006      *  StringUtils.trim(&quot;    abc    &quot;) = &quot;abc&quot;
1007      * </pre>
1008      *
1009      * @param bytes the byte array to be trimmed, may be null
1010      *
1011      * @return the trimmed byte array
1012      */
1013     public static byte[] trim( byte[] bytes )
1014     {
1015         if ( isEmpty( bytes ) )
1016         {
1017             return EMPTY_BYTES;
1018         }
1019 
1020         int start = trimLeft( bytes, 0 );
1021         int end = trimRight( bytes, bytes.length - 1 );
1022 
1023         int length = end - start + 1;
1024 
1025         if ( length != 0 )
1026         {
1027             byte[] newBytes = new byte[end - start + 1];
1028 
1029             System.arraycopy( bytes, start, newBytes, 0, length );
1030 
1031             return newBytes;
1032         }
1033         else
1034         {
1035             return EMPTY_BYTES;
1036         }
1037     }
1038 
1039 
1040     /**
1041      * <p>
1042      * Removes spaces (char &lt;= 32) from start of this String, handling
1043      * <code>null</code> by returning <code>null</code>.
1044      * </p>
1045      * Trim removes start characters &lt;= 32.
1046      *
1047      * <pre>
1048      *  StringUtils.trimLeft(null)          = null
1049      *  StringUtils.trimLeft(&quot;&quot;)            = &quot;&quot;
1050      *  StringUtils.trimLeft(&quot;     &quot;)       = &quot;&quot;
1051      *  StringUtils.trimLeft(&quot;abc&quot;)         = &quot;abc&quot;
1052      *  StringUtils.trimLeft(&quot;    abc    &quot;) = &quot;abc    &quot;
1053      * </pre>
1054      *
1055      * @param str the String to be trimmed, may be null
1056      * @return the trimmed string, <code>null</code> if null String input
1057      */
1058     public static String trimLeft( String str )
1059     {
1060         if ( isEmpty( str ) )
1061         {
1062             return "";
1063         }
1064 
1065         int start = 0;
1066         int end = str.length();
1067 
1068         while ( ( start < end ) && ( str.charAt( start ) == ' ' ) )
1069         {
1070             start++;
1071         }
1072 
1073         return start == 0 ? str : str.substring( start );
1074     }
1075 
1076 
1077     /**
1078      * <p>
1079      * Removes spaces (char &lt;= 32) from start of this array, handling
1080      * <code>null</code> by returning <code>null</code>.
1081      * </p>
1082      * Trim removes start characters &lt;= 32.
1083      *
1084      * <pre>
1085      *  StringUtils.trimLeft(null)          = null
1086      *  StringUtils.trimLeft(&quot;&quot;)            = &quot;&quot;
1087      *  StringUtils.trimLeft(&quot;     &quot;)       = &quot;&quot;
1088      *  StringUtils.trimLeft(&quot;abc&quot;)         = &quot;abc&quot;
1089      *  StringUtils.trimLeft(&quot;    abc    &quot;) = &quot;abc    &quot;
1090      * </pre>
1091      *
1092      * @param chars the chars array to be trimmed, may be null
1093      * @param pos The position in the char[]
1094      * @return the position of the first char which is not a space, or the last
1095      *         position of the array.
1096      */
1097     public static int trimLeft( char[] chars, int pos )
1098     {
1099         if ( chars == null )
1100         {
1101             return pos;
1102         }
1103 
1104         while ( ( pos < chars.length ) && ( chars[pos] == ' ' ) )
1105         {
1106             pos++;
1107         }
1108 
1109         return pos;
1110     }
1111 
1112 
1113     /**
1114      * <p>
1115      * Removes spaces (char &lt;= 32) from a position in this array, handling
1116      * <code>null</code> by returning <code>null</code>.
1117      * </p>
1118      * Trim removes start characters &lt;= 32.
1119      *
1120      * <pre>
1121      *  StringUtils.trimLeft(null)          = null
1122      *  StringUtils.trimLeft(&quot;&quot;,...)            = &quot;&quot;
1123      *  StringUtils.trimLeft(&quot;     &quot;,...)       = &quot;&quot;
1124      *  StringUtils.trimLeft(&quot;abc&quot;,...)         = &quot;abc&quot;
1125      *  StringUtils.trimLeft(&quot;    abc    &quot;,...) = &quot;abc    &quot;
1126      * </pre>
1127      *
1128      * @param string the string to be trimmed, may be null
1129      * @param pos The starting position
1130      */
1131     public static void trimLeft( String string, Position pos )
1132     {
1133         if ( string == null )
1134         {
1135             return;
1136         }
1137 
1138         int length = string.length();
1139 
1140         while ( ( pos.start < length ) && ( string.charAt( pos.start ) == ' ' ) )
1141         {
1142             pos.start++;
1143         }
1144 
1145         pos.end = pos.start;
1146     }
1147 
1148 
1149     /**
1150      * <p>
1151      * Removes spaces (char &lt;= 32) from a position in this array, handling
1152      * <code>null</code> by returning <code>null</code>.
1153      * </p>
1154      * Trim removes start characters &lt;= 32.
1155      *
1156      * <pre>
1157      *  StringUtils.trimLeft(null)          = null
1158      *  StringUtils.trimLeft(&quot;&quot;,...)            = &quot;&quot;
1159      *  StringUtils.trimLeft(&quot;     &quot;,...)       = &quot;&quot;
1160      *  StringUtils.trimLeft(&quot;abc&quot;,...)         = &quot;abc&quot;
1161      *  StringUtils.trimLeft(&quot;    abc    &quot;,...) = &quot;abc    &quot;
1162      * </pre>
1163      *
1164      * @param bytes the byte array to be trimmed, may be null
1165      * @param pos The starting position
1166      */
1167     public static void trimLeft( byte[] bytes, Position pos )
1168     {
1169         if ( bytes == null )
1170         {
1171             return;
1172         }
1173 
1174         int length = bytes.length;
1175 
1176         while ( ( pos.start < length ) && ( bytes[pos.start] == ' ' ) )
1177         {
1178             pos.start++;
1179         }
1180 
1181         pos.end = pos.start;
1182     }
1183 
1184 
1185     /**
1186      * <p>
1187      * Removes spaces (char &lt;= 32) from start of this array, handling
1188      * <code>null</code> by returning <code>null</code>.
1189      * </p>
1190      * Trim removes start characters &lt;= 32.
1191      *
1192      * <pre>
1193      *  StringUtils.trimLeft(null)          = null
1194      *  StringUtils.trimLeft(&quot;&quot;)            = &quot;&quot;
1195      *  StringUtils.trimLeft(&quot;     &quot;)       = &quot;&quot;
1196      *  StringUtils.trimLeft(&quot;abc&quot;)         = &quot;abc&quot;
1197      *  StringUtils.trimLeft(&quot;    abc    &quot;) = &quot;abc    &quot;
1198      * </pre>
1199      *
1200      * @param bytes the byte array to be trimmed, may be null
1201      * @param pos The position in the byte[]
1202      * @return the position of the first byte which is not a space, or the last
1203      *         position of the array.
1204      */
1205     public static int trimLeft( byte[] bytes, int pos )
1206     {
1207         if ( bytes == null )
1208         {
1209             return pos;
1210         }
1211 
1212         while ( ( pos < bytes.length ) && ( bytes[pos] == ' ' ) )
1213         {
1214             pos++;
1215         }
1216 
1217         return pos;
1218     }
1219 
1220 
1221     /**
1222      * <p>
1223      * Removes spaces (char &lt;= 32) from end of this String, handling
1224      * <code>null</code> by returning <code>null</code>.
1225      * </p>
1226      * Trim removes start characters &lt;= 32.
1227      *
1228      * <pre>
1229      *  StringUtils.trimRight(null)          = null
1230      *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
1231      *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
1232      *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
1233      *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
1234      * </pre>
1235      *
1236      * @param str the String to be trimmed, may be null
1237      * @return the trimmed string, <code>null</code> if null String input
1238      */
1239     public static String trimRight( String str )
1240     {
1241         if ( isEmpty( str ) )
1242         {
1243             return "";
1244         }
1245 
1246         int length = str.length();
1247         int end = length;
1248 
1249         while ( ( end > 0 ) && ( str.charAt( end - 1 ) == ' ' ) )
1250         {
1251             if ( ( end > 1 ) && ( str.charAt( end - 2 ) == '\\' ) )
1252             {
1253                 break;
1254             }
1255 
1256             end--;
1257         }
1258 
1259         return end == length ? str : str.substring( 0, end );
1260     }
1261 
1262 
1263     /**
1264      * <p>
1265      * Removes spaces (char &lt;= 32) from end of this String, handling
1266      * <code>null</code> by returning <code>null</code>.
1267      * </p>
1268      * Trim removes start characters &lt;= 32.
1269      *
1270      * <pre>
1271      *  StringUtils.trimRight(null)          = null
1272      *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
1273      *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
1274      *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
1275      *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
1276      * </pre>
1277      *
1278      * @param str the String to be trimmed, may be null
1279      * @param escapedSpace The last escaped space, if any
1280      * @return the trimmed string, <code>null</code> if null String input
1281      */
1282     public static String trimRight( String str, int escapedSpace )
1283     {
1284         if ( isEmpty( str ) )
1285         {
1286             return "";
1287         }
1288 
1289         int length = str.length();
1290         int end = length;
1291 
1292         while ( ( end > 0 ) && ( str.charAt( end - 1 ) == ' ' ) && ( end > escapedSpace ) )
1293         {
1294             if ( ( end > 1 ) && ( str.charAt( end - 2 ) == '\\' ) )
1295             {
1296                 break;
1297             }
1298 
1299             end--;
1300         }
1301 
1302         return end == length ? str : str.substring( 0, end );
1303     }
1304 
1305 
1306     /**
1307      * <p>
1308      * Removes spaces (char &lt;= 32) from end of this array, handling
1309      * <code>null</code> by returning <code>null</code>.
1310      * </p>
1311      * Trim removes start characters &lt;= 32.
1312      *
1313      * <pre>
1314      *  StringUtils.trimRight(null)          = null
1315      *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
1316      *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
1317      *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
1318      *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
1319      * </pre>
1320      *
1321      * @param chars the chars array to be trimmed, may be null
1322      * @param pos The position in the char[]
1323      * @return the position of the first char which is not a space, or the last
1324      *         position of the array.
1325      */
1326     public static int trimRight( char[] chars, int pos )
1327     {
1328         if ( chars == null )
1329         {
1330             return pos;
1331         }
1332 
1333         while ( ( pos >= 0 ) && ( chars[pos - 1] == ' ' ) )
1334         {
1335             pos--;
1336         }
1337 
1338         return pos;
1339     }
1340 
1341 
1342     /**
1343      * <p>
1344      * Removes spaces (char &lt;= 32) from end of this string, handling
1345      * <code>null</code> by returning <code>null</code>.
1346      * </p>
1347      * Trim removes start characters &lt;= 32.
1348      *
1349      * <pre>
1350      *  StringUtils.trimRight(null)          = null
1351      *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
1352      *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
1353      *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
1354      *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
1355      * </pre>
1356      *
1357      * @param string the string to be trimmed, may be null
1358      * @param pos The position in the String
1359      * @return the position of the first char which is not a space, or the last
1360      *         position of the string.
1361      */
1362     public static String trimRight( String string, Position pos )
1363     {
1364         if ( string == null )
1365         {
1366             return "";
1367         }
1368 
1369         while ( ( pos.end >= 0 ) && ( string.charAt( pos.end - 1 ) == ' ' ) )
1370         {
1371             if ( ( pos.end > 1 ) && ( string.charAt( pos.end - 2 ) == '\\' ) )
1372             {
1373                 break;
1374             }
1375 
1376             pos.end--;
1377         }
1378 
1379         return pos.end == string.length() ? string : string.substring( 0, pos.end );
1380     }
1381 
1382 
1383     /**
1384      * <p>
1385      * Removes spaces (char &lt;= 32) from end of this string, handling
1386      * <code>null</code> by returning <code>null</code>.
1387      * </p>
1388      * Trim removes start characters &lt;= 32.
1389      *
1390      * <pre>
1391      *  StringUtils.trimRight(null)          = null
1392      *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
1393      *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
1394      *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
1395      *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
1396      * </pre>
1397      *
1398      * @param bytes the byte array to be trimmed, may be null
1399      * @param pos The position in the byte[]
1400      * @return the position of the first char which is not a space, or the last
1401      *         position of the byte array.
1402      */
1403     public static String trimRight( byte[] bytes, Position pos )
1404     {
1405         if ( bytes == null )
1406         {
1407             return "";
1408         }
1409 
1410         while ( ( pos.end >= 0 ) && ( bytes[pos.end - 1] == ' ' ) )
1411         {
1412             if ( ( pos.end > 1 ) && ( bytes[pos.end - 2] == '\\' ) )
1413             {
1414                 break;
1415             }
1416 
1417             pos.end--;
1418         }
1419 
1420         if ( pos.end == bytes.length )
1421         {
1422             return utf8ToString( bytes );
1423         }
1424         else
1425         {
1426             return utf8ToString( bytes, pos.end );
1427         }
1428     }
1429 
1430 
1431     /**
1432      * <p>
1433      * Removes spaces (char &lt;= 32) from end of this array, handling
1434      * <code>null</code> by returning <code>null</code>.
1435      * </p>
1436      * Trim removes start characters &lt;= 32.
1437      *
1438      * <pre>
1439      *  StringUtils.trimRight(null)          = null
1440      *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
1441      *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
1442      *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
1443      *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
1444      * </pre>
1445      *
1446      * @param bytes the byte array to be trimmed, may be null
1447      * @param pos The position in the byte[]
1448      * @return the position of the first char which is not a space, or the last
1449      *         position of the array.
1450      */
1451     public static int trimRight( byte[] bytes, int pos )
1452     {
1453         if ( bytes == null )
1454         {
1455             return pos;
1456         }
1457 
1458         while ( ( pos >= 0 ) && ( bytes[pos] == ' ' ) )
1459         {
1460             pos--;
1461         }
1462 
1463         return pos;
1464     }
1465 
1466 
1467     /**
1468      * Get the character at a given position in a string, checking for limits
1469      *
1470      * @param string The string which contains the data
1471      * @param index Current position in the string
1472      * @return The character at the given position, or '\0' if something went wrong
1473      */
1474     public static char charAt( String string, int index )
1475     {
1476         if ( string == null )
1477         {
1478             return '\0';
1479         }
1480 
1481         int length = string.length();
1482 
1483         if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
1484         {
1485             return '\0';
1486         }
1487         else
1488         {
1489             return string.charAt( index );
1490         }
1491     }
1492 
1493 
1494     /**
1495      * Get the byte at a given position in a byte array, checking for limits
1496      *
1497      * @param bytes The byte[] which contains the data
1498      * @param index Current position in the byte[]
1499      * @return The byte at the given position, or '\0' if something went wrong
1500      */
1501     public static byte byteAt( byte[] bytes, int index )
1502     {
1503         if ( bytes == null )
1504         {
1505             return '\0';
1506         }
1507 
1508         int length = bytes.length;
1509 
1510         if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
1511         {
1512             return '\0';
1513         }
1514         else
1515         {
1516             return bytes[index];
1517         }
1518     }
1519 
1520 
1521     /**
1522      * Get the char at a given position in a byte array, checking for limits
1523      *
1524      * @param chars The char[] which contains the data
1525      * @param index Current position in the char[]
1526      * @return The byte at the given position, or '\0' if something went wrong
1527      */
1528     public static char charAt( char[] chars, int index )
1529     {
1530         if ( chars == null )
1531         {
1532             return '\0';
1533         }
1534 
1535         int length = chars.length;
1536 
1537         if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
1538         {
1539             return '\0';
1540         }
1541         else
1542         {
1543             return chars[index];
1544         }
1545     }
1546 
1547 
1548     /**
1549      * Transform an array of ASCII bytes to a string. the byte array should contains
1550      * only values in [0, 127].
1551      *
1552      * @param bytes The byte array to transform
1553      * @return The resulting string
1554      */
1555     public static String asciiBytesToString( byte[] bytes )
1556     {
1557         if ( ( bytes == null ) || ( bytes.length == 0 ) )
1558         {
1559             return "";
1560         }
1561 
1562         char[] result = new char[bytes.length];
1563 
1564         for ( int i = 0; i < bytes.length; i++ )
1565         {
1566             result[i] = ( char ) bytes[i];
1567         }
1568 
1569         return new String( result );
1570     }
1571 
1572 
1573     /**
1574      * Return UTF-8 encoded byte[] representation of a String
1575      *
1576      * @param string The string to be transformed to a byte array
1577      * @return The transformed byte array
1578      */
1579     public static byte[] getBytesUtf8( String string )
1580     {
1581         if ( string == null )
1582         {
1583             return EMPTY_BYTES;
1584         }
1585 
1586         return string.getBytes( StandardCharsets.UTF_8 );
1587     }
1588 
1589 
1590     /**
1591      * When the string to convert to bytes is pure ascii, this is a faster 
1592      * method than the getBytesUtf8. Otherwise, it's slower.
1593      * 
1594      * @param string The string to convert to byte[]
1595      * @return The bytes 
1596      */
1597     public static byte[] getBytesUtf8Ascii( String string )
1598     {
1599         if ( string == null )
1600         {
1601             return EMPTY_BYTES;
1602         }
1603 
1604         try
1605         {
1606             char[] chars = string.toCharArray();
1607             byte[] bytes = new byte[chars.length];
1608             int pos = 0;
1609 
1610             for ( char c : chars )
1611             {
1612                 bytes[pos++] = UTF8[c];
1613             }
1614 
1615             return bytes;
1616         }
1617         catch ( ArrayIndexOutOfBoundsException aioobe )
1618         {
1619             return string.getBytes( StandardCharsets.UTF_8 );
1620         }
1621     }
1622 
1623 
1624     /**
1625      * Get the default charset
1626      *
1627      * @return The default charset
1628      */
1629     public static String getDefaultCharsetName()
1630     {
1631         return Charset.defaultCharset().name();
1632     }
1633 
1634 
1635     /**
1636      * <p>
1637      * Compares two Strings, returning <code>true</code> if they are equal.
1638      * </p>
1639      * <p>
1640      * <code>null</code>s are handled without exceptions. Two
1641      * <code>null</code> references are considered to be equal. The comparison
1642      * is case sensitive.
1643      * </p>
1644      *
1645      * <pre>
1646      *  StringUtils.equals(null, null)   = true
1647      *  StringUtils.equals(null, &quot;abc&quot;)  = false
1648      *  StringUtils.equals(&quot;abc&quot;, null)  = false
1649      *  StringUtils.equals(&quot;abc&quot;, &quot;abc&quot;) = true
1650      *  StringUtils.equals(&quot;abc&quot;, &quot;ABC&quot;) = false
1651      * </pre>
1652      *
1653      * @see String#equals(Object)
1654      * @param str1 the first String, may be null
1655      * @param str2 the second String, may be null
1656      * @return <code>true</code> if the Strings are equal, case sensitive, or
1657      *         both <code>null</code>
1658      */
1659     public static boolean equals( String str1, String str2 )
1660     {
1661         return str1 == null ? str2 == null : str1.equals( str2 );
1662     }
1663 
1664 
1665     /**
1666      * Utility method that return a String representation of a list
1667      *
1668      * @param list The list to transform to a string
1669      * @return A csv string
1670      */
1671     public static String listToString( List<?> list )
1672     {
1673         if ( ( list == null ) || list.isEmpty() )
1674         {
1675             return "";
1676         }
1677 
1678         StringBuilder sb = new StringBuilder();
1679         boolean isFirst = true;
1680 
1681         for ( Object elem : list )
1682         {
1683             if ( isFirst )
1684             {
1685                 isFirst = false;
1686             }
1687             else
1688             {
1689                 sb.append( ", " );
1690             }
1691 
1692             sb.append( elem );
1693         }
1694 
1695         return sb.toString();
1696     }
1697 
1698 
1699     /**
1700      * Utility method that return a String representation of a set
1701      *
1702      * @param set The set to transform to a string
1703      * @return A csv string
1704      */
1705     public static String setToString( Set<?> set )
1706     {
1707         if ( ( set == null ) || set.isEmpty() )
1708         {
1709             return "";
1710         }
1711 
1712         StringBuilder sb = new StringBuilder();
1713         boolean isFirst = true;
1714 
1715         for ( Object elem : set )
1716         {
1717             if ( isFirst )
1718             {
1719                 isFirst = false;
1720             }
1721             else
1722             {
1723                 sb.append( ", " );
1724             }
1725 
1726             sb.append( elem );
1727         }
1728 
1729         return sb.toString();
1730     }
1731 
1732 
1733     /**
1734      * Utility method that return a String representation of a list
1735      *
1736      * @param list The list to transform to a string
1737      * @param tabs The tabs to add in front of the elements
1738      * @return A csv string
1739      */
1740     public static String listToString( List<?> list, String tabs )
1741     {
1742         if ( ( list == null ) || list.isEmpty() )
1743         {
1744             return "";
1745         }
1746 
1747         StringBuilder sb = new StringBuilder();
1748 
1749         for ( Object elem : list )
1750         {
1751             sb.append( tabs );
1752             sb.append( elem );
1753             sb.append( '\n' );
1754         }
1755 
1756         return sb.toString();
1757     }
1758 
1759 
1760     /**
1761      * Utility method that return a String representation of a map. The elements
1762      * will be represented as "key = value"
1763      *
1764      * @param map The map to transform to a string
1765      * @return A csv string
1766      */
1767     public static String mapToString( Map<?, ?> map )
1768     {
1769         if ( ( map == null ) || map.isEmpty() )
1770         {
1771             return "";
1772         }
1773 
1774         StringBuilder sb = new StringBuilder();
1775         boolean isFirst = true;
1776 
1777         for ( Map.Entry<?, ?> entry : map.entrySet() )
1778         {
1779             if ( isFirst )
1780             {
1781                 isFirst = false;
1782             }
1783             else
1784             {
1785                 sb.append( ", " );
1786             }
1787 
1788             sb.append( entry.getKey() );
1789             sb.append( " = '" ).append( entry.getValue() ).append( "'" );
1790         }
1791 
1792         return sb.toString();
1793     }
1794 
1795 
1796     /**
1797      * Utility method that return a String representation of a map. The elements
1798      * will be represented as "key = value"
1799      *
1800      * @param map The map to transform to a string
1801      * @param tabs The tabs to add in ffront of the elements
1802      * @return A csv string
1803      */
1804     public static String mapToString( Map<?, ?> map, String tabs )
1805     {
1806         if ( ( map == null ) || map.isEmpty() )
1807         {
1808             return "";
1809         }
1810 
1811         StringBuilder sb = new StringBuilder();
1812 
1813         for ( Map.Entry<?, ?> entry : map.entrySet() )
1814         {
1815             sb.append( tabs );
1816             sb.append( entry.getKey() );
1817 
1818             sb.append( " = '" ).append( entry.getValue().toString() ).append( "'\n" );
1819         }
1820 
1821         return sb.toString();
1822     }
1823 
1824 
1825     /**
1826      * Rewrote the toLowercase method to improve performances.
1827      * In Ldap, attributesType are supposed to use ASCII chars :
1828      * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
1829      *
1830      * @param value The String to lowercase
1831      * @return The lowercase string
1832      * @deprecated Use {@link #toLowerCaseAscii(String)}
1833      */
1834     @Deprecated
1835     public static String toLowerCase( String value )
1836     {
1837         if ( ( null == value ) || ( value.length() == 0 ) )
1838         {
1839             return "";
1840         }
1841 
1842         char[] chars = value.toCharArray();
1843 
1844         for ( int i = 0; i < chars.length; i++ )
1845         {
1846             chars[i] = TO_LOWER_CASE[chars[i]];
1847         }
1848 
1849         return new String( chars );
1850     }
1851 
1852 
1853     /**
1854      * Rewrote the toLowercase method to improve performances.
1855      * In Ldap, attributesType are supposed to use ASCII chars :
1856      * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
1857      *
1858      * @param value The String to lowercase
1859      * @return The lowercase string
1860      */
1861     public static String toLowerCaseAscii( String value )
1862     {
1863         if ( ( null == value ) || ( value.length() == 0 ) )
1864         {
1865             return "";
1866         }
1867 
1868         char[] chars = value.toCharArray();
1869 
1870         for ( int i = 0; i < chars.length; i++ )
1871         {
1872             chars[i] = TO_LOWER_CASE[chars[i]];
1873         }
1874 
1875         return new String( chars );
1876     }
1877 
1878 
1879     /**
1880      * Rewrote the toLowercase method to improve performances.
1881      * In Ldap, attributesType are supposed to use ASCII chars :
1882      * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
1883      *
1884      * @param value The byte[] to lowercase
1885      * @return The lowercase string
1886      */
1887     public static String toLowerCase( byte[] value )
1888     {
1889         if ( ( null == value ) || ( value.length == 0 ) )
1890         {
1891             return "";
1892         }
1893 
1894         for ( int i = 0; i < value.length; i++ )
1895         {
1896             value[i] = TO_LOWER_CASE_BYTE[value[i]];
1897         }
1898 
1899         return Strings.utf8ToString( value );
1900     }
1901 
1902 
1903     /**
1904      * Rewrote the toLowercase method to improve performances.
1905      * In Ldap, attributesType are supposed to use ASCII chars :
1906      * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
1907      *
1908      * @param value The String to uppercase
1909      * @return The uppercase string
1910      * @deprecated Use {@link #toUpperCaseAscii(String)}
1911      */
1912     @Deprecated
1913     public static String toUpperCase( String value )
1914     {
1915         if ( ( null == value ) || ( value.length() == 0 ) )
1916         {
1917             return "";
1918         }
1919 
1920         char[] chars = value.toCharArray();
1921 
1922         for ( int i = 0; i < chars.length; i++ )
1923         {
1924             chars[i] = UPPER_CASE[chars[i]];
1925         }
1926 
1927         return new String( chars );
1928     }
1929 
1930 
1931     /**
1932      * Rewrote the toLowercase method to improve performances.
1933      * In Ldap, attributesType are supposed to use ASCII chars :
1934      * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
1935      *
1936      * @param value The String to uppercase
1937      * @return The uppercase string
1938      */
1939     public static String toUpperCaseAscii( String value )
1940     {
1941         if ( ( null == value ) || ( value.length() == 0 ) )
1942         {
1943             return "";
1944         }
1945 
1946         char[] chars = value.toCharArray();
1947 
1948         for ( int i = 0; i < chars.length; i++ )
1949         {
1950             chars[i] = UPPER_CASE[chars[i]];
1951         }
1952 
1953         return new String( chars );
1954     }
1955 
1956 
1957     /**
1958      * <p>
1959      * Converts a String to upper case as per {@link String#toUpperCase( Locale )}.
1960      * </p>
1961      * <p>
1962      * A <code>null</code> input String returns <code>null</code>.
1963      * </p>
1964      *
1965      * <pre>
1966      *  StringUtils.upperCase(null)  = null
1967      *  StringUtils.upperCase(&quot;&quot;)    = &quot;&quot;
1968      *  StringUtils.upperCase(&quot;aBc&quot;) = &quot;ABC&quot;
1969      * </pre>
1970      *
1971      * @param str the String to upper case, may be null
1972      * @return the upper cased String, <code>null</code> if null String input
1973      */
1974     public static String upperCase( String str )
1975     {
1976         if ( str == null )
1977         {
1978             return null;
1979         }
1980 
1981         return str.toUpperCase( Locale.ROOT );
1982     }
1983 
1984 
1985     /**
1986      * <p>
1987      * Converts a String to lower case as per {@link String#toLowerCase()}.
1988      * </p>
1989      * <p>
1990      * A <code>null</code> input String returns <code>null</code>.
1991      * </p>
1992      *
1993      * <pre>
1994      *  StringUtils.lowerCase(null)  = null
1995      *  StringUtils.lowerCase(&quot;&quot;)    = &quot;&quot;
1996      *  StringUtils.lowerCase(&quot;aBc&quot;) = &quot;abc&quot;
1997      * </pre>
1998      *
1999      * @param str the String to lower case, may be null
2000      * @return the lower cased String, <code>null</code> if null String input
2001      */
2002     public static String lowerCase( String str )
2003     {
2004         if ( str == null )
2005         {
2006             return null;
2007         }
2008 
2009         return str.toLowerCase( Locale.ROOT );
2010     }
2011 
2012 
2013     /**
2014      * Rewrote the toLowercase method to improve performances.
2015      * In Ldap, attributesType are supposed to use ASCII chars :
2016      * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only. We will take
2017      * care of any other chars either.
2018      *
2019      * @param str The String to lowercase
2020      * @return The lowercase string
2021      */
2022     public static String lowerCaseAscii( String str )
2023     {
2024         if ( str == null )
2025         {
2026             return null;
2027         }
2028 
2029         char[] chars = str.toCharArray();
2030         int pos = 0;
2031 
2032         for ( char c : chars )
2033         {
2034             chars[pos++] = TO_LOWER_CASE[c];
2035         }
2036 
2037         return new String( chars );
2038     }
2039 
2040 
2041     /**
2042      *
2043      * Check that a String is a valid PrintableString. A PrintableString contains only
2044      * the following set of chars :
2045      * { ' ', ''', '(', ')', '+', '-', '.', '/', [0-9], ':', '=', '?', [A-Z], [a-z]}
2046      *
2047      * @param str The String to check
2048      * @return <code>true</code> if the string is a PrintableString or is empty,
2049      * <code>false</code> otherwise
2050      */
2051     public static boolean isPrintableString( String str )
2052     {
2053         if ( ( str == null ) || ( str.length() == 0 ) )
2054         {
2055             return true;
2056         }
2057 
2058         for ( char c : str.toCharArray() )
2059         {
2060             if ( ( c > 127 ) || !IS_PRINTABLE_CHAR[c] )
2061             {
2062                 return false;
2063             }
2064         }
2065 
2066         return true;
2067     }
2068 
2069 
2070     /**
2071      * <p>
2072      * Checks if a String is not empty ("") and not null.
2073      * </p>
2074      *
2075      * <pre>
2076      *  StringUtils.isNotEmpty(null)      = false
2077      *  StringUtils.isNotEmpty(&quot;&quot;)        = false
2078      *  StringUtils.isNotEmpty(&quot; &quot;)       = true
2079      *  StringUtils.isNotEmpty(&quot;bob&quot;)     = true
2080      *  StringUtils.isNotEmpty(&quot;  bob  &quot;) = true
2081      * </pre>
2082      *
2083      * @param str the String to check, may be null
2084      * @return <code>true</code> if the String is not empty and not null
2085      */
2086     public static boolean isNotEmpty( String str )
2087     {
2088         return ( str != null ) && ( str.length() > 0 );
2089     }
2090 
2091 
2092     /**
2093      *
2094      * Check that a String is a valid IA5String. An IA5String contains only
2095      * char which values is between [0, 7F]
2096      *
2097      * @param str The String to check
2098      * @return <code>true</code> if the string is an IA5String or is empty,
2099      * <code>false</code> otherwise
2100      */
2101     public static boolean isIA5String( String str )
2102     {
2103         if ( ( str == null ) || ( str.length() == 0 ) )
2104         {
2105             return true;
2106         }
2107 
2108         // All the chars must be in [0x00, 0x7F]
2109         for ( char c : str.toCharArray() )
2110         {
2111             if ( ( c < 0 ) || ( c > 0x7F ) )
2112             {
2113                 return false;
2114             }
2115         }
2116 
2117         return true;
2118     }
2119 
2120 
2121     /**
2122      * Checks to see if a String is a valid UUID.
2123      *
2124      * @param uuid the UUID to check for validity
2125      * @return true if the UUID is valid, false otherwise
2126      */
2127     public static boolean isValidUuid( String uuid )
2128     {
2129         if ( uuid.length() < 36 )
2130         {
2131             return false;
2132         }
2133 
2134         if ( isHex( uuid.charAt( 0 ) ) && isHex( uuid.charAt( 1 ) ) && isHex( uuid.charAt( 2 ) )
2135             && isHex( uuid.charAt( 3 ) ) && isHex( uuid.charAt( 4 ) ) && isHex( uuid.charAt( 5 ) )
2136             && isHex( uuid.charAt( 6 ) ) && isHex( uuid.charAt( 7 ) ) && ( uuid.charAt( 8 ) == '-' )
2137             && isHex( uuid.charAt( 9 ) ) && isHex( uuid.charAt( 10 ) ) && isHex( uuid.charAt( 11 ) )
2138             && isHex( uuid.charAt( 12 ) ) && ( uuid.charAt( 13 ) == '-' ) && isHex( uuid.charAt( 14 ) )
2139             && isHex( uuid.charAt( 15 ) ) && isHex( uuid.charAt( 16 ) ) && isHex( uuid.charAt( 17 ) )
2140             && ( uuid.charAt( 18 ) == '-' ) && isHex( uuid.charAt( 19 ) ) && isHex( uuid.charAt( 20 ) )
2141             && isHex( uuid.charAt( 21 ) ) && isHex( uuid.charAt( 22 ) ) && ( uuid.charAt( 23 ) == '-' )
2142             && isHex( uuid.charAt( 24 ) ) && isHex( uuid.charAt( 25 ) ) && isHex( uuid.charAt( 26 ) )
2143             && isHex( uuid.charAt( 27 ) ) && isHex( uuid.charAt( 28 ) ) && isHex( uuid.charAt( 29 ) )
2144             && isHex( uuid.charAt( 30 ) ) && isHex( uuid.charAt( 31 ) ) && isHex( uuid.charAt( 32 ) )
2145             && isHex( uuid.charAt( 33 ) ) && isHex( uuid.charAt( 34 ) ) && isHex( uuid.charAt( 35 ) ) )
2146         {
2147             // There is not that much more we can check.
2148             LOG.debug( "Syntax valid for '{}'", uuid );
2149             return true;
2150         }
2151 
2152         LOG.debug( "Syntax invalid for '{}'", uuid );
2153         return false;
2154     }
2155 
2156 
2157     /**
2158      * converts the bytes of a UUID to string
2159      *
2160      * @param bytes bytes of a UUID
2161      * @return UUID in string format
2162      */
2163     public static String uuidToString( byte[] bytes )
2164     {
2165         if ( ( bytes == null ) || ( bytes.length != 16 ) )
2166         {
2167             return "Invalid UUID";
2168         }
2169 
2170         char[] hex = encodeHex( bytes );
2171         StringBuilder sb = new StringBuilder();
2172         sb.append( hex, 0, 8 );
2173         sb.append( '-' );
2174         sb.append( hex, 8, 4 );
2175         sb.append( '-' );
2176         sb.append( hex, 12, 4 );
2177         sb.append( '-' );
2178         sb.append( hex, 16, 4 );
2179         sb.append( '-' );
2180         sb.append( hex, 20, 12 );
2181 
2182         return Strings.toLowerCaseAscii( sb.toString() );
2183     }
2184 
2185 
2186     /**
2187      * converts the string representation of an UUID to bytes
2188      *
2189      * @param string the string representation of an UUID
2190      * @return the bytes, null if the the syntax is not valid
2191      */
2192     public static byte[] uuidToBytes( String string )
2193     {
2194         if ( !isValidUuid( string ) )
2195         {
2196             return null;
2197         }
2198 
2199         char[] chars = string.toCharArray();
2200         byte[] bytes = new byte[16];
2201         bytes[0] = getHexValue( chars[0], chars[1] );
2202         bytes[1] = getHexValue( chars[2], chars[3] );
2203         bytes[2] = getHexValue( chars[4], chars[5] );
2204         bytes[3] = getHexValue( chars[6], chars[7] );
2205 
2206         bytes[4] = getHexValue( chars[9], chars[10] );
2207         bytes[5] = getHexValue( chars[11], chars[12] );
2208 
2209         bytes[6] = getHexValue( chars[14], chars[15] );
2210         bytes[7] = getHexValue( chars[16], chars[17] );
2211 
2212         bytes[8] = getHexValue( chars[19], chars[20] );
2213         bytes[9] = getHexValue( chars[21], chars[22] );
2214 
2215         bytes[10] = getHexValue( chars[24], chars[25] );
2216         bytes[11] = getHexValue( chars[26], chars[27] );
2217         bytes[12] = getHexValue( chars[28], chars[29] );
2218         bytes[13] = getHexValue( chars[30], chars[31] );
2219         bytes[14] = getHexValue( chars[32], chars[33] );
2220         bytes[15] = getHexValue( chars[34], chars[35] );
2221 
2222         return bytes;
2223     }
2224 
2225 
2226     /**
2227      * Copy a byte array into a new byte array
2228      *
2229      * @param value the byte array to copy
2230      * @return The copied byte array
2231      */
2232     public static byte[] copy( byte[] value )
2233     {
2234         if ( isEmpty( value ) )
2235         {
2236             return EMPTY_BYTES;
2237         }
2238 
2239         byte[] copy = new byte[value.length];
2240         System.arraycopy( value, 0, copy, 0, value.length );
2241 
2242         return copy;
2243     }
2244 
2245 
2246     /**
2247      * From commons-httpclients. Converts the byte array of HTTP content
2248      * characters to a string. If the specified charset is not supported,
2249      * default system encoding is used.
2250      *
2251      * @param data the byte array to be encoded
2252      * @param offset the index of the first byte to encode
2253      * @param length the number of bytes to encode
2254      * @param charset the desired character encoding
2255      * @return The result of the conversion.
2256      * @since 3.0
2257      */
2258     public static String getString( final byte[] data, int offset, int length, String charset )
2259     {
2260         if ( data == null )
2261         {
2262             throw new IllegalArgumentException( I18n.err( I18n.ERR_04411 ) );
2263         }
2264 
2265         if ( ( charset == null ) || ( charset.length() == 0 ) )
2266         {
2267             throw new IllegalArgumentException( I18n.err( I18n.ERR_04412 ) );
2268         }
2269 
2270         try
2271         {
2272             return new String( data, offset, length, charset );
2273         }
2274         catch ( UnsupportedEncodingException e )
2275         {
2276             return new String( data, offset, length, Charset.defaultCharset() );
2277         }
2278     }
2279 
2280 
2281     /**
2282      * From commons-httpclients. Converts the byte array of HTTP content
2283      * characters to a string. If the specified charset is not supported,
2284      * default system encoding is used.
2285      *
2286      * @param data the byte array to be encoded
2287      * @param charset the desired character encoding
2288      * @return The result of the conversion.
2289      * @since 3.0
2290      */
2291     public static String getString( final byte[] data, String charset )
2292     {
2293         return getString( data, 0, data.length, charset );
2294     }
2295 
2296 
2297     /**
2298      * Create a new UUID using a long as the least significant bits
2299      * 
2300      * @param value The least significant bits.
2301      * @return The created UUID
2302      */
2303     public static String getUUID( long value )
2304     {
2305         return new UUID( 0, value ).toString();
2306     }
2307     
2308     
2309     /**
2310      * Past an ASCII String to a number
2311      *
2312      * @param value The string to parse
2313      * @return the parsed value.
2314      */
2315     public static int parseInt( String value )
2316     {
2317         long res = 0;
2318         
2319         for ( char c : value.toCharArray() )
2320         {
2321             if ( ( c >= '0' ) && ( c <= '9' ) )
2322             {
2323                 res = res * 10 + ( c - '0' );
2324                 
2325                 if ( res > Integer.MAX_VALUE )
2326                 {
2327                     throw new NumberFormatException( "Integer " + value + " is too big" );
2328                 }
2329             }
2330             else
2331             {
2332                 throw new NumberFormatException( "Integer " + value + " is not valid" );
2333             }
2334         }
2335         
2336         return ( int ) res;
2337     }
2338 }