001: /*
002: * @(#)CharToByteDBCS_EBCDIC.java 1.11 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: package sun.io;
028:
029: public abstract class CharToByteDBCS_EBCDIC extends CharToByteConverter {
030: private static final int SBCS = 0;
031: private static final int DBCS = 1;
032: private static final byte SO = 0x0e;
033: private static final byte SI = 0x0f;
034: private int currentState;
035: private char highHalfZoneCode;
036: private byte[] outputByte = new byte[2];
037: protected short index1[];
038: protected String index2;
039: protected String index2a;
040: protected int mask1;
041: protected int mask2;
042: protected int shift;
043:
044: public CharToByteDBCS_EBCDIC() {
045: super ();
046: highHalfZoneCode = 0;
047: currentState = SBCS;
048: }
049:
050: /**
051: * flush out any residual data and reset the buffer state
052: */
053: public int flush(byte[] output, int outStart, int outEnd)
054: throws MalformedInputException,
055: ConversionBufferFullException {
056: int bytesOut = 0;
057: if (highHalfZoneCode != 0) {
058: reset();
059: badInputLength = 0;
060: throw new MalformedInputException();
061: }
062: if (currentState == DBCS) {
063: if (outStart >= outEnd)
064: throw new ConversionBufferFullException();
065: output[outStart] = SI;
066: bytesOut++;
067: }
068: reset();
069: return bytesOut;
070: }
071:
072: /**
073: * Character conversion
074: */
075: public int convert(char[] input, int inOff, int inEnd,
076: byte[] output, int outOff, int outEnd)
077: throws UnknownCharacterException, MalformedInputException,
078: ConversionBufferFullException {
079: char inputChar;
080: int inputSize;
081: byteOff = outOff;
082: charOff = inOff;
083: while (charOff < inEnd) {
084: int index;
085: int theBytes;
086: int spaceNeeded;
087: if (highHalfZoneCode == 0) {
088: inputChar = input[charOff];
089: inputSize = 1;
090: } else {
091: inputChar = highHalfZoneCode;
092: inputSize = 0;
093: highHalfZoneCode = 0;
094: }
095: // Is this a high surrogate?
096: if (inputChar >= '\ud800' && inputChar <= '\udbff') {
097: // Is this the last character of the input?
098: if (charOff + inputSize >= inEnd) {
099: highHalfZoneCode = inputChar;
100: charOff += inputSize;
101: break;
102: }
103: // Is there a low surrogate following?
104: inputChar = input[charOff + inputSize];
105: if (inputChar >= '\udc00' && inputChar <= '\udfff') {
106: // We have a valid surrogate pair. Too bad we don't do
107: // surrogates. Is substitution enabled?
108: if (subMode) {
109: if (subBytes.length == 1) {
110: outputByte[0] = 0x00;
111: outputByte[1] = subBytes[0];
112: } else {
113: outputByte[0] = subBytes[0];
114: outputByte[1] = subBytes[1];
115: }
116: inputSize++;
117: } else {
118: badInputLength = 2;
119: throw new UnknownCharacterException();
120: }
121: } else {
122: // We have a malformed surrogate pair
123: badInputLength = 1;
124: throw new MalformedInputException();
125: }
126: } // Is this an unaccompanied low surrogate?
127: else if (inputChar >= '\uDC00' && inputChar <= '\uDFFF') {
128: badInputLength = 1;
129: throw new MalformedInputException();
130: } else {
131: // We have a valid character, get the bytes for it
132: index = index1[((inputChar & mask1) >> shift)]
133: + (inputChar & mask2);
134: if (index < 15000)
135: theBytes = (int) (index2.charAt(index));
136: else
137: theBytes = (int) (index2a.charAt(index - 15000));
138: outputByte[0] = (byte) ((theBytes & 0x0000ff00) >> 8);
139: outputByte[1] = (byte) (theBytes & 0x000000ff);
140: }
141: // if there was no mapping - look for substitution characters
142: if (outputByte[0] == 0x00 && outputByte[1] == 0x00
143: && inputChar != '\u0000') {
144: if (subMode) {
145: if (subBytes.length == 1) {
146: outputByte[0] = 0x00;
147: outputByte[1] = subBytes[0];
148: } else {
149: outputByte[0] = subBytes[0];
150: outputByte[1] = subBytes[1];
151: }
152: } else {
153: badInputLength = 1;
154: throw new UnknownCharacterException();
155: }
156: }
157: //Set the output buffer into the correct state
158:
159: if (currentState == DBCS && outputByte[0] == 0x00) {
160: if (byteOff >= outEnd)
161: throw new ConversionBufferFullException();
162: currentState = SBCS;
163: output[byteOff++] = SI;
164: } else if (currentState == SBCS && outputByte[0] != 0x00) {
165: if (byteOff >= outEnd)
166: throw new ConversionBufferFullException();
167: currentState = DBCS;
168: output[byteOff++] = SO;
169: }
170: if (currentState == DBCS)
171: spaceNeeded = 2;
172: else
173: spaceNeeded = 1;
174: if (byteOff + spaceNeeded > outEnd)
175: throw new ConversionBufferFullException();
176: if (currentState == SBCS)
177: output[byteOff++] = outputByte[1];
178: else {
179: output[byteOff++] = outputByte[0];
180: output[byteOff++] = outputByte[1];
181: }
182: charOff += inputSize;
183: }
184: return byteOff - outOff;
185: }
186:
187: /**
188: * Resets converter to its initial state.
189: */
190: public void reset() {
191: charOff = byteOff = 0;
192: highHalfZoneCode = 0;
193: currentState = SBCS;
194: }
195:
196: /**
197: * Returns the maximum number of bytes needed to convert a char.
198: */
199: public int getMaxBytesPerChar() {
200: return 3;
201: }
202:
203: /**
204: * Sets the substitution bytes to use when the converter is in
205: * substitution mode. The given bytes should represent a valid
206: * character in the target character encoding.
207: */
208:
209: public void setSubstitutionBytes(byte[] newSubBytes)
210: throws IllegalArgumentException {
211: if (newSubBytes.length > 2 || newSubBytes.length == 0) {
212: throw new IllegalArgumentException();
213: }
214: subBytes = new byte[newSubBytes.length];
215: System.arraycopy(newSubBytes, 0, subBytes, 0,
216: newSubBytes.length);
217: }
218:
219: /**
220: * Returns true if the given character can be converted to the
221: * target character encoding.
222: */
223: public boolean canConvert(char ch) {
224: int index;
225: int theBytes;
226: index = index1[((ch & mask1) >> shift)] + (ch & mask2);
227: if (index < 15000)
228: theBytes = (int) (index2.charAt(index));
229: else
230: theBytes = (int) (index2a.charAt(index - 15000));
231: if (theBytes != 0)
232: return (true);
233: // only return true if input char was unicode null - all others are
234: // undefined
235: return (ch == '\u0000');
236: }
237: }
|