jaroslav@1646
|
1 |
/*
|
jaroslav@1646
|
2 |
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
jaroslav@1646
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
jaroslav@1646
|
4 |
*
|
jaroslav@1646
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
jaroslav@1646
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
jaroslav@1646
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
jaroslav@1646
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
jaroslav@1646
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
jaroslav@1646
|
10 |
*
|
jaroslav@1646
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
jaroslav@1646
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
jaroslav@1646
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
jaroslav@1646
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
jaroslav@1646
|
15 |
* accompanied this code).
|
jaroslav@1646
|
16 |
*
|
jaroslav@1646
|
17 |
* You should have received a copy of the GNU General Public License version
|
jaroslav@1646
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
jaroslav@1646
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
jaroslav@1646
|
20 |
*
|
jaroslav@1646
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
jaroslav@1646
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
jaroslav@1646
|
23 |
* questions.
|
jaroslav@1646
|
24 |
*/
|
jaroslav@1646
|
25 |
|
jaroslav@1646
|
26 |
package sun.invoke.anon;
|
jaroslav@1646
|
27 |
|
jaroslav@1646
|
28 |
import java.io.IOException;
|
jaroslav@1646
|
29 |
import java.io.OutputStream;
|
jaroslav@1646
|
30 |
import java.nio.BufferUnderflowException;
|
jaroslav@1646
|
31 |
import java.nio.ByteBuffer;
|
jaroslav@1646
|
32 |
|
jaroslav@1646
|
33 |
import static sun.invoke.anon.ConstantPoolVisitor.*;
|
jaroslav@1646
|
34 |
|
jaroslav@1646
|
35 |
/** A constant pool parser.
|
jaroslav@1646
|
36 |
*/
|
jaroslav@1646
|
37 |
public class ConstantPoolParser {
|
jaroslav@1646
|
38 |
final byte[] classFile;
|
jaroslav@1646
|
39 |
final byte[] tags;
|
jaroslav@1646
|
40 |
final char[] firstHeader; // maghi, maglo, minor, major, cplen
|
jaroslav@1646
|
41 |
|
jaroslav@1646
|
42 |
// these are filled in on first parse:
|
jaroslav@1646
|
43 |
int endOffset;
|
jaroslav@1646
|
44 |
char[] secondHeader; // flags, this_class, super_class, intlen
|
jaroslav@1646
|
45 |
|
jaroslav@1646
|
46 |
// used to decode UTF8 array
|
jaroslav@1646
|
47 |
private char[] charArray = new char[80];
|
jaroslav@1646
|
48 |
|
jaroslav@1646
|
49 |
/** Creates a constant pool parser.
|
jaroslav@1646
|
50 |
* @param classFile an array of bytes containing a class.
|
jaroslav@1646
|
51 |
* @throws InvalidConstantPoolFormatException if the header of the class has errors.
|
jaroslav@1646
|
52 |
*/
|
jaroslav@1646
|
53 |
public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException {
|
jaroslav@1646
|
54 |
this.classFile = classFile;
|
jaroslav@1646
|
55 |
this.firstHeader = parseHeader(classFile);
|
jaroslav@1646
|
56 |
this.tags = new byte[firstHeader[4]];
|
jaroslav@1646
|
57 |
}
|
jaroslav@1646
|
58 |
|
jaroslav@1646
|
59 |
/** Create a constant pool parser by loading the bytecodes of the
|
jaroslav@1646
|
60 |
* class taken as argument.
|
jaroslav@1646
|
61 |
*
|
jaroslav@1646
|
62 |
* @param templateClass the class to parse.
|
jaroslav@1646
|
63 |
*
|
jaroslav@1646
|
64 |
* @throws IOException raised if an I/O occurs when loading
|
jaroslav@1646
|
65 |
* the bytecode of the template class.
|
jaroslav@1646
|
66 |
* @throws InvalidConstantPoolFormatException if the header of the class has errors.
|
jaroslav@1646
|
67 |
*
|
jaroslav@1646
|
68 |
* @see #ConstantPoolParser(byte[])
|
jaroslav@1646
|
69 |
* @see AnonymousClassLoader#readClassFile(Class)
|
jaroslav@1646
|
70 |
*/
|
jaroslav@1646
|
71 |
public ConstantPoolParser(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
|
jaroslav@1646
|
72 |
this(AnonymousClassLoader.readClassFile(templateClass));
|
jaroslav@1646
|
73 |
}
|
jaroslav@1646
|
74 |
|
jaroslav@1646
|
75 |
/** Creates an empty patch to patch the class file
|
jaroslav@1646
|
76 |
* used by the current parser.
|
jaroslav@1646
|
77 |
* @return a new class patch.
|
jaroslav@1646
|
78 |
*/
|
jaroslav@1646
|
79 |
public ConstantPoolPatch createPatch() {
|
jaroslav@1646
|
80 |
return new ConstantPoolPatch(this);
|
jaroslav@1646
|
81 |
}
|
jaroslav@1646
|
82 |
|
jaroslav@1646
|
83 |
/** Report the tag of the indicated CP entry.
|
jaroslav@1646
|
84 |
* @param index
|
jaroslav@1646
|
85 |
* @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc.
|
jaroslav@1646
|
86 |
*/
|
jaroslav@1646
|
87 |
public byte getTag(int index) {
|
jaroslav@1646
|
88 |
getEndOffset(); // trigger an exception if we haven't parsed yet
|
jaroslav@1646
|
89 |
return tags[index];
|
jaroslav@1646
|
90 |
}
|
jaroslav@1646
|
91 |
|
jaroslav@1646
|
92 |
/** Report the length of the constant pool. */
|
jaroslav@1646
|
93 |
public int getLength() {
|
jaroslav@1646
|
94 |
return firstHeader[4];
|
jaroslav@1646
|
95 |
}
|
jaroslav@1646
|
96 |
|
jaroslav@1646
|
97 |
/** Report the offset, within the class file, of the start of the constant pool. */
|
jaroslav@1646
|
98 |
public int getStartOffset() {
|
jaroslav@1646
|
99 |
return firstHeader.length * 2;
|
jaroslav@1646
|
100 |
}
|
jaroslav@1646
|
101 |
|
jaroslav@1646
|
102 |
/** Report the offset, within the class file, of the end of the constant pool. */
|
jaroslav@1646
|
103 |
public int getEndOffset() {
|
jaroslav@1646
|
104 |
if (endOffset == 0)
|
jaroslav@1646
|
105 |
throw new IllegalStateException("class file has not yet been parsed");
|
jaroslav@1646
|
106 |
return endOffset;
|
jaroslav@1646
|
107 |
}
|
jaroslav@1646
|
108 |
|
jaroslav@1646
|
109 |
/** Report the CP index of this class's own name. */
|
jaroslav@1646
|
110 |
public int getThisClassIndex() {
|
jaroslav@1646
|
111 |
getEndOffset(); // provoke exception if not yet parsed
|
jaroslav@1646
|
112 |
return secondHeader[1];
|
jaroslav@1646
|
113 |
}
|
jaroslav@1646
|
114 |
|
jaroslav@1646
|
115 |
/** Report the total size of the class file. */
|
jaroslav@1646
|
116 |
public int getTailLength() {
|
jaroslav@1646
|
117 |
return classFile.length - getEndOffset();
|
jaroslav@1646
|
118 |
}
|
jaroslav@1646
|
119 |
|
jaroslav@1646
|
120 |
/** Write the head (header plus constant pool)
|
jaroslav@1646
|
121 |
* of the class file to the indicated stream.
|
jaroslav@1646
|
122 |
*/
|
jaroslav@1646
|
123 |
public void writeHead(OutputStream out) throws IOException {
|
jaroslav@1646
|
124 |
out.write(classFile, 0, getEndOffset());
|
jaroslav@1646
|
125 |
}
|
jaroslav@1646
|
126 |
|
jaroslav@1646
|
127 |
/** Write the head (header plus constant pool)
|
jaroslav@1646
|
128 |
* of the class file to the indicated stream,
|
jaroslav@1646
|
129 |
* incorporating the non-null entries of the given array
|
jaroslav@1646
|
130 |
* as patches.
|
jaroslav@1646
|
131 |
*/
|
jaroslav@1646
|
132 |
void writePatchedHead(OutputStream out, Object[] patchArray) {
|
jaroslav@1646
|
133 |
// this will be useful to partially emulate the class loader on old JVMs
|
jaroslav@1646
|
134 |
throw new UnsupportedOperationException("Not yet implemented");
|
jaroslav@1646
|
135 |
}
|
jaroslav@1646
|
136 |
|
jaroslav@1646
|
137 |
/** Write the tail (everything after the constant pool)
|
jaroslav@1646
|
138 |
* of the class file to the indicated stream.
|
jaroslav@1646
|
139 |
*/
|
jaroslav@1646
|
140 |
public void writeTail(OutputStream out) throws IOException {
|
jaroslav@1646
|
141 |
out.write(classFile, getEndOffset(), getTailLength());
|
jaroslav@1646
|
142 |
}
|
jaroslav@1646
|
143 |
|
jaroslav@1646
|
144 |
private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException {
|
jaroslav@1646
|
145 |
char[] result = new char[5];
|
jaroslav@1646
|
146 |
ByteBuffer buffer = ByteBuffer.wrap(classFile);
|
jaroslav@1646
|
147 |
for (int i = 0; i < result.length; i++)
|
jaroslav@1646
|
148 |
result[i] = (char) getUnsignedShort(buffer);
|
jaroslav@1646
|
149 |
int magic = result[0] << 16 | result[1] << 0;
|
jaroslav@1646
|
150 |
if (magic != 0xCAFEBABE)
|
jaroslav@1646
|
151 |
throw new InvalidConstantPoolFormatException("invalid magic number "+magic);
|
jaroslav@1646
|
152 |
// skip major, minor version
|
jaroslav@1646
|
153 |
int len = result[4];
|
jaroslav@1646
|
154 |
if (len < 1)
|
jaroslav@1646
|
155 |
throw new InvalidConstantPoolFormatException("constant pool length < 1");
|
jaroslav@1646
|
156 |
return result;
|
jaroslav@1646
|
157 |
}
|
jaroslav@1646
|
158 |
|
jaroslav@1646
|
159 |
/** Parse the constant pool of the class
|
jaroslav@1646
|
160 |
* calling a method visit* each time a constant pool entry is parsed.
|
jaroslav@1646
|
161 |
*
|
jaroslav@1646
|
162 |
* The order of the calls to visit* is not guaranteed to be the same
|
jaroslav@1646
|
163 |
* than the order of the constant pool entry in the bytecode array.
|
jaroslav@1646
|
164 |
*
|
jaroslav@1646
|
165 |
* @param visitor
|
jaroslav@1646
|
166 |
* @throws InvalidConstantPoolFormatException
|
jaroslav@1646
|
167 |
*/
|
jaroslav@1646
|
168 |
public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
|
jaroslav@1646
|
169 |
ByteBuffer buffer = ByteBuffer.wrap(classFile);
|
jaroslav@1646
|
170 |
buffer.position(getStartOffset()); //skip header
|
jaroslav@1646
|
171 |
|
jaroslav@1646
|
172 |
Object[] values = new Object[getLength()];
|
jaroslav@1646
|
173 |
try {
|
jaroslav@1646
|
174 |
parseConstantPool(buffer, values, visitor);
|
jaroslav@1646
|
175 |
} catch(BufferUnderflowException e) {
|
jaroslav@1646
|
176 |
throw new InvalidConstantPoolFormatException(e);
|
jaroslav@1646
|
177 |
}
|
jaroslav@1646
|
178 |
if (endOffset == 0) {
|
jaroslav@1646
|
179 |
endOffset = buffer.position();
|
jaroslav@1646
|
180 |
secondHeader = new char[4];
|
jaroslav@1646
|
181 |
for (int i = 0; i < secondHeader.length; i++) {
|
jaroslav@1646
|
182 |
secondHeader[i] = (char) getUnsignedShort(buffer);
|
jaroslav@1646
|
183 |
}
|
jaroslav@1646
|
184 |
}
|
jaroslav@1646
|
185 |
resolveConstantPool(values, visitor);
|
jaroslav@1646
|
186 |
}
|
jaroslav@1646
|
187 |
|
jaroslav@1646
|
188 |
private char[] getCharArray(int utfLength) {
|
jaroslav@1646
|
189 |
if (utfLength <= charArray.length)
|
jaroslav@1646
|
190 |
return charArray;
|
jaroslav@1646
|
191 |
return charArray = new char[utfLength];
|
jaroslav@1646
|
192 |
}
|
jaroslav@1646
|
193 |
|
jaroslav@1646
|
194 |
private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException {
|
jaroslav@1646
|
195 |
for (int i = 1; i < tags.length; ) {
|
jaroslav@1646
|
196 |
byte tag = (byte) getUnsignedByte(buffer);
|
jaroslav@1646
|
197 |
assert(tags[i] == 0 || tags[i] == tag);
|
jaroslav@1646
|
198 |
tags[i] = tag;
|
jaroslav@1646
|
199 |
switch (tag) {
|
jaroslav@1646
|
200 |
case CONSTANT_Utf8:
|
jaroslav@1646
|
201 |
int utfLen = getUnsignedShort(buffer);
|
jaroslav@1646
|
202 |
String value = getUTF8(buffer, utfLen, getCharArray(utfLen));
|
jaroslav@1646
|
203 |
visitor.visitUTF8(i, CONSTANT_Utf8, value);
|
jaroslav@1646
|
204 |
tags[i] = tag;
|
jaroslav@1646
|
205 |
values[i++] = value;
|
jaroslav@1646
|
206 |
break;
|
jaroslav@1646
|
207 |
case CONSTANT_Integer:
|
jaroslav@1646
|
208 |
visitor.visitConstantValue(i, tag, buffer.getInt());
|
jaroslav@1646
|
209 |
i++;
|
jaroslav@1646
|
210 |
break;
|
jaroslav@1646
|
211 |
case CONSTANT_Float:
|
jaroslav@1646
|
212 |
visitor.visitConstantValue(i, tag, buffer.getFloat());
|
jaroslav@1646
|
213 |
i++;
|
jaroslav@1646
|
214 |
break;
|
jaroslav@1646
|
215 |
case CONSTANT_Long:
|
jaroslav@1646
|
216 |
visitor.visitConstantValue(i, tag, buffer.getLong());
|
jaroslav@1646
|
217 |
i+=2;
|
jaroslav@1646
|
218 |
break;
|
jaroslav@1646
|
219 |
case CONSTANT_Double:
|
jaroslav@1646
|
220 |
visitor.visitConstantValue(i, tag, buffer.getDouble());
|
jaroslav@1646
|
221 |
i+=2;
|
jaroslav@1646
|
222 |
break;
|
jaroslav@1646
|
223 |
|
jaroslav@1646
|
224 |
case CONSTANT_Class: // fall through:
|
jaroslav@1646
|
225 |
case CONSTANT_String:
|
jaroslav@1646
|
226 |
tags[i] = tag;
|
jaroslav@1646
|
227 |
values[i++] = new int[] { getUnsignedShort(buffer) };
|
jaroslav@1646
|
228 |
break;
|
jaroslav@1646
|
229 |
|
jaroslav@1646
|
230 |
case CONSTANT_Fieldref: // fall through:
|
jaroslav@1646
|
231 |
case CONSTANT_Methodref: // fall through:
|
jaroslav@1646
|
232 |
case CONSTANT_InterfaceMethodref: // fall through:
|
jaroslav@1646
|
233 |
case CONSTANT_NameAndType:
|
jaroslav@1646
|
234 |
tags[i] = tag;
|
jaroslav@1646
|
235 |
values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) };
|
jaroslav@1646
|
236 |
break;
|
jaroslav@1646
|
237 |
default:
|
jaroslav@1646
|
238 |
throw new AssertionError("invalid constant "+tag);
|
jaroslav@1646
|
239 |
}
|
jaroslav@1646
|
240 |
}
|
jaroslav@1646
|
241 |
}
|
jaroslav@1646
|
242 |
|
jaroslav@1646
|
243 |
private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) {
|
jaroslav@1646
|
244 |
// clean out the int[] values, which are temporary
|
jaroslav@1646
|
245 |
for (int beg = 1, end = values.length-1, beg2, end2;
|
jaroslav@1646
|
246 |
beg <= end;
|
jaroslav@1646
|
247 |
beg = beg2, end = end2) {
|
jaroslav@1646
|
248 |
beg2 = end; end2 = beg-1;
|
jaroslav@1646
|
249 |
//System.out.println("CP resolve pass: "+beg+".."+end);
|
jaroslav@1646
|
250 |
for (int i = beg; i <= end; i++) {
|
jaroslav@1646
|
251 |
Object value = values[i];
|
jaroslav@1646
|
252 |
if (!(value instanceof int[]))
|
jaroslav@1646
|
253 |
continue;
|
jaroslav@1646
|
254 |
int[] array = (int[]) value;
|
jaroslav@1646
|
255 |
byte tag = tags[i];
|
jaroslav@1646
|
256 |
switch (tag) {
|
jaroslav@1646
|
257 |
case CONSTANT_String:
|
jaroslav@1646
|
258 |
String stringBody = (String) values[array[0]];
|
jaroslav@1646
|
259 |
visitor.visitConstantString(i, tag, stringBody, array[0]);
|
jaroslav@1646
|
260 |
values[i] = null;
|
jaroslav@1646
|
261 |
break;
|
jaroslav@1646
|
262 |
case CONSTANT_Class: {
|
jaroslav@1646
|
263 |
String className = (String) values[array[0]];
|
jaroslav@1646
|
264 |
// use the external form favored by Class.forName:
|
jaroslav@1646
|
265 |
className = className.replace('/', '.');
|
jaroslav@1646
|
266 |
visitor.visitConstantString(i, tag, className, array[0]);
|
jaroslav@1646
|
267 |
values[i] = className;
|
jaroslav@1646
|
268 |
break;
|
jaroslav@1646
|
269 |
}
|
jaroslav@1646
|
270 |
case CONSTANT_NameAndType: {
|
jaroslav@1646
|
271 |
String memberName = (String) values[array[0]];
|
jaroslav@1646
|
272 |
String signature = (String) values[array[1]];
|
jaroslav@1646
|
273 |
visitor.visitDescriptor(i, tag, memberName, signature,
|
jaroslav@1646
|
274 |
array[0], array[1]);
|
jaroslav@1646
|
275 |
values[i] = new String[] {memberName, signature};
|
jaroslav@1646
|
276 |
break;
|
jaroslav@1646
|
277 |
}
|
jaroslav@1646
|
278 |
case CONSTANT_Fieldref: // fall through:
|
jaroslav@1646
|
279 |
case CONSTANT_Methodref: // fall through:
|
jaroslav@1646
|
280 |
case CONSTANT_InterfaceMethodref: {
|
jaroslav@1646
|
281 |
Object className = values[array[0]];
|
jaroslav@1646
|
282 |
Object nameAndType = values[array[1]];
|
jaroslav@1646
|
283 |
if (!(className instanceof String) ||
|
jaroslav@1646
|
284 |
!(nameAndType instanceof String[])) {
|
jaroslav@1646
|
285 |
// one more pass is needed
|
jaroslav@1646
|
286 |
if (beg2 > i) beg2 = i;
|
jaroslav@1646
|
287 |
if (end2 < i) end2 = i;
|
jaroslav@1646
|
288 |
continue;
|
jaroslav@1646
|
289 |
}
|
jaroslav@1646
|
290 |
String[] nameAndTypeArray = (String[]) nameAndType;
|
jaroslav@1646
|
291 |
visitor.visitMemberRef(i, tag,
|
jaroslav@1646
|
292 |
(String)className,
|
jaroslav@1646
|
293 |
nameAndTypeArray[0],
|
jaroslav@1646
|
294 |
nameAndTypeArray[1],
|
jaroslav@1646
|
295 |
array[0], array[1]);
|
jaroslav@1646
|
296 |
values[i] = null;
|
jaroslav@1646
|
297 |
}
|
jaroslav@1646
|
298 |
break;
|
jaroslav@1646
|
299 |
default:
|
jaroslav@1646
|
300 |
continue;
|
jaroslav@1646
|
301 |
}
|
jaroslav@1646
|
302 |
}
|
jaroslav@1646
|
303 |
}
|
jaroslav@1646
|
304 |
}
|
jaroslav@1646
|
305 |
|
jaroslav@1646
|
306 |
private static int getUnsignedByte(ByteBuffer buffer) {
|
jaroslav@1646
|
307 |
return buffer.get() & 0xFF;
|
jaroslav@1646
|
308 |
}
|
jaroslav@1646
|
309 |
|
jaroslav@1646
|
310 |
private static int getUnsignedShort(ByteBuffer buffer) {
|
jaroslav@1646
|
311 |
int b1 = getUnsignedByte(buffer);
|
jaroslav@1646
|
312 |
int b2 = getUnsignedByte(buffer);
|
jaroslav@1646
|
313 |
return (b1 << 8) + (b2 << 0);
|
jaroslav@1646
|
314 |
}
|
jaroslav@1646
|
315 |
|
jaroslav@1646
|
316 |
private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException {
|
jaroslav@1646
|
317 |
int utfLimit = buffer.position() + utfLen;
|
jaroslav@1646
|
318 |
int index = 0;
|
jaroslav@1646
|
319 |
while (buffer.position() < utfLimit) {
|
jaroslav@1646
|
320 |
int c = buffer.get() & 0xff;
|
jaroslav@1646
|
321 |
if (c > 127) {
|
jaroslav@1646
|
322 |
buffer.position(buffer.position() - 1);
|
jaroslav@1646
|
323 |
return getUTF8Extended(buffer, utfLimit, charArray, index);
|
jaroslav@1646
|
324 |
}
|
jaroslav@1646
|
325 |
charArray[index++] = (char)c;
|
jaroslav@1646
|
326 |
}
|
jaroslav@1646
|
327 |
return new String(charArray, 0, index);
|
jaroslav@1646
|
328 |
}
|
jaroslav@1646
|
329 |
|
jaroslav@1646
|
330 |
private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException {
|
jaroslav@1646
|
331 |
int c, c2, c3;
|
jaroslav@1646
|
332 |
while (buffer.position() < utfLimit) {
|
jaroslav@1646
|
333 |
c = buffer.get() & 0xff;
|
jaroslav@1646
|
334 |
switch (c >> 4) {
|
jaroslav@1646
|
335 |
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
jaroslav@1646
|
336 |
/* 0xxxxxxx*/
|
jaroslav@1646
|
337 |
charArray[index++] = (char)c;
|
jaroslav@1646
|
338 |
break;
|
jaroslav@1646
|
339 |
case 12: case 13:
|
jaroslav@1646
|
340 |
/* 110x xxxx 10xx xxxx*/
|
jaroslav@1646
|
341 |
c2 = buffer.get();
|
jaroslav@1646
|
342 |
if ((c2 & 0xC0) != 0x80)
|
jaroslav@1646
|
343 |
throw new InvalidConstantPoolFormatException(
|
jaroslav@1646
|
344 |
"malformed input around byte " + buffer.position());
|
jaroslav@1646
|
345 |
charArray[index++] = (char)(((c & 0x1F) << 6) |
|
jaroslav@1646
|
346 |
(c2 & 0x3F));
|
jaroslav@1646
|
347 |
break;
|
jaroslav@1646
|
348 |
case 14:
|
jaroslav@1646
|
349 |
/* 1110 xxxx 10xx xxxx 10xx xxxx */
|
jaroslav@1646
|
350 |
c2 = buffer.get();
|
jaroslav@1646
|
351 |
c3 = buffer.get();
|
jaroslav@1646
|
352 |
if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80))
|
jaroslav@1646
|
353 |
throw new InvalidConstantPoolFormatException(
|
jaroslav@1646
|
354 |
"malformed input around byte " + (buffer.position()));
|
jaroslav@1646
|
355 |
charArray[index++] = (char)(((c & 0x0F) << 12) |
|
jaroslav@1646
|
356 |
((c2 & 0x3F) << 6) |
|
jaroslav@1646
|
357 |
((c3 & 0x3F) << 0));
|
jaroslav@1646
|
358 |
break;
|
jaroslav@1646
|
359 |
default:
|
jaroslav@1646
|
360 |
/* 10xx xxxx, 1111 xxxx */
|
jaroslav@1646
|
361 |
throw new InvalidConstantPoolFormatException(
|
jaroslav@1646
|
362 |
"malformed input around byte " + buffer.position());
|
jaroslav@1646
|
363 |
}
|
jaroslav@1646
|
364 |
}
|
jaroslav@1646
|
365 |
// The number of chars produced may be less than utflen
|
jaroslav@1646
|
366 |
return new String(charArray, 0, index);
|
jaroslav@1646
|
367 |
}
|
jaroslav@1646
|
368 |
}
|