blob: 1229699d31fbca5e7f48e6e2d3502685e83d2e9d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.nio.cs;
27
28import java.nio.ByteBuffer;
29import java.nio.CharBuffer;
30import java.nio.charset.Charset;
31import java.nio.charset.CoderResult;
32import java.nio.charset.CharsetDecoder;
33import java.nio.charset.CharsetEncoder;
34
35class UTF_32Coder {
36 protected static final int BOM_BIG = 0xFEFF;
37 protected static final int BOM_LITTLE = 0xFFFE0000;
38 protected static final int NONE = 0;
39 protected static final int BIG = 1;
40 protected static final int LITTLE = 2;
41
42 protected static class Decoder extends CharsetDecoder {
43 private int currentBO;
44 private int expectedBO;
45
46 protected Decoder(Charset cs, int bo) {
47 super(cs, 0.25f, 1.0f);
48 this.expectedBO = bo;
49 this.currentBO = NONE;
50 }
51
52 private int getCP(ByteBuffer src) {
53 return (currentBO==BIG)
54 ?(((src.get() & 0xff) << 24) |
55 ((src.get() & 0xff) << 16) |
56 ((src.get() & 0xff) << 8) |
57 (src.get() & 0xff))
58 :((src.get() & 0xff) |
59 ((src.get() & 0xff) << 8) |
60 ((src.get() & 0xff) << 16) |
61 ((src.get() & 0xff) << 24));
62 }
63
64 protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
65 if (src.remaining() < 4)
66 return CoderResult.UNDERFLOW;
67 int mark = src.position();
68 int cp;
69 try {
70 if (currentBO == NONE) {
71 cp = ((src.get() & 0xff) << 24) |
72 ((src.get() & 0xff) << 16) |
73 ((src.get() & 0xff) << 8) |
74 (src.get() & 0xff);
75 if (cp == BOM_BIG && expectedBO != LITTLE) {
76 currentBO = BIG;
77 mark += 4;
78 } else if (cp == BOM_LITTLE && expectedBO != BIG) {
79 currentBO = LITTLE;
80 mark += 4;
81 } else {
82 if (expectedBO == NONE)
83 currentBO = BIG;
84 else
85 currentBO = expectedBO;
86 src.position(mark);
87 }
88 }
89 while (src.remaining() > 3) {
90 cp = getCP(src);
91 if (cp < 0 || cp > Surrogate.UCS4_MAX) {
92 return CoderResult.malformedForLength(4);
93 }
94 if (cp < Surrogate.UCS4_MIN) {
95 if (!dst.hasRemaining())
96 return CoderResult.OVERFLOW;
97 mark += 4;
98 dst.put((char)cp);
99 } else {
100 if (dst.remaining() < 2)
101 return CoderResult.OVERFLOW;
102 mark += 4;
103 dst.put(Surrogate.high(cp));
104 dst.put(Surrogate.low(cp));
105 }
106 }
107 return CoderResult.UNDERFLOW;
108 } finally {
109 src.position(mark);
110 }
111 }
112 protected void implReset() {
113 currentBO = NONE;
114 }
115 }
116
117 protected static class Encoder extends CharsetEncoder {
118 private boolean doBOM = false;
119 private boolean doneBOM = true;
120 private int byteOrder;
121
122 protected void put(int cp, ByteBuffer dst) {
123 if (byteOrder==BIG) {
124 dst.put((byte)(cp >> 24));
125 dst.put((byte)(cp >> 16));
126 dst.put((byte)(cp >> 8));
127 dst.put((byte)cp);
128 } else {
129 dst.put((byte)cp);
130 dst.put((byte)(cp >> 8));
131 dst.put((byte)(cp >> 16));
132 dst.put((byte)(cp >> 24));
133 }
134 }
135
136 protected Encoder(Charset cs, int byteOrder, boolean doBOM) {
137 super(cs, 4.0f,
138 doBOM?8.0f:4.0f,
139 (byteOrder==BIG)?new byte[]{(byte)0, (byte)0, (byte)0xff, (byte)0xfd}
140 :new byte[]{(byte)0xfd, (byte)0xff, (byte)0, (byte)0});
141 this.byteOrder = byteOrder;
142 this.doBOM = doBOM;
143 this.doneBOM = !doBOM;
144 }
145
146 protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
147 int mark = src.position();
148 if (!doneBOM) {
149 if (dst.remaining() < 4)
150 return CoderResult.OVERFLOW;
151 put(BOM_BIG, dst);
152 doneBOM = true;
153 }
154 try {
155 while (src.hasRemaining()) {
156 char c = src.get();
157 if (Surrogate.isHigh(c)) {
158 if (!src.hasRemaining())
159 return CoderResult.UNDERFLOW;
160 char low = src.get();
161 if (Surrogate.isLow(low)) {
162 if (dst.remaining() < 4)
163 return CoderResult.OVERFLOW;
164 mark += 2;
165 put(Surrogate.toUCS4(c, low), dst);
166 } else {
167 return CoderResult.malformedForLength(1);
168 }
169 } else if (Surrogate.isLow(c)) {
170 return CoderResult.malformedForLength(1);
171 } else {
172 if (dst.remaining() < 4)
173 return CoderResult.OVERFLOW;
174 mark++;
175 put(c, dst);
176 }
177 }
178 return CoderResult.UNDERFLOW;
179 } finally {
180 src.position(mark);
181 }
182 }
183
184 protected void implReset() {
185 doneBOM = !doBOM;
186 }
187
188 }
189}