1/*
2 * Copyright (c) 2002, 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.font;
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
38public abstract class DoubleByteEncoder
39    extends CharsetEncoder
40{
41
42    private short index1[];
43    private String index2[];
44
45    private final Surrogate.Parser sgp = new Surrogate.Parser();
46
47    protected DoubleByteEncoder(Charset cs,
48                                short[] index1, String[] index2)
49    {
50        super(cs, 2.0f, 2.0f);
51        this.index1 = index1;
52        this.index2 = index2;
53    }
54
55    protected DoubleByteEncoder(Charset cs,
56                                short[] index1, String[] index2,
57                                float avg, float max)
58    {
59        super(cs, avg, max);
60        this.index1 = index1;
61        this.index2 = index2;
62    }
63
64    protected DoubleByteEncoder(Charset cs,
65                                short[] index1, String[] index2, byte[] repl)
66    {
67        super(cs, 2.0f, 2.0f, repl);
68        this.index1 = index1;
69        this.index2 = index2;
70    }
71
72
73    protected DoubleByteEncoder(Charset cs,
74                                short[] index1, String[] index2,
75                                byte[] repl, float avg, float max)
76    {
77        super(cs, avg, max,repl);
78        this.index1 = index1;
79        this.index2 = index2;
80    }
81
82    public boolean canEncode(char c) {
83        return (encodeSingle(c) != -1 ||
84                encodeDouble(c) != 0);
85    }
86
87    private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
88        char[] sa = src.array();
89        int sp = src.arrayOffset() + src.position();
90        int sl = src.arrayOffset() + src.limit();
91        byte[] da = dst.array();
92        int dp = dst.arrayOffset() + dst.position();
93        int dl = dst.arrayOffset() + dst.limit();
94
95        try {
96            while (sp < sl) {
97                char c = sa[sp];
98                if (Character.isSurrogate(c)) {
99                    if (sgp.parse(c, sa, sp, sl) < 0)
100                        return sgp.error();
101                    if (sl - sp < 2)
102                        return CoderResult.UNDERFLOW;
103                    char c2 = sa[sp + 1];
104
105                    byte[] outputBytes = new byte[2];
106                    outputBytes = encodeSurrogate(c, c2);
107
108                    if (outputBytes == null) {
109                        return sgp.unmappableResult();
110                    }
111                    else {
112                        if (dl - dp < 2)
113                            return CoderResult.OVERFLOW;
114                        da[dp++] = outputBytes[0];
115                        da[dp++] = outputBytes[1];
116                        sp += 2;
117                        continue;
118                    }
119                }
120                if (c >= '\uFFFE')
121                    return CoderResult.unmappableForLength(1);
122
123                int b = encodeSingle(c);
124                if (b != -1) { // Single Byte
125                    if (dl - dp < 1)
126                        return CoderResult.OVERFLOW;
127                    da[dp++] = (byte)b;
128                    sp++;
129                    continue;
130                }
131
132                int ncode  = encodeDouble(c);
133                if (ncode != 0 && c != '\u0000' ) {
134                    if (dl - dp < 2)
135                        return CoderResult.OVERFLOW;
136                    da[dp++] = (byte) ((ncode & 0xff00) >> 8);
137                    da[dp++] = (byte) (ncode & 0xff);
138                    sp++;
139                    continue;
140                }
141                return CoderResult.unmappableForLength(1);
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 encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
151        int mark = src.position();
152
153        try {
154            while (src.hasRemaining()) {
155                char c = src.get();
156                if (Character.isSurrogate(c)) {
157                    int surr;
158                    if ((surr = sgp.parse(c, src)) < 0)
159                        return sgp.error();
160                    char c2 = Surrogate.low(surr);
161                    byte[] outputBytes = new byte[2];
162                    outputBytes = encodeSurrogate(c, c2);
163
164                    if (outputBytes == null) {
165                        return sgp.unmappableResult();
166                    } else {
167                        if (dst.remaining() < 2)
168                            return CoderResult.OVERFLOW;
169                        mark += 2;
170                        dst.put(outputBytes[0]);
171                        dst.put(outputBytes[1]);
172                        continue;
173                    }
174                }
175                if (c >= '\uFFFE')
176                    return CoderResult.unmappableForLength(1);
177                int b = encodeSingle(c);
178
179                if (b != -1) { // Single-byte character
180                    if (dst.remaining() < 1)
181                        return CoderResult.OVERFLOW;
182                    mark++;
183                    dst.put((byte)b);
184                    continue;
185                }
186                // Double Byte character
187
188                int ncode = encodeDouble(c);
189                if (ncode != 0 && c != '\u0000') {
190                    if (dst.remaining() < 2)
191                        return CoderResult.OVERFLOW;
192                    mark++;
193                    dst.put((byte) ((ncode & 0xff00) >> 8));
194                    dst.put((byte) ncode);
195                    continue;
196                }
197                return CoderResult.unmappableForLength(1);
198            }
199
200            return CoderResult.UNDERFLOW;
201        } finally {
202            src.position(mark);
203        }
204    }
205
206    protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
207        if (true && src.hasArray() && dst.hasArray())
208            return encodeArrayLoop(src, dst);
209        else
210            return encodeBufferLoop(src, dst);
211    }
212
213    /*
214     * Can be changed by subclass
215     */
216    protected int encodeDouble(char ch) {
217        int offset = index1[((ch & 0xff00) >> 8 )] << 8;
218        return index2[offset >> 12].charAt((offset & 0xfff) + (ch & 0xff));
219    }
220
221    /*
222     * Can be changed by subclass
223     */
224    protected int encodeSingle(char inputChar) {
225        if (inputChar < 0x80)
226            return (byte)inputChar;
227        else
228            return -1;
229    }
230
231    /**
232     *  Protected method which should be overridden by concrete DBCS
233     *  CharsetEncoder classes which included supplementary characters
234     *  within their mapping coverage.
235     *  null return value indicates surrogate values could not be
236     *  handled or encoded.
237     */
238    protected byte[] encodeSurrogate(char highSurrogate, char lowSurrogate) {
239        return null;
240    }
241}
242