/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.utility.classfile;
import java.io.IOException;
import org.eclipse.persistence.tools.workbench.utility.classfile.tools.ClassFileDataInputStream;
import org.eclipse.persistence.tools.workbench.utility.io.IndentingPrintWriter;
/**
* This class models a class file UTF8 constant:
* u1 tag;
* u2 length;
* u1[] bytes;
*
* See "The Java Virtual Machine Specification" Chapter 4.
*/
public class UTF8Constant extends Constant {
private String value;
/**
* Construct a class file constant from the specified stream
* of byte codes.
*/
UTF8Constant(ConstantPool pool, byte tag, ClassFileDataInputStream stream) throws IOException {
super(pool, tag, stream);
}
void initialize(ClassFileDataInputStream stream) throws IOException {
this.value = this.readStringFrom(stream);
}
private String readStringFrom(ClassFileDataInputStream stream) throws IOException {
short len = stream.readU2();
StringBuffer sb = new StringBuffer(len);
for (short count = 0; count < len; count++) {
byte b = stream.readU1();
if ((b & 0x80) == 0) {
// if the first bit is 0, we have a single-byte character
sb.append((char) b);
} else {
// if the first bit is 1, we have a multi-byte character
if ((b & 0x40) == 0) {
// if the second bit is 0 at this point, something is wrong...
throw this.badByte(b);
}
short s;
if ((b & 0x20) == 0) {
// if the third bit is 0, we have a 2-byte character
s = (short) ((b & 0x1F) << 6); // bits 4-0 become bits 10-6
} else {
// if the third bit is 1, we have a 3-byte character
s = (short) ((b & 0x0F) << 12); // bits 3-0 become bits 15-12
b = stream.readU1();
this.checkContinuation(b);
count++;
s |= ((b & 0x3f) << 6); // bits 5-0 become bits 11-6
}
b = stream.readU1();
this.checkContinuation(b);
count++;
s |= (b & 0x3f); // bits 5-0 become bits 5-0
sb.append((char) s);
}
}
return sb.toString();
}
private final IOException badByte(byte b) {
return new IOException("Invalid UTF-8 byte: " + Byte.toString(b));
}
private final void checkContinuation(byte b) throws IOException {
// the first bit must be 1, the second bit must be 0
if (((b & 0x80) == 0) || ((b & 0x40) != 0)) {
throw this.badByte(b);
}
}
public void displayStringOn(IndentingPrintWriter writer) {
super.displayStringOn(writer);
writer.print(" value: \"");
writer.print(this.value);
writer.println("\"");
}
public String description() {
return "UTF8";
}
public String string() {
return this.value;
}
public Object value() {
return this.value;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}