Path: blob/master/src/java.base/share/classes/sun/nio/cs/HKSCS.java
67862 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 final char[][] b2cBmp;45private final char[][] b2cSupp;46private final 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;96if (c == UNMAPPABLE_DECODING) {97if (sl - sp < 2)98return CoderResult.UNDERFLOW;99int b2 = sa[sp + 1] & 0xff;100inSize++;101if (b2 < b2Min || b2 > b2Max)102return CoderResult.unmappableForLength(2);103c = decodeDouble(b1, b2); //bmp104if (c == UNMAPPABLE_DECODING) {105c = decodeDoubleEx(b1, b2); //supp106if (c == UNMAPPABLE_DECODING) {107c = decodeBig5(b1, b2); //big5108if (c == UNMAPPABLE_DECODING)109return CoderResult.unmappableForLength(2);110} else {111// supplementary character in u+2xxxx area112outSize = 2;113}114}115}116if (dl - dp < outSize)117return CoderResult.OVERFLOW;118if (outSize == 2) {119// supplementary characters120da[dp++] = Surrogate.high(0x20000 + c);121da[dp++] = Surrogate.low(0x20000 + c);122} else {123da[dp++] = c;124}125sp += inSize;126}127return CoderResult.UNDERFLOW;128} finally {129src.position(sp - src.arrayOffset());130dst.position(dp - dst.arrayOffset());131}132}133134protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {135int mark = src.position();136try {137while (src.hasRemaining()) {138int b1 = src.get() & 0xff;139int inSize = 1, outSize = 1;140char c = decodeSingle(b1);141if (c == UNMAPPABLE_DECODING) {142if (src.remaining() < 1)143return CoderResult.UNDERFLOW;144int b2 = src.get() & 0xff;145inSize++;146if (b2 < b2Min || b2 > b2Max)147return CoderResult.unmappableForLength(2);148c = decodeDouble(b1, b2); //bmp149if (c == UNMAPPABLE_DECODING) {150c = decodeDoubleEx(b1, b2); //supp151if (c == UNMAPPABLE_DECODING) {152c = decodeBig5(b1, b2); //big5153if (c == UNMAPPABLE_DECODING)154return CoderResult.unmappableForLength(2);155} else {156outSize = 2;157}158}159}160if (dst.remaining() < outSize)161return CoderResult.OVERFLOW;162if (outSize == 2) {163dst.put(Surrogate.high(0x20000 + c));164dst.put(Surrogate.low(0x20000 + c));165} else {166dst.put(c);167}168mark += inSize;169}170return CoderResult.UNDERFLOW;171} finally {172src.position(mark);173}174}175176public int decode(byte[] src, int sp, int len, char[] dst) {177int dp = 0;178int sl = sp + len;179char repl = replacement().charAt(0);180while (sp < sl) {181int b1 = src[sp++] & 0xff;182char c = decodeSingle(b1);183if (c == UNMAPPABLE_DECODING) {184if (sl == sp) {185c = repl;186} else {187int b2 = src[sp++] & 0xff;188if (b2 < b2Min || b2 > b2Max) {189c = repl;190} else if ((c = decodeDouble(b1, b2)) == UNMAPPABLE_DECODING) {191c = decodeDoubleEx(b1, b2); //supp192if (c == UNMAPPABLE_DECODING) {193c = decodeBig5(b1, b2); //big5194if (c == UNMAPPABLE_DECODING)195c = repl;196} else {197// supplementary character in u+2xxxx area198dst[dp++] = Surrogate.high(0x20000 + c);199dst[dp++] = Surrogate.low(0x20000 + c);200continue;201}202}203}204}205dst[dp++] = c;206}207return dp;208}209210public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {211if (src.hasArray() && dst.hasArray())212return decodeArrayLoop(src, dst);213else214return decodeBufferLoop(src, dst);215}216217public static void initb2c(char[][]b2c, String[] b2cStr)218{219for (int i = 0; i < b2cStr.length; i++) {220if (b2cStr[i] == null)221b2c[i] = DoubleByte.B2C_UNMAPPABLE;222else223b2c[i] = b2cStr[i].toCharArray();224}225}226227}228229public static class Encoder extends DoubleByte.Encoder {230private final DoubleByte.Encoder big5Enc;231private final char[][] c2bBmp;232private final char[][] c2bSupp;233234protected Encoder(Charset cs,235DoubleByte.Encoder big5Enc,236char[][] c2bBmp,237char[][] c2bSupp)238{239super(cs, null, null, true);240this.big5Enc = big5Enc;241this.c2bBmp = c2bBmp;242this.c2bSupp = c2bSupp;243}244245public int encodeBig5(char ch) {246return big5Enc.encodeChar(ch);247}248249public int encodeChar(char ch) {250int bb = c2bBmp[ch >> 8][ch & 0xff];251if (bb == UNMAPPABLE_ENCODING)252return encodeBig5(ch);253return bb;254}255256public int encodeSupp(int cp) {257if ((cp & 0xf0000) != 0x20000)258return UNMAPPABLE_ENCODING;259return c2bSupp[(cp >> 8) & 0xff][cp & 0xff];260}261262public boolean canEncode(char c) {263return encodeChar(c) != UNMAPPABLE_ENCODING;264}265266protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {267char[] sa = src.array();268int sp = src.arrayOffset() + src.position();269int sl = src.arrayOffset() + src.limit();270271byte[] da = dst.array();272int dp = dst.arrayOffset() + dst.position();273int dl = dst.arrayOffset() + dst.limit();274275try {276while (sp < sl) {277char c = sa[sp];278int inSize = 1;279int bb = encodeChar(c);280if (bb == UNMAPPABLE_ENCODING) {281if (Character.isSurrogate(c)) {282int cp;283if ((cp = sgp().parse(c, sa, sp, sl)) < 0)284return sgp.error();285bb = encodeSupp(cp);286if (bb == UNMAPPABLE_ENCODING)287return CoderResult.unmappableForLength(2);288inSize = 2;289} else {290return CoderResult.unmappableForLength(1);291}292}293if (bb > MAX_SINGLEBYTE) { // DoubleByte294if (dl - dp < 2)295return CoderResult.OVERFLOW;296da[dp++] = (byte)(bb >> 8);297da[dp++] = (byte)bb;298} else { // SingleByte299if (dl - dp < 1)300return CoderResult.OVERFLOW;301da[dp++] = (byte)bb;302}303sp += inSize;304}305return CoderResult.UNDERFLOW;306} finally {307src.position(sp - src.arrayOffset());308dst.position(dp - dst.arrayOffset());309}310}311312protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {313int mark = src.position();314try {315while (src.hasRemaining()) {316int inSize = 1;317char c = src.get();318int bb = encodeChar(c);319if (bb == UNMAPPABLE_ENCODING) {320if (Character.isSurrogate(c)) {321int cp;322if ((cp = sgp().parse(c, src)) < 0)323return sgp.error();324bb = encodeSupp(cp);325if (bb == UNMAPPABLE_ENCODING)326return CoderResult.unmappableForLength(2);327inSize = 2;328} else {329return CoderResult.unmappableForLength(1);330}331}332if (bb > MAX_SINGLEBYTE) { // DoubleByte333if (dst.remaining() < 2)334return CoderResult.OVERFLOW;335dst.put((byte)(bb >> 8));336dst.put((byte)(bb));337} else {338if (dst.remaining() < 1)339return CoderResult.OVERFLOW;340dst.put((byte)bb);341}342mark += inSize;343}344return CoderResult.UNDERFLOW;345} finally {346src.position(mark);347}348}349350protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {351if (src.hasArray() && dst.hasArray())352return encodeArrayLoop(src, dst);353else354return encodeBufferLoop(src, dst);355}356357private byte[] repl = replacement();358protected void implReplaceWith(byte[] newReplacement) {359repl = newReplacement;360}361362public int encode(char[] src, int sp, int len, byte[] dst) {363int dp = 0;364int sl = sp + len;365while (sp < sl) {366char c = src[sp++];367int bb = encodeChar(c);368if (bb == UNMAPPABLE_ENCODING) {369if (!Character.isHighSurrogate(c) || sp == sl ||370!Character.isLowSurrogate(src[sp]) ||371(bb = encodeSupp(Character.toCodePoint(c, src[sp++])))372== UNMAPPABLE_ENCODING) {373dst[dp++] = repl[0];374if (repl.length > 1)375dst[dp++] = repl[1];376continue;377}378}379if (bb > MAX_SINGLEBYTE) { // DoubleByte380dst[dp++] = (byte)(bb >> 8);381dst[dp++] = (byte)bb;382} else { // SingleByte383dst[dp++] = (byte)bb;384}385}386return dp;387}388389public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {390int dp = 0;391int sl = sp + len;392int dl = dst.length;393while (sp < sl) {394char c = StringUTF16.getChar(src, sp++);395int bb = encodeChar(c);396if (bb == UNMAPPABLE_ENCODING) {397if (!Character.isHighSurrogate(c) || sp == sl ||398!Character.isLowSurrogate(StringUTF16.getChar(src,sp)) ||399(bb = encodeSupp(Character.toCodePoint(c, StringUTF16.getChar(src, sp++))))400== UNMAPPABLE_ENCODING) {401dst[dp++] = repl[0];402if (repl.length > 1)403dst[dp++] = repl[1];404continue;405}406}407if (bb > MAX_SINGLEBYTE) { // DoubleByte408dst[dp++] = (byte)(bb >> 8);409dst[dp++] = (byte)bb;410} else { // SingleByte411dst[dp++] = (byte)bb;412}413}414return dp;415}416417static char[] C2B_UNMAPPABLE = new char[0x100];418static {419Arrays.fill(C2B_UNMAPPABLE, (char)UNMAPPABLE_ENCODING);420}421422public static void initc2b(char[][] c2b, String[] b2cStr, String pua) {423// init c2b/c2bSupp from b2cStr and supp424int b2Min = 0x40;425Arrays.fill(c2b, C2B_UNMAPPABLE);426for (int b1 = 0; b1 < 0x100; b1++) {427String s = b2cStr[b1];428if (s == null)429continue;430for (int i = 0; i < s.length(); i++) {431char c = s.charAt(i);432if (c == UNMAPPABLE_DECODING)433continue;434int hi = c >> 8;435if (c2b[hi] == C2B_UNMAPPABLE) {436c2b[hi] = new char[0x100];437Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);438}439c2b[hi][c & 0xff] = (char)((b1 << 8) | (i + b2Min));440}441}442if (pua != null) { // add the compatibility pua entries443char c = '\ue000'; //first pua character444for (int i = 0; i < pua.length(); i++) {445char bb = pua.charAt(i);446if (bb != UNMAPPABLE_DECODING) {447int hi = c >> 8;448if (c2b[hi] == C2B_UNMAPPABLE) {449c2b[hi] = new char[0x100];450Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);451}452c2b[hi][c & 0xff] = bb;453}454c++;455}456}457}458}459}460461462