1 /* 2 * Copyright (c) 2005, 2010, 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 package sun.nio.cs; 27 28 import java.nio.ByteBuffer; 29 import java.nio.CharBuffer; 30 import java.nio.charset.Charset; 31 import java.nio.charset.CoderResult; 32 import java.nio.charset.CharsetDecoder; 33 import java.nio.charset.CharsetEncoder; 34 35 class 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() >= 4) { 90 cp = getCP(src); 91 if (Character.isBmpCodePoint(cp)) { 92 if (!dst.hasRemaining()) 93 return CoderResult.OVERFLOW; 94 mark += 4; 95 dst.put((char) cp); 96 } else if (Character.isValidCodePoint(cp)) { 97 if (dst.remaining() < 2) 98 return CoderResult.OVERFLOW; 99 mark += 4; 100 dst.put(Character.highSurrogate(cp)); 101 dst.put(Character.lowSurrogate(cp)); 102 } else { 103 return CoderResult.malformedForLength(4); 104 } 105 } 106 return CoderResult.UNDERFLOW; 107 } finally { 108 src.position(mark); 109 } 110 } 111 protected void implReset() { 112 currentBO = NONE; 113 } 114 } 115 116 protected static class Encoder extends CharsetEncoder { 117 private boolean doBOM = false; 118 private boolean doneBOM = true; 119 private int byteOrder; 120 121 protected void put(int cp, ByteBuffer dst) { 122 if (byteOrder==BIG) { 123 dst.put((byte)(cp >> 24)); 124 dst.put((byte)(cp >> 16)); 125 dst.put((byte)(cp >> 8)); 126 dst.put((byte)cp); 127 } else { 128 dst.put((byte)cp); 129 dst.put((byte)(cp >> 8)); 130 dst.put((byte)(cp >> 16)); 131 dst.put((byte)(cp >> 24)); 132 } 133 } 134 135 protected Encoder(Charset cs, int byteOrder, boolean doBOM) { 136 super(cs, 4.0f, 137 doBOM?8.0f:4.0f, 138 (byteOrder==BIG)?new byte[]{(byte)0, (byte)0, (byte)0xff, (byte)0xfd} 139 :new byte[]{(byte)0xfd, (byte)0xff, (byte)0, (byte)0}); 140 this.byteOrder = byteOrder; 141 this.doBOM = doBOM; 142 this.doneBOM = !doBOM; 143 } 144 145 protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { 146 int mark = src.position(); 147 if (!doneBOM && src.hasRemaining()) { 148 if (dst.remaining() < 4) 149 return CoderResult.OVERFLOW; 150 put(BOM_BIG, dst); 151 doneBOM = true; 152 } 153 try { 154 while (src.hasRemaining()) { 155 char c = src.get(); 156 if (!Character.isSurrogate(c)) { 157 if (dst.remaining() < 4) 158 return CoderResult.OVERFLOW; 159 mark++; 160 put(c, dst); 161 } else if (Character.isHighSurrogate(c)) { 162 if (!src.hasRemaining()) 163 return CoderResult.UNDERFLOW; 164 char low = src.get(); 165 if (Character.isLowSurrogate(low)) { 166 if (dst.remaining() < 4) 167 return CoderResult.OVERFLOW; 168 mark += 2; 169 put(Character.toCodePoint(c, low), dst); 170 } else { 171 return CoderResult.malformedForLength(1); 172 } 173 } else { 174 // assert Character.isLowSurrogate(c); 175 return CoderResult.malformedForLength(1); 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 }