1package org.bouncycastle.util; 2 3import java.io.ByteArrayOutputStream; 4import java.io.IOException; 5import java.io.OutputStream; 6import java.security.AccessController; 7import java.security.PrivilegedAction; 8import java.util.ArrayList; 9import java.util.Vector; 10 11/** 12 * String utilities. 13 */ 14public final class Strings 15{ 16 private static String LINE_SEPARATOR; 17 18 static 19 { 20 try 21 { 22 LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction<String>() 23 { 24 public String run() 25 { 26 // the easy way 27 return System.getProperty("line.separator"); 28 } 29 }); 30 31 } 32 catch (Exception e) 33 { 34 try 35 { 36 // the harder way 37 LINE_SEPARATOR = String.format("%n"); 38 } 39 catch (Exception ef) 40 { 41 LINE_SEPARATOR = "\n"; // we're desperate use this... 42 } 43 } 44 } 45 46 public static String fromUTF8ByteArray(byte[] bytes) 47 { 48 int i = 0; 49 int length = 0; 50 51 while (i < bytes.length) 52 { 53 length++; 54 if ((bytes[i] & 0xf0) == 0xf0) 55 { 56 // surrogate pair 57 length++; 58 i += 4; 59 } 60 else if ((bytes[i] & 0xe0) == 0xe0) 61 { 62 i += 3; 63 } 64 else if ((bytes[i] & 0xc0) == 0xc0) 65 { 66 i += 2; 67 } 68 else 69 { 70 i += 1; 71 } 72 } 73 74 char[] cs = new char[length]; 75 76 i = 0; 77 length = 0; 78 79 while (i < bytes.length) 80 { 81 char ch; 82 83 if ((bytes[i] & 0xf0) == 0xf0) 84 { 85 int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i + 1] & 0x3F) << 12) | ((bytes[i + 2] & 0x3F) << 6) | (bytes[i + 3] & 0x3F); 86 int U = codePoint - 0x10000; 87 char W1 = (char)(0xD800 | (U >> 10)); 88 char W2 = (char)(0xDC00 | (U & 0x3FF)); 89 cs[length++] = W1; 90 ch = W2; 91 i += 4; 92 } 93 else if ((bytes[i] & 0xe0) == 0xe0) 94 { 95 ch = (char)(((bytes[i] & 0x0f) << 12) 96 | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)); 97 i += 3; 98 } 99 else if ((bytes[i] & 0xd0) == 0xd0) 100 { 101 ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); 102 i += 2; 103 } 104 else if ((bytes[i] & 0xc0) == 0xc0) 105 { 106 ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); 107 i += 2; 108 } 109 else 110 { 111 ch = (char)(bytes[i] & 0xff); 112 i += 1; 113 } 114 115 cs[length++] = ch; 116 } 117 118 return new String(cs); 119 } 120 121 public static byte[] toUTF8ByteArray(String string) 122 { 123 return toUTF8ByteArray(string.toCharArray()); 124 } 125 126 public static byte[] toUTF8ByteArray(char[] string) 127 { 128 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 129 130 try 131 { 132 toUTF8ByteArray(string, bOut); 133 } 134 catch (IOException e) 135 { 136 throw new IllegalStateException("cannot encode string to byte array!"); 137 } 138 139 return bOut.toByteArray(); 140 } 141 142 public static void toUTF8ByteArray(char[] string, OutputStream sOut) 143 throws IOException 144 { 145 char[] c = string; 146 int i = 0; 147 148 while (i < c.length) 149 { 150 char ch = c[i]; 151 152 if (ch < 0x0080) 153 { 154 sOut.write(ch); 155 } 156 else if (ch < 0x0800) 157 { 158 sOut.write(0xc0 | (ch >> 6)); 159 sOut.write(0x80 | (ch & 0x3f)); 160 } 161 // surrogate pair 162 else if (ch >= 0xD800 && ch <= 0xDFFF) 163 { 164 // in error - can only happen, if the Java String class has a 165 // bug. 166 if (i + 1 >= c.length) 167 { 168 throw new IllegalStateException("invalid UTF-16 codepoint"); 169 } 170 char W1 = ch; 171 ch = c[++i]; 172 char W2 = ch; 173 // in error - can only happen, if the Java String class has a 174 // bug. 175 if (W1 > 0xDBFF) 176 { 177 throw new IllegalStateException("invalid UTF-16 codepoint"); 178 } 179 int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000; 180 sOut.write(0xf0 | (codePoint >> 18)); 181 sOut.write(0x80 | ((codePoint >> 12) & 0x3F)); 182 sOut.write(0x80 | ((codePoint >> 6) & 0x3F)); 183 sOut.write(0x80 | (codePoint & 0x3F)); 184 } 185 else 186 { 187 sOut.write(0xe0 | (ch >> 12)); 188 sOut.write(0x80 | ((ch >> 6) & 0x3F)); 189 sOut.write(0x80 | (ch & 0x3F)); 190 } 191 192 i++; 193 } 194 } 195 196 /** 197 * A locale independent version of toUpperCase. 198 * 199 * @param string input to be converted 200 * @return a US Ascii uppercase version 201 */ 202 public static String toUpperCase(String string) 203 { 204 boolean changed = false; 205 char[] chars = string.toCharArray(); 206 207 for (int i = 0; i != chars.length; i++) 208 { 209 char ch = chars[i]; 210 if ('a' <= ch && 'z' >= ch) 211 { 212 changed = true; 213 chars[i] = (char)(ch - 'a' + 'A'); 214 } 215 } 216 217 if (changed) 218 { 219 return new String(chars); 220 } 221 222 return string; 223 } 224 225 /** 226 * A locale independent version of toLowerCase. 227 * 228 * @param string input to be converted 229 * @return a US ASCII lowercase version 230 */ 231 public static String toLowerCase(String string) 232 { 233 boolean changed = false; 234 char[] chars = string.toCharArray(); 235 236 for (int i = 0; i != chars.length; i++) 237 { 238 char ch = chars[i]; 239 if ('A' <= ch && 'Z' >= ch) 240 { 241 changed = true; 242 chars[i] = (char)(ch - 'A' + 'a'); 243 } 244 } 245 246 if (changed) 247 { 248 return new String(chars); 249 } 250 251 return string; 252 } 253 254 public static byte[] toByteArray(char[] chars) 255 { 256 byte[] bytes = new byte[chars.length]; 257 258 for (int i = 0; i != bytes.length; i++) 259 { 260 bytes[i] = (byte)chars[i]; 261 } 262 263 return bytes; 264 } 265 266 public static byte[] toByteArray(String string) 267 { 268 byte[] bytes = new byte[string.length()]; 269 270 for (int i = 0; i != bytes.length; i++) 271 { 272 char ch = string.charAt(i); 273 274 bytes[i] = (byte)ch; 275 } 276 277 return bytes; 278 } 279 280 public static int toByteArray(String s, byte[] buf, int off) 281 { 282 int count = s.length(); 283 for (int i = 0; i < count; ++i) 284 { 285 char c = s.charAt(i); 286 buf[off + i] = (byte)c; 287 } 288 return count; 289 } 290 291 /** 292 * Convert an array of 8 bit characters into a string. 293 * 294 * @param bytes 8 bit characters. 295 * @return resulting String. 296 */ 297 public static String fromByteArray(byte[] bytes) 298 { 299 return new String(asCharArray(bytes)); 300 } 301 302 /** 303 * Do a simple conversion of an array of 8 bit characters into a string. 304 * 305 * @param bytes 8 bit characters. 306 * @return resulting String. 307 */ 308 public static char[] asCharArray(byte[] bytes) 309 { 310 char[] chars = new char[bytes.length]; 311 312 for (int i = 0; i != chars.length; i++) 313 { 314 chars[i] = (char)(bytes[i] & 0xff); 315 } 316 317 return chars; 318 } 319 320 public static String[] split(String input, char delimiter) 321 { 322 Vector v = new Vector(); 323 boolean moreTokens = true; 324 String subString; 325 326 while (moreTokens) 327 { 328 int tokenLocation = input.indexOf(delimiter); 329 if (tokenLocation > 0) 330 { 331 subString = input.substring(0, tokenLocation); 332 v.addElement(subString); 333 input = input.substring(tokenLocation + 1); 334 } 335 else 336 { 337 moreTokens = false; 338 v.addElement(input); 339 } 340 } 341 342 String[] res = new String[v.size()]; 343 344 for (int i = 0; i != res.length; i++) 345 { 346 res[i] = (String)v.elementAt(i); 347 } 348 return res; 349 } 350 351 public static StringList newList() 352 { 353 return new StringListImpl(); 354 } 355 356 public static String lineSeparator() 357 { 358 return LINE_SEPARATOR; 359 } 360 361 private static class StringListImpl 362 extends ArrayList<String> 363 implements StringList 364 { 365 public boolean add(String s) 366 { 367 return super.add(s); 368 } 369 370 public String set(int index, String element) 371 { 372 return super.set(index, element); 373 } 374 375 public void add(int index, String element) 376 { 377 super.add(index, element); 378 } 379 380 public String[] toStringArray() 381 { 382 String[] strs = new String[this.size()]; 383 384 for (int i = 0; i != strs.length; i++) 385 { 386 strs[i] = this.get(i); 387 } 388 389 return strs; 390 } 391 392 public String[] toStringArray(int from, int to) 393 { 394 String[] strs = new String[to - from]; 395 396 for (int i = from; i != this.size() && i != to; i++) 397 { 398 strs[i - from] = this.get(i); 399 } 400 401 return strs; 402 } 403 } 404} 405