/* * Copyright (c) 2008, 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.CharsetEncoder;import java.nio.charset.CharsetDecoder;import java.nio.charset.CoderResult;import java.util.Arrays;import sun.nio.cs.CharsetMapping; /* * 5 types of entry in SJIS_X_0213/Unicode mapping table * * (1)Single-Byte * JIS_X_0213 does not define single-byte character itself, the * JIS_X_0201 entries are added in for sjis implementation. * * (2)Double-Byte SJIS <-> BMP Unicode * ex: 0x8140 U+3000 # IDEOGRAPHIC SPACE * * (3)Double-Byte SJIS <-> Supplementary * ex: 0xFCF0 U+2A61A # <cjk> [2000] [Unicode3.1] * * (4)Double-Byte SJIS <-> Composite * ex: 0x83F6 U+31F7+309A # [2000] * * (5)"Windows-only" special mapping entries * are handled by MS932_0213. */ public class SJIS_0213 extends Charset { public SJIS_0213() { super("x-SJIS_0213", ExtendedCharsets.aliasesFor("SJIS_0213")); } public boolean contains(Charset cs) { return ((cs.name().equals("US-ASCII")) || (cs instanceof SJIS) || (cs instanceof SJIS_0213)); } public CharsetDecoder newDecoder() { return new Decoder(this); } public CharsetEncoder newEncoder() { return new Encoder(this); } static CharsetMapping mapping = CharsetMapping.get(SJIS_0213.class.getResourceAsStream("sjis0213.dat")); protected static class Decoder extends CharsetDecoder { protected static final char UNMAPPABLE = CharsetMapping.UNMAPPABLE_DECODING; protected Decoder(Charset cs) { super(cs, 0.5f, 1.0f); } private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { byte[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); char[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); try { while (sp < sl) { int b1 = sa[sp] & 0xff; char c = decodeSingle(b1); int inSize = 1, outSize = 1; char[] cc = null; if (c == UNMAPPABLE) { if (sl - sp < 2) return CoderResult.UNDERFLOW; int b2 = sa[sp + 1] & 0xff; c = decodeDouble(b1, b2); inSize++; if (c == UNMAPPABLE) { cc = decodeDoubleEx(b1, b2); if (cc == null) { if (decodeSingle(b2) == UNMAPPABLE) return CoderResult.unmappableForLength(2); else return CoderResult.unmappableForLength(1); } outSize++; } } if (dl - dp < outSize) return CoderResult.OVERFLOW; if (outSize == 2) { da[dp++] = cc[0]; da[dp++] = cc[1]; } else { da[dp++] = c; } sp += inSize; } 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(); try { while (src.hasRemaining()) { char[] cc = null; int b1 = src.get() & 0xff; char c = decodeSingle(b1); int inSize = 1, outSize = 1; if (c == UNMAPPABLE) { if (src.remaining() < 1) return CoderResult.UNDERFLOW; int b2 = src.get() & 0xff; inSize++; c = decodeDouble(b1, b2); if (c == UNMAPPABLE) { cc = decodeDoubleEx(b1, b2); if (cc == null) { if (decodeSingle(b2) == UNMAPPABLE) return CoderResult.unmappableForLength(2); else return CoderResult.unmappableForLength(1); } outSize++; } } if (dst.remaining() < outSize) return CoderResult.OVERFLOW; if (outSize == 2) { dst.put(cc[0]); dst.put(cc[1]); } else { dst.put(c); } mark += inSize; } return CoderResult.UNDERFLOW; } finally { src.position(mark); } } protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { if (src.hasArray() && dst.hasArray()) return decodeArrayLoop(src, dst); else return decodeBufferLoop(src, dst); } protected char decodeSingle(int b) { return mapping.decodeSingle(b); } protected char decodeDouble(int b1, int b2) { return mapping.decodeDouble(b1, b2); } private char[] cc = new char[2]; private CharsetMapping.Entry comp = new CharsetMapping.Entry(); protected char[] decodeDoubleEx(int b1, int b2) { int db = (b1 << 8) | b2; if (mapping.decodeSurrogate(db, cc) != null) return cc; comp.bs = db; if (mapping.decodeComposite(comp, cc) != null) return cc; return null; } } protected static class Encoder extends CharsetEncoder { protected static final int UNMAPPABLE = CharsetMapping.UNMAPPABLE_ENCODING; protected static final int MAX_SINGLEBYTE = 0xff; protected Encoder(Charset cs) { super(cs, 2.0f, 2.0f); } public boolean canEncode(char c) { return (encodeChar(c) != UNMAPPABLE); } protected int encodeChar(char ch) { return mapping.encodeChar(ch); } protected int encodeSurrogate(char hi, char lo) { return mapping.encodeSurrogate(hi, lo); } private CharsetMapping.Entry comp = new CharsetMapping.Entry(); protected int encodeComposite(char base, char cc) { comp.cp = base; comp.cp2 = cc; return mapping.encodeComposite(comp); } protected boolean isCompositeBase(char ch) { comp.cp = ch; return mapping.isCompositeBase(comp); } // Unlike surrogate pair, the base character of a base+cc composite // itself is a legal codepoint in 0213, if we simply return UNDERFLOW // when a base candidate is the last input char in the CharBuffer, like // what we do for the surrogte pair, encoding will fail if this base // character is indeed the last character of the input char sequence. // Keep this base candidate in "leftoverBase" so we can flush it out // at the end of the encoding circle. char leftoverBase = 0; protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { char[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); byte[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); try { while (sp < sl) { int db; char c = sa[sp]; if (leftoverBase != 0) { boolean isComp = false; db = encodeComposite(leftoverBase, c); if (db == UNMAPPABLE) db = encodeChar(leftoverBase); else isComp = true; if (dl - dp < 2) return CoderResult.OVERFLOW; da[dp++] = (byte)(db >> 8); da[dp++] = (byte)db; leftoverBase = 0; if (isComp) { sp++; continue; } } if (isCompositeBase(c)) { leftoverBase = c; } else { db = encodeChar(c); if (db <= MAX_SINGLEBYTE) { // SingleByte if (dl <= dp) return CoderResult.OVERFLOW; da[dp++] = (byte)db; } else if (db != UNMAPPABLE) { // DoubleByte if (dl - dp < 2) return CoderResult.OVERFLOW; da[dp++] = (byte)(db >> 8); da[dp++] = (byte)db; } else if (Character.isHighSurrogate(c)) { if ((sp + 1) == sl) return CoderResult.UNDERFLOW; char c2 = sa[sp + 1]; if (!Character.isLowSurrogate(c2)) return CoderResult.malformedForLength(1); db = encodeSurrogate(c, c2); if (db == UNMAPPABLE) return CoderResult.unmappableForLength(2); if (dl - dp < 2) return CoderResult.OVERFLOW; da[dp++] = (byte)(db >> 8); da[dp++] = (byte)db; sp++; } else if (Character.isLowSurrogate(c)) { return CoderResult.malformedForLength(1); } else { return CoderResult.unmappableForLength(1); } } sp++; } return CoderResult.UNDERFLOW; } finally { src.position(sp - src.arrayOffset()); dst.position(dp - dst.arrayOffset()); } } protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { int mark = src.position(); try { while (src.hasRemaining()) { int db; char c = src.get(); if (leftoverBase != 0) { boolean isComp = false; db = encodeComposite(leftoverBase, c); if (db == UNMAPPABLE) db = encodeChar(leftoverBase); else isComp = true; if (dst.remaining() < 2) return CoderResult.OVERFLOW; dst.put((byte)(db >> 8)); dst.put((byte)(db)); leftoverBase = 0; if (isComp) { mark++; continue; } } if (isCompositeBase(c)) { leftoverBase = c; } else { db = encodeChar(c); if (db <= MAX_SINGLEBYTE) { // Single-byte if (dst.remaining() < 1) return CoderResult.OVERFLOW; dst.put((byte)db); } else if (db != UNMAPPABLE) { // DoubleByte if (dst.remaining() < 2) return CoderResult.OVERFLOW; dst.put((byte)(db >> 8)); dst.put((byte)(db)); } else if (Character.isHighSurrogate(c)) { if (!src.hasRemaining()) // Surrogates return CoderResult.UNDERFLOW; char c2 = src.get(); if (!Character.isLowSurrogate(c2)) return CoderResult.malformedForLength(1); db = encodeSurrogate(c, c2); if (db == UNMAPPABLE) return CoderResult.unmappableForLength(2); if (dst.remaining() < 2) return CoderResult.OVERFLOW; dst.put((byte)(db >> 8)); dst.put((byte)(db)); mark++; } else if (Character.isLowSurrogate(c)) { return CoderResult.malformedForLength(1); } else { return CoderResult.unmappableForLength(1); } } mark++; } return CoderResult.UNDERFLOW; } finally { src.position(mark); } } protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { if (src.hasArray() && dst.hasArray()) return encodeArrayLoop(src, dst); else return encodeBufferLoop(src, dst); } protected CoderResult implFlush(ByteBuffer dst) { if (leftoverBase > 0) { if (dst.remaining() < 2) return CoderResult.OVERFLOW; int db = encodeChar(leftoverBase); dst.put((byte)(db >> 8)); dst.put((byte)(db)); leftoverBase = 0; } return CoderResult.UNDERFLOW; } protected void implReset() { leftoverBase = 0; } }}
/*
* Copyright (c) 2008, 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.CharsetEncoder;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.util.Arrays;
import sun.nio.cs.CharsetMapping;
/*
* 5 types of entry in SJIS_X_0213/Unicode mapping table
*
* (1)Single-Byte
* JIS_X_0213 does not define single-byte character itself, the
* JIS_X_0201 entries are added in for sjis implementation.
*
* (2)Double-Byte SJIS <-> BMP Unicode
* ex: 0x8140 U+3000 # IDEOGRAPHIC SPACE
*
* (3)Double-Byte SJIS <-> Supplementary
* ex: 0xFCF0 U+2A61A # <cjk> [2000] [Unicode3.1]
*
* (4)Double-Byte SJIS <-> Composite
* ex: 0x83F6 U+31F7+309A # [2000]
*
* (5)"Windows-only" special mapping entries
* are handled by MS932_0213.
*/
public class SJIS_0213 extends Charset {
public SJIS_0213() {
super("x-SJIS_0213", ExtendedCharsets.aliasesFor("SJIS_0213"));
}
public boolean contains(Charset cs) {
return ((cs.name().equals("US-ASCII"))
|| (cs instanceof SJIS)
|| (cs instanceof SJIS_0213));
}
public CharsetDecoder newDecoder() {
return new Decoder(this);
}
public CharsetEncoder newEncoder() {
return new Encoder(this);
}
static CharsetMapping mapping =
CharsetMapping.get(SJIS_0213.class.getResourceAsStream("sjis0213.dat"));
protected static class Decoder extends CharsetDecoder {
protected static final char UNMAPPABLE = CharsetMapping.UNMAPPABLE_DECODING;
protected Decoder(Charset cs) {
super(cs, 0.5f, 1.0f);
}
private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
try {
while (sp < sl) {
int b1 = sa[sp] & 0xff;
char c = decodeSingle(b1);
int inSize = 1, outSize = 1;
char[] cc = null;
if (c == UNMAPPABLE) {
if (sl - sp < 2)
return CoderResult.UNDERFLOW;
int b2 = sa[sp + 1] & 0xff;
c = decodeDouble(b1, b2);
inSize++;
if (c == UNMAPPABLE) {
cc = decodeDoubleEx(b1, b2);
if (cc == null) {
if (decodeSingle(b2) == UNMAPPABLE)
return CoderResult.unmappableForLength(2);
else
return CoderResult.unmappableForLength(1);
}
outSize++;
}
}
if (dl - dp < outSize)
return CoderResult.OVERFLOW;
if (outSize == 2) {
da[dp++] = cc[0];
da[dp++] = cc[1];
} else {
da[dp++] = c;
}
sp += inSize;
}
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();
try {
while (src.hasRemaining()) {
char[] cc = null;
int b1 = src.get() & 0xff;
char c = decodeSingle(b1);
int inSize = 1, outSize = 1;
if (c == UNMAPPABLE) {
if (src.remaining() < 1)
return CoderResult.UNDERFLOW;
int b2 = src.get() & 0xff;
inSize++;
c = decodeDouble(b1, b2);
if (c == UNMAPPABLE) {
cc = decodeDoubleEx(b1, b2);
if (cc == null) {
if (decodeSingle(b2) == UNMAPPABLE)
return CoderResult.unmappableForLength(2);
else
return CoderResult.unmappableForLength(1);
}
outSize++;
}
}
if (dst.remaining() < outSize)
return CoderResult.OVERFLOW;
if (outSize == 2) {
dst.put(cc[0]);
dst.put(cc[1]);
} else {
dst.put(c);
}
mark += inSize;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
if (src.hasArray() && dst.hasArray())
return decodeArrayLoop(src, dst);
else
return decodeBufferLoop(src, dst);
}
protected char decodeSingle(int b) {
return mapping.decodeSingle(b);
}
protected char decodeDouble(int b1, int b2) {
return mapping.decodeDouble(b1, b2);
}
private char[] cc = new char[2];
private CharsetMapping.Entry comp = new CharsetMapping.Entry();
protected char[] decodeDoubleEx(int b1, int b2) {
int db = (b1 << 8) | b2;
if (mapping.decodeSurrogate(db, cc) != null)
return cc;
comp.bs = db;
if (mapping.decodeComposite(comp, cc) != null)
return cc;
return null;
}
}
protected static class Encoder extends CharsetEncoder {
protected static final int UNMAPPABLE = CharsetMapping.UNMAPPABLE_ENCODING;
protected static final int MAX_SINGLEBYTE = 0xff;
protected Encoder(Charset cs) {
super(cs, 2.0f, 2.0f);
}
public boolean canEncode(char c) {
return (encodeChar(c) != UNMAPPABLE);
}
protected int encodeChar(char ch) {
return mapping.encodeChar(ch);
}
protected int encodeSurrogate(char hi, char lo) {
return mapping.encodeSurrogate(hi, lo);
}
private CharsetMapping.Entry comp = new CharsetMapping.Entry();
protected int encodeComposite(char base, char cc) {
comp.cp = base;
comp.cp2 = cc;
return mapping.encodeComposite(comp);
}
protected boolean isCompositeBase(char ch) {
comp.cp = ch;
return mapping.isCompositeBase(comp);
}
// Unlike surrogate pair, the base character of a base+cc composite
// itself is a legal codepoint in 0213, if we simply return UNDERFLOW
// when a base candidate is the last input char in the CharBuffer, like
// what we do for the surrogte pair, encoding will fail if this base
// character is indeed the last character of the input char sequence.
// Keep this base candidate in "leftoverBase" so we can flush it out
// at the end of the encoding circle.
char leftoverBase = 0;
protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
char[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
byte[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
try {
while (sp < sl) {
int db;
char c = sa[sp];
if (leftoverBase != 0) {
boolean isComp = false;
db = encodeComposite(leftoverBase, c);
if (db == UNMAPPABLE)
db = encodeChar(leftoverBase);
else
isComp = true;
if (dl - dp < 2)
return CoderResult.OVERFLOW;
da[dp++] = (byte)(db >> 8);
da[dp++] = (byte)db;
leftoverBase = 0;
if (isComp) {
sp++;
continue;
}
}
if (isCompositeBase(c)) {
leftoverBase = c;
} else {
db = encodeChar(c);
if (db <= MAX_SINGLEBYTE) { // SingleByte
if (dl <= dp)
return CoderResult.OVERFLOW;
da[dp++] = (byte)db;
} else if (db != UNMAPPABLE) { // DoubleByte
if (dl - dp < 2)
return CoderResult.OVERFLOW;
da[dp++] = (byte)(db >> 8);
da[dp++] = (byte)db;
} else if (Character.isHighSurrogate(c)) {
if ((sp + 1) == sl)
return CoderResult.UNDERFLOW;
char c2 = sa[sp + 1];
if (!Character.isLowSurrogate(c2))
return CoderResult.malformedForLength(1);
db = encodeSurrogate(c, c2);
if (db == UNMAPPABLE)
return CoderResult.unmappableForLength(2);
if (dl - dp < 2)
return CoderResult.OVERFLOW;
da[dp++] = (byte)(db >> 8);
da[dp++] = (byte)db;
sp++;
} else if (Character.isLowSurrogate(c)) {
return CoderResult.malformedForLength(1);
} else {
return CoderResult.unmappableForLength(1);
}
}
sp++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
}
}
protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
int mark = src.position();
try {
while (src.hasRemaining()) {
int db;
char c = src.get();
if (leftoverBase != 0) {
boolean isComp = false;
db = encodeComposite(leftoverBase, c);
if (db == UNMAPPABLE)
db = encodeChar(leftoverBase);
else
isComp = true;
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
dst.put((byte)(db >> 8));
dst.put((byte)(db));
leftoverBase = 0;
if (isComp) {
mark++;
continue;
}
}
if (isCompositeBase(c)) {
leftoverBase = c;
} else {
db = encodeChar(c);
if (db <= MAX_SINGLEBYTE) { // Single-byte
if (dst.remaining() < 1)
return CoderResult.OVERFLOW;
dst.put((byte)db);
} else if (db != UNMAPPABLE) { // DoubleByte
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
dst.put((byte)(db >> 8));
dst.put((byte)(db));
} else if (Character.isHighSurrogate(c)) {
if (!src.hasRemaining()) // Surrogates
return CoderResult.UNDERFLOW;
char c2 = src.get();
if (!Character.isLowSurrogate(c2))
return CoderResult.malformedForLength(1);
db = encodeSurrogate(c, c2);
if (db == UNMAPPABLE)
return CoderResult.unmappableForLength(2);
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
dst.put((byte)(db >> 8));
dst.put((byte)(db));
mark++;
} else if (Character.isLowSurrogate(c)) {
return CoderResult.malformedForLength(1);
} else {
return CoderResult.unmappableForLength(1);
}
}
mark++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(mark);
}
}
protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
if (src.hasArray() && dst.hasArray())
return encodeArrayLoop(src, dst);
else
return encodeBufferLoop(src, dst);
}
protected CoderResult implFlush(ByteBuffer dst) {
if (leftoverBase > 0) {
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
int db = encodeChar(leftoverBase);
dst.put((byte)(db >> 8));
dst.put((byte)(db));
leftoverBase = 0;
}
return CoderResult.UNDERFLOW;
}
protected void implReset() {
leftoverBase = 0;
}
}
}