787 lines · 32.9 KB · Java
RawDownload
/* * Copyright (c) 2002, 2007, 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.ext; 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;import sun.nio.cs.HistoricallyNamedCharset;import sun.nio.cs.Surrogate;import sun.nio.cs.US_ASCII; /* * Implementation notes: * * (1)"Standard based" (ASCII, JIS_X_0201 and JIS_X_0208) ISO2022-JP charset * is provided by the base implementation of this class. * * Three Microsoft ISO2022-JP variants, MS50220, MS50221 and MSISO2022JP * are provided via subclasses. * * (2)MS50220 and MS50221 are assumed to work the same way as Microsoft * CP50220 and CP50221's 7-bit implementation works by using CP5022X * specific JIS0208 and JIS0212 mapping tables (generated via Microsoft's * MultiByteToWideChar/WideCharToMultiByte APIs). The only difference * between these 2 classes is that MS50220 does not support singlebyte * halfwidth kana (Uff61-Uff9f) shiftin mechanism when "encoding", instead * these halfwidth kana characters are converted to their fullwidth JIS0208 * counterparts. * * The difference between the standard JIS_X_0208 and JIS_X_0212 mappings * and the CP50220/50221 specific are * * 0208 mapping: *              1)0x213d <-> U2015 (compared to U2014) *              2)One way mappings for 5 characters below *                u2225 (ms) -> 0x2142 <-> u2016 (jis) *                uff0d (ms) -> 0x215d <-> u2212 (jis) *                uffe0 (ms) -> 0x2171 <-> u00a2 (jis) *                uffe1 (ms) -> 0x2172 <-> u00a3 (jis) *                uffe2 (ms) -> 0x224c <-> u00ac (jis) *                //should consider 0xff5e -> 0x2141 <-> U301c? *              3)NEC Row13 0x2d21-0x2d79 *              4)85-94 ku <-> UE000,UE3AB (includes NEC selected *                IBM kanji in 89-92ku) *              5)UFF61-UFF9f -> Fullwidth 0208 KANA * * 0212 mapping: *              1)0x2237 <-> UFF5E (Fullwidth Tilde) *              2)0x2271 <-> U2116 (Numero Sign) *              3)85-94 ku <-> UE3AC - UE757 * * (3)MSISO2022JP uses a JIS0208 mapping generated from MS932DB.b2c * and MS932DB.c2b by converting the SJIS codepoints back to their * JIS0208 counterparts. With the exception of * * (a)Codepoints with a resulting JIS0208 codepoints beyond 0x7e00 are *    dropped (this includs the IBM Extended Kanji/Non-kanji from 0x9321 *    to 0x972c) * (b)The Unicode codepoints that the IBM Extended Kanji/Non-kanji are *    mapped to (in MS932) are mapped back to NEC selected IBM Kanji/ *    Non-kanji area at 0x7921-0x7c7e. * * Compared to JIS_X_0208 mapping, this MS932 based mapping has  * (a)different mappings for 7 JIS codepoints *        0x213d <-> U2015 *        0x2141 <-> UFF5E *        0x2142 <-> U2225 *        0x215d <-> Uff0d *        0x2171 <-> Uffe0 *        0x2172 <-> Uffe1 *        0x224c <-> Uffe2 * (b)added one-way c2b mappings for *        U00b8 -> 0x2124 *        U00b7 -> 0x2126 *        U00af -> 0x2131 *        U00ab -> 0x2263 *        U00bb -> 0x2264 *        U3094 -> 0x2574 *        U00b5 -> 0x264c * (c)NEC Row 13 * (d)NEC selected IBM extended Kanji/Non-kanji *    These codepoints are mapped to the same Unicode codepoints as *    the MS932 does, while MS50220/50221 maps them to the Unicode *    private area. * * # There is also an interesting difference when compared to MS5022X *   0208 mapping for JIS codepoint "0x2D60", MS932 maps it to U301d *   but MS5022X maps it to U301e, obvious MS5022X is wrong, but... */ public class ISO2022_JP    extends Charset    implements HistoricallyNamedCharset{    private static final int ASCII = 0;                 // ESC ( B    private static final int JISX0201_1976 = 1;         // ESC ( J    private static final int JISX0208_1978 = 2;         // ESC $ @    private static final int JISX0208_1983 = 3;         // ESC $ B    private static final int JISX0212_1990 = 4;         // ESC $ ( D    private static final int JISX0201_1976_KANA = 5;    // ESC ( I    private static final int SHIFTOUT = 6;     private static final int ESC = 0x1b;    private static final int SO = 0x0e;    private static final int SI = 0x0f;     public ISO2022_JP() {        super("ISO-2022-JP",              ExtendedCharsets.aliasesFor("ISO-2022-JP"));    }     protected ISO2022_JP(String canonicalName,                         String[] aliases) {        super(canonicalName, aliases);    }     public String historicalName() {        return "ISO2022JP";    }     public boolean contains(Charset cs) {        return ((cs instanceof JIS_X_0201)                || (cs instanceof US_ASCII)                || (cs instanceof JIS_X_0208)                || (cs instanceof ISO2022_JP));    }     public CharsetDecoder newDecoder() {        return new Decoder(this,                           getDecIndex1(),                           getDecIndex2(),                           get0212Decoder());    }     public CharsetEncoder newEncoder() {        return new Encoder(this,                           getEncIndex1(),                           getEncIndex2(),                           get0212Encoder(),                           doSBKANA());    }     protected short[] getDecIndex1() {        return JIS_X_0208_Decoder.getIndex1();    }     protected String[] getDecIndex2() {        return JIS_X_0208_Decoder.getIndex2();    }     protected DoubleByteDecoder get0212Decoder() {        return null;    }     protected short[] getEncIndex1() {        return JIS_X_0208_Encoder.getIndex1();    }     protected String[] getEncIndex2() {        return JIS_X_0208_Encoder.getIndex2();    }     protected DoubleByteEncoder get0212Encoder() {        return null;    }     protected boolean doSBKANA() {        return true;    }     private static class Decoder extends DoubleByteDecoder        implements DelegatableDecoder {         private int currentState;        private int previousState;        private DoubleByteDecoder decoder0212;         protected Decoder(Charset cs,                          short[] index1,                          String[] index2,                          DoubleByteDecoder decoder0212) {            super(cs,                  index1,                  index2,                  0x21,                  0x7e);            this.decoder0212 = decoder0212;            currentState = ASCII;            previousState = ASCII;        }         protected char convSingleByte(int b) {            return REPLACE_CHAR;        }         public void implReset() {            currentState = ASCII;            previousState = ASCII;        }         private CoderResult decodeArrayLoop(ByteBuffer src,                                            CharBuffer dst)        {            int inputSize = 0;            int b1 = 0, b2 = 0, b3 = 0, b4 = 0;            char c = REPLACE_CHAR;            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) {                    b1 = sa[sp] & 0xff;                    inputSize = 1;                    if ((b1 & 0x80) != 0) {                        return CoderResult.malformedForLength(inputSize);                    }                    if (b1 == ESC || b1 == SO || b1 == SI) {                        if (b1 == ESC) {                            if (sp + inputSize + 2 > sl)                                return CoderResult.UNDERFLOW;                            b2 = sa[sp + inputSize++] & 0xff;                            if (b2 == '(') {                                b3 = sa[sp + inputSize++] & 0xff;                                if (b3 == 'B'){                                    currentState = ASCII;                                } else if (b3 == 'J'){                                    currentState = JISX0201_1976;                                } else if (b3 == 'I'){                                    currentState = JISX0201_1976_KANA;                                } else {                                    return CoderResult.malformedForLength(inputSize);                                }                            } else if (b2 == '$'){                                b3 = sa[sp + inputSize++] & 0xff;                                if (b3 == '@'){                                    currentState = JISX0208_1978;                                } else if (b3 == 'B'){                                    currentState = JISX0208_1983;                                } else if (b3 == '(' && decoder0212 != null) {                                    if (sp + inputSize + 1 > sl)                                        return CoderResult.UNDERFLOW;                                    b4 = sa[sp + inputSize++] & 0xff;                                    if (b4 == 'D') {                                        currentState = JISX0212_1990;                                    } else {                                        return CoderResult.malformedForLength(inputSize);                                    }                                } else {                                    return CoderResult.malformedForLength(inputSize);                                }                            } else {                                return CoderResult.malformedForLength(inputSize);                            }                        } else if (b1 == SO) {                            previousState = currentState;                            currentState = SHIFTOUT;                        } else if (b1 == SI) {                            currentState = previousState;                        }                        sp += inputSize;                        continue;                    }                    if (dp + 1 > dl)                        return CoderResult.OVERFLOW;                     switch (currentState){                        case ASCII:                            da[dp++] = (char)(b1 & 0xff);                            break;                        case JISX0201_1976:                          switch (b1) {                              case 0x5c:  // Yen/tilde substitution                                da[dp++] = '\u00a5';                                break;                              case 0x7e:                                da[dp++] = '\u203e';                                break;                              default:                                da[dp++] = (char)b1;                                break;                            }                            break;                        case JISX0208_1978:                        case JISX0208_1983:                            if (sp + inputSize + 1 > sl)                                return CoderResult.UNDERFLOW;                            b2 = sa[sp + inputSize++] & 0xff;                            c = decodeDouble(b1,b2);                            if (c == REPLACE_CHAR)                                return CoderResult.unmappableForLength(inputSize);                            da[dp++] = c;                            break;                        case JISX0212_1990:                            if (sp + inputSize + 1 > sl)                                return CoderResult.UNDERFLOW;                            b2 = sa[sp + inputSize++] & 0xff;                            c = decoder0212.decodeDouble(b1,b2);                            if (c == REPLACE_CHAR)                                return CoderResult.unmappableForLength(inputSize);                            da[dp++] = c;                            break;                        case JISX0201_1976_KANA:                        case SHIFTOUT:                            if (b1 > 0x60) {                                return CoderResult.malformedForLength(inputSize);                            }                            da[dp++] = (char)(b1 + 0xff40);                            break;                    }                    sp += inputSize;                }                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();            int b1 = 0, b2 = 0, b3 = 0, b4=0;            char c = REPLACE_CHAR;            int inputSize = 0;            try {                while (src.hasRemaining()) {                    b1 = src.get() & 0xff;                    inputSize = 1;                    if ((b1 & 0x80) != 0)                        return CoderResult.malformedForLength(inputSize);                    if (b1 == ESC || b1 == SO || b1 == SI) {                        if (b1 == ESC) {  // ESC                            if (src.remaining() < 2)                                return CoderResult.UNDERFLOW;                            b2 = src.get() & 0xff;                            inputSize++;                            if (b2 == '(') {                                b3 = src.get() & 0xff;                                inputSize++;                                if (b3 == 'B'){                                    currentState = ASCII;                                } else if (b3 == 'J'){                                    currentState = JISX0201_1976;                                } else if (b3 == 'I'){                                    currentState = JISX0201_1976_KANA;                                } else {                                   return CoderResult.malformedForLength(inputSize);                                }                            } else if (b2 == '$'){                                b3 = src.get() & 0xff;                                inputSize++;                                if (b3 == '@'){                                    currentState = JISX0208_1978;                                } else if (b3 == 'B'){                                    currentState = JISX0208_1983;                                } else if (b3 == '(' && decoder0212 != null) {                                    if (!src.hasRemaining())                                        return CoderResult.UNDERFLOW;                                    b4 = src.get() & 0xff;                                    inputSize++;                                    if (b4 == 'D') {                                        currentState = JISX0212_1990;                                    } else {                                        return CoderResult.malformedForLength(inputSize);                                    }                                } else {                                    return CoderResult.malformedForLength(inputSize);                                }                            } else {                                return CoderResult.malformedForLength(inputSize);                            }                        } else if (b1 == SO) {                            previousState = currentState;                            currentState = SHIFTOUT;                        } else if (b1 == SI) { // shift back in                            currentState = previousState;                        }                        mark += inputSize;                        continue;                    }                    if (!dst.hasRemaining())                        return CoderResult.OVERFLOW;                     switch (currentState){                        case ASCII:                            dst.put((char)(b1 & 0xff));                            break;                        case JISX0201_1976:                            switch (b1) {                              case 0x5c:  // Yen/tilde substitution                                dst.put('\u00a5');                                break;                              case 0x7e:                                dst.put('\u203e');                                break;                              default:                                dst.put((char)b1);                                break;                            }                            break;                        case JISX0208_1978:                        case JISX0208_1983:                            if (!src.hasRemaining())                                return CoderResult.UNDERFLOW;                            b2 = src.get() & 0xff;                            inputSize++;                            c = decodeDouble(b1,b2);                            if (c == REPLACE_CHAR)                                return CoderResult.unmappableForLength(inputSize);                            dst.put(c);                            break;                        case JISX0212_1990:                            if (!src.hasRemaining())                                return CoderResult.UNDERFLOW;                            b2 = src.get() & 0xff;                            inputSize++;                            c = decoder0212.decodeDouble(b1,b2);                            if (c == REPLACE_CHAR)                                return CoderResult.unmappableForLength(inputSize);                            dst.put(c);                            break;                        case JISX0201_1976_KANA:                        case SHIFTOUT:                            if (b1 > 0x60) {                                return CoderResult.malformedForLength(inputSize);                            }                            dst.put((char)(b1 + 0xff40));                            break;                    }                    mark += inputSize;                }                return CoderResult.UNDERFLOW;            } finally {                src.position(mark);            }        }         // Make some protected methods public for use by JISAutoDetect        public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {            if (src.hasArray() && dst.hasArray())                return decodeArrayLoop(src, dst);            else                return decodeBufferLoop(src, dst);        }         public CoderResult implFlush(CharBuffer out) {            return super.implFlush(out);        }    }     private static class Encoder extends DoubleByteEncoder {        private static byte[] repl = { (byte)0x21, (byte)0x29 };        private int currentMode = ASCII;        private int replaceMode = JISX0208_1983;        private DoubleByteEncoder encoder0212 = null;        private boolean doSBKANA;         private Encoder(Charset cs,                        short[] index1,                        String[] index2,                        DoubleByteEncoder encoder0212,                        boolean doSBKANA) {

Lines 1–500 of 787.