177N/A/*
5163N/A * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
177N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
177N/A *
177N/A * This code is free software; you can redistribute it and/or modify it
177N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
177N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
177N/A *
177N/A * This code is distributed in the hope that it will be useful, but WITHOUT
177N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
177N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
177N/A * version 2 for more details (a copy is included in the LICENSE file that
177N/A * accompanied this code).
177N/A *
177N/A * You should have received a copy of the GNU General Public License version
177N/A * 2 along with this work; if not, write to the Free Software Foundation,
177N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
177N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
177N/A */
177N/A
177N/Apackage sun.nio.cs.ext;
177N/A
177N/Aimport java.nio.ByteBuffer;
177N/Aimport java.nio.CharBuffer;
177N/Aimport java.nio.charset.Charset;
177N/Aimport java.nio.charset.CharsetEncoder;
177N/Aimport java.nio.charset.CharsetDecoder;
177N/Aimport java.nio.charset.CoderResult;
5163N/Aimport java.security.AccessController;
5163N/Aimport java.security.PrivilegedAction;
177N/Aimport java.util.Arrays;
177N/Aimport sun.nio.cs.CharsetMapping;
177N/A
177N/A/*
177N/A * 5 types of entry in SJIS_X_0213/Unicode mapping table
177N/A *
177N/A * (1)Single-Byte
177N/A * JIS_X_0213 does not define single-byte character itself, the
177N/A * JIS_X_0201 entries are added in for sjis implementation.
177N/A *
177N/A * (2)Double-Byte SJIS <-> BMP Unicode
177N/A * ex: 0x8140 U+3000 # IDEOGRAPHIC SPACE
177N/A *
177N/A * (3)Double-Byte SJIS <-> Supplementary
177N/A * ex: 0xFCF0 U+2A61A # <cjk> [2000] [Unicode3.1]
177N/A *
177N/A * (4)Double-Byte SJIS <-> Composite
177N/A * ex: 0x83F6 U+31F7+309A # [2000]
177N/A *
177N/A * (5)"Windows-only" special mapping entries
177N/A * are handled by MS932_0213.
177N/A */
177N/A
177N/Apublic class SJIS_0213 extends Charset {
177N/A public SJIS_0213() {
177N/A super("x-SJIS_0213", ExtendedCharsets.aliasesFor("SJIS_0213"));
177N/A }
177N/A
177N/A public boolean contains(Charset cs) {
177N/A return ((cs.name().equals("US-ASCII"))
177N/A || (cs instanceof SJIS)
177N/A || (cs instanceof SJIS_0213));
177N/A }
177N/A
177N/A public CharsetDecoder newDecoder() {
177N/A return new Decoder(this);
177N/A }
177N/A
177N/A public CharsetEncoder newEncoder() {
177N/A return new Encoder(this);
177N/A }
177N/A
5163N/A static CharsetMapping mapping = AccessController.doPrivileged(
5163N/A new PrivilegedAction<CharsetMapping>() {
5163N/A public CharsetMapping run() {
5163N/A return CharsetMapping.get(SJIS_0213.class.getResourceAsStream("sjis0213.dat"));
5163N/A }
5163N/A });
177N/A
177N/A protected static class Decoder extends CharsetDecoder {
177N/A protected static final char UNMAPPABLE = CharsetMapping.UNMAPPABLE_DECODING;
177N/A
177N/A protected Decoder(Charset cs) {
177N/A super(cs, 0.5f, 1.0f);
177N/A }
177N/A
177N/A private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
177N/A byte[] sa = src.array();
177N/A int sp = src.arrayOffset() + src.position();
177N/A int sl = src.arrayOffset() + src.limit();
177N/A
177N/A char[] da = dst.array();
177N/A int dp = dst.arrayOffset() + dst.position();
177N/A int dl = dst.arrayOffset() + dst.limit();
177N/A
177N/A try {
177N/A while (sp < sl) {
177N/A int b1 = sa[sp] & 0xff;
177N/A char c = decodeSingle(b1);
177N/A int inSize = 1, outSize = 1;
177N/A char[] cc = null;
177N/A if (c == UNMAPPABLE) {
177N/A if (sl - sp < 2)
177N/A return CoderResult.UNDERFLOW;
177N/A int b2 = sa[sp + 1] & 0xff;
177N/A c = decodeDouble(b1, b2);
177N/A inSize++;
177N/A if (c == UNMAPPABLE) {
177N/A cc = decodeDoubleEx(b1, b2);
177N/A if (cc == null) {
177N/A if (decodeSingle(b2) == UNMAPPABLE)
177N/A return CoderResult.unmappableForLength(2);
177N/A else
177N/A return CoderResult.unmappableForLength(1);
177N/A }
177N/A outSize++;
177N/A }
177N/A }
177N/A if (dl - dp < outSize)
177N/A return CoderResult.OVERFLOW;
177N/A if (outSize == 2) {
177N/A da[dp++] = cc[0];
177N/A da[dp++] = cc[1];
177N/A } else {
177N/A da[dp++] = c;
177N/A }
177N/A sp += inSize;
177N/A }
177N/A return CoderResult.UNDERFLOW;
177N/A } finally {
177N/A src.position(sp - src.arrayOffset());
177N/A dst.position(dp - dst.arrayOffset());
177N/A }
177N/A }
177N/A
177N/A private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
177N/A int mark = src.position();
177N/A try {
177N/A while (src.hasRemaining()) {
177N/A char[] cc = null;
177N/A int b1 = src.get() & 0xff;
177N/A char c = decodeSingle(b1);
177N/A int inSize = 1, outSize = 1;
177N/A if (c == UNMAPPABLE) {
177N/A if (src.remaining() < 1)
177N/A return CoderResult.UNDERFLOW;
177N/A int b2 = src.get() & 0xff;
177N/A inSize++;
177N/A c = decodeDouble(b1, b2);
177N/A if (c == UNMAPPABLE) {
177N/A cc = decodeDoubleEx(b1, b2);
177N/A if (cc == null) {
177N/A if (decodeSingle(b2) == UNMAPPABLE)
177N/A return CoderResult.unmappableForLength(2);
177N/A else
177N/A return CoderResult.unmappableForLength(1);
177N/A }
177N/A outSize++;
177N/A }
177N/A }
177N/A if (dst.remaining() < outSize)
177N/A return CoderResult.OVERFLOW;
177N/A if (outSize == 2) {
177N/A dst.put(cc[0]);
177N/A dst.put(cc[1]);
177N/A } else {
177N/A dst.put(c);
177N/A }
177N/A mark += inSize;
177N/A }
177N/A return CoderResult.UNDERFLOW;
177N/A } finally {
177N/A src.position(mark);
177N/A }
177N/A }
177N/A
177N/A protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
177N/A if (src.hasArray() && dst.hasArray())
177N/A return decodeArrayLoop(src, dst);
177N/A else
177N/A return decodeBufferLoop(src, dst);
177N/A }
177N/A
177N/A protected char decodeSingle(int b) {
177N/A return mapping.decodeSingle(b);
177N/A }
177N/A
177N/A protected char decodeDouble(int b1, int b2) {
177N/A return mapping.decodeDouble(b1, b2);
177N/A }
177N/A
177N/A private char[] cc = new char[2];
177N/A private CharsetMapping.Entry comp = new CharsetMapping.Entry();
177N/A protected char[] decodeDoubleEx(int b1, int b2) {
177N/A int db = (b1 << 8) | b2;
177N/A if (mapping.decodeSurrogate(db, cc) != null)
177N/A return cc;
177N/A comp.bs = db;
177N/A if (mapping.decodeComposite(comp, cc) != null)
177N/A return cc;
177N/A return null;
177N/A }
177N/A }
177N/A
177N/A protected static class Encoder extends CharsetEncoder {
177N/A protected static final int UNMAPPABLE = CharsetMapping.UNMAPPABLE_ENCODING;
177N/A protected static final int MAX_SINGLEBYTE = 0xff;
177N/A
177N/A protected Encoder(Charset cs) {
177N/A super(cs, 2.0f, 2.0f);
177N/A }
177N/A
177N/A public boolean canEncode(char c) {
177N/A return (encodeChar(c) != UNMAPPABLE);
177N/A }
177N/A
177N/A protected int encodeChar(char ch) {
177N/A return mapping.encodeChar(ch);
177N/A }
177N/A
177N/A protected int encodeSurrogate(char hi, char lo) {
177N/A return mapping.encodeSurrogate(hi, lo);
177N/A }
177N/A
177N/A private CharsetMapping.Entry comp = new CharsetMapping.Entry();
177N/A protected int encodeComposite(char base, char cc) {
177N/A comp.cp = base;
177N/A comp.cp2 = cc;
177N/A return mapping.encodeComposite(comp);
177N/A }
177N/A
177N/A protected boolean isCompositeBase(char ch) {
177N/A comp.cp = ch;
177N/A return mapping.isCompositeBase(comp);
177N/A }
177N/A
177N/A // Unlike surrogate pair, the base character of a base+cc composite
177N/A // itself is a legal codepoint in 0213, if we simply return UNDERFLOW
177N/A // when a base candidate is the last input char in the CharBuffer, like
177N/A // what we do for the surrogte pair, encoding will fail if this base
177N/A // character is indeed the last character of the input char sequence.
177N/A // Keep this base candidate in "leftoverBase" so we can flush it out
177N/A // at the end of the encoding circle.
177N/A char leftoverBase = 0;
177N/A protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
177N/A char[] sa = src.array();
177N/A int sp = src.arrayOffset() + src.position();
177N/A int sl = src.arrayOffset() + src.limit();
177N/A byte[] da = dst.array();
177N/A int dp = dst.arrayOffset() + dst.position();
177N/A int dl = dst.arrayOffset() + dst.limit();
177N/A
177N/A try {
177N/A while (sp < sl) {
177N/A int db;
177N/A char c = sa[sp];
177N/A if (leftoverBase != 0) {
177N/A boolean isComp = false;
177N/A db = encodeComposite(leftoverBase, c);
177N/A if (db == UNMAPPABLE)
177N/A db = encodeChar(leftoverBase);
177N/A else
177N/A isComp = true;
177N/A if (dl - dp < 2)
177N/A return CoderResult.OVERFLOW;
177N/A da[dp++] = (byte)(db >> 8);
177N/A da[dp++] = (byte)db;
177N/A leftoverBase = 0;
177N/A if (isComp) {
177N/A sp++;
177N/A continue;
177N/A }
177N/A }
177N/A if (isCompositeBase(c)) {
177N/A leftoverBase = c;
177N/A } else {
177N/A db = encodeChar(c);
354N/A if (db <= MAX_SINGLEBYTE) { // SingleByte
354N/A if (dl <= dp)
354N/A return CoderResult.OVERFLOW;
354N/A da[dp++] = (byte)db;
354N/A } else if (db != UNMAPPABLE) { // DoubleByte
177N/A if (dl - dp < 2)
177N/A return CoderResult.OVERFLOW;
177N/A da[dp++] = (byte)(db >> 8);
177N/A da[dp++] = (byte)db;
177N/A } else if (Character.isHighSurrogate(c)) {
177N/A if ((sp + 1) == sl)
177N/A return CoderResult.UNDERFLOW;
177N/A char c2 = sa[sp + 1];
177N/A if (!Character.isLowSurrogate(c2))
177N/A return CoderResult.malformedForLength(1);
177N/A db = encodeSurrogate(c, c2);
177N/A if (db == UNMAPPABLE)
177N/A return CoderResult.unmappableForLength(2);
177N/A if (dl - dp < 2)
177N/A return CoderResult.OVERFLOW;
177N/A da[dp++] = (byte)(db >> 8);
177N/A da[dp++] = (byte)db;
177N/A sp++;
354N/A } else if (Character.isLowSurrogate(c)) {
354N/A return CoderResult.malformedForLength(1);
177N/A } else {
177N/A return CoderResult.unmappableForLength(1);
177N/A }
177N/A }
177N/A sp++;
177N/A }
177N/A return CoderResult.UNDERFLOW;
177N/A } finally {
177N/A src.position(sp - src.arrayOffset());
177N/A dst.position(dp - dst.arrayOffset());
177N/A }
177N/A }
177N/A
177N/A protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
177N/A int mark = src.position();
177N/A try {
177N/A while (src.hasRemaining()) {
177N/A int db;
177N/A char c = src.get();
177N/A if (leftoverBase != 0) {
177N/A boolean isComp = false;
177N/A db = encodeComposite(leftoverBase, c);
177N/A if (db == UNMAPPABLE)
177N/A db = encodeChar(leftoverBase);
177N/A else
177N/A isComp = true;
177N/A if (dst.remaining() < 2)
177N/A return CoderResult.OVERFLOW;
177N/A dst.put((byte)(db >> 8));
177N/A dst.put((byte)(db));
177N/A leftoverBase = 0;
177N/A if (isComp) {
177N/A mark++;
177N/A continue;
177N/A }
177N/A }
177N/A if (isCompositeBase(c)) {
177N/A leftoverBase = c;
177N/A } else {
177N/A db = encodeChar(c);
354N/A if (db <= MAX_SINGLEBYTE) { // Single-byte
354N/A if (dst.remaining() < 1)
354N/A return CoderResult.OVERFLOW;
354N/A dst.put((byte)db);
354N/A } else if (db != UNMAPPABLE) { // DoubleByte
177N/A if (dst.remaining() < 2)
177N/A return CoderResult.OVERFLOW;
177N/A dst.put((byte)(db >> 8));
177N/A dst.put((byte)(db));
177N/A } else if (Character.isHighSurrogate(c)) {
177N/A if (!src.hasRemaining()) // Surrogates
177N/A return CoderResult.UNDERFLOW;
177N/A char c2 = src.get();
177N/A if (!Character.isLowSurrogate(c2))
177N/A return CoderResult.malformedForLength(1);
177N/A db = encodeSurrogate(c, c2);
177N/A if (db == UNMAPPABLE)
177N/A return CoderResult.unmappableForLength(2);
177N/A if (dst.remaining() < 2)
177N/A return CoderResult.OVERFLOW;
177N/A dst.put((byte)(db >> 8));
177N/A dst.put((byte)(db));
177N/A mark++;
354N/A } else if (Character.isLowSurrogate(c)) {
354N/A return CoderResult.malformedForLength(1);
177N/A } else {
177N/A return CoderResult.unmappableForLength(1);
177N/A }
177N/A }
177N/A mark++;
177N/A }
177N/A return CoderResult.UNDERFLOW;
177N/A } finally {
177N/A src.position(mark);
177N/A }
177N/A }
177N/A
177N/A protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
177N/A if (src.hasArray() && dst.hasArray())
177N/A return encodeArrayLoop(src, dst);
177N/A else
177N/A return encodeBufferLoop(src, dst);
177N/A }
177N/A
177N/A protected CoderResult implFlush(ByteBuffer dst) {
177N/A if (leftoverBase > 0) {
177N/A if (dst.remaining() < 2)
177N/A return CoderResult.OVERFLOW;
177N/A int db = encodeChar(leftoverBase);
177N/A dst.put((byte)(db >> 8));
177N/A dst.put((byte)(db));
177N/A leftoverBase = 0;
177N/A }
177N/A return CoderResult.UNDERFLOW;
177N/A }
177N/A
177N/A protected void implReset() {
177N/A leftoverBase = 0;
177N/A }
177N/A }
177N/A}