1 /*
2  * Copyright (c) 2000, 2012, 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 
30 import java.nio.ByteBuffer;
31 import java.nio.CharBuffer;
32 import java.nio.charset.Charset;
33 import java.nio.charset.CharsetEncoder;
34 import java.nio.charset.CoderResult;
35 import java.nio.charset.CharacterCodingException;
36 import java.nio.charset.MalformedInputException;
37 import java.nio.charset.UnmappableCharacterException;
38 import sun.nio.cs.Surrogate;
39 
40 
41 public abstract class SingleByteEncoder
42     extends CharsetEncoder
43 {
44 
45     private final short index1[];
46     private final String index2;
47     private final int mask1;
48     private final int mask2;
49     private final int shift;
50 
51     private final Surrogate.Parser sgp = new Surrogate.Parser();
52 
SingleByteEncoder(Charset cs, short[] index1, String index2, int mask1, int mask2, int shift)53     protected SingleByteEncoder(Charset cs,
54                                 short[] index1, String index2,
55                                 int mask1, int mask2, int shift)
56     {
57         super(cs, 1.0f, 1.0f);
58         this.index1 = index1;
59         this.index2 = index2;
60         this.mask1 = mask1;
61         this.mask2 = mask2;
62         this.shift = shift;
63     }
64 
canEncode(char c)65     public boolean canEncode(char c) {
66         char testEncode = index2.charAt(index1[(c & mask1) >> shift]
67                                         + (c & mask2));
68         return testEncode != '\u0000' || c == '\u0000';
69     }
70 
encodeArrayLoop(CharBuffer src, ByteBuffer dst)71     private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
72         char[] 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         byte[] 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                 char c = sa[sp];
86                 if (Character.isSurrogate(c)) {
87                     if (sgp.parse(c, sa, sp, sl) < 0)
88                         return sgp.error();
89                     return sgp.unmappableResult();
90                 }
91                 if (c >= '\uFFFE')
92                     return CoderResult.unmappableForLength(1);
93                 if (dl - dp < 1)
94                     return CoderResult.OVERFLOW;
95 
96                 char e = index2.charAt(index1[(c & mask1) >> shift]
97                                        + (c & mask2));
98 
99                 // If output byte is zero because input char is zero
100                 // then character is mappable, o.w. fail
101                 if (e == '\u0000' && c != '\u0000')
102                     return CoderResult.unmappableForLength(1);
103 
104                 sp++;
105                 da[dp++] = (byte)e;
106             }
107             return CoderResult.UNDERFLOW;
108         } finally {
109             src.position(sp - src.arrayOffset());
110             dst.position(dp - dst.arrayOffset());
111         }
112     }
113 
encodeBufferLoop(CharBuffer src, ByteBuffer dst)114     private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
115         int mark = src.position();
116         try {
117             while (src.hasRemaining()) {
118                 char c = src.get();
119                 if (Character.isSurrogate(c)) {
120                     if (sgp.parse(c, src) < 0)
121                         return sgp.error();
122                     return sgp.unmappableResult();
123                 }
124                 if (c >= '\uFFFE')
125                     return CoderResult.unmappableForLength(1);
126                 if (!dst.hasRemaining())
127                     return CoderResult.OVERFLOW;
128 
129                 char e = index2.charAt(index1[(c & mask1) >> shift]
130                                        + (c & mask2));
131 
132                 // If output byte is zero because input char is zero
133                 // then character is mappable, o.w. fail
134                 if (e == '\u0000' && c != '\u0000')
135                     return CoderResult.unmappableForLength(1);
136 
137                 mark++;
138                 dst.put((byte)e);
139             }
140             return CoderResult.UNDERFLOW;
141         } finally {
142             src.position(mark);
143         }
144     }
145 
encodeLoop(CharBuffer src, ByteBuffer dst)146     protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
147         if (true && src.hasArray() && dst.hasArray())
148             return encodeArrayLoop(src, dst);
149         else
150             return encodeBufferLoop(src, dst);
151     }
152 
encode(char inputChar)153     public byte encode(char inputChar) {
154         return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] +
155                 (inputChar & mask2));
156     }
157 }
158