mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
39
src/java.base/share/classes/sun/nio/cs/ArrayDecoder.java
Normal file
39
src/java.base/share/classes/sun/nio/cs/ArrayDecoder.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
/*
|
||||
* FastPath byte[]->char[] decoder, REPLACE on malformed or
|
||||
* unmappable input.
|
||||
*/
|
||||
|
||||
public interface ArrayDecoder {
|
||||
int decode(byte[] src, int off, int len, char[] dst);
|
||||
|
||||
default boolean isASCIICompatible() {
|
||||
return false;
|
||||
}
|
||||
}
|
49
src/java.base/share/classes/sun/nio/cs/ArrayEncoder.java
Normal file
49
src/java.base/share/classes/sun/nio/cs/ArrayEncoder.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
/*
|
||||
* FastPath char[]/byte[] -> byte[] encoder, REPLACE on malformed input or
|
||||
* unmappable input.
|
||||
*/
|
||||
|
||||
public interface ArrayEncoder {
|
||||
|
||||
// is only used by j.u.zip.ZipCoder for utf8
|
||||
int encode(char[] src, int off, int len, byte[] dst);
|
||||
|
||||
default int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
default int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
default boolean isASCIICompatible() {
|
||||
return false;
|
||||
}
|
||||
}
|
604
src/java.base/share/classes/sun/nio/cs/CESU_8.java
Normal file
604
src/java.base/share/classes/sun/nio/cs/CESU_8.java
Normal file
|
@ -0,0 +1,604 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
|
||||
/* Legal CESU-8 Byte Sequences
|
||||
*
|
||||
* # Code Points Bits Bit/Byte pattern
|
||||
* 1 7 0xxxxxxx
|
||||
* U+0000..U+007F 00..7F
|
||||
*
|
||||
* 2 11 110xxxxx 10xxxxxx
|
||||
* U+0080..U+07FF C2..DF 80..BF
|
||||
*
|
||||
* 3 16 1110xxxx 10xxxxxx 10xxxxxx
|
||||
* U+0800..U+0FFF E0 A0..BF 80..BF
|
||||
* U+1000..U+FFFF E1..EF 80..BF 80..BF
|
||||
*
|
||||
*/
|
||||
|
||||
class CESU_8 extends Unicode
|
||||
{
|
||||
public CESU_8() {
|
||||
super("CESU-8", StandardCharsets.aliases_CESU_8());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "CESU8";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static final void updatePositions(Buffer src, int sp,
|
||||
Buffer dst, int dp) {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
|
||||
private static class Decoder extends CharsetDecoder
|
||||
implements ArrayDecoder {
|
||||
private Decoder(Charset cs) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
private static boolean isNotContinuation(int b) {
|
||||
return (b & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// [E0] [A0..BF] [80..BF]
|
||||
// [E1..EF] [80..BF] [80..BF]
|
||||
private static boolean isMalformed3(int b1, int b2, int b3) {
|
||||
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// only used when there is only one byte left in src buffer
|
||||
private static boolean isMalformed3_2(int b1, int b2) {
|
||||
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
(b2 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
|
||||
// [F0] [90..BF] [80..BF] [80..BF]
|
||||
// [F1..F3] [80..BF] [80..BF] [80..BF]
|
||||
// [F4] [80..8F] [80..BF] [80..BF]
|
||||
// only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...]
|
||||
// will be checked by Character.isSupplementaryCodePoint(uc)
|
||||
private static boolean isMalformed4(int b2, int b3, int b4) {
|
||||
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
|
||||
(b4 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// only used when there is less than 4 bytes left in src buffer
|
||||
private static boolean isMalformed4_2(int b1, int b2) {
|
||||
return (b1 == 0xf0 && b2 == 0x90) ||
|
||||
(b2 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static boolean isMalformed4_3(int b3) {
|
||||
return (b3 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static CoderResult malformedN(ByteBuffer src, int nb) {
|
||||
switch (nb) {
|
||||
case 1:
|
||||
case 2: // always 1
|
||||
return CoderResult.malformedForLength(1);
|
||||
case 3:
|
||||
int b1 = src.get();
|
||||
int b2 = src.get(); // no need to lookup b3
|
||||
return CoderResult.malformedForLength(
|
||||
((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
isNotContinuation(b2)) ? 1 : 2);
|
||||
case 4: // we don't care the speed here
|
||||
b1 = src.get() & 0xff;
|
||||
b2 = src.get() & 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
|
||||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
|
||||
isNotContinuation(b2))
|
||||
return CoderResult.malformedForLength(1);
|
||||
if (isNotContinuation(src.get()))
|
||||
return CoderResult.malformedForLength(2);
|
||||
return CoderResult.malformedForLength(3);
|
||||
default:
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static CoderResult malformed(ByteBuffer src, int sp,
|
||||
CharBuffer dst, int dp,
|
||||
int nb)
|
||||
{
|
||||
src.position(sp - src.arrayOffset());
|
||||
CoderResult cr = malformedN(src, nb);
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return cr;
|
||||
}
|
||||
|
||||
|
||||
private static CoderResult malformed(ByteBuffer src,
|
||||
int mark, int nb)
|
||||
{
|
||||
src.position(mark);
|
||||
CoderResult cr = malformedN(src, nb);
|
||||
src.position(mark);
|
||||
return cr;
|
||||
}
|
||||
|
||||
private static CoderResult malformedForLength(ByteBuffer src,
|
||||
int sp,
|
||||
CharBuffer dst,
|
||||
int dp,
|
||||
int malformedNB)
|
||||
{
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return CoderResult.malformedForLength(malformedNB);
|
||||
}
|
||||
|
||||
private static CoderResult malformedForLength(ByteBuffer src,
|
||||
int mark,
|
||||
int malformedNB)
|
||||
{
|
||||
src.position(mark);
|
||||
return CoderResult.malformedForLength(malformedNB);
|
||||
}
|
||||
|
||||
|
||||
private static CoderResult xflow(Buffer src, int sp, int sl,
|
||||
Buffer dst, int dp, int nb) {
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return (nb == 0 || sl - sp < nb)
|
||||
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private static CoderResult xflow(Buffer src, int mark, int nb) {
|
||||
src.position(mark);
|
||||
return (nb == 0 || src.remaining() < nb)
|
||||
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private CoderResult decodeArrayLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
// This method is optimized for ASCII input.
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
char[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int dlASCII = dp + Math.min(sl - sp, dl - dp);
|
||||
|
||||
// ASCII only loop
|
||||
while (dp < dlASCII && sa[sp] >= 0)
|
||||
da[dp++] = (char) sa[sp++];
|
||||
while (sp < sl) {
|
||||
int b1 = sa[sp];
|
||||
if (b1 >= 0) {
|
||||
// 1 byte, 7 bits: 0xxxxxxx
|
||||
if (dp >= dl)
|
||||
return xflow(src, sp, sl, dst, dp, 1);
|
||||
da[dp++] = (char) b1;
|
||||
sp++;
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||
if (sl - sp < 2 || dp >= dl)
|
||||
return xflow(src, sp, sl, dst, dp, 2);
|
||||
int b2 = sa[sp + 1];
|
||||
if (isNotContinuation(b2))
|
||||
return malformedForLength(src, sp, dst, dp, 1);
|
||||
da[dp++] = (char) (((b1 << 6) ^ b2)
|
||||
^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0)));
|
||||
sp += 2;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||
int srcRemaining = sl - sp;
|
||||
if (srcRemaining < 3 || dp >= dl) {
|
||||
if (srcRemaining > 1 && isMalformed3_2(b1, sa[sp + 1]))
|
||||
return malformedForLength(src, sp, dst, dp, 1);
|
||||
return xflow(src, sp, sl, dst, dp, 3);
|
||||
}
|
||||
int b2 = sa[sp + 1];
|
||||
int b3 = sa[sp + 2];
|
||||
if (isMalformed3(b1, b2, b3))
|
||||
return malformed(src, sp, dst, dp, 3);
|
||||
da[dp++] = (char)
|
||||
((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
sp += 3;
|
||||
} else {
|
||||
return malformed(src, sp, dst, dp, 1);
|
||||
}
|
||||
}
|
||||
return xflow(src, sp, sl, dst, dp, 0);
|
||||
}
|
||||
|
||||
private CoderResult decodeBufferLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
int limit = src.limit();
|
||||
while (mark < limit) {
|
||||
int b1 = src.get();
|
||||
if (b1 >= 0) {
|
||||
// 1 byte, 7 bits: 0xxxxxxx
|
||||
if (dst.remaining() < 1)
|
||||
return xflow(src, mark, 1); // overflow
|
||||
dst.put((char) b1);
|
||||
mark++;
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||
if (limit - mark < 2|| dst.remaining() < 1)
|
||||
return xflow(src, mark, 2);
|
||||
int b2 = src.get();
|
||||
if (isNotContinuation(b2))
|
||||
return malformedForLength(src, mark, 1);
|
||||
dst.put((char) (((b1 << 6) ^ b2)
|
||||
^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
mark += 2;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||
int srcRemaining = limit - mark;
|
||||
if (srcRemaining < 3 || dst.remaining() < 1) {
|
||||
if (srcRemaining > 1 && isMalformed3_2(b1, src.get()))
|
||||
return malformedForLength(src, mark, 1);
|
||||
return xflow(src, mark, 3);
|
||||
}
|
||||
int b2 = src.get();
|
||||
int b3 = src.get();
|
||||
if (isMalformed3(b1, b2, b3))
|
||||
return malformed(src, mark, 3);
|
||||
dst.put((char)
|
||||
((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0)))));
|
||||
mark += 3;
|
||||
} else {
|
||||
return malformed(src, mark, 1);
|
||||
}
|
||||
}
|
||||
return xflow(src, mark, 0);
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArrayLoop(src, dst);
|
||||
else
|
||||
return decodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private static ByteBuffer getByteBuffer(ByteBuffer bb, byte[] ba, int sp)
|
||||
{
|
||||
if (bb == null)
|
||||
bb = ByteBuffer.wrap(ba);
|
||||
bb.position(sp);
|
||||
return bb;
|
||||
}
|
||||
|
||||
// returns -1 if there is/are malformed byte(s) and the
|
||||
// "action" for malformed input is not REPLACE.
|
||||
public int decode(byte[] sa, int sp, int len, char[] da) {
|
||||
final int sl = sp + len;
|
||||
int dp = 0;
|
||||
int dlASCII = Math.min(len, da.length);
|
||||
ByteBuffer bb = null; // only necessary if malformed
|
||||
|
||||
// ASCII only optimized loop
|
||||
while (dp < dlASCII && sa[sp] >= 0)
|
||||
da[dp++] = (char) sa[sp++];
|
||||
|
||||
while (sp < sl) {
|
||||
int b1 = sa[sp++];
|
||||
if (b1 >= 0) {
|
||||
// 1 byte, 7 bits: 0xxxxxxx
|
||||
da[dp++] = (char) b1;
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||
if (sp < sl) {
|
||||
int b2 = sa[sp++];
|
||||
if (isNotContinuation(b2)) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
sp--; // malformedN(bb, 2) always returns 1
|
||||
} else {
|
||||
da[dp++] = (char) (((b1 << 6) ^ b2)^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0)));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
return dp;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if (sp + 1 < sl) {
|
||||
int b2 = sa[sp++];
|
||||
int b3 = sa[sp++];
|
||||
if (isMalformed3(b1, b2, b3)) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
sp -=3;
|
||||
bb = getByteBuffer(bb, sa, sp);
|
||||
sp += malformedN(bb, 3).length();
|
||||
} else {
|
||||
da[dp++] = (char)((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
if (sp < sl && isMalformed3_2(b1, sa[sp])) {
|
||||
da[dp++] = replacement().charAt(0);
|
||||
continue;
|
||||
|
||||
}
|
||||
da[dp++] = replacement().charAt(0);
|
||||
return dp;
|
||||
} else {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends CharsetEncoder
|
||||
implements ArrayEncoder {
|
||||
|
||||
private Encoder(Charset cs) {
|
||||
super(cs, 1.1f, 3.0f);
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return !Character.isSurrogate(c);
|
||||
}
|
||||
|
||||
public boolean isLegalReplacement(byte[] repl) {
|
||||
return ((repl.length == 1 && repl[0] >= 0) ||
|
||||
super.isLegalReplacement(repl));
|
||||
}
|
||||
|
||||
private static CoderResult overflow(CharBuffer src, int sp,
|
||||
ByteBuffer dst, int dp) {
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private static CoderResult overflow(CharBuffer src, int mark) {
|
||||
src.position(mark);
|
||||
return CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private static void to3Bytes(byte[] da, int dp, char c) {
|
||||
da[dp] = (byte)(0xe0 | ((c >> 12)));
|
||||
da[dp + 1] = (byte)(0x80 | ((c >> 6) & 0x3f));
|
||||
da[dp + 2] = (byte)(0x80 | (c & 0x3f));
|
||||
}
|
||||
|
||||
private static void to3Bytes(ByteBuffer dst, char c) {
|
||||
dst.put((byte)(0xe0 | ((c >> 12))));
|
||||
dst.put((byte)(0x80 | ((c >> 6) & 0x3f)));
|
||||
dst.put((byte)(0x80 | (c & 0x3f)));
|
||||
}
|
||||
|
||||
private Surrogate.Parser sgp;
|
||||
private char[] c2;
|
||||
private CoderResult encodeArrayLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
char[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int dlASCII = dp + Math.min(sl - sp, dl - dp);
|
||||
|
||||
// ASCII only loop
|
||||
while (dp < dlASCII && sa[sp] < '\u0080')
|
||||
da[dp++] = (byte) sa[sp++];
|
||||
while (sp < sl) {
|
||||
char c = sa[sp];
|
||||
if (c < 0x80) {
|
||||
// Have at most seven bits
|
||||
if (dp >= dl)
|
||||
return overflow(src, sp, dst, dp);
|
||||
da[dp++] = (byte)c;
|
||||
} else if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
if (dl - dp < 2)
|
||||
return overflow(src, sp, dst, dp);
|
||||
da[dp++] = (byte)(0xc0 | (c >> 6));
|
||||
da[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
// Have a surrogate pair
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
int uc = sgp.parse(c, sa, sp, sl);
|
||||
if (uc < 0) {
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return sgp.error();
|
||||
}
|
||||
if (dl - dp < 6)
|
||||
return overflow(src, sp, dst, dp);
|
||||
to3Bytes(da, dp, Character.highSurrogate(uc));
|
||||
dp += 3;
|
||||
to3Bytes(da, dp, Character.lowSurrogate(uc));
|
||||
dp += 3;
|
||||
sp++; // 2 chars
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
if (dl - dp < 3)
|
||||
return overflow(src, sp, dst, dp);
|
||||
to3Bytes(da, dp, c);
|
||||
dp += 3;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return CoderResult.UNDERFLOW;
|
||||
}
|
||||
|
||||
private CoderResult encodeBufferLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
if (c < 0x80) {
|
||||
// Have at most seven bits
|
||||
if (!dst.hasRemaining())
|
||||
return overflow(src, mark);
|
||||
dst.put((byte)c);
|
||||
} else if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
if (dst.remaining() < 2)
|
||||
return overflow(src, mark);
|
||||
dst.put((byte)(0xc0 | (c >> 6)));
|
||||
dst.put((byte)(0x80 | (c & 0x3f)));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
// Have a surrogate pair
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
int uc = sgp.parse(c, src);
|
||||
if (uc < 0) {
|
||||
src.position(mark);
|
||||
return sgp.error();
|
||||
}
|
||||
if (dst.remaining() < 6)
|
||||
return overflow(src, mark);
|
||||
to3Bytes(dst, Character.highSurrogate(uc));
|
||||
to3Bytes(dst, Character.lowSurrogate(uc));
|
||||
mark++; // 2 chars
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
if (dst.remaining() < 3)
|
||||
return overflow(src, mark);
|
||||
to3Bytes(dst, c);
|
||||
}
|
||||
mark++;
|
||||
}
|
||||
src.position(mark);
|
||||
return CoderResult.UNDERFLOW;
|
||||
}
|
||||
|
||||
protected final CoderResult encodeLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArrayLoop(src, dst);
|
||||
else
|
||||
return encodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
// returns -1 if there is malformed char(s) and the
|
||||
// "action" for malformed input is not REPLACE.
|
||||
public int encode(char[] sa, int sp, int len, byte[] da) {
|
||||
int sl = sp + len;
|
||||
int dp = 0;
|
||||
int dlASCII = dp + Math.min(len, da.length);
|
||||
|
||||
// ASCII only optimized loop
|
||||
while (dp < dlASCII && sa[sp] < '\u0080')
|
||||
da[dp++] = (byte) sa[sp++];
|
||||
|
||||
while (sp < sl) {
|
||||
char c = sa[sp++];
|
||||
if (c < 0x80) {
|
||||
// Have at most seven bits
|
||||
da[dp++] = (byte)c;
|
||||
} else if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
da[dp++] = (byte)(0xc0 | (c >> 6));
|
||||
da[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
int uc = sgp.parse(c, sa, sp - 1, sl);
|
||||
if (uc < 0) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement()[0];
|
||||
} else {
|
||||
to3Bytes(da, dp, Character.highSurrogate(uc));
|
||||
dp += 3;
|
||||
to3Bytes(da, dp, Character.lowSurrogate(uc));
|
||||
dp += 3;
|
||||
sp++; // 2 chars
|
||||
}
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
to3Bytes(da, dp, c);
|
||||
dp += 3;
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
}
|
353
src/java.base/share/classes/sun/nio/cs/CharsetMapping.java
Normal file
353
src/java.base/share/classes/sun/nio/cs/CharsetMapping.java
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
|
||||
public class CharsetMapping {
|
||||
public static final char UNMAPPABLE_DECODING = '\uFFFD';
|
||||
public static final int UNMAPPABLE_ENCODING = 0xFFFD;
|
||||
|
||||
char[] b2cSB; //singlebyte b->c
|
||||
char[] b2cDB1; //dobulebyte b->c /db1
|
||||
char[] b2cDB2; //dobulebyte b->c /db2
|
||||
|
||||
int b2Min, b2Max; //min/max(start/end) value of 2nd byte
|
||||
int b1MinDB1, b1MaxDB1; //min/Max(start/end) value of 1st byte/db1
|
||||
int b1MinDB2, b1MaxDB2; //min/Max(start/end) value of 1st byte/db2
|
||||
int dbSegSize;
|
||||
|
||||
char[] c2b;
|
||||
char[] c2bIndex;
|
||||
|
||||
// Supplementary
|
||||
char[] b2cSupp;
|
||||
char[] c2bSupp;
|
||||
|
||||
// Composite
|
||||
Entry[] b2cComp;
|
||||
Entry[] c2bComp;
|
||||
|
||||
public char decodeSingle(int b) {
|
||||
return b2cSB[b];
|
||||
}
|
||||
|
||||
public char decodeDouble(int b1, int b2) {
|
||||
if (b2 >= b2Min && b2 < b2Max) {
|
||||
b2 -= b2Min;
|
||||
if (b1 >= b1MinDB1 && b1 <= b1MaxDB1) {
|
||||
b1 -= b1MinDB1;
|
||||
return b2cDB1[b1 * dbSegSize + b2];
|
||||
}
|
||||
if (b1 >= b1MinDB2 && b1 <= b1MaxDB2) {
|
||||
b1 -= b1MinDB2;
|
||||
return b2cDB2[b1 * dbSegSize + b2];
|
||||
}
|
||||
}
|
||||
return UNMAPPABLE_DECODING;
|
||||
}
|
||||
|
||||
// for jis0213 all supplementary characters are in 0x2xxxx range,
|
||||
// so only the xxxx part is now stored, should actually store the
|
||||
// codepoint value instead.
|
||||
public char[] decodeSurrogate(int db, char[] cc) {
|
||||
int end = b2cSupp.length / 2;
|
||||
int i = Arrays.binarySearch(b2cSupp, 0, end, (char)db);
|
||||
if (i >= 0) {
|
||||
Character.toChars(b2cSupp[end + i] + 0x20000, cc, 0);
|
||||
return cc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public char[] decodeComposite(Entry comp, char[] cc) {
|
||||
int i = findBytes(b2cComp, comp);
|
||||
if (i >= 0) {
|
||||
cc[0] = (char)b2cComp[i].cp;
|
||||
cc[1] = (char)b2cComp[i].cp2;
|
||||
return cc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int encodeChar(char ch) {
|
||||
int index = c2bIndex[ch >> 8];
|
||||
if (index == 0xffff)
|
||||
return UNMAPPABLE_ENCODING;
|
||||
return c2b[index + (ch & 0xff)];
|
||||
}
|
||||
|
||||
public int encodeSurrogate(char hi, char lo) {
|
||||
int cp = Character.toCodePoint(hi, lo);
|
||||
if (cp < 0x20000 || cp >= 0x30000)
|
||||
return UNMAPPABLE_ENCODING;
|
||||
int end = c2bSupp.length / 2;
|
||||
int i = Arrays.binarySearch(c2bSupp, 0, end, (char)cp);
|
||||
if (i >= 0)
|
||||
return c2bSupp[end + i];
|
||||
return UNMAPPABLE_ENCODING;
|
||||
}
|
||||
|
||||
public boolean isCompositeBase(Entry comp) {
|
||||
if (comp.cp <= 0x31f7 && comp.cp >= 0xe6) {
|
||||
return (findCP(c2bComp, comp) >= 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int encodeComposite(Entry comp) {
|
||||
int i = findComp(c2bComp, comp);
|
||||
if (i >= 0)
|
||||
return c2bComp[i].bs;
|
||||
return UNMAPPABLE_ENCODING;
|
||||
}
|
||||
|
||||
// init the CharsetMapping object from the .dat binary file
|
||||
public static CharsetMapping get(final InputStream is) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
public CharsetMapping run() {
|
||||
return new CharsetMapping().load(is);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static class Entry {
|
||||
public int bs; //byte sequence reps
|
||||
public int cp; //Unicode codepoint
|
||||
public int cp2; //CC of composite
|
||||
}
|
||||
|
||||
static Comparator<Entry> comparatorBytes =
|
||||
new Comparator<Entry>() {
|
||||
public int compare(Entry m1, Entry m2) {
|
||||
return m1.bs - m2.bs;
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
};
|
||||
|
||||
static Comparator<Entry> comparatorCP =
|
||||
new Comparator<Entry>() {
|
||||
public int compare(Entry m1, Entry m2) {
|
||||
return m1.cp - m2.cp;
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
};
|
||||
|
||||
static Comparator<Entry> comparatorComp =
|
||||
new Comparator<Entry>() {
|
||||
public int compare(Entry m1, Entry m2) {
|
||||
int v = m1.cp - m2.cp;
|
||||
if (v == 0)
|
||||
v = m1.cp2 - m2.cp2;
|
||||
return v;
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
};
|
||||
|
||||
static int findBytes(Entry[] a, Entry k) {
|
||||
return Arrays.binarySearch(a, 0, a.length, k, comparatorBytes);
|
||||
}
|
||||
|
||||
static int findCP(Entry[] a, Entry k) {
|
||||
return Arrays.binarySearch(a, 0, a.length, k, comparatorCP);
|
||||
}
|
||||
|
||||
static int findComp(Entry[] a, Entry k) {
|
||||
return Arrays.binarySearch(a, 0, a.length, k, comparatorComp);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
// tags of different charset mapping tables
|
||||
private static final int MAP_SINGLEBYTE = 0x1; // 0..256 : c
|
||||
private static final int MAP_DOUBLEBYTE1 = 0x2; // min..max: c
|
||||
private static final int MAP_DOUBLEBYTE2 = 0x3; // min..max: c [DB2]
|
||||
private static final int MAP_SUPPLEMENT = 0x5; // db,c
|
||||
private static final int MAP_SUPPLEMENT_C2B = 0x6; // c,db
|
||||
private static final int MAP_COMPOSITE = 0x7; // db,base,cc
|
||||
private static final int MAP_INDEXC2B = 0x8; // index table of c->bb
|
||||
|
||||
private static final boolean readNBytes(InputStream in, byte[] bb, int N)
|
||||
throws IOException
|
||||
{
|
||||
int off = 0;
|
||||
while (N > 0) {
|
||||
int n = in.read(bb, off, N);
|
||||
if (n == -1)
|
||||
return false;
|
||||
N = N - n;
|
||||
off += n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int off = 0;
|
||||
byte[] bb;
|
||||
private char[] readCharArray() {
|
||||
// first 2 bytes are the number of "chars" stored in this table
|
||||
int size = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
char [] cc = new char[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
cc[i] = (char)(((bb[off++]&0xff)<<8) | (bb[off++]&0xff));
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
||||
void readSINGLEBYTE() {
|
||||
char[] map = readCharArray();
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
char c = map[i];
|
||||
if (c != UNMAPPABLE_DECODING) {
|
||||
c2b[c2bIndex[c >> 8] + (c&0xff)] = (char)i;
|
||||
}
|
||||
}
|
||||
b2cSB = map;
|
||||
}
|
||||
|
||||
void readINDEXC2B() {
|
||||
char[] map = readCharArray();
|
||||
for (int i = map.length - 1; i >= 0; i--) {
|
||||
if (c2b == null && map[i] != -1) {
|
||||
c2b = new char[map[i] + 256];
|
||||
Arrays.fill(c2b, (char)UNMAPPABLE_ENCODING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
c2bIndex = map;
|
||||
}
|
||||
|
||||
char[] readDB(int b1Min, int b2Min, int segSize) {
|
||||
char[] map = readCharArray();
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
char c = map[i];
|
||||
if (c != UNMAPPABLE_DECODING) {
|
||||
int b1 = i / segSize;
|
||||
int b2 = i % segSize;
|
||||
int b = (b1 + b1Min)* 256 + (b2 + b2Min);
|
||||
//System.out.printf(" DB %x\t%x%n", b, c & 0xffff);
|
||||
c2b[c2bIndex[c >> 8] + (c&0xff)] = (char)(b);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
void readDOUBLEBYTE1() {
|
||||
b1MinDB1 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
b1MaxDB1 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
b2Min = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
b2Max = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
dbSegSize = b2Max - b2Min + 1;
|
||||
b2cDB1 = readDB(b1MinDB1, b2Min, dbSegSize);
|
||||
}
|
||||
|
||||
void readDOUBLEBYTE2() {
|
||||
b1MinDB2 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
b1MaxDB2 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
b2Min = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
b2Max = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
dbSegSize = b2Max - b2Min + 1;
|
||||
b2cDB2 = readDB(b1MinDB2, b2Min, dbSegSize);
|
||||
}
|
||||
|
||||
void readCOMPOSITE() {
|
||||
char[] map = readCharArray();
|
||||
int mLen = map.length/3;
|
||||
b2cComp = new Entry[mLen];
|
||||
c2bComp = new Entry[mLen];
|
||||
for (int i = 0, j= 0; i < mLen; i++) {
|
||||
Entry m = new Entry();
|
||||
m.bs = map[j++];
|
||||
m.cp = map[j++];
|
||||
m.cp2 = map[j++];
|
||||
b2cComp[i] = m;
|
||||
c2bComp[i] = m;
|
||||
}
|
||||
Arrays.sort(c2bComp, 0, c2bComp.length, comparatorComp);
|
||||
}
|
||||
|
||||
CharsetMapping load(InputStream in) {
|
||||
try {
|
||||
// The first 4 bytes are the size of the total data followed in
|
||||
// this .dat file.
|
||||
int len = ((in.read()&0xff) << 24) | ((in.read()&0xff) << 16) |
|
||||
((in.read()&0xff) << 8) | (in.read()&0xff);
|
||||
bb = new byte[len];
|
||||
off = 0;
|
||||
//System.out.printf("In : Total=%d%n", len);
|
||||
// Read in all bytes
|
||||
if (!readNBytes(in, bb, len))
|
||||
throw new RuntimeException("Corrupted data file");
|
||||
in.close();
|
||||
|
||||
while (off < len) {
|
||||
int type = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);
|
||||
switch(type) {
|
||||
case MAP_INDEXC2B:
|
||||
readINDEXC2B();
|
||||
break;
|
||||
case MAP_SINGLEBYTE:
|
||||
readSINGLEBYTE();
|
||||
break;
|
||||
case MAP_DOUBLEBYTE1:
|
||||
readDOUBLEBYTE1();
|
||||
break;
|
||||
case MAP_DOUBLEBYTE2:
|
||||
readDOUBLEBYTE2();
|
||||
break;
|
||||
case MAP_SUPPLEMENT:
|
||||
b2cSupp = readCharArray();
|
||||
break;
|
||||
case MAP_SUPPLEMENT_C2B:
|
||||
c2bSupp = readCharArray();
|
||||
break;
|
||||
case MAP_COMPOSITE:
|
||||
readCOMPOSITE();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Corrupted data file");
|
||||
}
|
||||
}
|
||||
bb = null;
|
||||
return this;
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CoderResult;
|
||||
|
||||
/**
|
||||
* A decoder that can be delegated to by another decoder
|
||||
* when normal inheritance cannot be used.
|
||||
* Used by autodecting decoders.
|
||||
*/
|
||||
public interface DelegatableDecoder {
|
||||
CoderResult decodeLoop(ByteBuffer src, CharBuffer dst);
|
||||
void implReset();
|
||||
CoderResult implFlush(CharBuffer out);
|
||||
}
|
1102
src/java.base/share/classes/sun/nio/cs/DoubleByte.java
Normal file
1102
src/java.base/share/classes/sun/nio/cs/DoubleByte.java
Normal file
File diff suppressed because it is too large
Load diff
161
src/java.base/share/classes/sun/nio/cs/FastCharsetProvider.java
Normal file
161
src/java.base/share/classes/sun/nio/cs/FastCharsetProvider.java
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.spi.CharsetProvider;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for fast charset providers.
|
||||
*
|
||||
* @author Mark Reinhold
|
||||
*/
|
||||
|
||||
public class FastCharsetProvider
|
||||
extends CharsetProvider
|
||||
{
|
||||
|
||||
// Maps canonical names to class names
|
||||
private Map<String,String> classMap;
|
||||
|
||||
// Maps alias names to canonical names
|
||||
private Map<String,String> aliasMap;
|
||||
|
||||
// Maps canonical names to cached instances
|
||||
private Map<String,Charset> cache;
|
||||
|
||||
private String packagePrefix;
|
||||
|
||||
protected FastCharsetProvider(String pp,
|
||||
Map<String,String> am,
|
||||
Map<String,String> cm,
|
||||
Map<String,Charset> c)
|
||||
{
|
||||
packagePrefix = pp;
|
||||
aliasMap = am;
|
||||
classMap = cm;
|
||||
cache = c;
|
||||
}
|
||||
|
||||
private String canonicalize(String csn) {
|
||||
String acn = aliasMap.get(csn);
|
||||
return (acn != null) ? acn : csn;
|
||||
}
|
||||
|
||||
// Private ASCII-only version, optimized for interpretation during startup
|
||||
//
|
||||
private static String toLower(String s) {
|
||||
int n = s.length();
|
||||
boolean allLower = true;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int c = s.charAt(i);
|
||||
if (((c - 'A') | ('Z' - c)) >= 0) {
|
||||
allLower = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allLower)
|
||||
return s;
|
||||
char[] ca = new char[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
int c = s.charAt(i);
|
||||
if (((c - 'A') | ('Z' - c)) >= 0)
|
||||
ca[i] = (char)(c + 0x20);
|
||||
else
|
||||
ca[i] = (char)c;
|
||||
}
|
||||
return new String(ca);
|
||||
}
|
||||
|
||||
private Charset lookup(String charsetName) {
|
||||
|
||||
String csn = canonicalize(toLower(charsetName));
|
||||
|
||||
// Check cache first
|
||||
Charset cs = cache.get(csn);
|
||||
if (cs != null)
|
||||
return cs;
|
||||
|
||||
// Do we even support this charset?
|
||||
String cln = classMap.get(csn);
|
||||
if (cln == null)
|
||||
return null;
|
||||
|
||||
if (cln.equals("US_ASCII")) {
|
||||
cs = new US_ASCII();
|
||||
cache.put(csn, cs);
|
||||
return cs;
|
||||
}
|
||||
|
||||
// Instantiate the charset and cache it
|
||||
try {
|
||||
@SuppressWarnings("deprecation")
|
||||
Object o= Class.forName(packagePrefix + "." + cln,
|
||||
true,
|
||||
this.getClass().getClassLoader()).newInstance();
|
||||
cs = (Charset)o;
|
||||
cache.put(csn, cs);
|
||||
return cs;
|
||||
} catch (ClassNotFoundException |
|
||||
IllegalAccessException |
|
||||
InstantiationException x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final Charset charsetForName(String charsetName) {
|
||||
synchronized (this) {
|
||||
return lookup(canonicalize(charsetName));
|
||||
}
|
||||
}
|
||||
|
||||
public final Iterator<Charset> charsets() {
|
||||
|
||||
return new Iterator<Charset>() {
|
||||
|
||||
Iterator<String> i = classMap.keySet().iterator();
|
||||
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
public Charset next() {
|
||||
String csn = i.next();
|
||||
return lookup(csn);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
462
src/java.base/share/classes/sun/nio/cs/HKSCS.java
Normal file
462
src/java.base/share/classes/sun/nio/cs/HKSCS.java
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.Arrays;
|
||||
import sun.nio.cs.DoubleByte;
|
||||
import sun.nio.cs.Surrogate;
|
||||
import static sun.nio.cs.CharsetMapping.*;
|
||||
|
||||
public class HKSCS {
|
||||
|
||||
public static class Decoder extends DoubleByte.Decoder {
|
||||
static int b2Min = 0x40;
|
||||
static int b2Max = 0xfe;
|
||||
|
||||
private char[][] b2cBmp;
|
||||
private char[][] b2cSupp;
|
||||
private DoubleByte.Decoder big5Dec;
|
||||
|
||||
protected Decoder(Charset cs,
|
||||
DoubleByte.Decoder big5Dec,
|
||||
char[][] b2cBmp, char[][] b2cSupp)
|
||||
{
|
||||
// super(cs, 0.5f, 1.0f);
|
||||
// need to extends DoubleByte.Decoder so the
|
||||
// sun.io can use it. this implementation
|
||||
super(cs, 0.5f, 1.0f, null, null, 0, 0, true);
|
||||
this.big5Dec = big5Dec;
|
||||
this.b2cBmp = b2cBmp;
|
||||
this.b2cSupp = b2cSupp;
|
||||
}
|
||||
|
||||
public char decodeSingle(int b) {
|
||||
return big5Dec.decodeSingle(b);
|
||||
}
|
||||
|
||||
public char decodeBig5(int b1, int b2) {
|
||||
return big5Dec.decodeDouble(b1, b2);
|
||||
}
|
||||
|
||||
public char decodeDouble(int b1, int b2) {
|
||||
return b2cBmp[b1][b2 - b2Min];
|
||||
}
|
||||
|
||||
public char decodeDoubleEx(int b1, int b2) {
|
||||
/* if the b2cSupp is null, the subclass need
|
||||
to override the methold
|
||||
if (b2cSupp == null)
|
||||
return UNMAPPABLE_DECODING;
|
||||
*/
|
||||
return b2cSupp[b1][b2 - b2Min];
|
||||
}
|
||||
|
||||
protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
char[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
|
||||
try {
|
||||
while (sp < sl) {
|
||||
int b1 = sa[sp] & 0xff;
|
||||
char c = decodeSingle(b1);
|
||||
int inSize = 1, outSize = 1;
|
||||
char[] cc = null;
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
if (sl - sp < 2)
|
||||
return CoderResult.UNDERFLOW;
|
||||
int b2 = sa[sp + 1] & 0xff;
|
||||
inSize++;
|
||||
if (b2 < b2Min || b2 > b2Max)
|
||||
return CoderResult.unmappableForLength(2);
|
||||
c = decodeDouble(b1, b2); //bmp
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
c = decodeDoubleEx(b1, b2); //supp
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
c = decodeBig5(b1, b2); //big5
|
||||
if (c == UNMAPPABLE_DECODING)
|
||||
return CoderResult.unmappableForLength(2);
|
||||
} else {
|
||||
// supplementary character in u+2xxxx area
|
||||
outSize = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dl - dp < outSize)
|
||||
return CoderResult.OVERFLOW;
|
||||
if (outSize == 2) {
|
||||
// supplementary characters
|
||||
da[dp++] = Surrogate.high(0x20000 + c);
|
||||
da[dp++] = Surrogate.low(0x20000 + c);
|
||||
} else {
|
||||
da[dp++] = c;
|
||||
}
|
||||
sp += inSize;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char[] cc = null;
|
||||
int b1 = src.get() & 0xff;
|
||||
int inSize = 1, outSize = 1;
|
||||
char c = decodeSingle(b1);
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
if (src.remaining() < 1)
|
||||
return CoderResult.UNDERFLOW;
|
||||
int b2 = src.get() & 0xff;
|
||||
inSize++;
|
||||
if (b2 < b2Min || b2 > b2Max)
|
||||
return CoderResult.unmappableForLength(2);
|
||||
c = decodeDouble(b1, b2); //bmp
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
c = decodeDoubleEx(b1, b2); //supp
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
c = decodeBig5(b1, b2); //big5
|
||||
if (c == UNMAPPABLE_DECODING)
|
||||
return CoderResult.unmappableForLength(2);
|
||||
} else {
|
||||
outSize = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dst.remaining() < outSize)
|
||||
return CoderResult.OVERFLOW;
|
||||
if (outSize == 2) {
|
||||
dst.put(Surrogate.high(0x20000 + c));
|
||||
dst.put(Surrogate.low(0x20000 + c));
|
||||
} else {
|
||||
dst.put(c);
|
||||
}
|
||||
mark += inSize;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
public int decode(byte[] src, int sp, int len, char[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + len;
|
||||
char repl = replacement().charAt(0);
|
||||
while (sp < sl) {
|
||||
int b1 = src[sp++] & 0xff;
|
||||
char c = decodeSingle(b1);
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
if (sl == sp) {
|
||||
c = repl;
|
||||
} else {
|
||||
int b2 = src[sp++] & 0xff;
|
||||
if (b2 < b2Min || b2 > b2Max) {
|
||||
c = repl;
|
||||
} else if ((c = decodeDouble(b1, b2)) == UNMAPPABLE_DECODING) {
|
||||
c = decodeDoubleEx(b1, b2); //supp
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
c = decodeBig5(b1, b2); //big5
|
||||
if (c == UNMAPPABLE_DECODING)
|
||||
c = repl;
|
||||
} else {
|
||||
// supplementary character in u+2xxxx area
|
||||
dst[dp++] = Surrogate.high(0x20000 + c);
|
||||
dst[dp++] = Surrogate.low(0x20000 + c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dst[dp++] = c;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArrayLoop(src, dst);
|
||||
else
|
||||
return decodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
public static void initb2c(char[][]b2c, String[] b2cStr)
|
||||
{
|
||||
for (int i = 0; i < b2cStr.length; i++) {
|
||||
if (b2cStr[i] == null)
|
||||
b2c[i] = DoubleByte.B2C_UNMAPPABLE;
|
||||
else
|
||||
b2c[i] = b2cStr[i].toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Encoder extends DoubleByte.Encoder {
|
||||
private DoubleByte.Encoder big5Enc;
|
||||
private char[][] c2bBmp;
|
||||
private char[][] c2bSupp;
|
||||
|
||||
protected Encoder(Charset cs,
|
||||
DoubleByte.Encoder big5Enc,
|
||||
char[][] c2bBmp,
|
||||
char[][] c2bSupp)
|
||||
{
|
||||
super(cs, null, null, true);
|
||||
this.big5Enc = big5Enc;
|
||||
this.c2bBmp = c2bBmp;
|
||||
this.c2bSupp = c2bSupp;
|
||||
}
|
||||
|
||||
public int encodeBig5(char ch) {
|
||||
return big5Enc.encodeChar(ch);
|
||||
}
|
||||
|
||||
public int encodeChar(char ch) {
|
||||
int bb = c2bBmp[ch >> 8][ch & 0xff];
|
||||
if (bb == UNMAPPABLE_ENCODING)
|
||||
return encodeBig5(ch);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public int encodeSupp(int cp) {
|
||||
if ((cp & 0xf0000) != 0x20000)
|
||||
return UNMAPPABLE_ENCODING;
|
||||
return c2bSupp[(cp >> 8) & 0xff][cp & 0xff];
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return encodeChar(c) != UNMAPPABLE_ENCODING;
|
||||
}
|
||||
|
||||
protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
|
||||
char[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
|
||||
try {
|
||||
while (sp < sl) {
|
||||
char c = sa[sp];
|
||||
int inSize = 1;
|
||||
int bb = encodeChar(c);
|
||||
if (bb == UNMAPPABLE_ENCODING) {
|
||||
if (Character.isSurrogate(c)) {
|
||||
int cp;
|
||||
if ((cp = sgp().parse(c, sa, sp, sl)) < 0)
|
||||
return sgp.error();
|
||||
bb = encodeSupp(cp);
|
||||
if (bb == UNMAPPABLE_ENCODING)
|
||||
return CoderResult.unmappableForLength(2);
|
||||
inSize = 2;
|
||||
} else {
|
||||
return CoderResult.unmappableForLength(1);
|
||||
}
|
||||
}
|
||||
if (bb > MAX_SINGLEBYTE) { // DoubleByte
|
||||
if (dl - dp < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (byte)(bb >> 8);
|
||||
da[dp++] = (byte)bb;
|
||||
} else { // SingleByte
|
||||
if (dl - dp < 1)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (byte)bb;
|
||||
}
|
||||
sp += inSize;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
int inSize = 1;
|
||||
char c = src.get();
|
||||
int bb = encodeChar(c);
|
||||
if (bb == UNMAPPABLE_ENCODING) {
|
||||
if (Character.isSurrogate(c)) {
|
||||
int cp;
|
||||
if ((cp = sgp().parse(c, src)) < 0)
|
||||
return sgp.error();
|
||||
bb = encodeSupp(cp);
|
||||
if (bb == UNMAPPABLE_ENCODING)
|
||||
return CoderResult.unmappableForLength(2);
|
||||
inSize = 2;
|
||||
} else {
|
||||
return CoderResult.unmappableForLength(1);
|
||||
}
|
||||
}
|
||||
if (bb > MAX_SINGLEBYTE) { // DoubleByte
|
||||
if (dst.remaining() < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)(bb >> 8));
|
||||
dst.put((byte)(bb));
|
||||
} else {
|
||||
if (dst.remaining() < 1)
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)bb);
|
||||
}
|
||||
mark += inSize;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArrayLoop(src, dst);
|
||||
else
|
||||
return encodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private byte[] repl = replacement();
|
||||
protected void implReplaceWith(byte[] newReplacement) {
|
||||
repl = newReplacement;
|
||||
}
|
||||
|
||||
public int encode(char[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + len;
|
||||
while (sp < sl) {
|
||||
char c = src[sp++];
|
||||
int bb = encodeChar(c);
|
||||
if (bb == UNMAPPABLE_ENCODING) {
|
||||
if (!Character.isHighSurrogate(c) || sp == sl ||
|
||||
!Character.isLowSurrogate(src[sp]) ||
|
||||
(bb = encodeSupp(Character.toCodePoint(c, src[sp++])))
|
||||
== UNMAPPABLE_ENCODING) {
|
||||
dst[dp++] = repl[0];
|
||||
if (repl.length > 1)
|
||||
dst[dp++] = repl[1];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (bb > MAX_SINGLEBYTE) { // DoubleByte
|
||||
dst[dp++] = (byte)(bb >> 8);
|
||||
dst[dp++] = (byte)bb;
|
||||
} else { // SingleByte
|
||||
dst[dp++] = (byte)bb;
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + len;
|
||||
int dl = dst.length;
|
||||
while (sp < sl) {
|
||||
char c = StringUTF16.getChar(src, sp++);
|
||||
int bb = encodeChar(c);
|
||||
if (bb == UNMAPPABLE_ENCODING) {
|
||||
if (!Character.isHighSurrogate(c) || sp == sl ||
|
||||
!Character.isLowSurrogate(StringUTF16.getChar(src,sp)) ||
|
||||
(bb = encodeSupp(Character.toCodePoint(c, StringUTF16.getChar(src, sp++))))
|
||||
== UNMAPPABLE_ENCODING) {
|
||||
dst[dp++] = repl[0];
|
||||
if (repl.length > 1)
|
||||
dst[dp++] = repl[1];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (bb > MAX_SINGLEBYTE) { // DoubleByte
|
||||
dst[dp++] = (byte)(bb >> 8);
|
||||
dst[dp++] = (byte)bb;
|
||||
} else { // SingleByte
|
||||
dst[dp++] = (byte)bb;
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
static char[] C2B_UNMAPPABLE = new char[0x100];
|
||||
static {
|
||||
Arrays.fill(C2B_UNMAPPABLE, (char)UNMAPPABLE_ENCODING);
|
||||
}
|
||||
|
||||
public static void initc2b(char[][] c2b, String[] b2cStr, String pua) {
|
||||
// init c2b/c2bSupp from b2cStr and supp
|
||||
int b2Min = 0x40;
|
||||
Arrays.fill(c2b, C2B_UNMAPPABLE);
|
||||
for (int b1 = 0; b1 < 0x100; b1++) {
|
||||
String s = b2cStr[b1];
|
||||
if (s == null)
|
||||
continue;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c == UNMAPPABLE_DECODING)
|
||||
continue;
|
||||
int hi = c >> 8;
|
||||
if (c2b[hi] == C2B_UNMAPPABLE) {
|
||||
c2b[hi] = new char[0x100];
|
||||
Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
|
||||
}
|
||||
c2b[hi][c & 0xff] = (char)((b1 << 8) | (i + b2Min));
|
||||
}
|
||||
}
|
||||
if (pua != null) { // add the compatibility pua entries
|
||||
char c = '\ue000'; //first pua character
|
||||
for (int i = 0; i < pua.length(); i++) {
|
||||
char bb = pua.charAt(i);
|
||||
if (bb != UNMAPPABLE_DECODING) {
|
||||
int hi = c >> 8;
|
||||
if (c2b[hi] == C2B_UNMAPPABLE) {
|
||||
c2b[hi] = new char[0x100];
|
||||
Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
|
||||
}
|
||||
c2b[hi][c & 0xff] = bb;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
|
||||
public interface HistoricallyNamedCharset {
|
||||
|
||||
public String historicalName();
|
||||
|
||||
}
|
309
src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java
Normal file
309
src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
public class ISO_8859_1
|
||||
extends Charset
|
||||
implements HistoricallyNamedCharset
|
||||
{
|
||||
|
||||
public static final ISO_8859_1 INSTANCE = new ISO_8859_1();
|
||||
|
||||
public ISO_8859_1() {
|
||||
super("ISO-8859-1", StandardCharsets.aliases_ISO_8859_1());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "ISO8859_1";
|
||||
}
|
||||
|
||||
public boolean contains(Charset cs) {
|
||||
return ((cs instanceof US_ASCII)
|
||||
|| (cs instanceof ISO_8859_1));
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static class Decoder extends CharsetDecoder
|
||||
implements ArrayDecoder {
|
||||
private Decoder(Charset cs) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
private CoderResult decodeArrayLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
assert (sp <= sl);
|
||||
sp = (sp <= sl ? sp : sl);
|
||||
char[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
assert (dp <= dl);
|
||||
dp = (dp <= dl ? dp : dl);
|
||||
|
||||
try {
|
||||
while (sp < sl) {
|
||||
byte b = sa[sp];
|
||||
if (dp >= dl)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (char)(b & 0xff);
|
||||
sp++;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
}
|
||||
|
||||
private CoderResult decodeBufferLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
byte b = src.get();
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((char)(b & 0xff));
|
||||
mark++;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArrayLoop(src, dst);
|
||||
else
|
||||
return decodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
public int decode(byte[] src, int sp, int len, char[] dst) {
|
||||
if (len > dst.length)
|
||||
len = dst.length;
|
||||
int dp = 0;
|
||||
while (dp < len)
|
||||
dst[dp++] = (char)(src[sp++] & 0xff);
|
||||
return dp;
|
||||
}
|
||||
|
||||
public boolean isASCIICompatible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends CharsetEncoder
|
||||
implements ArrayEncoder {
|
||||
private Encoder(Charset cs) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return c <= '\u00FF';
|
||||
}
|
||||
|
||||
public boolean isLegalReplacement(byte[] repl) {
|
||||
return true; // we accept any byte value
|
||||
}
|
||||
|
||||
private final Surrogate.Parser sgp = new Surrogate.Parser();
|
||||
|
||||
// Method possible replaced with a compiler intrinsic.
|
||||
private static int encodeISOArray(char[] sa, int sp,
|
||||
byte[] da, int dp, int len) {
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
encodeISOArrayCheck(sa, sp, da, dp, len);
|
||||
return implEncodeISOArray(sa, sp, da, dp, len);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static int implEncodeISOArray(char[] sa, int sp,
|
||||
byte[] da, int dp, int len)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < len; i++) {
|
||||
char c = sa[sp++];
|
||||
if (c > '\u00FF')
|
||||
break;
|
||||
da[dp++] = (byte)c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private static void encodeISOArrayCheck(char[] sa, int sp,
|
||||
byte[] da, int dp, int len) {
|
||||
Objects.requireNonNull(sa);
|
||||
Objects.requireNonNull(da);
|
||||
|
||||
if (sp < 0 || sp >= sa.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(sp);
|
||||
}
|
||||
|
||||
if (dp < 0 || dp >= da.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(dp);
|
||||
}
|
||||
|
||||
int endIndexSP = sp + len - 1;
|
||||
if (endIndexSP < 0 || endIndexSP >= sa.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(endIndexSP);
|
||||
}
|
||||
|
||||
int endIndexDP = dp + len - 1;
|
||||
if (endIndexDP < 0 || endIndexDP >= da.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(endIndexDP);
|
||||
}
|
||||
}
|
||||
|
||||
private CoderResult encodeArrayLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
char[] sa = src.array();
|
||||
int soff = src.arrayOffset();
|
||||
int sp = soff + src.position();
|
||||
int sl = soff + src.limit();
|
||||
assert (sp <= sl);
|
||||
sp = (sp <= sl ? sp : sl);
|
||||
byte[] da = dst.array();
|
||||
int doff = dst.arrayOffset();
|
||||
int dp = doff + dst.position();
|
||||
int dl = doff + dst.limit();
|
||||
assert (dp <= dl);
|
||||
dp = (dp <= dl ? dp : dl);
|
||||
int dlen = dl - dp;
|
||||
int slen = sl - sp;
|
||||
int len = (dlen < slen) ? dlen : slen;
|
||||
try {
|
||||
int ret = encodeISOArray(sa, sp, da, dp, len);
|
||||
sp = sp + ret;
|
||||
dp = dp + ret;
|
||||
if (ret != len) {
|
||||
if (sgp.parse(sa[sp], sa, sp, sl) < 0)
|
||||
return sgp.error();
|
||||
return sgp.unmappableResult();
|
||||
}
|
||||
if (len < slen)
|
||||
return CoderResult.OVERFLOW;
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(sp - soff);
|
||||
dst.position(dp - doff);
|
||||
}
|
||||
}
|
||||
|
||||
private CoderResult encodeBufferLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
if (c <= '\u00FF') {
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)c);
|
||||
mark++;
|
||||
continue;
|
||||
}
|
||||
if (sgp.parse(c, src) < 0)
|
||||
return sgp.error();
|
||||
return sgp.unmappableResult();
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult encodeLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArrayLoop(src, dst);
|
||||
else
|
||||
return encodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private byte repl = (byte)'?';
|
||||
protected void implReplaceWith(byte[] newReplacement) {
|
||||
repl = newReplacement[0];
|
||||
}
|
||||
|
||||
public int encode(char[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int slen = Math.min(len, dst.length);
|
||||
int sl = sp + slen;
|
||||
while (sp < sl) {
|
||||
int ret = encodeISOArray(src, sp, dst, dp, slen);
|
||||
sp = sp + ret;
|
||||
dp = dp + ret;
|
||||
if (ret != slen) {
|
||||
char c = src[sp++];
|
||||
if (Character.isHighSurrogate(c) && sp < sl &&
|
||||
Character.isLowSurrogate(src[sp])) {
|
||||
if (len > dst.length) {
|
||||
sl++;
|
||||
len--;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
dst[dp++] = repl;
|
||||
slen = Math.min((sl - sp), (dst.length - dp));
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public boolean isASCIICompatible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
354
src/java.base/share/classes/sun/nio/cs/SingleByte.java
Normal file
354
src/java.base/share/classes/sun/nio/cs/SingleByte.java
Normal file
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.util.Arrays;
|
||||
import static sun.nio.cs.CharsetMapping.*;
|
||||
|
||||
public class SingleByte
|
||||
{
|
||||
private static final CoderResult withResult(CoderResult cr,
|
||||
Buffer src, int sp,
|
||||
Buffer dst, int dp)
|
||||
{
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
return cr;
|
||||
}
|
||||
|
||||
public static final class Decoder extends CharsetDecoder
|
||||
implements ArrayDecoder {
|
||||
private final char[] b2c;
|
||||
private final boolean isASCIICompatible;
|
||||
|
||||
public Decoder(Charset cs, char[] b2c) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
this.b2c = b2c;
|
||||
this.isASCIICompatible = false;
|
||||
}
|
||||
|
||||
public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
this.b2c = b2c;
|
||||
this.isASCIICompatible = isASCIICompatible;
|
||||
}
|
||||
|
||||
private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
char[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
|
||||
CoderResult cr = CoderResult.UNDERFLOW;
|
||||
if ((dl - dp) < (sl - sp)) {
|
||||
sl = sp + (dl - dp);
|
||||
cr = CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
while (sp < sl) {
|
||||
char c = decode(sa[sp]);
|
||||
if (c == UNMAPPABLE_DECODING) {
|
||||
return withResult(CoderResult.unmappableForLength(1),
|
||||
src, sp, dst, dp);
|
||||
}
|
||||
da[dp++] = c;
|
||||
sp++;
|
||||
}
|
||||
return withResult(cr, src, sp, dst, dp);
|
||||
}
|
||||
|
||||
private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char c = decode(src.get());
|
||||
if (c == UNMAPPABLE_DECODING)
|
||||
return CoderResult.unmappableForLength(1);
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put(c);
|
||||
mark++;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArrayLoop(src, dst);
|
||||
else
|
||||
return decodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
public final char decode(int b) {
|
||||
return b2c[b + 128];
|
||||
}
|
||||
|
||||
private char repl = '\uFFFD';
|
||||
protected void implReplaceWith(String newReplacement) {
|
||||
repl = newReplacement.charAt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decode(byte[] src, int sp, int len, char[] dst) {
|
||||
if (len > dst.length)
|
||||
len = dst.length;
|
||||
int dp = 0;
|
||||
while (dp < len) {
|
||||
dst[dp] = decode(src[sp++]);
|
||||
if (dst[dp] == UNMAPPABLE_DECODING) {
|
||||
dst[dp] = repl;
|
||||
}
|
||||
dp++;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isASCIICompatible() {
|
||||
return isASCIICompatible;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Encoder extends CharsetEncoder
|
||||
implements ArrayEncoder {
|
||||
private Surrogate.Parser sgp;
|
||||
private final char[] c2b;
|
||||
private final char[] c2bIndex;
|
||||
private final boolean isASCIICompatible;
|
||||
|
||||
public Encoder(Charset cs, char[] c2b, char[] c2bIndex, boolean isASCIICompatible) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
this.c2b = c2b;
|
||||
this.c2bIndex = c2bIndex;
|
||||
this.isASCIICompatible = isASCIICompatible;
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return encode(c) != UNMAPPABLE_ENCODING;
|
||||
}
|
||||
|
||||
public boolean isLegalReplacement(byte[] repl) {
|
||||
return ((repl.length == 1 && repl[0] == (byte)'?') ||
|
||||
super.isLegalReplacement(repl));
|
||||
}
|
||||
|
||||
private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
|
||||
char[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int len = Math.min(dl - dp, sl - sp);
|
||||
|
||||
while (len-- > 0) {
|
||||
char c = sa[sp];
|
||||
int b = encode(c);
|
||||
if (b == UNMAPPABLE_ENCODING) {
|
||||
if (Character.isSurrogate(c)) {
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
if (sgp.parse(c, sa, sp, sl) < 0) {
|
||||
return withResult(sgp.error(), src, sp, dst, dp);
|
||||
}
|
||||
return withResult(sgp.unmappableResult(), src, sp, dst, dp);
|
||||
}
|
||||
return withResult(CoderResult.unmappableForLength(1),
|
||||
src, sp, dst, dp);
|
||||
}
|
||||
da[dp++] = (byte)b;
|
||||
sp++;
|
||||
}
|
||||
return withResult(sp < sl ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW,
|
||||
src, sp, dst, dp);
|
||||
}
|
||||
|
||||
private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
int b = encode(c);
|
||||
if (b == UNMAPPABLE_ENCODING) {
|
||||
if (Character.isSurrogate(c)) {
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
if (sgp.parse(c, src) < 0)
|
||||
return sgp.error();
|
||||
return sgp.unmappableResult();
|
||||
}
|
||||
return CoderResult.unmappableForLength(1);
|
||||
}
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)b);
|
||||
mark++;
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArrayLoop(src, dst);
|
||||
else
|
||||
return encodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
public final int encode(char ch) {
|
||||
char index = c2bIndex[ch >> 8];
|
||||
if (index == UNMAPPABLE_ENCODING)
|
||||
return UNMAPPABLE_ENCODING;
|
||||
return c2b[index + (ch & 0xff)];
|
||||
}
|
||||
|
||||
private byte repl = (byte)'?';
|
||||
protected void implReplaceWith(byte[] newReplacement) {
|
||||
repl = newReplacement[0];
|
||||
}
|
||||
|
||||
public int encode(char[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + Math.min(len, dst.length);
|
||||
while (sp < sl) {
|
||||
char c = src[sp++];
|
||||
int b = encode(c);
|
||||
if (b != UNMAPPABLE_ENCODING) {
|
||||
dst[dp++] = (byte)b;
|
||||
continue;
|
||||
}
|
||||
if (Character.isHighSurrogate(c) && sp < sl &&
|
||||
Character.isLowSurrogate(src[sp])) {
|
||||
if (len > dst.length) {
|
||||
sl++;
|
||||
len--;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
dst[dp++] = repl;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + Math.min(len, dst.length);
|
||||
while (sp < sl) {
|
||||
char c = (char)(src[sp++] & 0xff);
|
||||
int b = encode(c);
|
||||
if (b == UNMAPPABLE_ENCODING) {
|
||||
dst[dp++] = repl;
|
||||
} else {
|
||||
dst[dp++] = (byte)b;
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + Math.min(len, dst.length);
|
||||
while (sp < sl) {
|
||||
char c = StringUTF16.getChar(src, sp++);
|
||||
int b = encode(c);
|
||||
if (b != UNMAPPABLE_ENCODING) {
|
||||
dst[dp++] = (byte)b;
|
||||
continue;
|
||||
}
|
||||
if (Character.isHighSurrogate(c) && sp < sl &&
|
||||
Character.isLowSurrogate(StringUTF16.getChar(src, sp))) {
|
||||
if (len > dst.length) {
|
||||
sl++;
|
||||
len--;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
dst[dp++] = repl;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isASCIICompatible() {
|
||||
return isASCIICompatible;
|
||||
}
|
||||
}
|
||||
|
||||
// init the c2b and c2bIndex tables from b2c.
|
||||
public static void initC2B(char[] b2c, char[] c2bNR,
|
||||
char[] c2b, char[] c2bIndex) {
|
||||
for (int i = 0; i < c2bIndex.length; i++)
|
||||
c2bIndex[i] = UNMAPPABLE_ENCODING;
|
||||
for (int i = 0; i < c2b.length; i++)
|
||||
c2b[i] = UNMAPPABLE_ENCODING;
|
||||
int off = 0;
|
||||
for (int i = 0; i < b2c.length; i++) {
|
||||
char c = b2c[i];
|
||||
if (c == UNMAPPABLE_DECODING)
|
||||
continue;
|
||||
int index = (c >> 8);
|
||||
if (c2bIndex[index] == UNMAPPABLE_ENCODING) {
|
||||
c2bIndex[index] = (char)off;
|
||||
off += 0x100;
|
||||
}
|
||||
index = c2bIndex[index] + (c & 0xff);
|
||||
c2b[index] = (char)((i>=0x80)?(i-0x80):(i+0x80));
|
||||
}
|
||||
if (c2bNR != null) {
|
||||
// c-->b nr entries
|
||||
int i = 0;
|
||||
while (i < c2bNR.length) {
|
||||
char b = c2bNR[i++];
|
||||
char c = c2bNR[i++];
|
||||
int index = (c >> 8);
|
||||
if (c2bIndex[index] == UNMAPPABLE_ENCODING) {
|
||||
c2bIndex[index] = (char)off;
|
||||
off += 0x100;
|
||||
}
|
||||
index = c2bIndex[index] + (c & 0xff);
|
||||
c2b[index] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.spi.CharsetProvider;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
public class StandardCharsets extends CharsetProvider {
|
||||
|
||||
_INCLUDE_ALIASES_TABLES_
|
||||
_INCLUDE_ALIASES_MAP_
|
||||
_INCLUDE_CLASSES_MAP_
|
||||
_INCLUDE_CACHE_MAP_
|
||||
|
||||
// Maps canonical names to class names
|
||||
private @Stable Map<String,String> classMap;
|
||||
|
||||
// Maps alias names to canonical names
|
||||
private @Stable Map<String,String> aliasMap;
|
||||
|
||||
// Maps canonical names to cached instances
|
||||
private @Stable Map<String,Charset> cache;
|
||||
|
||||
private static final String packagePrefix = "sun.nio.cs.";
|
||||
|
||||
public StandardCharsets() {
|
||||
}
|
||||
|
||||
private String canonicalize(String csn) {
|
||||
String acn = aliasMap().get(csn);
|
||||
return (acn != null) ? acn : csn;
|
||||
}
|
||||
|
||||
private Map<String,String> aliasMap() {
|
||||
Map<String,String> map = aliasMap;
|
||||
if (map == null) {
|
||||
aliasMap = map = new Aliases();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map<String,String> classMap() {
|
||||
Map<String,String> map = classMap;
|
||||
if (map == null) {
|
||||
classMap = map = new Classes();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map<String,Charset> cache() {
|
||||
Map<String,Charset> map = cache;
|
||||
if (map == null) {
|
||||
map = new Cache();
|
||||
map.put("utf-8", UTF_8.INSTANCE);
|
||||
map.put("iso-8859-1", ISO_8859_1.INSTANCE);
|
||||
map.put("us-ascii", US_ASCII.INSTANCE);
|
||||
cache = map;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// Private ASCII-only version, optimized for interpretation during startup
|
||||
//
|
||||
private static String toLower(String s) {
|
||||
int n = s.length();
|
||||
boolean allLower = true;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int c = s.charAt(i);
|
||||
if (((c - 'A') | ('Z' - c)) >= 0) {
|
||||
allLower = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allLower)
|
||||
return s;
|
||||
StringBuilder sb = new StringBuilder(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
int c = s.charAt(i);
|
||||
if (((c - 'A') | ('Z' - c)) >= 0)
|
||||
sb.append((char)(c + 0x20));
|
||||
else
|
||||
sb.append((char)c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Charset lookup(String charsetName) {
|
||||
init();
|
||||
|
||||
// By checking these built-ins we can avoid initializing Aliases and
|
||||
// Classes eagerly during bootstrap
|
||||
String csn;
|
||||
if (charsetName.equals("UTF-8")) {
|
||||
return UTF_8.INSTANCE;
|
||||
} else if (charsetName.equals("US-ASCII")) {
|
||||
return US_ASCII.INSTANCE;
|
||||
} else if (charsetName.equals("ISO-8859-1")) {
|
||||
return ISO_8859_1.INSTANCE;
|
||||
} else {
|
||||
csn = canonicalize(toLower(charsetName));
|
||||
}
|
||||
|
||||
// Check cache first
|
||||
Charset cs = cache().get(csn);
|
||||
if (cs != null)
|
||||
return cs;
|
||||
|
||||
// Do we even support this charset?
|
||||
String cln = classMap().get(csn);
|
||||
if (cln == null)
|
||||
return null;
|
||||
|
||||
// Instantiate the charset and cache it
|
||||
try {
|
||||
@SuppressWarnings("deprecation")
|
||||
Object o = Class.forName(packagePrefix + cln,
|
||||
true,
|
||||
this.getClass().getClassLoader()).newInstance();
|
||||
return cache(csn, (Charset)o);
|
||||
} catch (ClassNotFoundException |
|
||||
IllegalAccessException |
|
||||
InstantiationException x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Charset cache(String csn, Charset cs) {
|
||||
cache().put(csn, cs);
|
||||
return cs;
|
||||
}
|
||||
|
||||
public final Charset charsetForName(String charsetName) {
|
||||
synchronized (this) {
|
||||
return lookup(charsetName);
|
||||
}
|
||||
}
|
||||
|
||||
public final Iterator<Charset> charsets() {
|
||||
Set<String> charsetNames;
|
||||
synchronized (this) {
|
||||
init();
|
||||
// Ensure initialized in synchronized block
|
||||
charsetNames = classMap().keySet();
|
||||
aliasMap();
|
||||
cache();
|
||||
}
|
||||
return new Iterator<Charset>() {
|
||||
|
||||
Iterator<String> i = charsetNames.iterator();
|
||||
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
public Charset next() {
|
||||
String csn = i.next();
|
||||
return lookup(csn);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
/* provider the sun.nio.cs.map property fir sjis/ms932 mapping hack
|
||||
*/
|
||||
private void init() {
|
||||
if (initialized)
|
||||
return;
|
||||
if (!jdk.internal.misc.VM.isBooted())
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
String map = GetPropertyAction.privilegedGetProperty("sun.nio.cs.map");
|
||||
if (map != null) {
|
||||
Map<String,String> aliasMap = aliasMap();
|
||||
Map<String,String> classMap = classMap();
|
||||
String[] maps = map.split(",");
|
||||
for (int i = 0; i < maps.length; i++) {
|
||||
if (maps[i].equalsIgnoreCase("Windows-31J/Shift_JIS")) {
|
||||
// if we dont have both sjis and ms932, do nothing
|
||||
if (classMap.get("shift_jis") == null ||
|
||||
classMap.get("windows-31j") == null) {
|
||||
break;
|
||||
}
|
||||
aliases_MS932 = new String[] {
|
||||
"MS932", // JDK historical
|
||||
"windows-932",
|
||||
"csWindows31J",
|
||||
"shift-jis",
|
||||
"ms_kanji",
|
||||
"x-sjis",
|
||||
"csShiftJIS",
|
||||
// This alias takes precedence over the actual
|
||||
// Shift_JIS charset itself since aliases are always
|
||||
// resolved first, before looking up canonical names.
|
||||
"shift_jis"
|
||||
};
|
||||
aliases_SJIS = new String[] { "sjis" };
|
||||
|
||||
for (String alias : aliases_MS932) {
|
||||
aliasMap.put(toLower(alias), "windows-31j");
|
||||
}
|
||||
cache().put("shift_jis", null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
381
src/java.base/share/classes/sun/nio/cs/StreamDecoder.java
Normal file
381
src/java.base/share/classes/sun/nio/cs/StreamDecoder.java
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.charset.*;
|
||||
|
||||
public class StreamDecoder extends Reader
|
||||
{
|
||||
|
||||
private static final int MIN_BYTE_BUFFER_SIZE = 32;
|
||||
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
|
||||
|
||||
private volatile boolean closed;
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed)
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
|
||||
// In order to handle surrogates properly we must never try to produce
|
||||
// fewer than two characters at a time. If we're only asked to return one
|
||||
// character then the other is saved here to be returned later.
|
||||
//
|
||||
private boolean haveLeftoverChar = false;
|
||||
private char leftoverChar;
|
||||
|
||||
|
||||
// Factories for java.io.InputStreamReader
|
||||
|
||||
public static StreamDecoder forInputStreamReader(InputStream in,
|
||||
Object lock,
|
||||
String charsetName)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
String csn = charsetName;
|
||||
if (csn == null)
|
||||
csn = Charset.defaultCharset().name();
|
||||
try {
|
||||
if (Charset.isSupported(csn))
|
||||
return new StreamDecoder(in, lock, Charset.forName(csn));
|
||||
} catch (IllegalCharsetNameException x) { }
|
||||
throw new UnsupportedEncodingException (csn);
|
||||
}
|
||||
|
||||
public static StreamDecoder forInputStreamReader(InputStream in,
|
||||
Object lock,
|
||||
Charset cs)
|
||||
{
|
||||
return new StreamDecoder(in, lock, cs);
|
||||
}
|
||||
|
||||
public static StreamDecoder forInputStreamReader(InputStream in,
|
||||
Object lock,
|
||||
CharsetDecoder dec)
|
||||
{
|
||||
return new StreamDecoder(in, lock, dec);
|
||||
}
|
||||
|
||||
|
||||
// Factory for java.nio.channels.Channels.newReader
|
||||
|
||||
public static StreamDecoder forDecoder(ReadableByteChannel ch,
|
||||
CharsetDecoder dec,
|
||||
int minBufferCap)
|
||||
{
|
||||
return new StreamDecoder(ch, dec, minBufferCap);
|
||||
}
|
||||
|
||||
|
||||
// -- Public methods corresponding to those in InputStreamReader --
|
||||
|
||||
// All synchronization and state/argument checking is done in these public
|
||||
// methods; the concrete stream-decoder subclasses defined below need not
|
||||
// do any such checking.
|
||||
|
||||
public String getEncoding() {
|
||||
if (isOpen())
|
||||
return encodingName();
|
||||
return null;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
return read0();
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
private int read0() throws IOException {
|
||||
synchronized (lock) {
|
||||
|
||||
// Return the leftover char, if there is one
|
||||
if (haveLeftoverChar) {
|
||||
haveLeftoverChar = false;
|
||||
return leftoverChar;
|
||||
}
|
||||
|
||||
// Convert more bytes
|
||||
char cb[] = new char[2];
|
||||
int n = read(cb, 0, 2);
|
||||
switch (n) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 2:
|
||||
leftoverChar = cb[1];
|
||||
haveLeftoverChar = true;
|
||||
// FALL THROUGH
|
||||
case 1:
|
||||
return cb[0];
|
||||
default:
|
||||
assert false : n;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int read(char cbuf[], int offset, int length) throws IOException {
|
||||
int off = offset;
|
||||
int len = length;
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
|
||||
((off + len) > cbuf.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
int n = 0;
|
||||
|
||||
if (haveLeftoverChar) {
|
||||
// Copy the leftover char into the buffer
|
||||
cbuf[off] = leftoverChar;
|
||||
off++; len--;
|
||||
haveLeftoverChar = false;
|
||||
n = 1;
|
||||
if ((len == 0) || !implReady())
|
||||
// Return now if this is all we can produce w/o blocking
|
||||
return n;
|
||||
}
|
||||
|
||||
if (len == 1) {
|
||||
// Treat single-character array reads just like read()
|
||||
int c = read0();
|
||||
if (c == -1)
|
||||
return (n == 0) ? -1 : n;
|
||||
cbuf[off] = (char)c;
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
return n + implRead(cbuf, off, off + len);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ready() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
return haveLeftoverChar || implReady();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (closed)
|
||||
return;
|
||||
implClose();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
|
||||
// -- Charset-based stream decoder impl --
|
||||
|
||||
// In the early stages of the build we haven't yet built the NIO native
|
||||
// code, so guard against that by catching the first UnsatisfiedLinkError
|
||||
// and setting this flag so that later attempts fail quickly.
|
||||
//
|
||||
private static volatile boolean channelsAvailable = true;
|
||||
|
||||
private static FileChannel getChannel(FileInputStream in) {
|
||||
if (!channelsAvailable)
|
||||
return null;
|
||||
try {
|
||||
return in.getChannel();
|
||||
} catch (UnsatisfiedLinkError x) {
|
||||
channelsAvailable = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Charset cs;
|
||||
private CharsetDecoder decoder;
|
||||
private ByteBuffer bb;
|
||||
|
||||
// Exactly one of these is non-null
|
||||
private InputStream in;
|
||||
private ReadableByteChannel ch;
|
||||
|
||||
StreamDecoder(InputStream in, Object lock, Charset cs) {
|
||||
this(in, lock,
|
||||
cs.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE));
|
||||
}
|
||||
|
||||
StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
|
||||
super(lock);
|
||||
this.cs = dec.charset();
|
||||
this.decoder = dec;
|
||||
|
||||
// This path disabled until direct buffers are faster
|
||||
if (false && in instanceof FileInputStream) {
|
||||
ch = getChannel((FileInputStream)in);
|
||||
if (ch != null)
|
||||
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
|
||||
}
|
||||
if (ch == null) {
|
||||
this.in = in;
|
||||
this.ch = null;
|
||||
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
|
||||
}
|
||||
bb.flip(); // So that bb is initially empty
|
||||
}
|
||||
|
||||
StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
|
||||
this.in = null;
|
||||
this.ch = ch;
|
||||
this.decoder = dec;
|
||||
this.cs = dec.charset();
|
||||
this.bb = ByteBuffer.allocate(mbc < 0
|
||||
? DEFAULT_BYTE_BUFFER_SIZE
|
||||
: (mbc < MIN_BYTE_BUFFER_SIZE
|
||||
? MIN_BYTE_BUFFER_SIZE
|
||||
: mbc));
|
||||
bb.flip();
|
||||
}
|
||||
|
||||
private int readBytes() throws IOException {
|
||||
bb.compact();
|
||||
try {
|
||||
if (ch != null) {
|
||||
// Read from the channel
|
||||
int n = ch.read(bb);
|
||||
if (n < 0)
|
||||
return n;
|
||||
} else {
|
||||
// Read from the input stream, and then update the buffer
|
||||
int lim = bb.limit();
|
||||
int pos = bb.position();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
assert rem > 0;
|
||||
int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
|
||||
if (n < 0)
|
||||
return n;
|
||||
if (n == 0)
|
||||
throw new IOException("Underlying input stream returned zero bytes");
|
||||
assert (n <= rem) : "n = " + n + ", rem = " + rem;
|
||||
bb.position(pos + n);
|
||||
}
|
||||
} finally {
|
||||
// Flip even when an IOException is thrown,
|
||||
// otherwise the stream will stutter
|
||||
bb.flip();
|
||||
}
|
||||
|
||||
int rem = bb.remaining();
|
||||
assert (rem != 0) : rem;
|
||||
return rem;
|
||||
}
|
||||
|
||||
int implRead(char[] cbuf, int off, int end) throws IOException {
|
||||
|
||||
// In order to handle surrogate pairs, this method requires that
|
||||
// the invoker attempt to read at least two characters. Saving the
|
||||
// extra character, if any, at a higher level is easier than trying
|
||||
// to deal with it here.
|
||||
assert (end - off > 1);
|
||||
|
||||
CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
|
||||
if (cb.position() != 0)
|
||||
// Ensure that cb[0] == cbuf[off]
|
||||
cb = cb.slice();
|
||||
|
||||
boolean eof = false;
|
||||
for (;;) {
|
||||
CoderResult cr = decoder.decode(bb, cb, eof);
|
||||
if (cr.isUnderflow()) {
|
||||
if (eof)
|
||||
break;
|
||||
if (!cb.hasRemaining())
|
||||
break;
|
||||
if ((cb.position() > 0) && !inReady())
|
||||
break; // Block at most once
|
||||
int n = readBytes();
|
||||
if (n < 0) {
|
||||
eof = true;
|
||||
if ((cb.position() == 0) && (!bb.hasRemaining()))
|
||||
break;
|
||||
decoder.reset();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (cr.isOverflow()) {
|
||||
assert cb.position() > 0;
|
||||
break;
|
||||
}
|
||||
cr.throwException();
|
||||
}
|
||||
|
||||
if (eof) {
|
||||
// ## Need to flush decoder
|
||||
decoder.reset();
|
||||
}
|
||||
|
||||
if (cb.position() == 0) {
|
||||
if (eof)
|
||||
return -1;
|
||||
assert false;
|
||||
}
|
||||
return cb.position();
|
||||
}
|
||||
|
||||
String encodingName() {
|
||||
return ((cs instanceof HistoricallyNamedCharset)
|
||||
? ((HistoricallyNamedCharset)cs).historicalName()
|
||||
: cs.name());
|
||||
}
|
||||
|
||||
private boolean inReady() {
|
||||
try {
|
||||
return (((in != null) && (in.available() > 0))
|
||||
|| (ch instanceof FileChannel)); // ## RBC.available()?
|
||||
} catch (IOException x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean implReady() {
|
||||
return bb.hasRemaining() || inReady();
|
||||
}
|
||||
|
||||
void implClose() throws IOException {
|
||||
if (ch != null)
|
||||
ch.close();
|
||||
else
|
||||
in.close();
|
||||
}
|
||||
|
||||
}
|
353
src/java.base/share/classes/sun/nio/cs/StreamEncoder.java
Normal file
353
src/java.base/share/classes/sun/nio/cs/StreamEncoder.java
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.charset.*;
|
||||
|
||||
public class StreamEncoder extends Writer
|
||||
{
|
||||
|
||||
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
|
||||
|
||||
private volatile boolean closed;
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed)
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
|
||||
// Factories for java.io.OutputStreamWriter
|
||||
public static StreamEncoder forOutputStreamWriter(OutputStream out,
|
||||
Object lock,
|
||||
String charsetName)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
String csn = charsetName;
|
||||
if (csn == null)
|
||||
csn = Charset.defaultCharset().name();
|
||||
try {
|
||||
if (Charset.isSupported(csn))
|
||||
return new StreamEncoder(out, lock, Charset.forName(csn));
|
||||
} catch (IllegalCharsetNameException x) { }
|
||||
throw new UnsupportedEncodingException (csn);
|
||||
}
|
||||
|
||||
public static StreamEncoder forOutputStreamWriter(OutputStream out,
|
||||
Object lock,
|
||||
Charset cs)
|
||||
{
|
||||
return new StreamEncoder(out, lock, cs);
|
||||
}
|
||||
|
||||
public static StreamEncoder forOutputStreamWriter(OutputStream out,
|
||||
Object lock,
|
||||
CharsetEncoder enc)
|
||||
{
|
||||
return new StreamEncoder(out, lock, enc);
|
||||
}
|
||||
|
||||
|
||||
// Factory for java.nio.channels.Channels.newWriter
|
||||
|
||||
public static StreamEncoder forEncoder(WritableByteChannel ch,
|
||||
CharsetEncoder enc,
|
||||
int minBufferCap)
|
||||
{
|
||||
return new StreamEncoder(ch, enc, minBufferCap);
|
||||
}
|
||||
|
||||
|
||||
// -- Public methods corresponding to those in OutputStreamWriter --
|
||||
|
||||
// All synchronization and state/argument checking is done in these public
|
||||
// methods; the concrete stream-encoder subclasses defined below need not
|
||||
// do any such checking.
|
||||
|
||||
public String getEncoding() {
|
||||
if (isOpen())
|
||||
return encodingName();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (isOpen())
|
||||
implFlushBuffer();
|
||||
else
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int c) throws IOException {
|
||||
char cbuf[] = new char[1];
|
||||
cbuf[0] = (char) c;
|
||||
write(cbuf, 0, 1);
|
||||
}
|
||||
|
||||
public void write(char cbuf[], int off, int len) throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
|
||||
((off + len) > cbuf.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
implWrite(cbuf, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(String str, int off, int len) throws IOException {
|
||||
/* Check the len before creating a char buffer */
|
||||
if (len < 0)
|
||||
throw new IndexOutOfBoundsException();
|
||||
char cbuf[] = new char[len];
|
||||
str.getChars(off, off + len, cbuf, 0);
|
||||
write(cbuf, 0, len);
|
||||
}
|
||||
|
||||
public void write(CharBuffer cb) throws IOException {
|
||||
int position = cb.position();
|
||||
try {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
implWrite(cb);
|
||||
}
|
||||
} finally {
|
||||
cb.position(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
synchronized (lock) {
|
||||
ensureOpen();
|
||||
implFlush();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (closed)
|
||||
return;
|
||||
implClose();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
|
||||
// -- Charset-based stream encoder impl --
|
||||
|
||||
private Charset cs;
|
||||
private CharsetEncoder encoder;
|
||||
private ByteBuffer bb;
|
||||
|
||||
// Exactly one of these is non-null
|
||||
private final OutputStream out;
|
||||
private WritableByteChannel ch;
|
||||
|
||||
// Leftover first char in a surrogate pair
|
||||
private boolean haveLeftoverChar = false;
|
||||
private char leftoverChar;
|
||||
private CharBuffer lcb = null;
|
||||
|
||||
private StreamEncoder(OutputStream out, Object lock, Charset cs) {
|
||||
this(out, lock,
|
||||
cs.newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE));
|
||||
}
|
||||
|
||||
private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
|
||||
super(lock);
|
||||
this.out = out;
|
||||
this.ch = null;
|
||||
this.cs = enc.charset();
|
||||
this.encoder = enc;
|
||||
|
||||
// This path disabled until direct buffers are faster
|
||||
if (false && out instanceof FileOutputStream) {
|
||||
ch = ((FileOutputStream)out).getChannel();
|
||||
if (ch != null)
|
||||
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
|
||||
}
|
||||
if (ch == null) {
|
||||
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
|
||||
this.out = null;
|
||||
this.ch = ch;
|
||||
this.cs = enc.charset();
|
||||
this.encoder = enc;
|
||||
this.bb = ByteBuffer.allocate(mbc < 0
|
||||
? DEFAULT_BYTE_BUFFER_SIZE
|
||||
: mbc);
|
||||
}
|
||||
|
||||
private void writeBytes() throws IOException {
|
||||
bb.flip();
|
||||
int lim = bb.limit();
|
||||
int pos = bb.position();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
if (rem > 0) {
|
||||
if (ch != null) {
|
||||
if (ch.write(bb) != rem)
|
||||
assert false : rem;
|
||||
} else {
|
||||
out.write(bb.array(), bb.arrayOffset() + pos, rem);
|
||||
}
|
||||
}
|
||||
bb.clear();
|
||||
}
|
||||
|
||||
private void flushLeftoverChar(CharBuffer cb, boolean endOfInput)
|
||||
throws IOException
|
||||
{
|
||||
if (!haveLeftoverChar && !endOfInput)
|
||||
return;
|
||||
if (lcb == null)
|
||||
lcb = CharBuffer.allocate(2);
|
||||
else
|
||||
lcb.clear();
|
||||
if (haveLeftoverChar)
|
||||
lcb.put(leftoverChar);
|
||||
if ((cb != null) && cb.hasRemaining())
|
||||
lcb.put(cb.get());
|
||||
lcb.flip();
|
||||
while (lcb.hasRemaining() || endOfInput) {
|
||||
CoderResult cr = encoder.encode(lcb, bb, endOfInput);
|
||||
if (cr.isUnderflow()) {
|
||||
if (lcb.hasRemaining()) {
|
||||
leftoverChar = lcb.get();
|
||||
if (cb != null && cb.hasRemaining()) {
|
||||
lcb.clear();
|
||||
lcb.put(leftoverChar).put(cb.get()).flip();
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cr.isOverflow()) {
|
||||
assert bb.position() > 0;
|
||||
writeBytes();
|
||||
continue;
|
||||
}
|
||||
cr.throwException();
|
||||
}
|
||||
haveLeftoverChar = false;
|
||||
}
|
||||
|
||||
void implWrite(char cbuf[], int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
|
||||
implWrite(cb);
|
||||
}
|
||||
|
||||
void implWrite(CharBuffer cb)
|
||||
throws IOException
|
||||
{
|
||||
if (haveLeftoverChar) {
|
||||
flushLeftoverChar(cb, false);
|
||||
}
|
||||
|
||||
while (cb.hasRemaining()) {
|
||||
CoderResult cr = encoder.encode(cb, bb, false);
|
||||
if (cr.isUnderflow()) {
|
||||
assert (cb.remaining() <= 1) : cb.remaining();
|
||||
if (cb.remaining() == 1) {
|
||||
haveLeftoverChar = true;
|
||||
leftoverChar = cb.get();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cr.isOverflow()) {
|
||||
assert bb.position() > 0;
|
||||
writeBytes();
|
||||
continue;
|
||||
}
|
||||
cr.throwException();
|
||||
}
|
||||
}
|
||||
|
||||
void implFlushBuffer() throws IOException {
|
||||
if (bb.position() > 0)
|
||||
writeBytes();
|
||||
}
|
||||
|
||||
void implFlush() throws IOException {
|
||||
implFlushBuffer();
|
||||
if (out != null)
|
||||
out.flush();
|
||||
}
|
||||
|
||||
void implClose() throws IOException {
|
||||
flushLeftoverChar(null, true);
|
||||
try {
|
||||
for (;;) {
|
||||
CoderResult cr = encoder.flush(bb);
|
||||
if (cr.isUnderflow())
|
||||
break;
|
||||
if (cr.isOverflow()) {
|
||||
assert bb.position() > 0;
|
||||
writeBytes();
|
||||
continue;
|
||||
}
|
||||
cr.throwException();
|
||||
}
|
||||
|
||||
if (bb.position() > 0)
|
||||
writeBytes();
|
||||
if (ch != null)
|
||||
ch.close();
|
||||
else
|
||||
out.close();
|
||||
} catch (IOException x) {
|
||||
encoder.reset();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
String encodingName() {
|
||||
return ((cs instanceof HistoricallyNamedCharset)
|
||||
? ((HistoricallyNamedCharset)cs).historicalName()
|
||||
: cs.name());
|
||||
}
|
||||
}
|
39
src/java.base/share/classes/sun/nio/cs/StringUTF16.java
Normal file
39
src/java.base/share/classes/sun/nio/cs/StringUTF16.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
import static jdk.internal.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE;
|
||||
|
||||
class StringUTF16 {
|
||||
|
||||
public static char getChar(byte[] val, int index) {
|
||||
return unsafe.getChar(val,
|
||||
ARRAY_BYTE_BASE_OFFSET + ARRAY_BYTE_INDEX_SCALE * index * 2L);
|
||||
}
|
||||
|
||||
private static final jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
}
|
362
src/java.base/share/classes/sun/nio/cs/Surrogate.java
Normal file
362
src/java.base/share/classes/sun/nio/cs/Surrogate.java
Normal file
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.UnmappableCharacterException;
|
||||
|
||||
/**
|
||||
* Utility class for dealing with surrogates.
|
||||
*
|
||||
* @author Mark Reinhold
|
||||
* @author Martin Buchholz
|
||||
* @author Ulf Zibis
|
||||
*/
|
||||
public class Surrogate {
|
||||
|
||||
private Surrogate() { }
|
||||
|
||||
// TODO: Deprecate/remove the following redundant definitions
|
||||
public static final char MIN_HIGH = Character.MIN_HIGH_SURROGATE;
|
||||
public static final char MAX_HIGH = Character.MAX_HIGH_SURROGATE;
|
||||
public static final char MIN_LOW = Character.MIN_LOW_SURROGATE;
|
||||
public static final char MAX_LOW = Character.MAX_LOW_SURROGATE;
|
||||
public static final char MIN = Character.MIN_SURROGATE;
|
||||
public static final char MAX = Character.MAX_SURROGATE;
|
||||
public static final int UCS4_MIN = Character.MIN_SUPPLEMENTARY_CODE_POINT;
|
||||
public static final int UCS4_MAX = Character.MAX_CODE_POINT;
|
||||
|
||||
/**
|
||||
* Tells whether or not the given value is in the high surrogate range.
|
||||
* Use of {@link Character#isHighSurrogate} is generally preferred.
|
||||
*/
|
||||
public static boolean isHigh(int c) {
|
||||
return (MIN_HIGH <= c) && (c <= MAX_HIGH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not the given value is in the low surrogate range.
|
||||
* Use of {@link Character#isLowSurrogate} is generally preferred.
|
||||
*/
|
||||
public static boolean isLow(int c) {
|
||||
return (MIN_LOW <= c) && (c <= MAX_LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not the given value is in the surrogate range.
|
||||
* Use of {@link Character#isSurrogate} is generally preferred.
|
||||
*/
|
||||
public static boolean is(int c) {
|
||||
return (MIN <= c) && (c <= MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not the given UCS-4 character must be represented as a
|
||||
* surrogate pair in UTF-16.
|
||||
* Use of {@link Character#isSupplementaryCodePoint} is generally preferred.
|
||||
*/
|
||||
public static boolean neededFor(int uc) {
|
||||
return Character.isSupplementaryCodePoint(uc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the high UTF-16 surrogate for the given supplementary UCS-4 character.
|
||||
* Use of {@link Character#highSurrogate} is generally preferred.
|
||||
*/
|
||||
public static char high(int uc) {
|
||||
assert Character.isSupplementaryCodePoint(uc);
|
||||
return Character.highSurrogate(uc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the low UTF-16 surrogate for the given supplementary UCS-4 character.
|
||||
* Use of {@link Character#lowSurrogate} is generally preferred.
|
||||
*/
|
||||
public static char low(int uc) {
|
||||
assert Character.isSupplementaryCodePoint(uc);
|
||||
return Character.lowSurrogate(uc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given surrogate pair into a 32-bit UCS-4 character.
|
||||
* Use of {@link Character#toCodePoint} is generally preferred.
|
||||
*/
|
||||
public static int toUCS4(char c, char d) {
|
||||
assert Character.isHighSurrogate(c) && Character.isLowSurrogate(d);
|
||||
return Character.toCodePoint(c, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Surrogate parsing support. Charset implementations may use instances of
|
||||
* this class to handle the details of parsing UTF-16 surrogate pairs.
|
||||
*/
|
||||
public static class Parser {
|
||||
|
||||
public Parser() { }
|
||||
|
||||
private int character; // UCS-4
|
||||
private CoderResult error = CoderResult.UNDERFLOW;
|
||||
private boolean isPair;
|
||||
|
||||
/**
|
||||
* Returns the UCS-4 character previously parsed.
|
||||
*/
|
||||
public int character() {
|
||||
assert (error == null);
|
||||
return character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not the previously-parsed UCS-4 character was
|
||||
* originally represented by a surrogate pair.
|
||||
*/
|
||||
public boolean isPair() {
|
||||
assert (error == null);
|
||||
return isPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of UTF-16 characters consumed by the previous
|
||||
* parse.
|
||||
*/
|
||||
public int increment() {
|
||||
assert (error == null);
|
||||
return isPair ? 2 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the previous parse operation detected an error, return the object
|
||||
* describing that error.
|
||||
*/
|
||||
public CoderResult error() {
|
||||
assert (error != null);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmappable-input result object, with the appropriate
|
||||
* input length, for the previously-parsed character.
|
||||
*/
|
||||
public CoderResult unmappableResult() {
|
||||
assert (error == null);
|
||||
return CoderResult.unmappableForLength(isPair ? 2 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a UCS-4 character from the given source buffer, handling
|
||||
* surrogates.
|
||||
*
|
||||
* @param c The first character
|
||||
* @param in The source buffer, from which one more character
|
||||
* will be consumed if c is a high surrogate
|
||||
*
|
||||
* @return Either a parsed UCS-4 character, in which case the isPair()
|
||||
* and increment() methods will return meaningful values, or
|
||||
* -1, in which case error() will return a descriptive result
|
||||
* object
|
||||
*/
|
||||
public int parse(char c, CharBuffer in) {
|
||||
if (Character.isHighSurrogate(c)) {
|
||||
if (!in.hasRemaining()) {
|
||||
error = CoderResult.UNDERFLOW;
|
||||
return -1;
|
||||
}
|
||||
char d = in.get();
|
||||
if (Character.isLowSurrogate(d)) {
|
||||
character = Character.toCodePoint(c, d);
|
||||
isPair = true;
|
||||
error = null;
|
||||
return character;
|
||||
}
|
||||
error = CoderResult.malformedForLength(1);
|
||||
return -1;
|
||||
}
|
||||
if (Character.isLowSurrogate(c)) {
|
||||
error = CoderResult.malformedForLength(1);
|
||||
return -1;
|
||||
}
|
||||
character = c;
|
||||
isPair = false;
|
||||
error = null;
|
||||
return character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a UCS-4 character from the given source buffer, handling
|
||||
* surrogates.
|
||||
*
|
||||
* @param c The first character
|
||||
* @param ia The input array, from which one more character
|
||||
* will be consumed if c is a high surrogate
|
||||
* @param ip The input index
|
||||
* @param il The input limit
|
||||
*
|
||||
* @return Either a parsed UCS-4 character, in which case the isPair()
|
||||
* and increment() methods will return meaningful values, or
|
||||
* -1, in which case error() will return a descriptive result
|
||||
* object
|
||||
*/
|
||||
public int parse(char c, char[] ia, int ip, int il) {
|
||||
assert (ia[ip] == c);
|
||||
if (Character.isHighSurrogate(c)) {
|
||||
if (il - ip < 2) {
|
||||
error = CoderResult.UNDERFLOW;
|
||||
return -1;
|
||||
}
|
||||
char d = ia[ip + 1];
|
||||
if (Character.isLowSurrogate(d)) {
|
||||
character = Character.toCodePoint(c, d);
|
||||
isPair = true;
|
||||
error = null;
|
||||
return character;
|
||||
}
|
||||
error = CoderResult.malformedForLength(1);
|
||||
return -1;
|
||||
}
|
||||
if (Character.isLowSurrogate(c)) {
|
||||
error = CoderResult.malformedForLength(1);
|
||||
return -1;
|
||||
}
|
||||
character = c;
|
||||
isPair = false;
|
||||
error = null;
|
||||
return character;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Surrogate generation support. Charset implementations may use instances
|
||||
* of this class to handle the details of generating UTF-16 surrogate
|
||||
* pairs.
|
||||
*/
|
||||
public static class Generator {
|
||||
|
||||
public Generator() { }
|
||||
|
||||
private CoderResult error = CoderResult.OVERFLOW;
|
||||
|
||||
/**
|
||||
* If the previous generation operation detected an error, return the
|
||||
* object describing that error.
|
||||
*/
|
||||
public CoderResult error() {
|
||||
assert error != null;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates one or two UTF-16 characters to represent the given UCS-4
|
||||
* character.
|
||||
*
|
||||
* @param uc The UCS-4 character
|
||||
* @param len The number of input bytes from which the UCS-4 value
|
||||
* was constructed (used when creating result objects)
|
||||
* @param dst The destination buffer, to which one or two UTF-16
|
||||
* characters will be written
|
||||
*
|
||||
* @return Either a positive count of the number of UTF-16 characters
|
||||
* written to the destination buffer, or -1, in which case
|
||||
* error() will return a descriptive result object
|
||||
*/
|
||||
public int generate(int uc, int len, CharBuffer dst) {
|
||||
if (Character.isBmpCodePoint(uc)) {
|
||||
char c = (char) uc;
|
||||
if (Character.isSurrogate(c)) {
|
||||
error = CoderResult.malformedForLength(len);
|
||||
return -1;
|
||||
}
|
||||
if (dst.remaining() < 1) {
|
||||
error = CoderResult.OVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
dst.put(c);
|
||||
error = null;
|
||||
return 1;
|
||||
} else if (Character.isValidCodePoint(uc)) {
|
||||
if (dst.remaining() < 2) {
|
||||
error = CoderResult.OVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
dst.put(Character.highSurrogate(uc));
|
||||
dst.put(Character.lowSurrogate(uc));
|
||||
error = null;
|
||||
return 2;
|
||||
} else {
|
||||
error = CoderResult.unmappableForLength(len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates one or two UTF-16 characters to represent the given UCS-4
|
||||
* character.
|
||||
*
|
||||
* @param uc The UCS-4 character
|
||||
* @param len The number of input bytes from which the UCS-4 value
|
||||
* was constructed (used when creating result objects)
|
||||
* @param da The destination array, to which one or two UTF-16
|
||||
* characters will be written
|
||||
* @param dp The destination position
|
||||
* @param dl The destination limit
|
||||
*
|
||||
* @return Either a positive count of the number of UTF-16 characters
|
||||
* written to the destination buffer, or -1, in which case
|
||||
* error() will return a descriptive result object
|
||||
*/
|
||||
public int generate(int uc, int len, char[] da, int dp, int dl) {
|
||||
if (Character.isBmpCodePoint(uc)) {
|
||||
char c = (char) uc;
|
||||
if (Character.isSurrogate(c)) {
|
||||
error = CoderResult.malformedForLength(len);
|
||||
return -1;
|
||||
}
|
||||
if (dl - dp < 1) {
|
||||
error = CoderResult.OVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
da[dp] = c;
|
||||
error = null;
|
||||
return 1;
|
||||
} else if (Character.isValidCodePoint(uc)) {
|
||||
if (dl - dp < 2) {
|
||||
error = CoderResult.OVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
da[dp] = Character.highSurrogate(uc);
|
||||
da[dp + 1] = Character.lowSurrogate(uc);
|
||||
error = null;
|
||||
return 2;
|
||||
} else {
|
||||
error = CoderResult.unmappableForLength(len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
136
src/java.base/share/classes/sun/nio/cs/ThreadLocalCoders.java
Normal file
136
src/java.base/share/classes/sun/nio/cs/ThreadLocalCoders.java
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.*;
|
||||
|
||||
|
||||
/**
|
||||
* Utility class for caching per-thread decoders and encoders.
|
||||
*/
|
||||
|
||||
public class ThreadLocalCoders {
|
||||
|
||||
private static final int CACHE_SIZE = 3;
|
||||
|
||||
private abstract static class Cache {
|
||||
|
||||
// Thread-local reference to array of cached objects, in LRU order
|
||||
private ThreadLocal<Object[]> cache = new ThreadLocal<>();
|
||||
private final int size;
|
||||
|
||||
Cache(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
abstract Object create(Object name);
|
||||
|
||||
private void moveToFront(Object[] oa, int i) {
|
||||
Object ob = oa[i];
|
||||
for (int j = i; j > 0; j--)
|
||||
oa[j] = oa[j - 1];
|
||||
oa[0] = ob;
|
||||
}
|
||||
|
||||
abstract boolean hasName(Object ob, Object name);
|
||||
|
||||
Object forName(Object name) {
|
||||
Object[] oa = cache.get();
|
||||
if (oa == null) {
|
||||
oa = new Object[size];
|
||||
cache.set(oa);
|
||||
} else {
|
||||
for (int i = 0; i < oa.length; i++) {
|
||||
Object ob = oa[i];
|
||||
if (ob == null)
|
||||
continue;
|
||||
if (hasName(ob, name)) {
|
||||
if (i > 0)
|
||||
moveToFront(oa, i);
|
||||
return ob;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new object
|
||||
Object ob = create(name);
|
||||
oa[oa.length - 1] = ob;
|
||||
moveToFront(oa, oa.length - 1);
|
||||
return ob;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Cache decoderCache = new Cache(CACHE_SIZE) {
|
||||
boolean hasName(Object ob, Object name) {
|
||||
if (name instanceof String)
|
||||
return (((CharsetDecoder)ob).charset().name().equals(name));
|
||||
if (name instanceof Charset)
|
||||
return ((CharsetDecoder)ob).charset().equals(name);
|
||||
return false;
|
||||
}
|
||||
Object create(Object name) {
|
||||
if (name instanceof String)
|
||||
return Charset.forName((String)name).newDecoder();
|
||||
if (name instanceof Charset)
|
||||
return ((Charset)name).newDecoder();
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static CharsetDecoder decoderFor(Object name) {
|
||||
CharsetDecoder cd = (CharsetDecoder)decoderCache.forName(name);
|
||||
cd.reset();
|
||||
return cd;
|
||||
}
|
||||
|
||||
private static Cache encoderCache = new Cache(CACHE_SIZE) {
|
||||
boolean hasName(Object ob, Object name) {
|
||||
if (name instanceof String)
|
||||
return (((CharsetEncoder)ob).charset().name().equals(name));
|
||||
if (name instanceof Charset)
|
||||
return ((CharsetEncoder)ob).charset().equals(name);
|
||||
return false;
|
||||
}
|
||||
Object create(Object name) {
|
||||
if (name instanceof String)
|
||||
return Charset.forName((String)name).newEncoder();
|
||||
if (name instanceof Charset)
|
||||
return ((Charset)name).newEncoder();
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static CharsetEncoder encoderFor(Object name) {
|
||||
CharsetEncoder ce = (CharsetEncoder)encoderCache.forName(name);
|
||||
ce.reset();
|
||||
return ce;
|
||||
}
|
||||
|
||||
}
|
272
src/java.base/share/classes/sun/nio/cs/US_ASCII.java
Normal file
272
src/java.base/share/classes/sun/nio/cs/US_ASCII.java
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
|
||||
public class US_ASCII
|
||||
extends Charset
|
||||
implements HistoricallyNamedCharset
|
||||
{
|
||||
public static final US_ASCII INSTANCE = new US_ASCII();
|
||||
|
||||
public US_ASCII() {
|
||||
super("US-ASCII", StandardCharsets.aliases_US_ASCII());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "ASCII";
|
||||
}
|
||||
|
||||
public boolean contains(Charset cs) {
|
||||
return (cs instanceof US_ASCII);
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static class Decoder extends CharsetDecoder
|
||||
implements ArrayDecoder {
|
||||
|
||||
private Decoder(Charset cs) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
private CoderResult decodeArrayLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
assert (sp <= sl);
|
||||
sp = (sp <= sl ? sp : sl);
|
||||
char[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
assert (dp <= dl);
|
||||
dp = (dp <= dl ? dp : dl);
|
||||
|
||||
try {
|
||||
while (sp < sl) {
|
||||
byte b = sa[sp];
|
||||
if (b >= 0) {
|
||||
if (dp >= dl)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (char)b;
|
||||
sp++;
|
||||
continue;
|
||||
}
|
||||
return CoderResult.malformedForLength(1);
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
}
|
||||
|
||||
private CoderResult decodeBufferLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
byte b = src.get();
|
||||
if (b >= 0) {
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((char)b);
|
||||
mark++;
|
||||
continue;
|
||||
}
|
||||
return CoderResult.malformedForLength(1);
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArrayLoop(src, dst);
|
||||
else
|
||||
return decodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private char repl = '\uFFFD';
|
||||
protected void implReplaceWith(String newReplacement) {
|
||||
repl = newReplacement.charAt(0);
|
||||
}
|
||||
|
||||
public int decode(byte[] src, int sp, int len, char[] dst) {
|
||||
int dp = 0;
|
||||
len = Math.min(len, dst.length);
|
||||
while (dp < len) {
|
||||
byte b = src[sp++];
|
||||
if (b >= 0)
|
||||
dst[dp++] = (char)b;
|
||||
else
|
||||
dst[dp++] = repl;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public boolean isASCIICompatible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends CharsetEncoder
|
||||
implements ArrayEncoder {
|
||||
|
||||
private Encoder(Charset cs) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return c < 0x80;
|
||||
}
|
||||
|
||||
public boolean isLegalReplacement(byte[] repl) {
|
||||
return (repl.length == 1 && repl[0] >= 0) ||
|
||||
super.isLegalReplacement(repl);
|
||||
}
|
||||
|
||||
private final Surrogate.Parser sgp = new Surrogate.Parser();
|
||||
private CoderResult encodeArrayLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
char[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
assert (sp <= sl);
|
||||
sp = (sp <= sl ? sp : sl);
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
assert (dp <= dl);
|
||||
dp = (dp <= dl ? dp : dl);
|
||||
|
||||
try {
|
||||
while (sp < sl) {
|
||||
char c = sa[sp];
|
||||
if (c < 0x80) {
|
||||
if (dp >= dl)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp] = (byte)c;
|
||||
sp++; dp++;
|
||||
continue;
|
||||
}
|
||||
if (sgp.parse(c, sa, sp, sl) < 0)
|
||||
return sgp.error();
|
||||
return sgp.unmappableResult();
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
}
|
||||
|
||||
private CoderResult encodeBufferLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
if (c < 0x80) {
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)c);
|
||||
mark++;
|
||||
continue;
|
||||
}
|
||||
if (sgp.parse(c, src) < 0)
|
||||
return sgp.error();
|
||||
return sgp.unmappableResult();
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected CoderResult encodeLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArrayLoop(src, dst);
|
||||
else
|
||||
return encodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private byte repl = (byte)'?';
|
||||
protected void implReplaceWith(byte[] newReplacement) {
|
||||
repl = newReplacement[0];
|
||||
}
|
||||
|
||||
public int encode(char[] src, int sp, int len, byte[] dst) {
|
||||
int dp = 0;
|
||||
int sl = sp + Math.min(len, dst.length);
|
||||
while (sp < sl) {
|
||||
char c = src[sp++];
|
||||
if (c < 0x80) {
|
||||
dst[dp++] = (byte)c;
|
||||
continue;
|
||||
}
|
||||
if (Character.isHighSurrogate(c) && sp < sl &&
|
||||
Character.isLowSurrogate(src[sp])) {
|
||||
if (len > dst.length) {
|
||||
sl++;
|
||||
len--;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
dst[dp++] = repl;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public boolean isASCIICompatible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
src/java.base/share/classes/sun/nio/cs/UTF_16.java
Normal file
65
src/java.base/share/classes/sun/nio/cs/UTF_16.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
class UTF_16 extends Unicode
|
||||
{
|
||||
|
||||
public UTF_16() {
|
||||
super("UTF-16", StandardCharsets.aliases_UTF_16());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UTF-16";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static class Decoder extends UnicodeDecoder {
|
||||
|
||||
public Decoder(Charset cs) {
|
||||
super(cs, NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends UnicodeEncoder {
|
||||
|
||||
public Encoder(Charset cs) {
|
||||
super(cs, BIG, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
src/java.base/share/classes/sun/nio/cs/UTF_16BE.java
Normal file
65
src/java.base/share/classes/sun/nio/cs/UTF_16BE.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
class UTF_16BE extends Unicode
|
||||
{
|
||||
|
||||
public UTF_16BE() {
|
||||
super("UTF-16BE", StandardCharsets.aliases_UTF_16BE());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UnicodeBigUnmarked";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static class Decoder extends UnicodeDecoder {
|
||||
|
||||
public Decoder(Charset cs) {
|
||||
super(cs, BIG);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends UnicodeEncoder {
|
||||
|
||||
public Encoder(Charset cs) {
|
||||
super(cs, BIG, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
src/java.base/share/classes/sun/nio/cs/UTF_16LE.java
Normal file
65
src/java.base/share/classes/sun/nio/cs/UTF_16LE.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
class UTF_16LE extends Unicode
|
||||
{
|
||||
|
||||
public UTF_16LE() {
|
||||
super("UTF-16LE", StandardCharsets.aliases_UTF_16LE());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UnicodeLittleUnmarked";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static class Decoder extends UnicodeDecoder {
|
||||
|
||||
public Decoder(Charset cs) {
|
||||
super(cs, LITTLE);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends UnicodeEncoder {
|
||||
|
||||
public Encoder(Charset cs) {
|
||||
super(cs, LITTLE, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
src/java.base/share/classes/sun/nio/cs/UTF_16LE_BOM.java
Normal file
65
src/java.base/share/classes/sun/nio/cs/UTF_16LE_BOM.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
class UTF_16LE_BOM extends Unicode
|
||||
{
|
||||
|
||||
public UTF_16LE_BOM() {
|
||||
super("x-UTF-16LE-BOM", StandardCharsets.aliases_UTF_16LE_BOM());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UnicodeLittle";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
private static class Decoder extends UnicodeDecoder {
|
||||
|
||||
public Decoder(Charset cs) {
|
||||
super(cs, NONE, LITTLE);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Encoder extends UnicodeEncoder {
|
||||
|
||||
public Encoder(Charset cs) {
|
||||
super(cs, LITTLE, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
48
src/java.base/share/classes/sun/nio/cs/UTF_32.java
Normal file
48
src/java.base/share/classes/sun/nio/cs/UTF_32.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
public class UTF_32 extends Unicode
|
||||
{
|
||||
public UTF_32() {
|
||||
super("UTF-32", StandardCharsets.aliases_UTF_32());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UTF-32";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new UTF_32Coder.Decoder(this, UTF_32Coder.NONE);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new UTF_32Coder.Encoder(this, UTF_32Coder.BIG, false);
|
||||
}
|
||||
}
|
48
src/java.base/share/classes/sun/nio/cs/UTF_32BE.java
Normal file
48
src/java.base/share/classes/sun/nio/cs/UTF_32BE.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
public class UTF_32BE extends Unicode
|
||||
{
|
||||
public UTF_32BE() {
|
||||
super("UTF-32BE", StandardCharsets.aliases_UTF_32BE());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UTF-32BE";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new UTF_32Coder.Decoder(this, UTF_32Coder.BIG);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new UTF_32Coder.Encoder(this, UTF_32Coder.BIG, false);
|
||||
}
|
||||
}
|
48
src/java.base/share/classes/sun/nio/cs/UTF_32BE_BOM.java
Normal file
48
src/java.base/share/classes/sun/nio/cs/UTF_32BE_BOM.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
public class UTF_32BE_BOM extends Unicode
|
||||
{
|
||||
public UTF_32BE_BOM() {
|
||||
super("X-UTF-32BE-BOM", StandardCharsets.aliases_UTF_32BE_BOM());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "X-UTF-32BE-BOM";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new UTF_32Coder.Decoder(this, UTF_32Coder.BIG);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new UTF_32Coder.Encoder(this, UTF_32Coder.BIG, true);
|
||||
}
|
||||
}
|
189
src/java.base/share/classes/sun/nio/cs/UTF_32Coder.java
Normal file
189
src/java.base/share/classes/sun/nio/cs/UTF_32Coder.java
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
class UTF_32Coder {
|
||||
protected static final int BOM_BIG = 0xFEFF;
|
||||
protected static final int BOM_LITTLE = 0xFFFE0000;
|
||||
protected static final int NONE = 0;
|
||||
protected static final int BIG = 1;
|
||||
protected static final int LITTLE = 2;
|
||||
|
||||
protected static class Decoder extends CharsetDecoder {
|
||||
private int currentBO;
|
||||
private int expectedBO;
|
||||
|
||||
protected Decoder(Charset cs, int bo) {
|
||||
super(cs, 0.25f, 1.0f);
|
||||
this.expectedBO = bo;
|
||||
this.currentBO = NONE;
|
||||
}
|
||||
|
||||
private int getCP(ByteBuffer src) {
|
||||
return (currentBO==BIG)
|
||||
?(((src.get() & 0xff) << 24) |
|
||||
((src.get() & 0xff) << 16) |
|
||||
((src.get() & 0xff) << 8) |
|
||||
(src.get() & 0xff))
|
||||
:((src.get() & 0xff) |
|
||||
((src.get() & 0xff) << 8) |
|
||||
((src.get() & 0xff) << 16) |
|
||||
((src.get() & 0xff) << 24));
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
|
||||
if (src.remaining() < 4)
|
||||
return CoderResult.UNDERFLOW;
|
||||
int mark = src.position();
|
||||
int cp;
|
||||
try {
|
||||
if (currentBO == NONE) {
|
||||
cp = ((src.get() & 0xff) << 24) |
|
||||
((src.get() & 0xff) << 16) |
|
||||
((src.get() & 0xff) << 8) |
|
||||
(src.get() & 0xff);
|
||||
if (cp == BOM_BIG && expectedBO != LITTLE) {
|
||||
currentBO = BIG;
|
||||
mark += 4;
|
||||
} else if (cp == BOM_LITTLE && expectedBO != BIG) {
|
||||
currentBO = LITTLE;
|
||||
mark += 4;
|
||||
} else {
|
||||
if (expectedBO == NONE)
|
||||
currentBO = BIG;
|
||||
else
|
||||
currentBO = expectedBO;
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
while (src.remaining() >= 4) {
|
||||
cp = getCP(src);
|
||||
if (Character.isBmpCodePoint(cp)) {
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
mark += 4;
|
||||
dst.put((char) cp);
|
||||
} else if (Character.isValidCodePoint(cp)) {
|
||||
if (dst.remaining() < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
mark += 4;
|
||||
dst.put(Character.highSurrogate(cp));
|
||||
dst.put(Character.lowSurrogate(cp));
|
||||
} else {
|
||||
return CoderResult.malformedForLength(4);
|
||||
}
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
protected void implReset() {
|
||||
currentBO = NONE;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class Encoder extends CharsetEncoder {
|
||||
private boolean doBOM = false;
|
||||
private boolean doneBOM = true;
|
||||
private int byteOrder;
|
||||
|
||||
protected void put(int cp, ByteBuffer dst) {
|
||||
if (byteOrder==BIG) {
|
||||
dst.put((byte)(cp >> 24));
|
||||
dst.put((byte)(cp >> 16));
|
||||
dst.put((byte)(cp >> 8));
|
||||
dst.put((byte)cp);
|
||||
} else {
|
||||
dst.put((byte)cp);
|
||||
dst.put((byte)(cp >> 8));
|
||||
dst.put((byte)(cp >> 16));
|
||||
dst.put((byte)(cp >> 24));
|
||||
}
|
||||
}
|
||||
|
||||
protected Encoder(Charset cs, int byteOrder, boolean doBOM) {
|
||||
super(cs, 4.0f,
|
||||
doBOM?8.0f:4.0f,
|
||||
(byteOrder==BIG)?new byte[]{(byte)0, (byte)0, (byte)0xff, (byte)0xfd}
|
||||
:new byte[]{(byte)0xfd, (byte)0xff, (byte)0, (byte)0});
|
||||
this.byteOrder = byteOrder;
|
||||
this.doBOM = doBOM;
|
||||
this.doneBOM = !doBOM;
|
||||
}
|
||||
|
||||
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
|
||||
int mark = src.position();
|
||||
if (!doneBOM && src.hasRemaining()) {
|
||||
if (dst.remaining() < 4)
|
||||
return CoderResult.OVERFLOW;
|
||||
put(BOM_BIG, dst);
|
||||
doneBOM = true;
|
||||
}
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
if (!Character.isSurrogate(c)) {
|
||||
if (dst.remaining() < 4)
|
||||
return CoderResult.OVERFLOW;
|
||||
mark++;
|
||||
put(c, dst);
|
||||
} else if (Character.isHighSurrogate(c)) {
|
||||
if (!src.hasRemaining())
|
||||
return CoderResult.UNDERFLOW;
|
||||
char low = src.get();
|
||||
if (Character.isLowSurrogate(low)) {
|
||||
if (dst.remaining() < 4)
|
||||
return CoderResult.OVERFLOW;
|
||||
mark += 2;
|
||||
put(Character.toCodePoint(c, low), dst);
|
||||
} else {
|
||||
return CoderResult.malformedForLength(1);
|
||||
}
|
||||
} else {
|
||||
// assert Character.isLowSurrogate(c);
|
||||
return CoderResult.malformedForLength(1);
|
||||
}
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected void implReset() {
|
||||
doneBOM = !doBOM;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
49
src/java.base/share/classes/sun/nio/cs/UTF_32LE.java
Normal file
49
src/java.base/share/classes/sun/nio/cs/UTF_32LE.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
public class UTF_32LE extends Unicode
|
||||
{
|
||||
public UTF_32LE() {
|
||||
super("UTF-32LE", StandardCharsets.aliases_UTF_32LE());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UTF-32LE";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new UTF_32Coder.Decoder(this, UTF_32Coder.LITTLE);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new UTF_32Coder.Encoder(this, UTF_32Coder.LITTLE, false);
|
||||
}
|
||||
}
|
48
src/java.base/share/classes/sun/nio/cs/UTF_32LE_BOM.java
Normal file
48
src/java.base/share/classes/sun/nio/cs/UTF_32LE_BOM.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
public class UTF_32LE_BOM extends Unicode
|
||||
{
|
||||
public UTF_32LE_BOM() {
|
||||
super("X-UTF-32LE-BOM", StandardCharsets.aliases_UTF_32LE_BOM());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "X-UTF-32LE-BOM";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new UTF_32Coder.Decoder(this, UTF_32Coder.LITTLE);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new UTF_32Coder.Encoder(this, UTF_32Coder.LITTLE, true);
|
||||
}
|
||||
}
|
756
src/java.base/share/classes/sun/nio/cs/UTF_8.java
Normal file
756
src/java.base/share/classes/sun/nio/cs/UTF_8.java
Normal file
|
@ -0,0 +1,756 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
|
||||
/* Legal UTF-8 Byte Sequences
|
||||
*
|
||||
* # Code Points Bits Bit/Byte pattern
|
||||
* 1 7 0xxxxxxx
|
||||
* U+0000..U+007F 00..7F
|
||||
*
|
||||
* 2 11 110xxxxx 10xxxxxx
|
||||
* U+0080..U+07FF C2..DF 80..BF
|
||||
*
|
||||
* 3 16 1110xxxx 10xxxxxx 10xxxxxx
|
||||
* U+0800..U+0FFF E0 A0..BF 80..BF
|
||||
* U+1000..U+FFFF E1..EF 80..BF 80..BF
|
||||
*
|
||||
* 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
* U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
|
||||
* U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
|
||||
* U+100000..U10FFFF F4 80..8F 80..BF 80..BF
|
||||
*
|
||||
*/
|
||||
|
||||
public final class UTF_8 extends Unicode {
|
||||
|
||||
public static final UTF_8 INSTANCE = new UTF_8();
|
||||
|
||||
public UTF_8() {
|
||||
super("UTF-8", StandardCharsets.aliases_UTF_8());
|
||||
}
|
||||
|
||||
public String historicalName() {
|
||||
return "UTF8";
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new Decoder(this);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new Encoder(this);
|
||||
}
|
||||
|
||||
static final void updatePositions(Buffer src, int sp,
|
||||
Buffer dst, int dp) {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
|
||||
private static class Decoder extends CharsetDecoder
|
||||
implements ArrayDecoder {
|
||||
private Decoder(Charset cs) {
|
||||
super(cs, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
private static boolean isNotContinuation(int b) {
|
||||
return (b & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// [E0] [A0..BF] [80..BF]
|
||||
// [E1..EF] [80..BF] [80..BF]
|
||||
private static boolean isMalformed3(int b1, int b2, int b3) {
|
||||
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// only used when there is only one byte left in src buffer
|
||||
private static boolean isMalformed3_2(int b1, int b2) {
|
||||
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
(b2 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// [F0] [90..BF] [80..BF] [80..BF]
|
||||
// [F1..F3] [80..BF] [80..BF] [80..BF]
|
||||
// [F4] [80..8F] [80..BF] [80..BF]
|
||||
// only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...]
|
||||
// will be checked by Character.isSupplementaryCodePoint(uc)
|
||||
private static boolean isMalformed4(int b2, int b3, int b4) {
|
||||
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
|
||||
(b4 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// only used when there is less than 4 bytes left in src buffer.
|
||||
// both b1 and b2 should be "& 0xff" before passed in.
|
||||
private static boolean isMalformed4_2(int b1, int b2) {
|
||||
return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
|
||||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
|
||||
(b2 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// tests if b1 and b2 are malformed as the first 2 bytes of a
|
||||
// legal`4-byte utf-8 byte sequence.
|
||||
// only used when there is less than 4 bytes left in src buffer,
|
||||
// after isMalformed4_2 has been invoked.
|
||||
private static boolean isMalformed4_3(int b3) {
|
||||
return (b3 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static CoderResult lookupN(ByteBuffer src, int n)
|
||||
{
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (isNotContinuation(src.get()))
|
||||
return CoderResult.malformedForLength(i);
|
||||
}
|
||||
return CoderResult.malformedForLength(n);
|
||||
}
|
||||
|
||||
private static CoderResult malformedN(ByteBuffer src, int nb) {
|
||||
switch (nb) {
|
||||
case 1:
|
||||
case 2: // always 1
|
||||
return CoderResult.malformedForLength(1);
|
||||
case 3:
|
||||
int b1 = src.get();
|
||||
int b2 = src.get(); // no need to lookup b3
|
||||
return CoderResult.malformedForLength(
|
||||
((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
isNotContinuation(b2)) ? 1 : 2);
|
||||
case 4: // we don't care the speed here
|
||||
b1 = src.get() & 0xff;
|
||||
b2 = src.get() & 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
|
||||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
|
||||
isNotContinuation(b2))
|
||||
return CoderResult.malformedForLength(1);
|
||||
if (isNotContinuation(src.get()))
|
||||
return CoderResult.malformedForLength(2);
|
||||
return CoderResult.malformedForLength(3);
|
||||
default:
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static CoderResult malformed(ByteBuffer src, int sp,
|
||||
CharBuffer dst, int dp,
|
||||
int nb)
|
||||
{
|
||||
src.position(sp - src.arrayOffset());
|
||||
CoderResult cr = malformedN(src, nb);
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return cr;
|
||||
}
|
||||
|
||||
|
||||
private static CoderResult malformed(ByteBuffer src,
|
||||
int mark, int nb)
|
||||
{
|
||||
src.position(mark);
|
||||
CoderResult cr = malformedN(src, nb);
|
||||
src.position(mark);
|
||||
return cr;
|
||||
}
|
||||
|
||||
private static CoderResult malformedForLength(ByteBuffer src,
|
||||
int sp,
|
||||
CharBuffer dst,
|
||||
int dp,
|
||||
int malformedNB)
|
||||
{
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return CoderResult.malformedForLength(malformedNB);
|
||||
}
|
||||
|
||||
private static CoderResult malformedForLength(ByteBuffer src,
|
||||
int mark,
|
||||
int malformedNB)
|
||||
{
|
||||
src.position(mark);
|
||||
return CoderResult.malformedForLength(malformedNB);
|
||||
}
|
||||
|
||||
|
||||
private static CoderResult xflow(Buffer src, int sp, int sl,
|
||||
Buffer dst, int dp, int nb) {
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return (nb == 0 || sl - sp < nb)
|
||||
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private static CoderResult xflow(Buffer src, int mark, int nb) {
|
||||
src.position(mark);
|
||||
return (nb == 0 || src.remaining() < nb)
|
||||
? CoderResult.UNDERFLOW : CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private CoderResult decodeArrayLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
// This method is optimized for ASCII input.
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
char[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int dlASCII = dp + Math.min(sl - sp, dl - dp);
|
||||
|
||||
// ASCII only loop
|
||||
while (dp < dlASCII && sa[sp] >= 0)
|
||||
da[dp++] = (char) sa[sp++];
|
||||
while (sp < sl) {
|
||||
int b1 = sa[sp];
|
||||
if (b1 >= 0) {
|
||||
// 1 byte, 7 bits: 0xxxxxxx
|
||||
if (dp >= dl)
|
||||
return xflow(src, sp, sl, dst, dp, 1);
|
||||
da[dp++] = (char) b1;
|
||||
sp++;
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||
// [C2..DF] [80..BF]
|
||||
if (sl - sp < 2 || dp >= dl)
|
||||
return xflow(src, sp, sl, dst, dp, 2);
|
||||
int b2 = sa[sp + 1];
|
||||
// Now we check the first byte of 2-byte sequence as
|
||||
// if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0)
|
||||
// no longer need to check b1 against c1 & c0 for
|
||||
// malformed as we did in previous version
|
||||
// (b1 & 0x1e) == 0x0 || (b2 & 0xc0) != 0x80;
|
||||
// only need to check the second byte b2.
|
||||
if (isNotContinuation(b2))
|
||||
return malformedForLength(src, sp, dst, dp, 1);
|
||||
da[dp++] = (char) (((b1 << 6) ^ b2)
|
||||
^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0)));
|
||||
sp += 2;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||
int srcRemaining = sl - sp;
|
||||
if (srcRemaining < 3 || dp >= dl) {
|
||||
if (srcRemaining > 1 && isMalformed3_2(b1, sa[sp + 1]))
|
||||
return malformedForLength(src, sp, dst, dp, 1);
|
||||
return xflow(src, sp, sl, dst, dp, 3);
|
||||
}
|
||||
int b2 = sa[sp + 1];
|
||||
int b3 = sa[sp + 2];
|
||||
if (isMalformed3(b1, b2, b3))
|
||||
return malformed(src, sp, dst, dp, 3);
|
||||
char c = (char)
|
||||
((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (Character.isSurrogate(c))
|
||||
return malformedForLength(src, sp, dst, dp, 3);
|
||||
da[dp++] = c;
|
||||
sp += 3;
|
||||
} else if ((b1 >> 3) == -2) {
|
||||
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
int srcRemaining = sl - sp;
|
||||
if (srcRemaining < 4 || dl - dp < 2) {
|
||||
b1 &= 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1] & 0xff))
|
||||
return malformedForLength(src, sp, dst, dp, 1);
|
||||
if (srcRemaining > 2 && isMalformed4_3(sa[sp + 2]))
|
||||
return malformedForLength(src, sp, dst, dp, 2);
|
||||
return xflow(src, sp, sl, dst, dp, 4);
|
||||
}
|
||||
int b2 = sa[sp + 1];
|
||||
int b3 = sa[sp + 2];
|
||||
int b4 = sa[sp + 3];
|
||||
int uc = ((b1 << 18) ^
|
||||
(b2 << 12) ^
|
||||
(b3 << 6) ^
|
||||
(b4 ^
|
||||
(((byte) 0xF0 << 18) ^
|
||||
((byte) 0x80 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (isMalformed4(b2, b3, b4) ||
|
||||
// shortest form check
|
||||
!Character.isSupplementaryCodePoint(uc)) {
|
||||
return malformed(src, sp, dst, dp, 4);
|
||||
}
|
||||
da[dp++] = Character.highSurrogate(uc);
|
||||
da[dp++] = Character.lowSurrogate(uc);
|
||||
sp += 4;
|
||||
} else
|
||||
return malformed(src, sp, dst, dp, 1);
|
||||
}
|
||||
return xflow(src, sp, sl, dst, dp, 0);
|
||||
}
|
||||
|
||||
private CoderResult decodeBufferLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
int limit = src.limit();
|
||||
while (mark < limit) {
|
||||
int b1 = src.get();
|
||||
if (b1 >= 0) {
|
||||
// 1 byte, 7 bits: 0xxxxxxx
|
||||
if (dst.remaining() < 1)
|
||||
return xflow(src, mark, 1); // overflow
|
||||
dst.put((char) b1);
|
||||
mark++;
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||
if (limit - mark < 2|| dst.remaining() < 1)
|
||||
return xflow(src, mark, 2);
|
||||
int b2 = src.get();
|
||||
if (isNotContinuation(b2))
|
||||
return malformedForLength(src, mark, 1);
|
||||
dst.put((char) (((b1 << 6) ^ b2)
|
||||
^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
mark += 2;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||
int srcRemaining = limit - mark;
|
||||
if (srcRemaining < 3 || dst.remaining() < 1) {
|
||||
if (srcRemaining > 1 && isMalformed3_2(b1, src.get()))
|
||||
return malformedForLength(src, mark, 1);
|
||||
return xflow(src, mark, 3);
|
||||
}
|
||||
int b2 = src.get();
|
||||
int b3 = src.get();
|
||||
if (isMalformed3(b1, b2, b3))
|
||||
return malformed(src, mark, 3);
|
||||
char c = (char)
|
||||
((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (Character.isSurrogate(c))
|
||||
return malformedForLength(src, mark, 3);
|
||||
dst.put(c);
|
||||
mark += 3;
|
||||
} else if ((b1 >> 3) == -2) {
|
||||
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
int srcRemaining = limit - mark;
|
||||
if (srcRemaining < 4 || dst.remaining() < 2) {
|
||||
b1 &= 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
srcRemaining > 1 && isMalformed4_2(b1, src.get() & 0xff))
|
||||
return malformedForLength(src, mark, 1);
|
||||
if (srcRemaining > 2 && isMalformed4_3(src.get()))
|
||||
return malformedForLength(src, mark, 2);
|
||||
return xflow(src, mark, 4);
|
||||
}
|
||||
int b2 = src.get();
|
||||
int b3 = src.get();
|
||||
int b4 = src.get();
|
||||
int uc = ((b1 << 18) ^
|
||||
(b2 << 12) ^
|
||||
(b3 << 6) ^
|
||||
(b4 ^
|
||||
(((byte) 0xF0 << 18) ^
|
||||
((byte) 0x80 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (isMalformed4(b2, b3, b4) ||
|
||||
// shortest form check
|
||||
!Character.isSupplementaryCodePoint(uc)) {
|
||||
return malformed(src, mark, 4);
|
||||
}
|
||||
dst.put(Character.highSurrogate(uc));
|
||||
dst.put(Character.lowSurrogate(uc));
|
||||
mark += 4;
|
||||
} else {
|
||||
return malformed(src, mark, 1);
|
||||
}
|
||||
}
|
||||
return xflow(src, mark, 0);
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src,
|
||||
CharBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArrayLoop(src, dst);
|
||||
else
|
||||
return decodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private static ByteBuffer getByteBuffer(ByteBuffer bb, byte[] ba, int sp)
|
||||
{
|
||||
if (bb == null)
|
||||
bb = ByteBuffer.wrap(ba);
|
||||
bb.position(sp);
|
||||
return bb;
|
||||
}
|
||||
|
||||
// returns -1 if there is/are malformed byte(s) and the
|
||||
// "action" for malformed input is not REPLACE.
|
||||
public int decode(byte[] sa, int sp, int len, char[] da) {
|
||||
final int sl = sp + len;
|
||||
int dp = 0;
|
||||
int dlASCII = Math.min(len, da.length);
|
||||
ByteBuffer bb = null; // only necessary if malformed
|
||||
|
||||
// ASCII only optimized loop
|
||||
while (dp < dlASCII && sa[sp] >= 0)
|
||||
da[dp++] = (char) sa[sp++];
|
||||
|
||||
while (sp < sl) {
|
||||
int b1 = sa[sp++];
|
||||
if (b1 >= 0) {
|
||||
// 1 byte, 7 bits: 0xxxxxxx
|
||||
da[dp++] = (char) b1;
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||
if (sp < sl) {
|
||||
int b2 = sa[sp++];
|
||||
if (isNotContinuation(b2)) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
sp--; // malformedN(bb, 2) always returns 1
|
||||
} else {
|
||||
da[dp++] = (char) (((b1 << 6) ^ b2)^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0)));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
return dp;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if (sp + 1 < sl) {
|
||||
int b2 = sa[sp++];
|
||||
int b3 = sa[sp++];
|
||||
if (isMalformed3(b1, b2, b3)) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
sp -= 3;
|
||||
bb = getByteBuffer(bb, sa, sp);
|
||||
sp += malformedN(bb, 3).length();
|
||||
} else {
|
||||
char c = (char)((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (Character.isSurrogate(c)) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
} else {
|
||||
da[dp++] = c;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
if (sp < sl && isMalformed3_2(b1, sa[sp])) {
|
||||
da[dp++] = replacement().charAt(0);
|
||||
continue;
|
||||
|
||||
}
|
||||
da[dp++] = replacement().charAt(0);
|
||||
return dp;
|
||||
} else if ((b1 >> 3) == -2) {
|
||||
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
if (sp + 2 < sl) {
|
||||
int b2 = sa[sp++];
|
||||
int b3 = sa[sp++];
|
||||
int b4 = sa[sp++];
|
||||
int uc = ((b1 << 18) ^
|
||||
(b2 << 12) ^
|
||||
(b3 << 6) ^
|
||||
(b4 ^
|
||||
(((byte) 0xF0 << 18) ^
|
||||
((byte) 0x80 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (isMalformed4(b2, b3, b4) ||
|
||||
// shortest form check
|
||||
!Character.isSupplementaryCodePoint(uc)) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
sp -= 4;
|
||||
bb = getByteBuffer(bb, sa, sp);
|
||||
sp += malformedN(bb, 4).length();
|
||||
} else {
|
||||
da[dp++] = Character.highSurrogate(uc);
|
||||
da[dp++] = Character.lowSurrogate(uc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
b1 &= 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
sp < sl && isMalformed4_2(b1, sa[sp] & 0xff)) {
|
||||
da[dp++] = replacement().charAt(0);
|
||||
continue;
|
||||
}
|
||||
sp++;
|
||||
if (sp < sl && isMalformed4_3(sa[sp])) {
|
||||
da[dp++] = replacement().charAt(0);
|
||||
continue;
|
||||
}
|
||||
da[dp++] = replacement().charAt(0);
|
||||
return dp;
|
||||
} else {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = replacement().charAt(0);
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public boolean isASCIICompatible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Encoder extends CharsetEncoder
|
||||
implements ArrayEncoder {
|
||||
|
||||
private Encoder(Charset cs) {
|
||||
super(cs, 1.1f, 3.0f);
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return !Character.isSurrogate(c);
|
||||
}
|
||||
|
||||
public boolean isLegalReplacement(byte[] repl) {
|
||||
return ((repl.length == 1 && repl[0] >= 0) ||
|
||||
super.isLegalReplacement(repl));
|
||||
}
|
||||
|
||||
private static CoderResult overflow(CharBuffer src, int sp,
|
||||
ByteBuffer dst, int dp) {
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private static CoderResult overflow(CharBuffer src, int mark) {
|
||||
src.position(mark);
|
||||
return CoderResult.OVERFLOW;
|
||||
}
|
||||
|
||||
private Surrogate.Parser sgp;
|
||||
private CoderResult encodeArrayLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
char[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int dlASCII = dp + Math.min(sl - sp, dl - dp);
|
||||
|
||||
// ASCII only loop
|
||||
while (dp < dlASCII && sa[sp] < '\u0080')
|
||||
da[dp++] = (byte) sa[sp++];
|
||||
while (sp < sl) {
|
||||
char c = sa[sp];
|
||||
if (c < 0x80) {
|
||||
// Have at most seven bits
|
||||
if (dp >= dl)
|
||||
return overflow(src, sp, dst, dp);
|
||||
da[dp++] = (byte)c;
|
||||
} else if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
if (dl - dp < 2)
|
||||
return overflow(src, sp, dst, dp);
|
||||
da[dp++] = (byte)(0xc0 | (c >> 6));
|
||||
da[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
// Have a surrogate pair
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
int uc = sgp.parse(c, sa, sp, sl);
|
||||
if (uc < 0) {
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return sgp.error();
|
||||
}
|
||||
if (dl - dp < 4)
|
||||
return overflow(src, sp, dst, dp);
|
||||
da[dp++] = (byte)(0xf0 | ((uc >> 18)));
|
||||
da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
|
||||
da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
|
||||
da[dp++] = (byte)(0x80 | (uc & 0x3f));
|
||||
sp++; // 2 chars
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
if (dl - dp < 3)
|
||||
return overflow(src, sp, dst, dp);
|
||||
da[dp++] = (byte)(0xe0 | ((c >> 12)));
|
||||
da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
|
||||
da[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
updatePositions(src, sp, dst, dp);
|
||||
return CoderResult.UNDERFLOW;
|
||||
}
|
||||
|
||||
private CoderResult encodeBufferLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
int mark = src.position();
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
if (c < 0x80) {
|
||||
// Have at most seven bits
|
||||
if (!dst.hasRemaining())
|
||||
return overflow(src, mark);
|
||||
dst.put((byte)c);
|
||||
} else if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
if (dst.remaining() < 2)
|
||||
return overflow(src, mark);
|
||||
dst.put((byte)(0xc0 | (c >> 6)));
|
||||
dst.put((byte)(0x80 | (c & 0x3f)));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
// Have a surrogate pair
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
int uc = sgp.parse(c, src);
|
||||
if (uc < 0) {
|
||||
src.position(mark);
|
||||
return sgp.error();
|
||||
}
|
||||
if (dst.remaining() < 4)
|
||||
return overflow(src, mark);
|
||||
dst.put((byte)(0xf0 | ((uc >> 18))));
|
||||
dst.put((byte)(0x80 | ((uc >> 12) & 0x3f)));
|
||||
dst.put((byte)(0x80 | ((uc >> 6) & 0x3f)));
|
||||
dst.put((byte)(0x80 | (uc & 0x3f)));
|
||||
mark++; // 2 chars
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
if (dst.remaining() < 3)
|
||||
return overflow(src, mark);
|
||||
dst.put((byte)(0xe0 | ((c >> 12))));
|
||||
dst.put((byte)(0x80 | ((c >> 6) & 0x3f)));
|
||||
dst.put((byte)(0x80 | (c & 0x3f)));
|
||||
}
|
||||
mark++;
|
||||
}
|
||||
src.position(mark);
|
||||
return CoderResult.UNDERFLOW;
|
||||
}
|
||||
|
||||
protected final CoderResult encodeLoop(CharBuffer src,
|
||||
ByteBuffer dst)
|
||||
{
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArrayLoop(src, dst);
|
||||
else
|
||||
return encodeBufferLoop(src, dst);
|
||||
}
|
||||
|
||||
private byte repl = (byte)'?';
|
||||
protected void implReplaceWith(byte[] newReplacement) {
|
||||
repl = newReplacement[0];
|
||||
}
|
||||
|
||||
// returns -1 if there is malformed char(s) and the
|
||||
// "action" for malformed input is not REPLACE.
|
||||
public int encode(char[] sa, int sp, int len, byte[] da) {
|
||||
int sl = sp + len;
|
||||
int dp = 0;
|
||||
int dlASCII = dp + Math.min(len, da.length);
|
||||
|
||||
// ASCII only optimized loop
|
||||
while (dp < dlASCII && sa[sp] < '\u0080')
|
||||
da[dp++] = (byte) sa[sp++];
|
||||
|
||||
while (sp < sl) {
|
||||
char c = sa[sp++];
|
||||
if (c < 0x80) {
|
||||
// Have at most seven bits
|
||||
da[dp++] = (byte)c;
|
||||
} else if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
da[dp++] = (byte)(0xc0 | (c >> 6));
|
||||
da[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
if (sgp == null)
|
||||
sgp = new Surrogate.Parser();
|
||||
int uc = sgp.parse(c, sa, sp - 1, sl);
|
||||
if (uc < 0) {
|
||||
if (malformedInputAction() != CodingErrorAction.REPLACE)
|
||||
return -1;
|
||||
da[dp++] = repl;
|
||||
} else {
|
||||
da[dp++] = (byte)(0xf0 | ((uc >> 18)));
|
||||
da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
|
||||
da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
|
||||
da[dp++] = (byte)(0x80 | (uc & 0x3f));
|
||||
sp++; // 2 chars
|
||||
}
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
da[dp++] = (byte)(0xe0 | ((c >> 12)));
|
||||
da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
|
||||
da[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
public boolean isASCIICompatible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
93
src/java.base/share/classes/sun/nio/cs/Unicode.java
Normal file
93
src/java.base/share/classes/sun/nio/cs/Unicode.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
abstract class Unicode extends Charset
|
||||
implements HistoricallyNamedCharset
|
||||
{
|
||||
public Unicode(String name, String[] aliases) {
|
||||
super(name, aliases);
|
||||
}
|
||||
|
||||
public boolean contains(Charset cs) {
|
||||
return ((cs instanceof US_ASCII)
|
||||
|| (cs instanceof ISO_8859_1)
|
||||
|| (cs instanceof ISO_8859_15)
|
||||
|| (cs instanceof ISO_8859_16)
|
||||
|| (cs instanceof MS1252)
|
||||
|| (cs instanceof UTF_8)
|
||||
|| (cs instanceof UTF_16)
|
||||
|| (cs instanceof UTF_16BE)
|
||||
|| (cs instanceof UTF_16LE)
|
||||
|| (cs instanceof UTF_16LE_BOM)
|
||||
|| (cs.name().equals("GBK"))
|
||||
|| (cs.name().equals("GB18030"))
|
||||
|| (cs.name().equals("ISO-8859-2"))
|
||||
|| (cs.name().equals("ISO-8859-3"))
|
||||
|| (cs.name().equals("ISO-8859-4"))
|
||||
|| (cs.name().equals("ISO-8859-5"))
|
||||
|| (cs.name().equals("ISO-8859-6"))
|
||||
|| (cs.name().equals("ISO-8859-7"))
|
||||
|| (cs.name().equals("ISO-8859-8"))
|
||||
|| (cs.name().equals("ISO-8859-9"))
|
||||
|| (cs.name().equals("ISO-8859-13"))
|
||||
|| (cs.name().equals("JIS_X0201"))
|
||||
|| (cs.name().equals("x-JIS0208"))
|
||||
|| (cs.name().equals("JIS_X0212-1990"))
|
||||
|| (cs.name().equals("GB2312"))
|
||||
|| (cs.name().equals("EUC-KR"))
|
||||
|| (cs.name().equals("x-EUC-TW"))
|
||||
|| (cs.name().equals("EUC-JP"))
|
||||
|| (cs.name().equals("x-euc-jp-linux"))
|
||||
|| (cs.name().equals("KOI8-R"))
|
||||
|| (cs.name().equals("TIS-620"))
|
||||
|| (cs.name().equals("x-ISCII91"))
|
||||
|| (cs.name().equals("windows-1251"))
|
||||
|| (cs.name().equals("windows-1253"))
|
||||
|| (cs.name().equals("windows-1254"))
|
||||
|| (cs.name().equals("windows-1255"))
|
||||
|| (cs.name().equals("windows-1256"))
|
||||
|| (cs.name().equals("windows-1257"))
|
||||
|| (cs.name().equals("windows-1258"))
|
||||
|| (cs.name().equals("windows-932"))
|
||||
|| (cs.name().equals("x-mswin-936"))
|
||||
|| (cs.name().equals("x-windows-949"))
|
||||
|| (cs.name().equals("x-windows-950"))
|
||||
|| (cs.name().equals("windows-31j"))
|
||||
|| (cs.name().equals("Big5"))
|
||||
|| (cs.name().equals("Big5-HKSCS"))
|
||||
|| (cs.name().equals("x-MS950-HKSCS"))
|
||||
|| (cs.name().equals("ISO-2022-JP"))
|
||||
|| (cs.name().equals("ISO-2022-KR"))
|
||||
|| (cs.name().equals("x-ISO-2022-CN-CNS"))
|
||||
|| (cs.name().equals("x-ISO-2022-CN-GB"))
|
||||
|| (cs.name().equals("Big5-HKSCS"))
|
||||
|| (cs.name().equals("x-Johab"))
|
||||
|| (cs.name().equals("Shift_JIS")));
|
||||
}
|
||||
}
|
135
src/java.base/share/classes/sun/nio/cs/UnicodeDecoder.java
Normal file
135
src/java.base/share/classes/sun/nio/cs/UnicodeDecoder.java
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
|
||||
|
||||
abstract class UnicodeDecoder extends CharsetDecoder {
|
||||
|
||||
protected static final char BYTE_ORDER_MARK = (char) 0xfeff;
|
||||
protected static final char REVERSED_MARK = (char) 0xfffe;
|
||||
|
||||
protected static final int NONE = 0;
|
||||
protected static final int BIG = 1;
|
||||
protected static final int LITTLE = 2;
|
||||
|
||||
private final int expectedByteOrder;
|
||||
private int currentByteOrder;
|
||||
private int defaultByteOrder = BIG;
|
||||
|
||||
public UnicodeDecoder(Charset cs, int bo) {
|
||||
super(cs, 0.5f, 1.0f);
|
||||
expectedByteOrder = currentByteOrder = bo;
|
||||
}
|
||||
|
||||
public UnicodeDecoder(Charset cs, int bo, int defaultBO) {
|
||||
this(cs, bo);
|
||||
defaultByteOrder = defaultBO;
|
||||
}
|
||||
|
||||
private char decode(int b1, int b2) {
|
||||
if (currentByteOrder == BIG)
|
||||
return (char)((b1 << 8) | b2);
|
||||
else
|
||||
return (char)((b2 << 8) | b1);
|
||||
}
|
||||
|
||||
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
|
||||
int mark = src.position();
|
||||
|
||||
try {
|
||||
while (src.remaining() > 1) {
|
||||
int b1 = src.get() & 0xff;
|
||||
int b2 = src.get() & 0xff;
|
||||
|
||||
// Byte Order Mark interpretation
|
||||
if (currentByteOrder == NONE) {
|
||||
char c = (char)((b1 << 8) | b2);
|
||||
if (c == BYTE_ORDER_MARK) {
|
||||
currentByteOrder = BIG;
|
||||
mark += 2;
|
||||
continue;
|
||||
} else if (c == REVERSED_MARK) {
|
||||
currentByteOrder = LITTLE;
|
||||
mark += 2;
|
||||
continue;
|
||||
} else {
|
||||
currentByteOrder = defaultByteOrder;
|
||||
// FALL THROUGH to process b1, b2 normally
|
||||
}
|
||||
}
|
||||
|
||||
char c = decode(b1, b2);
|
||||
|
||||
if (c == REVERSED_MARK) {
|
||||
// A reversed BOM cannot occur within middle of stream
|
||||
return CoderResult.malformedForLength(2);
|
||||
}
|
||||
|
||||
// Surrogates
|
||||
if (Character.isSurrogate(c)) {
|
||||
if (Character.isHighSurrogate(c)) {
|
||||
if (src.remaining() < 2)
|
||||
return CoderResult.UNDERFLOW;
|
||||
char c2 = decode(src.get() & 0xff, src.get() & 0xff);
|
||||
if (!Character.isLowSurrogate(c2))
|
||||
return CoderResult.malformedForLength(4);
|
||||
if (dst.remaining() < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
mark += 4;
|
||||
dst.put(c);
|
||||
dst.put(c2);
|
||||
continue;
|
||||
}
|
||||
// Unpaired low surrogate
|
||||
return CoderResult.malformedForLength(2);
|
||||
}
|
||||
|
||||
if (!dst.hasRemaining())
|
||||
return CoderResult.OVERFLOW;
|
||||
mark += 2;
|
||||
dst.put(c);
|
||||
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected void implReset() {
|
||||
currentByteOrder = expectedByteOrder;
|
||||
}
|
||||
|
||||
}
|
111
src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java
Normal file
111
src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.cs;
|
||||
|
||||
import java.nio.*;
|
||||
import java.nio.charset.*;
|
||||
|
||||
/**
|
||||
* Base class for different flavors of UTF-16 encoders
|
||||
*/
|
||||
public abstract class UnicodeEncoder extends CharsetEncoder {
|
||||
|
||||
protected static final char BYTE_ORDER_MARK = '\uFEFF';
|
||||
protected static final char REVERSED_MARK = '\uFFFE';
|
||||
|
||||
protected static final int BIG = 0;
|
||||
protected static final int LITTLE = 1;
|
||||
|
||||
private int byteOrder; /* Byte order in use */
|
||||
private boolean usesMark; /* Write an initial BOM */
|
||||
private boolean needsMark;
|
||||
|
||||
protected UnicodeEncoder(Charset cs, int bo, boolean m) {
|
||||
super(cs, 2.0f,
|
||||
// Four bytes max if you need a BOM
|
||||
m ? 4.0f : 2.0f,
|
||||
// Replacement depends upon byte order
|
||||
((bo == BIG)
|
||||
? new byte[] { (byte)0xff, (byte)0xfd }
|
||||
: new byte[] { (byte)0xfd, (byte)0xff }));
|
||||
usesMark = needsMark = m;
|
||||
byteOrder = bo;
|
||||
}
|
||||
|
||||
private void put(char c, ByteBuffer dst) {
|
||||
if (byteOrder == BIG) {
|
||||
dst.put((byte)(c >> 8));
|
||||
dst.put((byte)(c & 0xff));
|
||||
} else {
|
||||
dst.put((byte)(c & 0xff));
|
||||
dst.put((byte)(c >> 8));
|
||||
}
|
||||
}
|
||||
|
||||
private final Surrogate.Parser sgp = new Surrogate.Parser();
|
||||
|
||||
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
|
||||
int mark = src.position();
|
||||
|
||||
if (needsMark && src.hasRemaining()) {
|
||||
if (dst.remaining() < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
put(BYTE_ORDER_MARK, dst);
|
||||
needsMark = false;
|
||||
}
|
||||
try {
|
||||
while (src.hasRemaining()) {
|
||||
char c = src.get();
|
||||
if (!Character.isSurrogate(c)) {
|
||||
if (dst.remaining() < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
mark++;
|
||||
put(c, dst);
|
||||
continue;
|
||||
}
|
||||
int d = sgp.parse(c, src);
|
||||
if (d < 0)
|
||||
return sgp.error();
|
||||
if (dst.remaining() < 4)
|
||||
return CoderResult.OVERFLOW;
|
||||
mark += 2;
|
||||
put(Character.highSurrogate(d), dst);
|
||||
put(Character.lowSurrogate(d), dst);
|
||||
}
|
||||
return CoderResult.UNDERFLOW;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected void implReset() {
|
||||
needsMark = usesMark;
|
||||
}
|
||||
|
||||
public boolean canEncode(char c) {
|
||||
return ! Character.isSurrogate(c);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue