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