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.CharsetEncoder;
34import java.nio.charset.CoderResult;
35import sun.nio.cs.Surrogate;
36
37/**
38 * An abstract base class for subclasses which encodes
39 * IBM double byte host encodings such as ibm code
40 * pages 942,943,948, etc.
41 *
42 */
43
44public abstract class DBCS_IBM_EBCDIC_Encoder extends CharsetEncoder
45{
46
47    protected static final char REPLACE_CHAR='\uFFFD';
48    private byte b1;
49    private byte b2;
50
51    protected short index1[];
52    protected String index2;
53    protected String index2a;
54    protected int   mask1;
55    protected int   mask2;
56    protected int   shift;
57
58    private static final int SBCS = 0;
59    private static final int DBCS = 1;
60
61    private static final byte SO = 0x0e;
62    private static final byte SI = 0x0f;
63
64    private int  currentState;
65
66    private final Surrogate.Parser sgp = new Surrogate.Parser();
67
68    protected DBCS_IBM_EBCDIC_Encoder(Charset cs) {
69        super(cs, 4.0f, 5.0f, new byte[] {(byte)0x6f});
70    }
71
72    protected void implReset() {
73        currentState = SBCS;
74    }
75
76    protected CoderResult implFlush(ByteBuffer out) {
77        if (currentState == DBCS) {
78            if (out.remaining() < 1)
79                return CoderResult.OVERFLOW;
80            out.put(SI);
81        }
82        implReset();
83        return CoderResult.UNDERFLOW;
84    }
85
86    /**
87     * Returns true if the given character can be converted to the
88     * target character encoding.
89     */
90    public boolean canEncode(char ch) {
91       int  index;
92       int  theBytes;
93
94       index = index1[((ch & mask1) >> shift)] + (ch & mask2);
95       if (index  < 15000)
96         theBytes = (int)(index2.charAt(index));
97       else
98         theBytes = (int)(index2a.charAt(index-15000));
99
100       if (theBytes != 0)
101         return (true);
102
103       // only return true if input char was unicode null - all others are
104       //     undefined
105       return( ch == '\u0000');
106
107    }
108
109    private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
110        char[] sa = src.array();
111        int sp = src.arrayOffset() + src.position();
112        int sl = src.arrayOffset() + src.limit();
113        byte[] da = dst.array();
114        int dp = dst.arrayOffset() + dst.position();
115        int dl = dst.arrayOffset() + dst.limit();
116        int outputSize = 0;             // size of output
117        int spaceNeeded;
118
119        try {
120            while (sp < sl) {
121                int index;
122                int theBytes;
123                char c = sa[sp];
124                if (Surrogate.is(c)) {
125                    if (sgp.parse(c, sa, sp, sl) < 0)
126                        return sgp.error();
127                    return sgp.unmappableResult();
128                }
129                if (c >= '\uFFFE')
130                    return CoderResult.unmappableForLength(1);
131
132
133                index = index1[((c & mask1) >> shift)]
134                                + (c & mask2);
135                if (index < 15000)
136                    theBytes = (int)(index2.charAt(index));
137                else
138                    theBytes = (int)(index2a.charAt(index-15000));
139                b1= (byte)((theBytes & 0x0000ff00)>>8);
140                b2 = (byte)(theBytes & 0x000000ff);
141
142                if (b1 == 0x00 && b2 == 0x00
143                    && c != '\u0000') {
144                        return CoderResult.unmappableForLength(1);
145                }
146
147                if (currentState == DBCS && b1 == 0x00) {
148                    if (dl - dp < 1)
149                        return CoderResult.OVERFLOW;
150                    currentState = SBCS;
151                    da[dp++] = SI;
152                } else if (currentState == SBCS && b1 != 0x00) {
153                    if (dl - dp < 1)
154                        return CoderResult.OVERFLOW;
155                    currentState = DBCS;
156                    da[dp++] = SO;
157                }
158                if (currentState == DBCS)
159                    spaceNeeded = 2;
160                else
161                    spaceNeeded = 1;
162                if (dl - dp < spaceNeeded)
163                    return CoderResult.OVERFLOW;
164
165                if (currentState == SBCS)
166                    da[dp++] = b2;
167                else {
168                    da[dp++] = b1;
169                    da[dp++] = b2;
170                }
171                sp++;
172            }
173            return CoderResult.UNDERFLOW;
174        } finally {
175            src.position(sp - src.arrayOffset());
176            dst.position(dp - dst.arrayOffset());
177        }
178    }
179
180    private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
181        int mark = src.position();
182        int outputSize = 0;             // size of output
183        int spaceNeeded;
184
185        try {
186            while (src.hasRemaining()) {
187                int index;
188                int theBytes;
189                char c = src.get();
190                if (Surrogate.is(c)) {
191                    if (sgp.parse(c, src) < 0)
192                        return sgp.error();
193                    return sgp.unmappableResult();
194                }
195                if (c >= '\uFFFE')
196                    return CoderResult.unmappableForLength(1);
197
198                index = index1[((c & mask1) >> shift)]
199                                + (c & mask2);
200                if (index < 15000)
201                    theBytes = (int)(index2.charAt(index));
202                else
203                    theBytes = (int)(index2a.charAt(index-15000));
204                b1 = (byte)((theBytes & 0x0000ff00)>>8);
205                b2 = (byte)(theBytes & 0x000000ff);
206
207                if (b1== 0x00 && b2 == 0x00
208                    && c != '\u0000') {
209                        return CoderResult.unmappableForLength(1);
210                }
211
212                if (currentState == DBCS && b1 == 0x00) {
213                    if (dst.remaining() < 1)
214                        return CoderResult.OVERFLOW;
215                    currentState = SBCS;
216                    dst.put(SI);
217                } else if (currentState == SBCS && b1 != 0x00) {
218                    if (dst.remaining() < 1)
219                        return CoderResult.OVERFLOW;
220                    currentState = DBCS;
221                    dst.put(SO);
222                }
223
224                if (currentState == DBCS)
225                    spaceNeeded = 2;
226                else
227                    spaceNeeded = 1;
228
229                if (dst.remaining() < spaceNeeded)
230                    return CoderResult.OVERFLOW;
231
232                if (currentState == SBCS)
233                    dst.put(b2);
234                else {
235                    dst.put(b1);
236                    dst.put(b2);
237                }
238                mark++;
239             }
240            return CoderResult.UNDERFLOW;
241        } finally {
242            src.position(mark);
243        }
244    }
245
246    protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
247        if (true && src.hasArray() && dst.hasArray())
248            return encodeArrayLoop(src, dst);
249        else
250            return encodeBufferLoop(src, dst);
251    }
252
253}
254