src/java.base/share/classes/java/lang/StringCoding.java
Print this page
@@ -126,13 +126,12 @@
private final boolean isTrusted;
private StringDecoder(Charset cs, String rcn) {
this.requestedCharsetName = rcn;
this.cs = cs;
- this.cd = cs.newDecoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.cd = cs.newDecoder();
+ setupDecoder(cd);
this.isTrusted = (cs.getClass().getClassLoader0() == null);
}
String charsetName() {
if (cs instanceof HistoricallyNamedCharset)
@@ -153,31 +152,41 @@
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
cd.reset();
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
- CharBuffer cb = CharBuffer.wrap(ca);
- try {
- CoderResult cr = cd.decode(bb, cb, true);
- if (!cr.isUnderflow())
- cr.throwException();
- cr = cd.flush(cb);
- if (!cr.isUnderflow())
- cr.throwException();
- } catch (CharacterCodingException x) {
- // Substitution is always enabled,
- // so this shouldn't happen
- throw new Error(x);
+ return performDecode(cs, isTrusted, ca, cd, bb);
}
- return safeTrim(ca, cb.position(), cs, isTrusted);
+ }
+
+ char[] decode(ByteBuffer bb) {
+ int len = bb.remaining();
+ int en = scale(len, cd.maxCharsPerByte());
+ char[] ca = new char[en];
+ if (len == 0)
+ return ca;
+
+ if (!isTrusted) {
+ // copy the bytebuffer
+ ByteBuffer originalByteBuffer = bb;
+ bb = ByteBuffer.allocate(len)
+ .put(originalByteBuffer);
+ bb.position(0);
+ }
+
+ cd.reset();
+
+ return performDecode(cs, isTrusted, ca, cd, bb);
}
}
+
+ static char[] decode(String charsetName, byte[] ba, int off, int len) throws UnsupportedEncodingException {
+ StringDecoder sd = getStringDecoder(charsetName);
+ return sd.decode(ba, off, len);
}
- static char[] decode(String charsetName, byte[] ba, int off, int len)
- throws UnsupportedEncodingException
- {
+ private static StringDecoder getStringDecoder(String charsetName) throws UnsupportedEncodingException {
StringDecoder sd = deref(decoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
|| csn.equals(sd.charsetName()))) {
sd = null;
@@ -188,11 +197,11 @@
} catch (IllegalCharsetNameException x) {}
if (sd == null)
throw new UnsupportedEncodingException(csn);
set(decoder, sd);
}
- return sd.decode(ba, off, len);
+ return sd;
}
static char[] decode(Charset cs, byte[] ba, int off, int len) {
// (1)We never cache the "external" cs, the only benefit of creating
// an additional StringDe/Encoder object to wrap it is to share the
@@ -213,25 +222,72 @@
CharsetDecoder cd = cs.newDecoder();
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
- boolean isTrusted = false;
- if (System.getSecurityManager() != null) {
- if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
+
+ boolean isTrusted = isTrusted(cs);
+ if (!isTrusted) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
- }
- cd.onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE)
- .reset();
+
+ setupDecoder(cd);
+
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
+ return performDecode(cs, isTrusted, ca, cd, bb);
+ }
+ }
+
+ static char[] decode(Charset cs, ByteBuffer bb) {
+ // See comment at top of decode(Charset,byte[],int,int)
+ CharsetDecoder cd = cs.newDecoder();
+ int len = bb.remaining();
+ int en = scale(len, cd.maxCharsPerByte());
+ char[] ca = new char[en];
+ if (len == 0)
+ return ca;
+
+ boolean isTrusted = isTrusted(cs);
+ if (!isTrusted) {
+ // copy the bytebuffer
+ ByteBuffer originalByteBuffer = bb;
+ bb = ByteBuffer.allocate(len)
+ .put(originalByteBuffer);
+ bb.position(0);
+ }
+
+ setupDecoder(cd);
+
+ return performDecode(cs, isTrusted, ca, cd, bb);
+ }
+
+ static char[] decode(String charsetName, ByteBuffer bb) throws UnsupportedEncodingException {
+ StringDecoder sd = getStringDecoder(charsetName);
+ return sd.decode(bb);
+ }
+
+ private static boolean isTrusted(Charset cs) {
+ return System.getSecurityManager() != null
+ // null classloader means the class is on the boot classpath
+ && cs.getClass().getClassLoader0() == null;
+ }
+
+ private static void setupDecoder(CharsetDecoder cd) {
+ cd.onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE)
+ .reset();
+ }
+
+ static char[] performDecode(
+ Charset cs, boolean isTrusted, char[] ca,
+ CharsetDecoder cd, ByteBuffer bb) {
+
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
@@ -243,11 +299,10 @@
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
}
- }
static char[] decode(byte[] ba, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
// use charset name decode() variant which provides caching.
@@ -304,31 +359,23 @@
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ce.reset();
ByteBuffer bb = ByteBuffer.wrap(ba);
- CharBuffer cb = CharBuffer.wrap(ca, off, len);
- try {
- CoderResult cr = ce.encode(cb, bb, true);
- if (!cr.isUnderflow())
- cr.throwException();
- cr = ce.flush(bb);
- if (!cr.isUnderflow())
- cr.throwException();
- } catch (CharacterCodingException x) {
- // Substitution is always enabled,
- // so this shouldn't happen
- throw new Error(x);
- }
+ StringCoding.encode(ca, off, len, bb, ce);
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
}
static byte[] encode(String charsetName, char[] ca, int off, int len)
- throws UnsupportedEncodingException
- {
+ throws UnsupportedEncodingException {
+ StringEncoder se = getStringEncoder(charsetName);
+ return se.encode(ca, off, len);
+ }
+
+ private static StringEncoder getStringEncoder(String charsetName) throws UnsupportedEncodingException {
StringEncoder se = deref(encoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((se == null) || !(csn.equals(se.requestedCharsetName())
|| csn.equals(se.charsetName()))) {
se = null;
@@ -339,47 +386,83 @@
} catch (IllegalCharsetNameException x) {}
if (se == null)
throw new UnsupportedEncodingException (csn);
set(encoder, se);
}
- return se.encode(ca, off, len);
+ se.ce.reset();
+ return se;
}
static byte[] encode(Charset cs, char[] ca, int off, int len) {
CharsetEncoder ce = cs.newEncoder();
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
- boolean isTrusted = false;
- if (System.getSecurityManager() != null) {
- if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
+ boolean isTrusted = isTrusted(cs);
+ if (!isTrusted) {
ca = Arrays.copyOfRange(ca, off, off + len);
off = 0;
}
- }
- ce.onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE)
- .reset();
+ setupEncoder(ce);
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
+ encode(ca, off, len, bb, ce);
+ return safeTrim(ba, bb.position(), cs, isTrusted);
+ }
+ }
+
+
+ static int encode(Charset cs, char[] ca, int off, int len, byte[] destBuffer, int destOffset) {
+ ByteBuffer bb = ByteBuffer.wrap(destBuffer, destOffset, destBuffer.length - destOffset);
+ return encode(cs, ca, off, len, bb);
+ }
+
+ static int encode(Charset cs, char[] ca, int off, int len, ByteBuffer destBuffer) {
+ CharsetEncoder ce = cs.newEncoder();
+ return encodeBuffer(ca, off, len, destBuffer, ce);
+ }
+
+ static int encode(String charsetName, char[] ca, int off, int len, byte[] destBuffer, int destOffset) throws UnsupportedEncodingException {
+ ByteBuffer bb = ByteBuffer.wrap(destBuffer, destOffset, destBuffer.length - destOffset);
+ return encode(charsetName, ca, off, len, bb);
+ }
+
+ static int encode(String charsetName, char[] ca, int off, int len, ByteBuffer destBuffer) throws UnsupportedEncodingException {
+ StringEncoder se = getStringEncoder(charsetName);
+ return encodeBuffer(ca, off, len, destBuffer, se.ce);
+ }
+
+ // encode(charsetName, value, 0, value.length, destBuffer, destOffset);
+
+ private static int encodeBuffer(char[] ca, int off, int len, ByteBuffer destBuffer, CharsetEncoder ce) {
+ int originalPosition = destBuffer.position();
+ encode(ca, off, len, destBuffer, ce);
+ return destBuffer.position() - originalPosition;
+ }
+
+ private static void encode(char[] ca, int off, int len, ByteBuffer destBuffer, CharsetEncoder ce) {
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
- CoderResult cr = ce.encode(cb, bb, true);
+ CoderResult cr = ce.encode(cb, destBuffer, true);
if (!cr.isUnderflow())
cr.throwException();
- cr = ce.flush(bb);
+ cr = ce.flush(destBuffer);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
- return safeTrim(ba, bb.position(), cs, isTrusted);
}
+
+ private static void setupEncoder(CharsetEncoder encoder) {
+ encoder.onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE)
+ .reset();
}
static byte[] encode(char[] ca, int off, int len) {
String csn = Charset.defaultCharset().name();
try {