1 /*
   2  * Copyright (c) 2001, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.nio.CharBuffer;
  25 import java.nio.ByteBuffer;
  26 import java.nio.charset.*;
  27 import sun.nio.cs.*;
  28 import sun.nio.cs.ext.*;
  29 
  30 public abstract class X11CNS11643 extends Charset {
  31     private final int plane;
  32     public X11CNS11643 (int plane, String name) {
  33         super(name, null);
  34         switch (plane) {
  35         case 1:
  36             this.plane = 0; // CS1
  37             break;
  38         case 2:
  39         case 3:
  40             this.plane = plane;
  41             break;
  42         default:
  43             throw new IllegalArgumentException
  44                 ("Only planes 1, 2, and 3 supported");
  45         }
  46     }
  47 
  48     public CharsetEncoder newEncoder() {
  49         return new Encoder(this, plane);
  50     }
  51 
  52     public CharsetDecoder newDecoder() {
  53         return new Decoder(this, plane);
  54     }
  55 
  56     public boolean contains(Charset cs) {
  57         return cs instanceof X11CNS11643;
  58     }
  59 
  60     private class Encoder extends EUC_TW_OLD.Encoder {
  61         private int plane;
  62         public Encoder(Charset cs, int plane) {
  63             super(cs);
  64             this.plane = plane;
  65         }
  66         public boolean canEncode(char c) {
  67             if (c <= 0x7F) {
  68                 return false;
  69             }
  70             int p = getNative(c) >> 16;
  71             if (p == 1 && plane == 0 ||
  72                 p == 2 && plane == 2 ||
  73                 p == 3 && plane == 3)
  74                 return true;
  75             return false;
  76         }
  77 
  78         public boolean isLegalReplacement(byte[] repl) {
  79             return true;
  80         }
  81 
  82         protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
  83             char[] sa = src.array();
  84             int sp = src.arrayOffset() + src.position();
  85             int sl = src.arrayOffset() + src.limit();
  86             byte[] da = dst.array();
  87             int dp = dst.arrayOffset() + dst.position();
  88             int dl = dst.arrayOffset() + dst.limit();
  89 
  90             try {
  91                 while (sp < sl) {
  92                     char c = sa[sp];
  93                     if (c >= '\uFFFE' || c <= '\u007f')
  94                         return CoderResult.unmappableForLength(1);
  95                     int cns = getNative(c);
  96                     int p = cns >> 16;
  97                     if (p == 1 && plane == 0 ||
  98                         p == 2 && plane == 2 ||
  99                         p == 3 && plane == 3) {
 100                         if (dl - dp < 2)
 101                             return CoderResult.OVERFLOW;
 102                         da[dp++] = (byte) ((cns  >> 8) & 0x7f);
 103                         da[dp++] = (byte) (cns & 0x7f);
 104                         sp++;
 105                         continue;
 106                     }
 107                     return CoderResult.unmappableForLength(1);
 108                 }
 109                 return CoderResult.UNDERFLOW;
 110             } finally {
 111                 src.position(sp - src.arrayOffset());
 112                 dst.position(dp - dst.arrayOffset());
 113             }
 114         }
 115     }
 116 
 117     private class Decoder extends EUC_TW_OLD.Decoder {
 118         private String table;
 119         protected Decoder(Charset cs, int plane) {
 120             super(cs);
 121             switch (plane) {
 122             case 0:
 123                 table = unicodeCNS1;
 124                 break;
 125             case 2:
 126                 table = unicodeCNS2;
 127                 break;
 128             case 3:
 129                 table = unicodeCNS3;
 130                 break;
 131             default:
 132                 throw new IllegalArgumentException
 133                     ("Only planes 1, 2, and 3 supported");
 134             }
 135         }
 136 
 137         //we only work on array backed buffer.
 138         protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
 139             byte[] sa = src.array();
 140             int sp = src.arrayOffset() + src.position();
 141             int sl = src.arrayOffset() + src.limit();
 142             assert (sp <= sl);
 143             sp = (sp <= sl ? sp : sl);
 144 
 145             char[] da = dst.array();
 146             int dp = dst.arrayOffset() + dst.position();
 147             int dl = dst.arrayOffset() + dst.limit();
 148             assert (dp <= dl);
 149             dp = (dp <= dl ? dp : dl);
 150 
 151             try {
 152                 while (sp < sl) {
 153                     if ( sl - sp < 2) {
 154                         return CoderResult.UNDERFLOW;
 155                     }
 156                     byte b1 = sa[sp];
 157                     byte b2 = sa[sp + 1];
 158                     char c = replacement().charAt(0);
 159 
 160                     if (table == unicodeCNS3) {
 161                         char[] cc = convToSurrogate((byte)(b1 | 0x80),
 162                                                     (byte)(b2 | 0x80),
 163                                                     table);
 164                         if (cc != null && cc[0] == '\u0000')
 165                             c = cc[1];
 166                     } else {
 167                         c = convToUnicode((byte)(b1 | 0x80),
 168                                            (byte)(b2 | 0x80),
 169                                            table);
 170                     }
 171                     if (c == replacement().charAt(0)
 172                         //to keep the compatibility with b2cX11CNS11643
 173                         /*|| c == '\u0000'*/) {
 174                         return CoderResult.unmappableForLength(2);
 175                     }
 176                     if (dl - dp < 1)
 177                         return CoderResult.OVERFLOW;
 178                     da[dp++] = c;
 179                     sp +=2;
 180                 }
 181                 return CoderResult.UNDERFLOW;
 182             } finally {
 183                 src.position(sp - src.arrayOffset());
 184                 dst.position(dp - dst.arrayOffset());
 185             }
 186         }
 187     }
 188 }