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); | 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, int off, int len) { 237 // See comment at top of decode(Charset,byte[],int,int) 238 CharsetDecoder cd = cs.newDecoder(); 239 int en = scale(len, cd.maxCharsPerByte()); 240 char[] ca = new char[en]; 241 if (len == 0) 242 return ca; 243 244 boolean isTrusted = isTrusted(cs); 245 if (!isTrusted) { 246 // setup the bytebuffer for copying 247 ByteBuffer originalByteBuffer = bb; 248 int originalPosition = originalByteBuffer.position(); 249 int originalLimit = originalByteBuffer.limit(); 250 originalByteBuffer.position(off) 251 .limit(off + len); 252 253 // copy the bytebuffer 254 bb = ByteBuffer.allocateDirect(len) 255 .put(originalByteBuffer); 256 bb.position(0); 257 258 // reset the original bytebuffer 259 originalByteBuffer.position(originalPosition) 260 .limit(originalLimit); 261 262 off = 0; 263 } 264 265 setupDecoder(cd); 266 267 return performDecode(cs, isTrusted, ca, cd, bb); 268 } 269 270 private static boolean isTrusted(Charset cs) { 271 return System.getSecurityManager() != null 272 && cs.getClass().getClassLoader0() == null; 273 } 274 275 private static void setupDecoder(CharsetDecoder cd) { 276 cd.onMalformedInput(CodingErrorAction.REPLACE) 277 .onUnmappableCharacter(CodingErrorAction.REPLACE) 278 .reset(); 279 } 280 281 static char[] performDecode( 282 Charset cs, boolean isTrusted, char[] ca, 283 CharsetDecoder cd, ByteBuffer bb) { 284 285 CharBuffer cb = CharBuffer.wrap(ca); 286 try { 287 CoderResult cr = cd.decode(bb, cb, true); 288 if (!cr.isUnderflow()) 289 cr.throwException(); 290 cr = cd.flush(cb); 291 if (!cr.isUnderflow()) 292 cr.throwException(); 293 } catch (CharacterCodingException x) { 294 // Substitution is always enabled, 295 // so this shouldn't happen 296 throw new Error(x); 297 } 298 return safeTrim(ca, cb.position(), cs, isTrusted); 299 } 300 301 static char[] decode(byte[] ba, int off, int len) { 302 String csn = Charset.defaultCharset().name(); 303 try { 304 // use charset name decode() variant which provides caching. 305 return decode(csn, ba, off, len); 306 } catch (UnsupportedEncodingException x) { 307 warnUnsupportedCharset(csn); 308 } 309 try { 310 return decode("ISO-8859-1", ba, off, len); 311 } catch (UnsupportedEncodingException x) { 312 // If this code is hit during VM initialization, MessageUtils is 313 // the only way we will be able to get any kind of error message. 314 MessageUtils.err("ISO-8859-1 charset not available: " 315 + x.toString()); 316 // If we can not find ISO-8859-1 (a required encoding) then things 317 // are seriously wrong with the installation. 318 System.exit(1); |