jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/HKSCS.java
changeset 29257 550dfa936f27
parent 29256 751f31639710
parent 29014 d42eb758b048
child 29258 adf046d51c1c
equal deleted inserted replaced
29256:751f31639710 29257:550dfa936f27
     1 /*
       
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.nio.cs.ext;
       
    27 
       
    28 import java.nio.ByteBuffer;
       
    29 import java.nio.CharBuffer;
       
    30 import java.nio.charset.Charset;
       
    31 import java.nio.charset.CharsetDecoder;
       
    32 import java.nio.charset.CharsetEncoder;
       
    33 import java.nio.charset.CoderResult;
       
    34 import java.util.Arrays;
       
    35 import sun.nio.cs.Surrogate;
       
    36 import static sun.nio.cs.CharsetMapping.*;
       
    37 
       
    38 public class HKSCS {
       
    39 
       
    40     public static class Decoder extends DoubleByte.Decoder {
       
    41         static int b2Min = 0x40;
       
    42         static int b2Max = 0xfe;
       
    43 
       
    44         private char[][] b2cBmp;
       
    45         private char[][] b2cSupp;
       
    46         private DoubleByte.Decoder big5Dec;
       
    47 
       
    48         protected Decoder(Charset cs,
       
    49                           DoubleByte.Decoder big5Dec,
       
    50                           char[][] b2cBmp, char[][] b2cSupp)
       
    51         {
       
    52             // super(cs, 0.5f, 1.0f);
       
    53             // need to extends DoubleByte.Decoder so the
       
    54             // sun.io can use it. this implementation
       
    55             super(cs, 0.5f, 1.0f, null, null, 0, 0);
       
    56             this.big5Dec = big5Dec;
       
    57             this.b2cBmp = b2cBmp;
       
    58             this.b2cSupp = b2cSupp;
       
    59         }
       
    60 
       
    61         public char decodeSingle(int b) {
       
    62             return big5Dec.decodeSingle(b);
       
    63         }
       
    64 
       
    65         public char decodeBig5(int b1, int b2) {
       
    66             return big5Dec.decodeDouble(b1, b2);
       
    67         }
       
    68 
       
    69         public char decodeDouble(int b1, int b2) {
       
    70             return b2cBmp[b1][b2 - b2Min];
       
    71         }
       
    72 
       
    73         public char decodeDoubleEx(int b1, int b2) {
       
    74             /* if the b2cSupp is null, the subclass need
       
    75                to override the methold
       
    76             if (b2cSupp == null)
       
    77                 return UNMAPPABLE_DECODING;
       
    78              */
       
    79             return b2cSupp[b1][b2 - b2Min];
       
    80         }
       
    81 
       
    82         protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
       
    83             byte[] sa = src.array();
       
    84             int sp = src.arrayOffset() + src.position();
       
    85             int sl = src.arrayOffset() + src.limit();
       
    86 
       
    87             char[] da = dst.array();
       
    88             int dp = dst.arrayOffset() + dst.position();
       
    89             int dl = dst.arrayOffset() + dst.limit();
       
    90 
       
    91             try {
       
    92                 while (sp < sl) {
       
    93                     int b1 = sa[sp] & 0xff;
       
    94                     char c = decodeSingle(b1);
       
    95                     int inSize = 1, outSize = 1;
       
    96                     char[] cc = null;
       
    97                     if (c == UNMAPPABLE_DECODING) {
       
    98                         if (sl - sp < 2)
       
    99                             return CoderResult.UNDERFLOW;
       
   100                         int b2 = sa[sp + 1] & 0xff;
       
   101                         inSize++;
       
   102                         if (b2 < b2Min || b2 > b2Max)
       
   103                             return CoderResult.unmappableForLength(2);
       
   104                         c = decodeDouble(b1, b2);           //bmp
       
   105                         if (c == UNMAPPABLE_DECODING) {
       
   106                             c = decodeDoubleEx(b1, b2);     //supp
       
   107                             if (c == UNMAPPABLE_DECODING) {
       
   108                                 c = decodeBig5(b1, b2);     //big5
       
   109                                 if (c == UNMAPPABLE_DECODING)
       
   110                                     return CoderResult.unmappableForLength(2);
       
   111                             } else {
       
   112                                 // supplementary character in u+2xxxx area
       
   113                                 outSize = 2;
       
   114                             }
       
   115                         }
       
   116                     }
       
   117                     if (dl - dp < outSize)
       
   118                         return CoderResult.OVERFLOW;
       
   119                     if (outSize == 2) {
       
   120                         // supplementary characters
       
   121                         da[dp++] = Surrogate.high(0x20000 + c);
       
   122                         da[dp++] = Surrogate.low(0x20000 + c);
       
   123                     } else {
       
   124                         da[dp++] = c;
       
   125                     }
       
   126                     sp += inSize;
       
   127                 }
       
   128                 return CoderResult.UNDERFLOW;
       
   129             } finally {
       
   130                 src.position(sp - src.arrayOffset());
       
   131                 dst.position(dp - dst.arrayOffset());
       
   132             }
       
   133         }
       
   134 
       
   135         protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
       
   136             int mark = src.position();
       
   137             try {
       
   138                 while (src.hasRemaining()) {
       
   139                     char[] cc = null;
       
   140                     int b1 = src.get() & 0xff;
       
   141                     int inSize = 1, outSize = 1;
       
   142                     char c = decodeSingle(b1);
       
   143                     if (c == UNMAPPABLE_DECODING) {
       
   144                         if (src.remaining() < 1)
       
   145                             return CoderResult.UNDERFLOW;
       
   146                         int b2 = src.get() & 0xff;
       
   147                         inSize++;
       
   148                         if (b2 < b2Min || b2 > b2Max)
       
   149                             return CoderResult.unmappableForLength(2);
       
   150                         c = decodeDouble(b1, b2);           //bmp
       
   151                         if (c == UNMAPPABLE_DECODING) {
       
   152                             c = decodeDoubleEx(b1, b2);     //supp
       
   153                             if (c == UNMAPPABLE_DECODING) {
       
   154                                 c = decodeBig5(b1, b2);     //big5
       
   155                                 if (c == UNMAPPABLE_DECODING)
       
   156                                     return CoderResult.unmappableForLength(2);
       
   157                             } else {
       
   158                                 outSize = 2;
       
   159                             }
       
   160                         }
       
   161                     }
       
   162                     if (dst.remaining() < outSize)
       
   163                         return CoderResult.OVERFLOW;
       
   164                     if (outSize == 2) {
       
   165                         dst.put(Surrogate.high(0x20000 + c));
       
   166                         dst.put(Surrogate.low(0x20000 + c));
       
   167                     } else {
       
   168                         dst.put(c);
       
   169                     }
       
   170                     mark += inSize;
       
   171                 }
       
   172                 return CoderResult.UNDERFLOW;
       
   173             } finally {
       
   174                 src.position(mark);
       
   175             }
       
   176         }
       
   177 
       
   178         public int decode(byte[] src, int sp, int len, char[] dst) {
       
   179             int dp = 0;
       
   180             int sl = sp + len;
       
   181             char repl = replacement().charAt(0);
       
   182             while (sp < sl) {
       
   183                 int b1 = src[sp++] & 0xff;
       
   184                 char c = decodeSingle(b1);
       
   185                 if (c == UNMAPPABLE_DECODING) {
       
   186                     if (sl == sp) {
       
   187                         c = repl;
       
   188                     } else {
       
   189                         int b2 = src[sp++] & 0xff;
       
   190                         if (b2 < b2Min || b2 > b2Max) {
       
   191                             c = repl;
       
   192                         } else if ((c = decodeDouble(b1, b2)) == UNMAPPABLE_DECODING) {
       
   193                             c = decodeDoubleEx(b1, b2);     //supp
       
   194                             if (c == UNMAPPABLE_DECODING) {
       
   195                                 c = decodeBig5(b1, b2);     //big5
       
   196                                 if (c == UNMAPPABLE_DECODING)
       
   197                                     c = repl;
       
   198                             } else {
       
   199                                 // supplementary character in u+2xxxx area
       
   200                                 dst[dp++] = Surrogate.high(0x20000 + c);
       
   201                                 dst[dp++] = Surrogate.low(0x20000 + c);
       
   202                                 continue;
       
   203                             }
       
   204                         }
       
   205                     }
       
   206                 }
       
   207                 dst[dp++] = c;
       
   208             }
       
   209             return dp;
       
   210         }
       
   211 
       
   212         public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
       
   213             if (src.hasArray() && dst.hasArray())
       
   214                 return decodeArrayLoop(src, dst);
       
   215             else
       
   216                 return decodeBufferLoop(src, dst);
       
   217         }
       
   218 
       
   219         static void initb2c(char[][]b2c, String[] b2cStr)
       
   220         {
       
   221             for (int i = 0; i < b2cStr.length; i++) {
       
   222                 if (b2cStr[i] == null)
       
   223                     b2c[i] = DoubleByte.B2C_UNMAPPABLE;
       
   224                 else
       
   225                     b2c[i] = b2cStr[i].toCharArray();
       
   226             }
       
   227         }
       
   228 
       
   229     }
       
   230 
       
   231     public static class Encoder extends DoubleByte.Encoder {
       
   232         private DoubleByte.Encoder big5Enc;
       
   233         private char[][] c2bBmp;
       
   234         private char[][] c2bSupp;
       
   235 
       
   236         protected Encoder(Charset cs,
       
   237                           DoubleByte.Encoder big5Enc,
       
   238                           char[][] c2bBmp,
       
   239                           char[][] c2bSupp)
       
   240         {
       
   241             super(cs, null, null);
       
   242             this.big5Enc = big5Enc;
       
   243             this.c2bBmp = c2bBmp;
       
   244             this.c2bSupp = c2bSupp;
       
   245         }
       
   246 
       
   247         public int encodeBig5(char ch) {
       
   248             return big5Enc.encodeChar(ch);
       
   249         }
       
   250 
       
   251         public int encodeChar(char ch) {
       
   252             int bb = c2bBmp[ch >> 8][ch & 0xff];
       
   253             if (bb == UNMAPPABLE_ENCODING)
       
   254                 return encodeBig5(ch);
       
   255             return bb;
       
   256         }
       
   257 
       
   258         public int encodeSupp(int cp) {
       
   259             if ((cp & 0xf0000) != 0x20000)
       
   260                 return UNMAPPABLE_ENCODING;
       
   261             return c2bSupp[(cp >> 8) & 0xff][cp & 0xff];
       
   262         }
       
   263 
       
   264         public boolean canEncode(char c) {
       
   265             return encodeChar(c) != UNMAPPABLE_ENCODING;
       
   266         }
       
   267 
       
   268         protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
       
   269             char[] sa = src.array();
       
   270             int sp = src.arrayOffset() + src.position();
       
   271             int sl = src.arrayOffset() + src.limit();
       
   272 
       
   273             byte[] da = dst.array();
       
   274             int dp = dst.arrayOffset() + dst.position();
       
   275             int dl = dst.arrayOffset() + dst.limit();
       
   276 
       
   277             try {
       
   278                 while (sp < sl) {
       
   279                     char c = sa[sp];
       
   280                     int inSize = 1;
       
   281                     int bb = encodeChar(c);
       
   282                     if (bb == UNMAPPABLE_ENCODING) {
       
   283                         if (Character.isSurrogate(c)) {
       
   284                             int cp;
       
   285                             if ((cp = sgp().parse(c, sa, sp, sl)) < 0)
       
   286                                 return sgp.error();
       
   287                             bb = encodeSupp(cp);
       
   288                             if (bb == UNMAPPABLE_ENCODING)
       
   289                                 return CoderResult.unmappableForLength(2);
       
   290                             inSize = 2;
       
   291                         } else {
       
   292                             return CoderResult.unmappableForLength(1);
       
   293                         }
       
   294                     }
       
   295                     if (bb > MAX_SINGLEBYTE) {    // DoubleByte
       
   296                         if (dl - dp < 2)
       
   297                             return CoderResult.OVERFLOW;
       
   298                         da[dp++] = (byte)(bb >> 8);
       
   299                         da[dp++] = (byte)bb;
       
   300                     } else {                      // SingleByte
       
   301                         if (dl - dp < 1)
       
   302                             return CoderResult.OVERFLOW;
       
   303                         da[dp++] = (byte)bb;
       
   304                     }
       
   305                     sp += inSize;
       
   306                 }
       
   307                 return CoderResult.UNDERFLOW;
       
   308             } finally {
       
   309                 src.position(sp - src.arrayOffset());
       
   310                 dst.position(dp - dst.arrayOffset());
       
   311             }
       
   312         }
       
   313 
       
   314         protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
       
   315             int mark = src.position();
       
   316             try {
       
   317                 while (src.hasRemaining()) {
       
   318                     int inSize = 1;
       
   319                     char c = src.get();
       
   320                     int bb = encodeChar(c);
       
   321                     if (bb == UNMAPPABLE_ENCODING) {
       
   322                         if (Character.isSurrogate(c)) {
       
   323                             int cp;
       
   324                             if ((cp = sgp().parse(c, src)) < 0)
       
   325                                 return sgp.error();
       
   326                             bb = encodeSupp(cp);
       
   327                             if (bb == UNMAPPABLE_ENCODING)
       
   328                                 return CoderResult.unmappableForLength(2);
       
   329                             inSize = 2;
       
   330                         } else {
       
   331                             return CoderResult.unmappableForLength(1);
       
   332                         }
       
   333                     }
       
   334                     if (bb > MAX_SINGLEBYTE) {  // DoubleByte
       
   335                         if (dst.remaining() < 2)
       
   336                             return CoderResult.OVERFLOW;
       
   337                         dst.put((byte)(bb >> 8));
       
   338                         dst.put((byte)(bb));
       
   339                     } else {
       
   340                         if (dst.remaining() < 1)
       
   341                         return CoderResult.OVERFLOW;
       
   342                         dst.put((byte)bb);
       
   343                     }
       
   344                     mark += inSize;
       
   345                 }
       
   346                 return CoderResult.UNDERFLOW;
       
   347             } finally {
       
   348                 src.position(mark);
       
   349             }
       
   350         }
       
   351 
       
   352         protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
       
   353             if (src.hasArray() && dst.hasArray())
       
   354                 return encodeArrayLoop(src, dst);
       
   355             else
       
   356                 return encodeBufferLoop(src, dst);
       
   357         }
       
   358 
       
   359         private byte[] repl = replacement();
       
   360         protected void implReplaceWith(byte[] newReplacement) {
       
   361             repl = newReplacement;
       
   362         }
       
   363 
       
   364         public int encode(char[] src, int sp, int len, byte[] dst) {
       
   365             int dp = 0;
       
   366             int sl = sp + len;
       
   367             while (sp < sl) {
       
   368                 char c = src[sp++];
       
   369                 int bb = encodeChar(c);
       
   370                 if (bb == UNMAPPABLE_ENCODING) {
       
   371                     if (!Character.isHighSurrogate(c) || sp == sl ||
       
   372                         !Character.isLowSurrogate(src[sp]) ||
       
   373                         (bb = encodeSupp(Character.toCodePoint(c, src[sp++])))
       
   374                         == UNMAPPABLE_ENCODING) {
       
   375                         dst[dp++] = repl[0];
       
   376                         if (repl.length > 1)
       
   377                             dst[dp++] = repl[1];
       
   378                         continue;
       
   379                     }
       
   380                     sp++;
       
   381                 }
       
   382                 if (bb > MAX_SINGLEBYTE) {        // DoubleByte
       
   383                     dst[dp++] = (byte)(bb >> 8);
       
   384                     dst[dp++] = (byte)bb;
       
   385                 } else {                          // SingleByte
       
   386                     dst[dp++] = (byte)bb;
       
   387                 }
       
   388             }
       
   389             return dp;
       
   390         }
       
   391 
       
   392 
       
   393         static char[] C2B_UNMAPPABLE = new char[0x100];
       
   394         static {
       
   395             Arrays.fill(C2B_UNMAPPABLE, (char)UNMAPPABLE_ENCODING);
       
   396         }
       
   397 
       
   398        static void initc2b(char[][] c2b, String[] b2cStr, String pua) {
       
   399             // init c2b/c2bSupp from b2cStr and supp
       
   400             int b2Min = 0x40;
       
   401             Arrays.fill(c2b, C2B_UNMAPPABLE);
       
   402             for (int b1 = 0; b1 < 0x100; b1++) {
       
   403                 String s = b2cStr[b1];
       
   404                 if (s == null)
       
   405                     continue;
       
   406                 for (int i = 0; i < s.length(); i++) {
       
   407                     char c = s.charAt(i);
       
   408                     int hi = c >> 8;
       
   409                     if (c2b[hi] == C2B_UNMAPPABLE) {
       
   410                         c2b[hi] = new char[0x100];
       
   411                         Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
       
   412                     }
       
   413                     c2b[hi][c & 0xff] = (char)((b1 << 8) | (i + b2Min));
       
   414                 }
       
   415             }
       
   416             if (pua != null) {        // add the compatibility pua entries
       
   417                 char c = '\ue000';    //first pua character
       
   418                 for (int i = 0; i < pua.length(); i++) {
       
   419                     char bb = pua.charAt(i);
       
   420                     if (bb != UNMAPPABLE_DECODING) {
       
   421                         int hi = c >> 8;
       
   422                         if (c2b[hi] == C2B_UNMAPPABLE) {
       
   423                             c2b[hi] = new char[0x100];
       
   424                             Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);
       
   425                         }
       
   426                         c2b[hi][c & 0xff] = bb;
       
   427                     }
       
   428                     c++;
       
   429                 }
       
   430             }
       
   431         }
       
   432     }
       
   433 }