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
29package sun.nio.cs.ext;
30
31import java.nio.ByteBuffer;
32import java.nio.CharBuffer;
33import java.nio.charset.Charset;
34import java.nio.charset.CharsetEncoder;
35import java.nio.charset.CoderResult;
36import sun.nio.cs.Surrogate;
37
38
39public abstract class SimpleEUCEncoder
40    extends CharsetEncoder
41{
42
43    protected short  index1[];
44    protected String index2;
45    protected String index2a;
46    protected String index2b;
47    protected String index2c;
48    protected int    mask1;
49    protected int    mask2;
50    protected int    shift;
51
52    private byte[] outputByte = new byte[4];
53    private final Surrogate.Parser sgp = new Surrogate.Parser();
54
55    protected SimpleEUCEncoder(Charset cs)
56    {
57        super(cs, 3.0f, 4.0f);
58    }
59
60    /**
61     * Returns true if the given character can be converted to the
62     * target character encoding.
63     */
64
65    public boolean canEncode(char ch) {
66       int    index;
67       String theChars;
68
69       index = index1[((ch & mask1) >> shift)] + (ch & mask2);
70
71       if (index < 7500)
72         theChars = index2;
73       else
74         if (index < 15000) {
75           index = index - 7500;
76           theChars = index2a;
77         }
78         else
79           if (index < 22500){
80             index = index - 15000;
81             theChars = index2b;
82           }
83           else {
84             index = index - 22500;
85             theChars = index2c;
86           }
87
88       if (theChars.charAt(2*index) != '\u0000' ||
89                    theChars.charAt(2*index + 1) != '\u0000')
90         return (true);
91
92       // only return true if input char was unicode null - all others are
93       //     undefined
94       return( ch == '\u0000');
95
96    }
97    private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
98        char[] sa = src.array();
99        int sp = src.arrayOffset() + src.position();
100        int sl = src.arrayOffset() + src.limit();
101        assert (sp <= sl);
102        sp = (sp <= sl ? sp : sl);
103        byte[] da = dst.array();
104        int dp = dst.arrayOffset() + dst.position();
105        int dl = dst.arrayOffset() + dst.limit();
106        assert (dp <= dl);
107        dp = (dp <= dl ? dp : dl);
108
109        int     index;
110        int     spaceNeeded;
111        int     i;
112
113        try {
114            while (sp < sl) {
115                boolean allZeroes = true;
116                char inputChar = sa[sp];
117                if (Character.isSurrogate(inputChar)) {
118                    if (sgp.parse(inputChar, sa, sp, sl) < 0)
119                        return sgp.error();
120                    return sgp.unmappableResult();
121                }
122
123                if (inputChar >= '\uFFFE')
124                    return CoderResult.unmappableForLength(1);
125
126                String theChars;
127                char   aChar;
128
129                 // We have a valid character, get the bytes for it
130                index = index1[((inputChar & mask1) >> shift)] + (inputChar & mask2);
131
132                if (index < 7500)
133                    theChars = index2;
134                else if (index < 15000) {
135                     index = index - 7500;
136                     theChars = index2a;
137                } else if (index < 22500){
138                    index = index - 15000;
139                    theChars = index2b;
140                }
141                else {
142                    index = index - 22500;
143                    theChars = index2c;
144                }
145
146                aChar = theChars.charAt(2*index);
147                outputByte[0] = (byte)((aChar & 0xff00)>>8);
148                outputByte[1] = (byte)(aChar & 0x00ff);
149                aChar = theChars.charAt(2*index + 1);
150                outputByte[2] = (byte)((aChar & 0xff00)>>8);
151                outputByte[3] = (byte)(aChar & 0x00ff);
152
153            for (i = 0; i < outputByte.length; i++) {
154                if (outputByte[i] != 0x00) {
155                allZeroes = false;
156                break;
157                }
158            }
159
160            if (allZeroes && inputChar != '\u0000') {
161                return CoderResult.unmappableForLength(1);
162            }
163
164            int oindex = 0;
165
166            for (spaceNeeded = outputByte.length;
167                 spaceNeeded > 1; spaceNeeded--){
168                if (outputByte[oindex++] != 0x00 )
169                    break;
170            }
171
172            if (dp + spaceNeeded > dl)
173                return CoderResult.OVERFLOW;
174
175            for (i = outputByte.length - spaceNeeded;
176                 i < outputByte.length; i++) {
177                    da[dp++] = outputByte[i];
178            }
179            sp++;
180        }
181        return CoderResult.UNDERFLOW;
182        } finally {
183            src.position(sp - src.arrayOffset());
184            dst.position(dp - dst.arrayOffset());
185        }
186    }
187
188    private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
189        int     index;
190        int     spaceNeeded;
191        int     i;
192        int mark = src.position();
193        try {
194            while (src.hasRemaining()) {
195                char inputChar = src.get();
196                boolean allZeroes = true;
197                if (Character.isSurrogate(inputChar)) {
198                    if (sgp.parse(inputChar, src) < 0)
199                        return sgp.error();
200                    return sgp.unmappableResult();
201                }
202
203                if (inputChar >= '\uFFFE')
204                    return CoderResult.unmappableForLength(1);
205
206                String theChars;
207                char   aChar;
208
209                 // We have a valid character, get the bytes for it
210                index = index1[((inputChar & mask1) >> shift)] + (inputChar & mask2);
211
212                if (index < 7500)
213                    theChars = index2;
214                else if (index < 15000) {
215                     index = index - 7500;
216                     theChars = index2a;
217                } else if (index < 22500){
218                    index = index - 15000;
219                    theChars = index2b;
220                }
221                else {
222                    index = index - 22500;
223                    theChars = index2c;
224                }
225
226                aChar = theChars.charAt(2*index);
227                outputByte[0] = (byte)((aChar & 0xff00)>>8);
228                outputByte[1] = (byte)(aChar & 0x00ff);
229                aChar = theChars.charAt(2*index + 1);
230                outputByte[2] = (byte)((aChar & 0xff00)>>8);
231                outputByte[3] = (byte)(aChar & 0x00ff);
232
233            for (i = 0; i < outputByte.length; i++) {
234                if (outputByte[i] != 0x00) {
235                allZeroes = false;
236                break;
237                }
238            }
239            if (allZeroes && inputChar != '\u0000') {
240                return CoderResult.unmappableForLength(1);
241            }
242
243            int oindex = 0;
244
245            for (spaceNeeded = outputByte.length;
246                 spaceNeeded > 1; spaceNeeded--){
247                if (outputByte[oindex++] != 0x00 )
248                    break;
249            }
250            if (dst.remaining() < spaceNeeded)
251                return CoderResult.OVERFLOW;
252
253            for (i = outputByte.length - spaceNeeded;
254                 i < outputByte.length; i++) {
255                    dst.put(outputByte[i]);
256            }
257            mark++;
258            }
259            return CoderResult.UNDERFLOW;
260        } finally {
261            src.position(mark);
262        }
263    }
264
265    protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
266        if (true && src.hasArray() && dst.hasArray())
267            return encodeArrayLoop(src, dst);
268        else
269            return encodeBufferLoop(src, dst);
270    }
271
272    public byte encode(char inputChar) {
273        return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] +
274                (inputChar & mask2));
275    }
276}
277