0N/A/*
2362N/A * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/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
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/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.
0N/A */
0N/A
0N/Apackage sun.io;
0N/Aimport java.io.*;
0N/A
0N/Apublic class CharToByteISO2022JP extends CharToByteJIS0208 {
0N/A
0N/A private static final int ASCII = 0; // ESC ( B
0N/A private static final int JISX0201_1976 = 1; // ESC ( J
0N/A private static final int JISX0208_1978 = 2; // ESC $ @
0N/A private static final int JISX0208_1983 = 3; // ESC $ B
0N/A private static final int JISX0201_1976_KANA = 4; // ESC ( I
0N/A
0N/A private char highHalfZoneCode;
0N/A private boolean flushed = true;
0N/A
0N/A // JIS is state full encoding, so currentMode keep the
0N/A // current codeset
0N/A private int currentMode = ASCII;
0N/A
0N/A /**
0N/A * Bytes for substitute for unmappable input.
0N/A */
0N/A // XXX: Assumes subBytes are ASCII string. Need to change Escape sequence
0N/A // for other character sets.
0N/A protected byte[] subBytesEscape = { (byte)0x1b, (byte)0x28, (byte)0x42 }; // ESC ( B
0N/A protected int subBytesMode = ASCII;
0N/A
0N/A public int flush(byte[] output, int outStart, int outEnd)
0N/A throws MalformedInputException, ConversionBufferFullException
0N/A {
0N/A if (highHalfZoneCode != 0) {
0N/A highHalfZoneCode = 0;
0N/A badInputLength = 0;
0N/A throw new MalformedInputException();
0N/A }
0N/A
0N/A if (!flushed && (currentMode != ASCII)) {
0N/A if (outEnd - outStart < 3) {
0N/A throw new ConversionBufferFullException();
0N/A }
0N/A output[outStart] = (byte)0x1b;
0N/A output[outStart + 1] = (byte)0x28;
0N/A output[outStart + 2] = (byte)0x42;
0N/A byteOff += 3;
0N/A byteOff = charOff = 0;
0N/A flushed = true;
0N/A currentMode = ASCII;
0N/A return 3;
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A public int convert(char[] input, int inOff, int inEnd,
0N/A byte[] output, int outOff, int outEnd)
0N/A throws MalformedInputException, UnknownCharacterException,
0N/A ConversionBufferFullException
0N/A
0N/A {
0N/A char inputChar; // Input character to be converted
0N/A int inputSize; // Size of the input
0N/A int outputSize; // Size of the output
0N/A
0N/A // Buffer for output bytes
0N/A byte[] tmpArray = new byte[6];
0N/A byte[] outputByte;
0N/A
0N/A flushed = false;
0N/A
0N/A // Make copies of input and output indexes
0N/A charOff = inOff;
0N/A byteOff = outOff;
0N/A
0N/A if (highHalfZoneCode != 0) {
0N/A inputChar = highHalfZoneCode;
0N/A highHalfZoneCode = 0;
0N/A if (input[inOff] >= 0xdc00 && input[inOff] <= 0xdfff) {
0N/A // This is legal UTF16 sequence.
0N/A badInputLength = 1;
0N/A throw new UnknownCharacterException();
0N/A } else {
0N/A // This is illegal UTF16 sequence.
0N/A badInputLength = 0;
0N/A throw new MalformedInputException();
0N/A }
0N/A }
0N/A
0N/A // Loop until we run out of input
0N/A while(charOff < inEnd) {
0N/A outputByte = tmpArray;
0N/A int newMode = currentMode; // Trace character mode changing
0N/A
0N/A // Get the input character
0N/A inputChar = input[charOff];
0N/A inputSize = 1;
0N/A outputSize = 1;
0N/A
0N/A // Is this a high surrogate?
0N/A if(inputChar >= '\uD800' && inputChar <= '\uDBFF') {
0N/A // Is this the last character of the input?
0N/A if (charOff + 1 >= inEnd) {
0N/A highHalfZoneCode = inputChar;
0N/A break;
0N/A }
0N/A
0N/A // Is there a low surrogate following?
0N/A inputChar = input[charOff + 1];
0N/A if (inputChar >= '\uDC00' && inputChar <= '\uDFFF') {
0N/A // We have a valid surrogate pair. Too bad we don't do
0N/A // surrogates. Is substitution enabled?
0N/A if (subMode) {
0N/A if (currentMode != subBytesMode) {
0N/A System.arraycopy(subBytesEscape, 0, outputByte, 0,
0N/A subBytesEscape.length);
0N/A outputSize = subBytesEscape.length;
0N/A System.arraycopy(subBytes, 0, outputByte,
0N/A outputSize, subBytes.length);
0N/A outputSize += subBytes.length;
0N/A newMode = subBytesMode;
0N/A } else {
0N/A outputByte = subBytes;
0N/A outputSize = subBytes.length;
0N/A }
0N/A inputSize = 2;
0N/A } else {
0N/A badInputLength = 2;
0N/A throw new UnknownCharacterException();
0N/A }
0N/A } else {
0N/A // We have a malformed surrogate pair
0N/A badInputLength = 1;
0N/A throw new MalformedInputException();
0N/A }
0N/A }
0N/A
0N/A // Is this an unaccompanied low surrogate?
0N/A else if (inputChar >= '\uDC00' && inputChar <= '\uDFFF') {
0N/A badInputLength = 1;
0N/A throw new MalformedInputException();
0N/A } else {
0N/A // Not part of a surrogate
0N/A
0N/A // Does this map to the Roman range?
0N/A if (inputChar <= '\u007F') {
0N/A if (currentMode != ASCII) {
0N/A outputByte[0] = (byte)0x1b;
0N/A outputByte[1] = (byte)0x28;
0N/A outputByte[2] = (byte)0x42;
0N/A outputByte[3] = (byte)inputChar;
0N/A outputSize = 4;
0N/A newMode = ASCII;
0N/A } else {
0N/A outputByte[0] = (byte)inputChar;
0N/A outputSize = 1;
0N/A }
0N/A }
0N/A // Is it a single byte kana?
0N/A else if (inputChar >= 0xFF61 && inputChar <= 0xFF9F) {
0N/A if (currentMode != JISX0201_1976_KANA) {
0N/A outputByte[0] = (byte)0x1b;
0N/A outputByte[1] = (byte)0x28;
0N/A outputByte[2] = (byte)0x49;
0N/A outputByte[3] = (byte)(inputChar - 0xff40);
0N/A outputSize = 4;
0N/A newMode = JISX0201_1976_KANA;
0N/A } else {
0N/A outputByte[0] = (byte)(inputChar - 0xff40);
0N/A outputSize = 1;
0N/A }
0N/A }
0N/A // Is it a yen sign?
0N/A else if (inputChar == '\u00A5') {
0N/A if (currentMode != JISX0201_1976) {
0N/A outputByte[0] = (byte)0x1b;
0N/A outputByte[1] = (byte)0x28;
0N/A outputByte[2] = (byte)0x4a;
0N/A outputByte[3] = (byte)0x5c;
0N/A outputSize = 4;
0N/A newMode = JISX0201_1976;
0N/A } else {
0N/A outputByte[0] = (byte)0x5C;
0N/A outputSize = 1;
0N/A }
0N/A }
0N/A // Is it a tilde?
0N/A else if (inputChar == '\u203E')
0N/A {
0N/A if (currentMode != JISX0201_1976) {
0N/A outputByte[0] = (byte)0x1b;
0N/A outputByte[1] = (byte)0x28;
0N/A outputByte[2] = (byte)0x4a;
0N/A outputByte[3] = (byte)0x7e;
0N/A outputSize = 4;
0N/A newMode = JISX0201_1976;
0N/A } else {
0N/A outputByte[0] = (byte)0x7e;
0N/A outputSize = 1;
0N/A }
0N/A }
0N/A // Is it a JIS-X-0208 character?
0N/A else {
0N/A int index = getNative(inputChar);
0N/A if (index != 0) {
0N/A if (currentMode != JISX0208_1983) {
0N/A outputByte[0] = (byte)0x1b;
0N/A outputByte[1] = (byte)0x24;
0N/A outputByte[2] = (byte)0x42;
0N/A outputByte[3] = (byte)(index >> 8);
0N/A outputByte[4] = (byte)(index & 0xff);
0N/A outputSize = 5;
0N/A newMode = JISX0208_1983;
0N/A } else {
0N/A outputByte[0] = (byte)(index >> 8);
0N/A outputByte[1] = (byte)(index & 0xff);
0N/A outputSize = 2;
0N/A }
0N/A }
0N/A // It doesn't map to JIS-0208!
0N/A else {
0N/A if (subMode) {
0N/A if (currentMode != subBytesMode) {
0N/A System.arraycopy(subBytesEscape, 0, outputByte, 0,
0N/A subBytesEscape.length);
0N/A outputSize = subBytesEscape.length;
0N/A System.arraycopy(subBytes, 0, outputByte,
0N/A outputSize, subBytes.length);
0N/A outputSize += subBytes.length;
0N/A newMode = subBytesMode;
0N/A } else {
0N/A outputByte = subBytes;
0N/A outputSize = subBytes.length;
0N/A }
0N/A } else {
0N/A badInputLength = 1;
0N/A throw new UnknownCharacterException();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Is there room in the output buffer?
0N/A // XXX: The code assumes output buffer can hold at least 5 bytes,
0N/A // in this coverter case. However, there is no way for apps to
0N/A // see how many bytes will be necessary for next call.
0N/A // getMaxBytesPerChar() should be overriden in every subclass of
0N/A // CharToByteConverter and reflect real value (5 for this).
0N/A if (byteOff + outputSize > outEnd)
0N/A throw new ConversionBufferFullException();
0N/A
0N/A // Put the output into the buffer
0N/A for ( int i = 0 ; i < outputSize ; i++ )
0N/A output[byteOff++] = outputByte[i];
0N/A
0N/A // Advance the input pointer
0N/A charOff += inputSize;
0N/A
0N/A // We can successfuly output the characters, changes
0N/A // current mode. Fix for 4251646.
0N/A currentMode = newMode;
0N/A }
0N/A
0N/A // return mode ASCII at the end
0N/A if (currentMode != ASCII){
0N/A if (byteOff + 3 > outEnd)
0N/A throw new ConversionBufferFullException();
0N/A
0N/A output[byteOff++] = 0x1b;
0N/A output[byteOff++] = 0x28;
0N/A output[byteOff++] = 0x42;
0N/A currentMode = ASCII;
0N/A }
0N/A
0N/A // Return the length written to the output buffer
0N/A return byteOff-outOff;
0N/A }
0N/A
0N/A // Reset
0N/A public void reset() {
0N/A highHalfZoneCode = 0;
0N/A byteOff = charOff = 0;
0N/A currentMode = ASCII;
0N/A }
0N/A
0N/A /**
0N/A * returns the maximum number of bytes needed to convert a char
0N/A */
0N/A public int getMaxBytesPerChar() {
0N/A return 8;
0N/A }
0N/A
0N/A // Return the character set ID
0N/A public String getCharacterEncoding() {
0N/A return "ISO2022JP";
0N/A }
0N/A
0N/A}