1/*
2 * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 */
28
29
30import java.nio.ByteBuffer;
31import java.nio.CharBuffer;
32import java.nio.charset.Charset;
33import java.nio.charset.CharsetDecoder;
34import java.nio.charset.CoderResult;
35
36/**
37 * An abstract base class for subclasses which decode
38 * IBM double byte ebcdic host encodings such as ibm code
39 * pages 933, 935, 937,... etc
40 *
41 */
42
43public abstract class DBCS_IBM_EBCDIC_Decoder extends CharsetDecoder
44{
45
46    private DBCSDecoderMapping decoderMapping;
47    protected static final char REPLACE_CHAR='\uFFFD';
48
49    protected String  singleByteToChar;
50    protected short   index1[];
51    protected String  index2;
52    protected int     mask1;
53    protected int     mask2;
54    protected int     shift;
55
56    private static final int SBCS = 0;
57    private static final int DBCS = 1;
58
59    private static final int SO = 0x0e;
60    private static final int SI = 0x0f;
61    private int  currentState;
62
63    protected DBCS_IBM_EBCDIC_Decoder(Charset cs) {
64        super(cs, 0.5f, 1.0f);
65    }
66
67    protected void implReset() {
68        currentState = SBCS;
69    }
70
71    private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
72        byte[] sa = src.array();
73        int sp = src.arrayOffset() + src.position();
74        int sl = src.arrayOffset() + src.limit();
75        assert (sp <= sl);
76        sp = (sp <= sl ? sp : sl);
77        char[] da = dst.array();
78        int dp = dst.arrayOffset() + dst.position();
79        int dl = dst.arrayOffset() + dst.limit();
80        assert (dp <= dl);
81        dp = (dp <= dl ? dp : dl);
82
83        try {
84            while (sp < sl) {
85                int b1, b2;
86                b1 = sa[sp];
87                int inputSize = 1;
88                int v = 0;
89                char outputChar = REPLACE_CHAR;
90
91                if (b1 < 0)
92                    b1 += 256;
93
94                if (b1 == SO) {  // Shift out
95                    // For SO characters - simply validate the state and if OK
96                    //    update the state and go to the next byte
97
98                    if (currentState != SBCS)
99                        return CoderResult.malformedForLength(1);
100                    else
101                        currentState = DBCS;
102                } else if (b1 == SI) {
103                    // For SI characters - simply validate the state and if OK
104                    //    update the state and go to the next byte
105
106                    if (currentState != DBCS) {
107                        return CoderResult.malformedForLength(1);
108                    } else {
109                        currentState = SBCS;
110                    }
111                } else {
112                    if (currentState == SBCS) {
113                        outputChar = singleByteToChar.charAt(b1);
114                    } else {
115                    if (sl - sp < 2)
116                        return CoderResult.UNDERFLOW;
117                    b2 = sa[sp + 1];
118                    if (b2 < 0)
119                        b2 += 256;
120
121                    inputSize++;
122
123                    // Check validity of dbcs ebcdic byte pair values
124                    if ((b1 != 0x40 || b2 != 0x40) &&
125                      (b2 < 0x41 || b2 > 0xfe)) {
126                      return CoderResult.malformedForLength(2);
127                    }
128
129                    // Lookup in the two level index
130                    v = b1 * 256 + b2;
131                    outputChar = index2.charAt(index1[((v & mask1) >> shift)]
132                                                + (v & mask2));
133                    }
134                    if (outputChar == '\uFFFD')
135                        return CoderResult.unmappableForLength(inputSize);
136
137                    if (dl - dp < 1)
138                        return CoderResult.OVERFLOW;
139                    da[dp++] = outputChar;
140                }
141                sp += inputSize;
142            }
143            return CoderResult.UNDERFLOW;
144        } finally {
145            src.position(sp - src.arrayOffset());
146            dst.position(dp - dst.arrayOffset());
147        }
148    }
149
150    private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
151        int mark = src.position();
152
153        try {
154            while (src.hasRemaining()) {
155                int b1, b2;
156                int v = 0;
157                b1 = src.get();
158                int inputSize = 1;
159                char outputChar = REPLACE_CHAR;
160
161                if (b1 < 0)
162                    b1 += 256;
163
164
165                if (b1 == SO) {  // Shift out
166                    // For SO characters - simply validate the state and if OK
167                    //    update the state and go to the next byte
168
169                    if (currentState != SBCS)
170                        return CoderResult.malformedForLength(1);
171                    else
172                        currentState = DBCS;
173                } else if (b1 == SI) {
174                    // For SI characters - simply validate the state and if OK
175                    //    update the state and go to the next byte
176
177                    if (currentState != DBCS) {
178                        return CoderResult.malformedForLength(1);
179                    } else {
180                        currentState = SBCS;
181                    }
182                } else {
183                    if (currentState == SBCS) {
184                      outputChar = singleByteToChar.charAt(b1);
185                    } else {
186                        if (src.remaining() < 1)
187                            return CoderResult.UNDERFLOW;
188                        b2 = src.get();
189                        if (b2 < 0)
190                            b2 += 256;
191                        inputSize++;
192
193                        // Check validity of dbcs ebcdic byte pair values
194                        if ((b1 != 0x40 || b2 != 0x40) &&
195                           (b2 < 0x41 || b2 > 0xfe)) {
196                          return CoderResult.malformedForLength(2);
197                        }
198
199                        // Lookup in the two level index
200                        v = b1 * 256 + b2;
201                        outputChar = index2.charAt(index1[((v & mask1) >> shift)]
202                                                            + (v & mask2));
203                    }
204                    if (outputChar == REPLACE_CHAR)
205                        return CoderResult.unmappableForLength(inputSize);
206
207                    if (!dst.hasRemaining())
208                        return CoderResult.OVERFLOW;
209                    dst.put(outputChar);
210                }
211                mark += inputSize;
212            }
213            return CoderResult.UNDERFLOW;
214        } finally {
215            src.position(mark);
216        }
217    }
218
219    protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
220        if (src.hasArray() && dst.hasArray())
221            return decodeArrayLoop(src, dst);
222        else
223            return decodeBufferLoop(src, dst);
224    }
225}
226