Path: blob/master/src/java.base/share/classes/sun/nio/cs/HKSCS.java
41159 views
/*1* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.cs;2627import java.nio.ByteBuffer;28import java.nio.CharBuffer;29import java.nio.charset.Charset;30import java.nio.charset.CharsetDecoder;31import java.nio.charset.CharsetEncoder;32import java.nio.charset.CoderResult;33import java.util.Arrays;34import sun.nio.cs.DoubleByte;35import sun.nio.cs.Surrogate;36import static sun.nio.cs.CharsetMapping.*;3738public class HKSCS {3940public static class Decoder extends DoubleByte.Decoder {41static int b2Min = 0x40;42static int b2Max = 0xfe;4344private char[][] b2cBmp;45private char[][] b2cSupp;46private DoubleByte.Decoder big5Dec;4748protected Decoder(Charset cs,49DoubleByte.Decoder big5Dec,50char[][] b2cBmp, char[][] b2cSupp)51{52// super(cs, 0.5f, 1.0f);53// need to extends DoubleByte.Decoder so the54// sun.io can use it. this implementation55super(cs, 0.5f, 1.0f, null, null, 0, 0, true);56this.big5Dec = big5Dec;57this.b2cBmp = b2cBmp;58this.b2cSupp = b2cSupp;59}6061public char decodeSingle(int b) {62return big5Dec.decodeSingle(b);63}6465public char decodeBig5(int b1, int b2) {66return big5Dec.decodeDouble(b1, b2);67}6869public char decodeDouble(int b1, int b2) {70return b2cBmp[b1][b2 - b2Min];71}7273public char decodeDoubleEx(int b1, int b2) {74/* if the b2cSupp is null, the subclass need75to override the methold76if (b2cSupp == null)77return UNMAPPABLE_DECODING;78*/79return b2cSupp[b1][b2 - b2Min];80}8182protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {83byte[] sa = src.array();84int sp = src.arrayOffset() + src.position();85int sl = src.arrayOffset() + src.limit();8687char[] da = dst.array();88int dp = dst.arrayOffset() + dst.position();89int dl = dst.arrayOffset() + dst.limit();9091try {92while (sp < sl) {93int b1 = sa[sp] & 0xff;94char c = decodeSingle(b1);95int inSize = 1, outSize = 1;96char[] cc = null;97if (c == UNMAPPABLE_DECODING) {98if (sl - sp < 2)99return CoderResult.UNDERFLOW;100int b2 = sa[sp + 1] & 0xff;101inSize++;102if (b2 < b2Min || b2 > b2Max)103return CoderResult.unmappableForLength(2);104c = decodeDouble(b1, b2); //bmp105if (c == UNMAPPABLE_DECODING) {106c = decodeDoubleEx(b1, b2); //supp107if (c == UNMAPPABLE_DECODING) {108c = decodeBig5(b1, b2); //big5109if (c == UNMAPPABLE_DECODING)110return CoderResult.unmappableForLength(2);111} else {112// supplementary character in u+2xxxx area113outSize = 2;114}115}116}117if (dl - dp < outSize)118return CoderResult.OVERFLOW;119if (outSize == 2) {120// supplementary characters121da[dp++] = Surrogate.high(0x20000 + c);122da[dp++] = Surrogate.low(0x20000 + c);123} else {124da[dp++] = c;125}126sp += inSize;127}128return CoderResult.UNDERFLOW;129} finally {130src.position(sp - src.arrayOffset());131dst.position(dp - dst.arrayOffset());132}133}134135protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {136int mark = src.position();137try {138while (src.hasRemaining()) {139char[] cc = null;140int b1 = src.get() & 0xff;141int inSize = 1, outSize = 1;142char c = decodeSingle(b1);143if (c == UNMAPPABLE_DECODING) {144if (src.remaining() < 1)145return CoderResult.UNDERFLOW;146int b2 = src.get() & 0xff;147inSize++;148if (b2 < b2Min || b2 > b2Max)149return CoderResult.unmappableForLength(2);150c = decodeDouble(b1, b2); //bmp151if (c == UNMAPPABLE_DECODING) {152c = decodeDoubleEx(b1, b2); //supp153if (c == UNMAPPABLE_DECODING) {154c = decodeBig5(b1, b2); //big5155if (c == UNMAPPABLE_DECODING)156return CoderResult.unmappableForLength(2);157} else {158outSize = 2;159}160}161}162if (dst.remaining() < outSize)163return CoderResult.OVERFLOW;164if (outSize == 2) {165dst.put(Surrogate.high(0x20000 + c));166dst.put(Surrogate.low(0x20000 + c));167} else {168dst.put(c);169}170mark += inSize;171}172return CoderResult.UNDERFLOW;173} finally {174src.position(mark);175}176}177178public int decode(byte[] src, int sp, int len, char[] dst) {179int dp = 0;180int sl = sp + len;181char repl = replacement().charAt(0);182while (sp < sl) {183int b1 = src[sp++] & 0xff;184char c = decodeSingle(b1);185if (c == UNMAPPABLE_DECODING) {186if (sl == sp) {187c = repl;188} else {189int b2 = src[sp++] & 0xff;190if (b2 < b2Min || b2 > b2Max) {191c = repl;192} else if ((c = decodeDouble(b1, b2)) == UNMAPPABLE_DECODING) {193c = decodeDoubleEx(b1, b2); //supp194if (c == UNMAPPABLE_DECODING) {195c = decodeBig5(b1, b2); //big5196if (c == UNMAPPABLE_DECODING)197c = repl;198} else {199// supplementary character in u+2xxxx area200dst[dp++] = Surrogate.high(0x20000 + c);201dst[dp++] = Surrogate.low(0x20000 + c);202continue;203}204}205}206}207dst[dp++] = c;208}209return dp;210}211212public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {213if (src.hasArray() && dst.hasArray())214return decodeArrayLoop(src, dst);215else216return decodeBufferLoop(src, dst);217}218219public static void initb2c(char[][]b2c, String[] b2cStr)220{221for (int i = 0; i < b2cStr.length; i++) {222if (b2cStr[i] == null)223b2c[i] = DoubleByte.B2C_UNMAPPABLE;224else225b2c[i] = b2cStr[i].toCharArray();226}227}228229}230231public static class Encoder extends DoubleByte.Encoder {232private DoubleByte.Encoder big5Enc;233private char[][] c2bBmp;234private char[][] c2bSupp;235236protected Encoder(Charset cs,237DoubleByte.Encoder big5Enc,238char[][] c2bBmp,239char[][] c2bSupp)240{241super(cs, null, null, true);242this.big5Enc = big5Enc;243this.c2bBmp = c2bBmp;244this.c2bSupp = c2bSupp;245}246247public int encodeBig5(char ch) {248return big5Enc.encodeChar(ch);249}250251public int encodeChar(char ch) {252int bb = c2bBmp[ch >> 8][ch & 0xff];253if (bb == UNMAPPABLE_ENCODING)254return encodeBig5(ch);255return bb;256}257258public int encodeSupp(int cp) {259if ((cp & 0xf0000) != 0x20000)260return UNMAPPABLE_ENCODING;261return c2bSupp[(cp >> 8) & 0xff][cp & 0xff];262}263264public boolean canEncode(char c) {265return encodeChar(c) != UNMAPPABLE_ENCODING;266}267268protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {269char[] sa = src.array();270int sp = src.arrayOffset() + src.position();271int sl = src.arrayOffset() + src.limit();272273byte[] da = dst.array();274int dp = dst.arrayOffset() + dst.position();275int dl = dst.arrayOffset() + dst.limit();276277try {278while (sp < sl) {279char c = sa[sp];280int inSize = 1;281int bb = encodeChar(c);282if (bb == UNMAPPABLE_ENCODING) {283if (Character.isSurrogate(c)) {284int cp;285if ((cp = sgp().parse(c, sa, sp, sl)) < 0)286return sgp.error();287bb = encodeSupp(cp);288if (bb == UNMAPPABLE_ENCODING)289return CoderResult.unmappableForLength(2);290inSize = 2;291} else {292return CoderResult.unmappableForLength(1);293}294}295if (bb > MAX_SINGLEBYTE) { // DoubleByte296if (dl - dp < 2)297return CoderResult.OVERFLOW;298da[dp++] = (byte)(bb >> 8);299da[dp++] = (byte)bb;300} else { // SingleByte301if (dl - dp < 1)302return CoderResult.OVERFLOW;303da[dp++] = (byte)bb;304}305sp += inSize;306}307return CoderResult.UNDERFLOW;308} finally {309src.position(sp - src.arrayOffset());310dst.position(dp - dst.arrayOffset());311}312}313314protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {315int mark = src.position();316try {317while (src.hasRemaining()) {318int inSize = 1;319char c = src.get();320int bb = encodeChar(c);321if (bb == UNMAPPABLE_ENCODING) {322if (Character.isSurrogate(c)) {323int cp;324if ((cp = sgp().parse(c, src)) < 0)325return sgp.error();326bb = encodeSupp(cp);327if (bb == UNMAPPABLE_ENCODING)328return CoderResult.unmappableForLength(2);329inSize = 2;330} else {331return CoderResult.unmappableForLength(1);332}333}334if (bb > MAX_SINGLEBYTE) { // DoubleByte335if (dst.remaining() < 2)336return CoderResult.OVERFLOW;337dst.put((byte)(bb >> 8));338dst.put((byte)(bb));339} else {340if (dst.remaining() < 1)341return CoderResult.OVERFLOW;342dst.put((byte)bb);343}344mark += inSize;345}346return CoderResult.UNDERFLOW;347} finally {348src.position(mark);349}350}351352protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {353if (src.hasArray() && dst.hasArray())354return encodeArrayLoop(src, dst);355else356return encodeBufferLoop(src, dst);357}358359private byte[] repl = replacement();360protected void implReplaceWith(byte[] newReplacement) {361repl = newReplacement;362}363364public int encode(char[] src, int sp, int len, byte[] dst) {365int dp = 0;366int sl = sp + len;367while (sp < sl) {368char c = src[sp++];369int bb = encodeChar(c);370if (bb == UNMAPPABLE_ENCODING) {371if (!Character.isHighSurrogate(c) || sp == sl ||372!Character.isLowSurrogate(src[sp]) ||373(bb = encodeSupp(Character.toCodePoint(c, src[sp++])))374== UNMAPPABLE_ENCODING) {375dst[dp++] = repl[0];376if (repl.length > 1)377dst[dp++] = repl[1];378continue;379}380}381if (bb > MAX_SINGLEBYTE) { // DoubleByte382dst[dp++] = (byte)(bb >> 8);383dst[dp++] = (byte)bb;384} else { // SingleByte385dst[dp++] = (byte)bb;386}387}388return dp;389}390391public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {392int dp = 0;393int sl = sp + len;394int dl = dst.length;395while (sp < sl) {396char c = StringUTF16.getChar(src, sp++);397int bb = encodeChar(c);398if (bb == UNMAPPABLE_ENCODING) {399if (!Character.isHighSurrogate(c) || sp == sl ||400!Character.isLowSurrogate(StringUTF16.getChar(src,sp)) ||401(bb = encodeSupp(Character.toCodePoint(c, StringUTF16.getChar(src, sp++))))402== UNMAPPABLE_ENCODING) {403dst[dp++] = repl[0];404if (repl.length > 1)405dst[dp++] = repl[1];406continue;407}408}409if (bb > MAX_SINGLEBYTE) { // DoubleByte410dst[dp++] = (byte)(bb >> 8);411dst[dp++] = (byte)bb;412} else { // SingleByte413dst[dp++] = (byte)bb;414}415}416return dp;417}418419static char[] C2B_UNMAPPABLE = new char[0x100];420static {421Arrays.fill(C2B_UNMAPPABLE, (char)UNMAPPABLE_ENCODING);422}423424public static void initc2b(char[][] c2b, String[] b2cStr, String pua) {425// init c2b/c2bSupp from b2cStr and supp426int b2Min = 0x40;427Arrays.fill(c2b, C2B_UNMAPPABLE);428for (int b1 = 0; b1 < 0x100; b1++) {429String s = b2cStr[b1];430if (s == null)431continue;432for (int i = 0; i < s.length(); i++) {433char c = s.charAt(i);434if (c == UNMAPPABLE_DECODING)435continue;436int hi = c >> 8;437if (c2b[hi] == C2B_UNMAPPABLE) {438c2b[hi] = new char[0x100];439Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);440}441c2b[hi][c & 0xff] = (char)((b1 << 8) | (i + b2Min));442}443}444if (pua != null) { // add the compatibility pua entries445char c = '\ue000'; //first pua character446for (int i = 0; i < pua.length(); i++) {447char bb = pua.charAt(i);448if (bb != UNMAPPABLE_DECODING) {449int hi = c >> 8;450if (c2b[hi] == C2B_UNMAPPABLE) {451c2b[hi] = new char[0x100];452Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);453}454c2b[hi][c & 0xff] = bb;455}456c++;457}458}459}460}461}462463464