blob: 95e1fcb2d87fbfda70cacfff4ed605333cd0ccdc [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.cls;
import com.intellij.openapi.util.text.StringUtil;
/** @deprecated to be removed in IDEA 15 */
@SuppressWarnings("ALL")
public class ClsUtil {
public static final int MAGIC = 0xCAFEBABE;
public static final int CONSTANT_Class = 7;
public static final int CONSTANT_Fieldref = 9;
public static final int CONSTANT_Methodref = 10;
public static final int CONSTANT_InterfaceMethodref = 11;
public static final int CONSTANT_String = 8;
public static final int CONSTANT_Integer = 3;
public static final int CONSTANT_Float = 4;
public static final int CONSTANT_Long = 5;
public static final int CONSTANT_Double = 6;
public static final int CONSTANT_NameAndType = 12;
public static final int CONSTANT_Utf8 = 1;
public static final int CONSTANT_MethodHandle = 15;
public static final int CONSTANT_MethodType = 16;
public static final int CONSTANT_InvokeDynamic = 18;
public static final int ACC_PUBLIC = 0x0001;
public static final int ACC_PRIVATE = 0x0002;
public static final int ACC_PROTECTED = 0x0004;
public static final int ACC_STATIC = 0x0008;
public static final int ACC_FINAL = 0x0010;
public static final int ACC_SYNCHRONIZED = 0x0020;
public static final int ACC_BRIDGE = 0x0040;
public static final int ACC_VARARGS = 0x0080;
public static final int ACC_VOLATILE = 0x0040;
public static final int ACC_TRANSIENT = 0x0080;
public static final int ACC_NATIVE = 0x0100;
public static final int ACC_INTERFACE = 0x0200;
public static final int ACC_ABSTRACT = 0x0400;
public static final int ACC_SYNTHETIC = 0x1000;
public static final int ACC_ANNOTATION = 0x2000;
public static final int ACC_ENUM = 0x4000;
/**
* Mask of access_flags that are meaningful in .class file format (VM Spec 4.1)
*/
public static final int ACC_CLASS_MASK = ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT | ACC_STATIC | ACC_ANNOTATION;
public static final int ACC_FIELD_MASK = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_VOLATILE | ACC_TRANSIENT;
public static final int ACC_METHOD_MASK = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | ACC_ABSTRACT;
private static final int POSITIVE_INFINITY_AS_INT = 0x7f800000;
private static final long POSITIVE_INFINITY_AS_LONG = 0x7f80000000000000L;
private static final int NEGATIVE_INFINITY_AS_INT = 0xff800000;
private static final long NEGATIVE_INFINITY_AS_LONG = 0xff80000000000000L;
public static int readU1(BytePointer ptr) throws ClsFormatException {
if (ptr.offset < 0 || ptr.offset >= ptr.bytes.length) {
throw new ClsFormatException();
}
return ptr.bytes[ptr.offset++] & 0xFF;
}
public static int readU2(BytePointer ptr) throws ClsFormatException {
int b1 = readU1(ptr);
int b2 = readU1(ptr);
return (b1 << 8) + b2;
}
public static int readU4(BytePointer ptr) throws ClsFormatException {
int b1 = readU1(ptr);
int b2 = readU1(ptr);
int b3 = readU1(ptr);
int b4 = readU1(ptr);
return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
}
public static long readU8(BytePointer ptr) throws ClsFormatException {
long b1 = readU1(ptr);
long b2 = readU1(ptr);
long b3 = readU1(ptr);
long b4 = readU1(ptr);
long b5 = readU1(ptr);
long b6 = readU1(ptr);
long b7 = readU1(ptr);
long b8 = readU1(ptr);
return (b1 << 56) + (b2 << 48) + (b3 << 40) + (b4 << 32) + (b5 << 24) + (b6 << 16) + (b7 << 8) + b8;
}
public static String readUtf8Info(BytePointer ptr) throws ClsFormatException {
return readUtf8Info(ptr, -1, -1);
}
public static String readUtf8Info(BytePointer ptr, int oldChar, int newChar) throws ClsFormatException {
int tag = readU1(ptr);
if (tag != CONSTANT_Utf8) {
throw new ClsFormatException();
}
int length = readU2(ptr);
return readUtf8(ptr.bytes, ptr.offset, ptr.offset + length, oldChar, newChar);
}
public static String readUtf8Info(byte[] bytes, int startOffset) throws ClsFormatException {
int offset = startOffset;
if (offset + 3 > bytes.length) {
throw new ClsFormatException();
}
int tag = bytes[offset++] & 0xFF;
if (tag != CONSTANT_Utf8) {
throw new ClsFormatException();
}
int b1 = bytes[offset++] & 0xFF;
int b2 = bytes[offset++] & 0xFF;
int length = (b1 << 8) + b2;
if (offset + length > bytes.length) {
throw new ClsFormatException();
}
return readUtf8(bytes, offset, offset + length);
}
private static String readUtf8(byte[] bytes, int startOffset, int endOffset) throws ClsFormatException {
return readUtf8(bytes, startOffset, endOffset, -1, -1);
}
private static String readUtf8(byte[] bytes, int startOffset, int endOffset, int oldChar, int newChar) throws ClsFormatException {
char[] buffer = new char[endOffset - startOffset];
int bOffset = 0;
int offset = startOffset;
while (offset < endOffset) {
int b = bytes[offset++] & 0xFF;
if (b == 0 || b >= 0xF0) {
throw new ClsFormatException();
}
if (b < 0x80) {
buffer[bOffset++] = (char) (b == oldChar ? newChar : b);
} else {
if (offset == endOffset) {
throw new ClsFormatException();
}
int b1 = bytes[offset++] & 0xFF;
if ((b & 0x20) == 0) {
buffer[bOffset++] = (char) (((b & 0x1F) << 6) + (b1 & 0x3F));
} else {
if (offset == endOffset) {
throw new ClsFormatException();
}
int b2 = bytes[offset++] & 0xFF;
buffer[bOffset++] = (char) (((b & 0xF) << 12) + ((b1 & 0x3F) << 6) + (b2 & 0x3F));
}
}
}
return new String(buffer, 0, bOffset);
}
public static double readDouble(BytePointer ptr) throws ClsFormatException {
int high = readU4(ptr);
int low = readU4(ptr);
long longValue = ((long) high << 32) + low;
double doubleValue;
if (longValue == POSITIVE_INFINITY_AS_LONG) {
doubleValue = Double.POSITIVE_INFINITY;
}
else if (longValue == NEGATIVE_INFINITY_AS_LONG) {
doubleValue = Double.NEGATIVE_INFINITY;
}
else if (0x7ff0000000000001L <= longValue && longValue <= 0x7fffffffffffffffL) {
doubleValue = Double.NaN;
}
else if (0xfff0000000000001L <= longValue && longValue <= 0xffffffffffffffffL) {
doubleValue = Double.NaN;
}
else {
int s = ((longValue >> 63) == 0) ? 1 : -1;
int e = (int)((longValue >> 52) & 0x7ffL);
long m = (e == 0) ? ((longValue & 0xfffffffffffffL) << 1) : ((longValue & 0xfffffffffffffL) | 0x10000000000000L);
doubleValue = s * m * Math.pow(2, e - 1075);
}
return doubleValue;
}
public static float readFloat(BytePointer ptr) throws ClsFormatException {
int value = readU4(ptr);
float floatValue;
if (value == POSITIVE_INFINITY_AS_INT) {
floatValue = Float.POSITIVE_INFINITY;
} else if (value == NEGATIVE_INFINITY_AS_INT) {
floatValue = Float.NEGATIVE_INFINITY;
} else if ((value >= 0x7f800001 && value <= 0x7fffffff) || (value >= 0xff800001 && value <= 0xffffffff)) {
floatValue = Float.NaN;
} else {
int s = ((value >> 31) == 0) ? 1 : -1;
int e = ((value >> 23) & 0xff);
int m = (e == 0) ? (value & 0x7fffff) << 1 : (value & 0x7fffff) | 0x800000;
floatValue = (float) (s * m * Math.pow(2, e - 150));
}
return floatValue;
}
public static void skipAttribute(BytePointer ptr) throws ClsFormatException {
ptr.offset += 2;
int length = readU4(ptr);
ptr.offset += length;
}
public static void skipAttributes(BytePointer ptr) throws ClsFormatException {
int count = readU2(ptr);
for (int i = 0; i < count; i++) {
skipAttribute(ptr);
}
}
@SuppressWarnings({"HardCodedStringLiteral"})
public static String getTypeText(byte[] data, int offset) throws ClsFormatException {
int count = 0;
while (true) {
if (offset >= data.length) {
throw new ClsFormatException();
}
if (data[offset] != '[') break;
offset++;
count++;
}
String text;
switch ((char) data[offset]) {
default:
throw new ClsFormatException();
case 'B':
text = "byte";
break;
case 'C':
text = "char";
break;
case 'D':
text = "double";
break;
case 'F':
text = "float";
break;
case 'I':
text = "int";
break;
case 'J':
text = "long";
break;
case 'S':
text = "short";
break;
case 'Z':
text = "boolean";
break;
case 'V':
text = "void";
break;
case 'L':
int offset1 = offset + 1;
while (true) {
if (offset1 >= data.length) {
throw new ClsFormatException();
}
if (data[offset1] == ';') break;
offset1++;
}
String className = readUtf8(data, offset + 1, offset1, '/', '.');
text = convertClassName(className, false);
break;
}
for (int i = 0; i < count; i++) {
text += "[]";
}
return text;
}
public static int getTypeEndOffset(byte[] data, int startOffset) throws ClsFormatException {
int offset = startOffset;
while (true) {
if (offset >= data.length) {
throw new ClsFormatException();
}
if (data[offset] != '[') break;
offset++;
}
if (data[offset++] == 'L') {
while (true) {
if (offset >= data.length) {
throw new ClsFormatException();
}
if (data[offset++] == ';') break;
}
}
return offset;
}
public static String convertClassName(String internalClassName, boolean convertSlashesToDots) {
String className = convertSlashesToDots ? internalClassName.replace('/', '.') : internalClassName;
int index = className.indexOf('$');
if (index < 0) return className;
StringBuilder buffer = new StringBuilder(className);
while(true){
if (className.length() == index + 1) break;
char c = className.charAt(index + 1);
if (Character.isJavaIdentifierStart(c)){
buffer.setCharAt(index, '.');
}
index = className.indexOf('$', index + 1);
if (index < 0) break;
}
return buffer.toString();
}
public static boolean isPublic(int flags) {
return (ACC_PUBLIC & flags) != 0;
}
public static boolean isProtected(int flags) {
return (ACC_PROTECTED & flags) != 0;
}
public static boolean isPackageLocal(int flags) {
return !isPublic(flags) && !isProtected(flags) && !isPrivate(flags);
}
public static boolean isPrivate(int flags) {
return (ACC_PRIVATE & flags) != 0;
}
public static boolean isAbstract(int flags) {
return (ACC_ABSTRACT & flags) != 0;
}
public static boolean isBridge(int flags) {
return (ACC_BRIDGE & flags) != 0;
}
public static boolean isSynthetic(int flags) {
return (ACC_SYNTHETIC & flags) != 0;
}
public static boolean isAnnotation(int flags) {
return (ACC_ANNOTATION & flags) != 0;
}
public static boolean isFinal(int flags) {
return (ACC_FINAL & flags) != 0;
}
public static boolean isStatic(int flags) {
return (ACC_STATIC & flags) != 0;
}
public static String literalToString(CharSequence value, char quote) {
return quote + StringUtil.escapeStringCharacters(value.toString()) + quote;
}
}