198 // an additional StringDe/Encoder object to wrap it is to share the 199 // de/encode() method. These SD/E objects are short-lived, the young-gen 200 // gc should be able to take care of them well. But the best approach 201 // is still not to generate them if not really necessary. 202 // (2)The defensive copy of the input byte/char[] has a big performance 203 // impact, as well as the outgoing result byte/char[]. Need to do the 204 // optimization check of (sm==null && classLoader0==null) for both. 205 // (3)getClass().getClassLoader0() is expensive 206 // (4)There might be a timing gap in isTrusted setting. getClassLoader0() 207 // is only checked (and then isTrusted gets set) when (SM==null). It is 208 // possible that the SM==null for now but then SM is NOT null later 209 // when safeTrim() is invoked...the "safe" way to do is to redundant 210 // check (... && (isTrusted || SM == null || getClassLoader0())) in trim 211 // but it then can be argued that the SM is null when the operation 212 // is started... 213 CharsetDecoder cd = cs.newDecoder(); 214 int en = scale(len, cd.maxCharsPerByte()); 215 char[] ca = new char[en]; 216 if (len == 0) 217 return ca; 218 boolean isTrusted = false; 219 if (System.getSecurityManager() != null) { 220 if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { 221 ba = Arrays.copyOfRange(ba, off, off + len); 222 off = 0; 223 } 224 } 225 cd.onMalformedInput(CodingErrorAction.REPLACE) 226 .onUnmappableCharacter(CodingErrorAction.REPLACE) 227 .reset(); 228 if (cd instanceof ArrayDecoder) { 229 int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); 230 return safeTrim(ca, clen, cs, isTrusted); 231 } else { 232 ByteBuffer bb = ByteBuffer.wrap(ba, off, len); 233 CharBuffer cb = CharBuffer.wrap(ca); 234 try { 235 CoderResult cr = cd.decode(bb, cb, true); 236 if (!cr.isUnderflow()) 237 cr.throwException(); 238 cr = cd.flush(cb); 239 if (!cr.isUnderflow()) 240 cr.throwException(); 241 } catch (CharacterCodingException x) { 242 // Substitution is always enabled, 243 // so this shouldn't happen 244 throw new Error(x); 245 } 246 return safeTrim(ca, cb.position(), cs, isTrusted); 247 } 248 } 249 250 static char[] decode(byte[] ba, int off, int len) { 251 String csn = Charset.defaultCharset().name(); 252 try { 253 // use charset name decode() variant which provides caching. 254 return decode(csn, ba, off, len); 255 } catch (UnsupportedEncodingException x) { 256 warnUnsupportedCharset(csn); 257 } 258 try { 259 return decode("ISO-8859-1", ba, off, len); 260 } catch (UnsupportedEncodingException x) { 261 // If this code is hit during VM initialization, MessageUtils is 262 // the only way we will be able to get any kind of error message. 263 MessageUtils.err("ISO-8859-1 charset not available: " 264 + x.toString()); 265 // If we can not find ISO-8859-1 (a required encoding) then things 266 // are seriously wrong with the installation. 267 System.exit(1); 268 return null; 333 || csn.equals(se.charsetName()))) { 334 se = null; 335 try { 336 Charset cs = lookupCharset(csn); 337 if (cs != null) 338 se = new StringEncoder(cs, csn); 339 } catch (IllegalCharsetNameException x) {} 340 if (se == null) 341 throw new UnsupportedEncodingException (csn); 342 set(encoder, se); 343 } 344 return se.encode(ca, off, len); 345 } 346 347 static byte[] encode(Charset cs, char[] ca, int off, int len) { 348 CharsetEncoder ce = cs.newEncoder(); 349 int en = scale(len, ce.maxBytesPerChar()); 350 byte[] ba = new byte[en]; 351 if (len == 0) 352 return ba; 353 boolean isTrusted = false; 354 if (System.getSecurityManager() != null) { 355 if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { 356 ca = Arrays.copyOfRange(ca, off, off + len); 357 off = 0; 358 } 359 } 360 ce.onMalformedInput(CodingErrorAction.REPLACE) 361 .onUnmappableCharacter(CodingErrorAction.REPLACE) 362 .reset(); 363 if (ce instanceof ArrayEncoder) { 364 int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); 365 return safeTrim(ba, blen, cs, isTrusted); 366 } else { 367 ByteBuffer bb = ByteBuffer.wrap(ba); 368 CharBuffer cb = CharBuffer.wrap(ca, off, len); 369 try { 370 CoderResult cr = ce.encode(cb, bb, true); 371 if (!cr.isUnderflow()) 372 cr.throwException(); 373 cr = ce.flush(bb); 374 if (!cr.isUnderflow()) 375 cr.throwException(); 376 } catch (CharacterCodingException x) { 377 throw new Error(x); 378 } 379 return safeTrim(ba, bb.position(), cs, isTrusted); 380 } 381 } 382 383 static byte[] encode(char[] ca, int off, int len) { 384 String csn = Charset.defaultCharset().name(); 385 try { 386 // use charset name encode() variant which provides caching. 387 return encode(csn, ca, off, len); 388 } catch (UnsupportedEncodingException x) { 389 warnUnsupportedCharset(csn); 390 } 391 try { 392 return encode("ISO-8859-1", ca, off, len); 393 } catch (UnsupportedEncodingException x) { 394 // If this code is hit during VM initialization, MessageUtils is 395 // the only way we will be able to get any kind of error message. 396 MessageUtils.err("ISO-8859-1 charset not available: " 397 + x.toString()); 398 // If we can not find ISO-8859-1 (a required encoding) then things 399 // are seriously wrong with the installation. 400 System.exit(1); | 198 // an additional StringDe/Encoder object to wrap it is to share the 199 // de/encode() method. These SD/E objects are short-lived, the young-gen 200 // gc should be able to take care of them well. But the best approach 201 // is still not to generate them if not really necessary. 202 // (2)The defensive copy of the input byte/char[] has a big performance 203 // impact, as well as the outgoing result byte/char[]. Need to do the 204 // optimization check of (sm==null && classLoader0==null) for both. 205 // (3)getClass().getClassLoader0() is expensive 206 // (4)There might be a timing gap in isTrusted setting. getClassLoader0() 207 // is only checked (and then isTrusted gets set) when (SM==null). It is 208 // possible that the SM==null for now but then SM is NOT null later 209 // when safeTrim() is invoked...the "safe" way to do is to redundant 210 // check (... && (isTrusted || SM == null || getClassLoader0())) in trim 211 // but it then can be argued that the SM is null when the operation 212 // is started... 213 CharsetDecoder cd = cs.newDecoder(); 214 int en = scale(len, cd.maxCharsPerByte()); 215 char[] ca = new char[en]; 216 if (len == 0) 217 return ca; 218 219 boolean isTrusted = isTrusted(cs); 220 if (!isTrusted) { 221 ba = Arrays.copyOfRange(ba, off, off + len); 222 off = 0; 223 } 224 225 setupDecoder(cd); 226 227 if (cd instanceof ArrayDecoder) { 228 int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); 229 return safeTrim(ca, clen, cs, isTrusted); 230 } else { 231 ByteBuffer bb = ByteBuffer.wrap(ba, off, len); 232 return performDecode(cs, isTrusted, ca, cd, bb); 233 } 234 } 235 236 static char[] decode(Charset cs, ByteBuffer bb) { 237 // See comment at top of decode(Charset,byte[],int,int) 238 CharsetDecoder cd = cs.newDecoder(); 239 int len = bb.remaining(); 240 int en = scale(len, cd.maxCharsPerByte()); 241 char[] ca = new char[en]; 242 if (len == 0) 243 return ca; 244 245 boolean isTrusted = isTrusted(cs); 246 if (!isTrusted) { 247 // setup the bytebuffer for copying 248 249 // copy the bytebuffer 250 ByteBuffer originalByteBuffer = bb; 251 bb = ByteBuffer.allocateDirect(len) 252 .put(originalByteBuffer); 253 bb.position(0); 254 } 255 256 setupDecoder(cd); 257 258 return performDecode(cs, isTrusted, ca, cd, bb); 259 } 260 261 private static boolean isTrusted(Charset cs) { 262 return System.getSecurityManager() != null 263 // null classloader means the class is on the boot classpath 264 && cs.getClass().getClassLoader0() == null; 265 } 266 267 private static void setupDecoder(CharsetDecoder cd) { 268 cd.onMalformedInput(CodingErrorAction.REPLACE) 269 .onUnmappableCharacter(CodingErrorAction.REPLACE) 270 .reset(); 271 } 272 273 static char[] performDecode( 274 Charset cs, boolean isTrusted, char[] ca, 275 CharsetDecoder cd, ByteBuffer bb) { 276 277 CharBuffer cb = CharBuffer.wrap(ca); 278 try { 279 CoderResult cr = cd.decode(bb, cb, true); 280 if (!cr.isUnderflow()) 281 cr.throwException(); 282 cr = cd.flush(cb); 283 if (!cr.isUnderflow()) 284 cr.throwException(); 285 } catch (CharacterCodingException x) { 286 // Substitution is always enabled, 287 // so this shouldn't happen 288 throw new Error(x); 289 } 290 return safeTrim(ca, cb.position(), cs, isTrusted); 291 } 292 293 static char[] decode(byte[] ba, int off, int len) { 294 String csn = Charset.defaultCharset().name(); 295 try { 296 // use charset name decode() variant which provides caching. 297 return decode(csn, ba, off, len); 298 } catch (UnsupportedEncodingException x) { 299 warnUnsupportedCharset(csn); 300 } 301 try { 302 return decode("ISO-8859-1", ba, off, len); 303 } catch (UnsupportedEncodingException x) { 304 // If this code is hit during VM initialization, MessageUtils is 305 // the only way we will be able to get any kind of error message. 306 MessageUtils.err("ISO-8859-1 charset not available: " 307 + x.toString()); 308 // If we can not find ISO-8859-1 (a required encoding) then things 309 // are seriously wrong with the installation. 310 System.exit(1); 311 return null; 376 || csn.equals(se.charsetName()))) { 377 se = null; 378 try { 379 Charset cs = lookupCharset(csn); 380 if (cs != null) 381 se = new StringEncoder(cs, csn); 382 } catch (IllegalCharsetNameException x) {} 383 if (se == null) 384 throw new UnsupportedEncodingException (csn); 385 set(encoder, se); 386 } 387 return se.encode(ca, off, len); 388 } 389 390 static byte[] encode(Charset cs, char[] ca, int off, int len) { 391 CharsetEncoder ce = cs.newEncoder(); 392 int en = scale(len, ce.maxBytesPerChar()); 393 byte[] ba = new byte[en]; 394 if (len == 0) 395 return ba; 396 boolean isTrusted = isTrusted(cs); 397 if (!isTrusted) { 398 ca = Arrays.copyOfRange(ca, off, off + len); 399 off = 0; 400 } 401 setupEncoder(ce); 402 if (ce instanceof ArrayEncoder) { 403 int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); 404 return safeTrim(ba, blen, cs, isTrusted); 405 } else { 406 ByteBuffer bb = ByteBuffer.wrap(ba); 407 CharBuffer cb = CharBuffer.wrap(ca, off, len); 408 try { 409 CoderResult cr = ce.encode(cb, bb, true); 410 if (!cr.isUnderflow()) 411 cr.throwException(); 412 cr = ce.flush(bb); 413 if (!cr.isUnderflow()) 414 cr.throwException(); 415 } catch (CharacterCodingException x) { 416 throw new Error(x); 417 } 418 return safeTrim(ba, bb.position(), cs, isTrusted); 419 } 420 } 421 422 static int encode(Charset cs, char[] ca, int off, int len, byte[] destBuffer, int destOffset) { 423 ByteBuffer bb = ByteBuffer.wrap(destBuffer, destOffset, destBuffer.length - destOffset); 424 return encode(cs, ca, off, len, bb); 425 } 426 427 static int encode(Charset cs, char[] ca, int off, int len, ByteBuffer destBuffer) { 428 CharsetEncoder ce = cs.newEncoder(); 429 final int originalPosition = destBuffer.position(); 430 CharBuffer cb = CharBuffer.wrap(ca, off, len); 431 try { 432 CoderResult cr = ce.encode(cb, destBuffer, true); 433 if (!cr.isUnderflow()) 434 cr.throwException(); 435 cr = ce.flush(destBuffer); 436 if (!cr.isUnderflow()) 437 cr.throwException(); 438 } catch (CharacterCodingException x) { 439 throw new Error(x); 440 } 441 return destBuffer.position() - originalPosition; 442 } 443 444 private static void setupEncoder(CharsetEncoder encoder) { 445 encoder.onMalformedInput(CodingErrorAction.REPLACE) 446 .onUnmappableCharacter(CodingErrorAction.REPLACE) 447 .reset(); 448 } 449 450 static byte[] encode(char[] ca, int off, int len) { 451 String csn = Charset.defaultCharset().name(); 452 try { 453 // use charset name encode() variant which provides caching. 454 return encode(csn, ca, off, len); 455 } catch (UnsupportedEncodingException x) { 456 warnUnsupportedCharset(csn); 457 } 458 try { 459 return encode("ISO-8859-1", ca, off, len); 460 } catch (UnsupportedEncodingException x) { 461 // If this code is hit during VM initialization, MessageUtils is 462 // the only way we will be able to get any kind of error message. 463 MessageUtils.err("ISO-8859-1 charset not available: " 464 + x.toString()); 465 // If we can not find ISO-8859-1 (a required encoding) then things 466 // are seriously wrong with the installation. 467 System.exit(1); |