java-class-tools
Version:
Read and write java class files in node or browser.
1,025 lines (836 loc) • 35.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _bytebuffer = _interopRequireDefault(require("bytebuffer"));
var _constantType = _interopRequireDefault(require("./constant-type"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* All objects (structure) follow Jvm8 specification.
*
* @see https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html
*/
var JavaClassFileReader =
/*#__PURE__*/
function () {
function JavaClassFileReader() {
_classCallCheck(this, JavaClassFileReader);
}
_createClass(JavaClassFileReader, [{
key: "read",
/**
* Read and parse class file contents.
*
* @param {(Uint8Array|Buffer|ArrayBuffer)} source - Class file contents.
* @return {ClassFile}
* @see {@link https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.1}
*/
value: function read(source) {
if (source == undefined) {
throw TypeError('source cannot be null or undefined');
}
if (typeof source === 'string') {
return this.readFromFile(source);
}
this.buf = _bytebuffer["default"].wrap(source);
this.classFile = new function ClassFile() {}(); // Read magic
if (this.buf.readUint32() !== 0xCAFEBABE) {
throw Error('Invalid MAGIC value');
}
this.classFile.minor_version = this.buf.readUint16();
this.classFile.major_version = this.buf.readUint16();
this.classFile.constant_pool_count = this.buf.readUint16();
this.classFile.constant_pool = this._readConstantPool(this.classFile.constant_pool_count - 1);
this.classFile.access_flags = this.buf.readUint16();
this.classFile.this_class = this.buf.readUint16();
this.classFile.super_class = this.buf.readUint16();
this.classFile.interfaces_count = this.buf.readUint16();
this.classFile.interfaces = this._readInterfaces(this.classFile.interfaces_count);
this.classFile.fields_count = this.buf.readUint16();
this.classFile.fields = this._readMemberInfoArray(this.classFile.fields_count);
this.classFile.methods_count = this.buf.readUint16();
this.classFile.methods = this._readMemberInfoArray(this.classFile.methods_count);
this.classFile.attributes_count = this.buf.readUint16();
this.classFile.attributes = this._readAttributeInfoArray(this.classFile.attributes_count);
var classFile = this.classFile; // Dispose
delete this.buf;
delete this.classFile;
return classFile;
}
}, {
key: "readFromFile",
value: function readFromFile(path) {
if ((typeof process === "undefined" ? "undefined" : _typeof(process)) !== undefined) {
var fs = require('fs');
return this.read(fs.readFileSync(path));
} else {
throw Error('readFromFile is not supported in the browser.');
}
}
/**
* Read an array of field_info or method_info structures.
*
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5
*/
}, {
key: "_readMemberInfoArray",
value: function _readMemberInfoArray(count) {
var members = new Array(count);
for (var i = 0; i < count; i++) {
var memberInfo = {
access_flags: this.buf.readUint16(),
name_index: this.buf.readUint16(),
descriptor_index: this.buf.readUint16(),
attributes_count: this.buf.readUint16()
};
memberInfo.attributes = this._readAttributeInfoArray(memberInfo.attributes_count);
members[i] = memberInfo;
}
return members;
}
}, {
key: "_readAttributeInfoArray",
value: function _readAttributeInfoArray(attributes_count) {
var attributes = new Array(attributes_count);
for (var i = 0; i < attributes_count; i++) {
attributes[i] = this._readAttributeInfo();
}
return attributes;
}
/**
* Reads the "verification_type_info" structure.
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
*/
}, {
key: "_readVerificationTypeInfo",
value: function _readVerificationTypeInfo() {
var type_info = {
tag: this.buf.readUint8()
};
if (type_info.tag === 7) {
type_info.cpool_index = this.buf.readUint16();
} else if (type_info.tag === 8) {
type_info.offset = this.buf.readUint16();
}
return type_info;
}
/**
* Reads the "type_annotation" structure
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20
*/
}, {
key: "_readTypeAnnotation",
value: function _readTypeAnnotation() {
var type_annotation = {
target_type: this.buf.readUint8(),
target_info: {}
}; // Reads the "target_info" union.
// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20-400
switch (type_annotation.target_type) {
// type_parameter_target
case 0x00:
case 0x01:
type_annotation.target_info.type_parameter_index = this.buf.readUint8();
break;
// supertype_target
case 0x10:
type_annotation.target_info.supertype_index = this.buf.readUint16();
break;
// type_parameter_bound_target
case 0x11:
case 0x12:
type_annotation.target_info.type_parameter_index = this.buf.readUint8();
type_annotation.target_info.bound_index = this.buf.readUint8();
break;
// empty_target
case 0x13:
case 0x14:
case 0x15:
// empty
break;
// formal_parameter_target
case 0x16:
type_annotation.target_info.formal_parameter_index = this.buf.readUint8();
break;
// throws_target
case 0x17:
type_annotation.target_info.throws_type_index = this.buf.readUint16();
break;
// localvar_target
case 0x40:
case 0x41:
{
type_annotation.target_info.table_length = this.buf.readUint16();
type_annotation.target_info.table = new Array(type_annotation.target_info.table_length);
for (var i = 0; i < type_annotation.target_info.table_length; i++) {
var table_entry = {
start_pc: this.buf.readUint16(),
length: this.buf.readUint16(),
index: this.buf.readUint16()
};
type_annotation.target_info.table[i] = table_entry;
}
break;
}
// catch_target
case 0x42:
type_annotation.target_info.exception_table_index = this.buf.readUint16();
break;
// offset_target
case 0x43:
case 0x44:
case 0x45:
case 0x46:
type_annotation.target_info.offset = this.buf.readUint16();
break;
// type_argument_target
case 0x47:
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
type_annotation.target_info.offset = this.buf.readUint16();
type_annotation.target_info.type_argument_index = this.buf.readUint8();
break;
default:
throw Error("Unexpected target_type: ".concat(type_annotation.target_type));
} // Reads "type_path" structure
type_annotation.type_path = {
path_length: this.buf.readUint8()
};
type_annotation.type_path.path = new Array(type_annotation.type_path.path_length);
for (var _i = 0; _i < type_annotation.type_path.path_length; _i++) {
type_annotation.type_path.path[_i] = {
type_path_kind: this.buf.readUint8(),
type_argument_index: this.buf.readUint8()
};
}
type_annotation.type_index = this.buf.readUint16();
type_annotation.num_element_value_pairs = this.buf.readUint16();
type_annotation.element_value_pairs = new Array(type_annotation.num_element_value_pairs);
for (var _i2 = 0; _i2 < type_annotation.num_element_value_pairs; _i2++) {
type_annotation.element_value_pairs[_i2] = {
element_name_index: this.buf.readUint16(),
element_value: this._readElementValue()
};
}
return type_annotation;
}
/**
* Reads the "attribute_info" structure
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7
*/
}, {
key: "_readAttributeInfo",
value: function _readAttributeInfo() {
var attribute = {
attribute_name_index: this.buf.readUint16(),
attribute_length: this.buf.readUint32()
};
var attributeNameBytes = this.classFile.constant_pool[attribute.attribute_name_index].bytes;
var attributeName = String.fromCharCode.apply(null, attributeNameBytes); // TODO: is this safe?
switch (attributeName) {
case 'Deprecated':
case 'Synthetic':
break;
case 'RuntimeInvisibleAnnotations':
case 'RuntimeVisibleAnnotations':
{
attribute.num_annotations = this.buf.readUint16();
attribute.annotations = new Array(attribute.num_annotations);
for (var i = 0; i < attribute.num_annotations; i++) {
attribute.annotations[i] = this._readAttributeAnnotation();
}
break;
}
case 'InnerClasses':
{
attribute.number_of_classes = this.buf.readUint16();
attribute.classes = new Array(attribute.number_of_classes);
for (var _i3 = 0; _i3 < attribute.number_of_classes; _i3++) {
attribute.classes[_i3] = {
inner_class_info_index: this.buf.readUint16(),
outer_class_info_index: this.buf.readUint16(),
inner_name_index: this.buf.readUint16(),
inner_class_access_flags: this.buf.readUint16()
};
}
break;
}
case 'LocalVariableTable':
{
attribute.local_variable_table_length = this.buf.readUint16();
attribute.local_variable_table = new Array(attribute.local_variable_table_length);
for (var _i4 = 0; _i4 < attribute.local_variable_table_length; _i4++) {
attribute.local_variable_table[_i4] = {
start_pc: this.buf.readUint16(),
length: this.buf.readUint16(),
name_index: this.buf.readUint16(),
descriptor_index: this.buf.readUint16(),
index: this.buf.readUint16()
};
}
break;
}
case 'LocalVariableTypeTable':
{
attribute.local_variable_type_table_length = this.buf.readUint16();
attribute.local_variable_type_table = new Array(attribute.local_variable_type_table_length);
for (var _i5 = 0; _i5 < attribute.local_variable_type_table_length; _i5++) {
attribute.local_variable_type_table[_i5] = {
start_pc: this.buf.readUint16(),
length: this.buf.readUint16(),
name_index: this.buf.readUint16(),
signature_index: this.buf.readUint16(),
index: this.buf.readUint16()
};
}
break;
}
case 'RuntimeInvisibleParameterAnnotations':
case 'RuntimeVisibleParameterAnnotations':
{
attribute.num_parameters = this.buf.readUint8();
attribute.parameter_annotations = new Array(attribute.num_parameters);
for (var parameterIndex = 0; parameterIndex < attribute.num_parameters; parameterIndex++) {
var parameter_annotation = {
num_annotations: this.buf.readUint16()
};
parameter_annotation.annotations = new Array(parameter_annotation.num_annotations);
for (var annotationIndex = 0; annotationIndex < parameter_annotation.num_annotations; annotationIndex++) {
parameter_annotation.annotations[annotationIndex] = this._readAttributeAnnotation();
}
attribute.parameter_annotations[parameterIndex] = parameter_annotation;
}
break;
}
case 'BootstrapMethods':
{
attribute.num_bootstrap_methods = this.buf.readUint16();
attribute.bootstrap_methods = new Array(attribute.num_bootstrap_methods);
for (var bootstrapMethodIndex = 0; bootstrapMethodIndex < attribute.num_bootstrap_methods; bootstrapMethodIndex++) {
var bootstrap_method = {
bootstrap_method_ref: this.buf.readUint16(),
num_bootstrap_arguments: this.buf.readUint16()
};
bootstrap_method.bootstrap_arguments = new Array(bootstrap_method.num_bootstrap_arguments);
for (var bootstrapArgumentIndex = 0; bootstrapArgumentIndex < bootstrap_method.num_bootstrap_arguments; bootstrapArgumentIndex++) {
bootstrap_method.bootstrap_arguments[bootstrapArgumentIndex] = this.buf.readUint16();
}
attribute.bootstrap_methods[bootstrapMethodIndex] = bootstrap_method;
}
break;
}
case 'RuntimeInvisibleTypeAnnotations':
case 'RuntimeVisibleTypeAnnotations':
{
attribute.num_annotations = this.buf.readUint16();
attribute.annotations = new Array(attribute.num_annotations);
for (var _i6 = 0; _i6 < attribute.num_annotations; _i6++) {
attribute.annotations[_i6] = this._readTypeAnnotation();
}
break;
}
case 'SourceDebugExtension':
{
attribute.debug_extension = new Array(attribute.attribute_length);
for (var _i7 = 0; _i7 < attribute.attribute_length; _i7++) {
attribute.debug_extension[_i7] = this.buf.readUint8();
}
break;
}
case 'SourceFile':
attribute.sourcefile_index = this.buf.readUint16();
break;
case 'EnclosingMethod':
attribute.class_index = this.buf.readUint16();
attribute.method_index = this.buf.readUint16();
break;
case 'AnnotationDefault':
attribute.default_value = this._readElementValue();
break;
case 'MethodParameters':
{
attribute.parameters_count = this.buf.readUint8();
attribute.parameters = new Array(attribute.parameters_count);
for (var _i8 = 0; _i8 < attribute.parameters_count; _i8++) {
attribute.parameters[_i8] = {
name_index: this.buf.readUint16(),
access_flags: this.buf.readUint16()
};
}
break;
}
case 'ConstantValue':
attribute.constantvalue_index = this.buf.readUint16();
break;
case 'Signature':
attribute.signature_index = this.buf.readUint16();
break;
case 'StackMap':
return this._readStackMapAttribute(attribute);
case 'Exceptions':
return this._readExceptionsAttribute(attribute);
case 'StackMapTable':
return this._readStackMapTableAttribute(attribute);
case 'Code':
return this._readCodeAttribute(attribute);
case 'LineNumberTable':
return this._readLineNumberTableAttribute(attribute);
case 'Module':
return this._readModuleAttribute(attribute);
case 'ModulePackages':
return this._readModulePackagesAttribute(attribute);
case 'ModuleMainClass':
attribute.main_class_index = this.buf.readUint16();
break;
case 'NestHost':
attribute.host_class_index = this.buf.readUint16();
break;
case 'NestMembers':
attribute.number_of_classes = this.buf.readUint16();
attribute.classes = new Array(attribute.number_of_classes);
for (var _i9 = 0; _i9 < attribute.number_of_classes; _i9++) {
attribute.classes[_i9] = this.buf.readUint16();
}
break;
// Unknown attributes
// See: https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.1
default:
{
attribute.info = new Array(attribute.attribute_length);
for (var _i10 = 0; _i10 < attribute.attribute_length; _i10++) {
attribute.info[_i10] = this.buf.readUint8();
}
}
}
return attribute;
}
}, {
key: "_readCodeAttribute",
value: function _readCodeAttribute(attribute) {
attribute.max_stack = this.buf.readUint16();
attribute.max_locals = this.buf.readUint16();
attribute.code_length = this.buf.readUint32();
attribute.code = new Array(attribute.code_length); // Reads "code" array
for (var i = 0; i < attribute.code_length; i++) {
attribute.code[i] = this.buf.readUint8();
}
attribute.exception_table_length = this.buf.readUint16();
attribute.exception_table = new Array(attribute.exception_table_length); // Reads exception_table
for (var _i11 = 0; _i11 < attribute.exception_table_length; _i11++) {
attribute.exception_table[_i11] = {
start_pc: this.buf.readUint16(),
end_pc: this.buf.readUint16(),
handler_pc: this.buf.readUint16(),
catch_type: this.buf.readUint16()
};
}
attribute.attributes_count = this.buf.readUint16();
attribute.attributes = this._readAttributeInfoArray(attribute.attributes_count);
return attribute;
}
}, {
key: "_readLineNumberTableAttribute",
value: function _readLineNumberTableAttribute(attribute) {
attribute.line_number_table_length = this.buf.readUint16();
attribute.line_number_table = new Array(attribute.line_number_table_length);
for (var i = 0; i < attribute.line_number_table_length; i++) {
attribute.line_number_table[i] = {
start_pc: this.buf.readUint16(),
line_number: this.buf.readUint16()
};
}
return attribute;
} // TODO: this function is being deoptimized one time... Check why
}, {
key: "_readStackMapTableAttribute",
value: function _readStackMapTableAttribute(attribute) {
attribute.number_of_entries = this.buf.readUint16();
attribute.entries = new Array(attribute.number_of_entries);
for (var entryIndex = 0; entryIndex < attribute.number_of_entries; entryIndex++) {
var stack_map_frame = {
frame_type: this.buf.readUint8()
}; // Shorthand
var frame_type = stack_map_frame.frame_type;
/**
* offset_delta's that are "constant" are omitted.
* E.g:
* The offset_delta for the "same_frame" is the value of the tag item (frame_type).
* The offset_delta for the "same_locals_1_stack_item_frame " is given by the formula frame_type - 64.
*
* See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
* for more information.
*/
// SAME
if (frame_type >= 0 && frame_type <= 63) {
attribute.entries[entryIndex] = stack_map_frame;
continue;
} // SAME_LOCALS_1_STACK_ITEM
if (frame_type >= 64 && frame_type <= 127) {
stack_map_frame.stack = [this._readVerificationTypeInfo()];
} // SAME_LOCALS_1_STACK_ITEM_EXTENDED
else if (stack_map_frame.frame_type === 247) {
stack_map_frame.offset_delta = this.buf.readUint16();
stack_map_frame.stack = [this._readVerificationTypeInfo()];
} // CHOP = 248-250, SAME_FRAME_EXTENDED = 251
else if (frame_type >= 248 && frame_type <= 251) {
stack_map_frame.offset_delta = this.buf.readUint16();
} // APPEND
else if (frame_type >= 252 && frame_type <= 254) {
var numberOfLocals = frame_type - 251;
stack_map_frame.offset_delta = this.buf.readUint16();
stack_map_frame.locals = new Array(numberOfLocals);
for (var i = 0; i < numberOfLocals; i++) {
stack_map_frame.locals[i] = this._readVerificationTypeInfo();
}
} // FULL_FRAME
else if (frame_type === 255) {
stack_map_frame.offset_delta = this.buf.readUint16();
stack_map_frame.number_of_locals = this.buf.readUint16();
stack_map_frame.locals = new Array(stack_map_frame.number_of_locals);
for (var _i12 = 0; _i12 < stack_map_frame.number_of_locals; _i12++) {
stack_map_frame.locals[_i12] = this._readVerificationTypeInfo();
}
stack_map_frame.number_of_stack_items = this.buf.readUint16();
stack_map_frame.stack = new Array(stack_map_frame.number_of_stack_items);
for (var _i13 = 0; _i13 < stack_map_frame.number_of_stack_items; _i13++) {
stack_map_frame.stack[_i13] = this._readVerificationTypeInfo();
}
}
attribute.entries[entryIndex] = stack_map_frame;
}
return attribute;
}
}, {
key: "_readExceptionsAttribute",
value: function _readExceptionsAttribute(attribute) {
attribute.number_of_exceptions = this.buf.readUint16();
attribute.exception_index_table = new Array(attribute.number_of_exceptions);
for (var i = 0; i < attribute.number_of_exceptions; i++) {
attribute.exception_index_table[i] = this.buf.readUint16();
}
return attribute;
}
/**
* http://download.oracle.com/otndocs/jcp/7247-j2me_cldc-1.1-fr-spec-oth-JSpec/
*
* Appendix1-verifier.pdf at "2.1 Stack map format"
*
* "According to the CLDC specification, the sizes of some fields are not 16bit
* but 32bit if the code size is more than 64K or the number of the local variables
* is more than 64K. However, for the J2ME CLDC technology, they are always 16bit.
* The implementation of the StackMap class assumes they are 16bit." - javaassist
*/
}, {
key: "_readStackMapAttribute",
value: function _readStackMapAttribute(attribute) {
attribute.number_of_entries = this.buf.readUint16();
attribute.entries = new Array(attribute.number_of_entries);
for (var entryIndex = 0; entryIndex < attribute.number_of_entries; entryIndex++) {
var stack_map_frame = {
offset: this.buf.readUint16()
}; // Read locals
stack_map_frame.number_of_locals = this.buf.readUint16();
stack_map_frame.locals = new Array(stack_map_frame.number_of_locals);
for (var i = 0; i < stack_map_frame.number_of_locals; i++) {
stack_map_frame.locals[i] = this._readVerificationTypeInfo();
} // Read stack
stack_map_frame.number_of_stack_items = this.buf.readUint16();
stack_map_frame.stack = new Array(stack_map_frame.number_of_stack_items);
for (var _i14 = 0; _i14 < stack_map_frame.number_of_stack_items; _i14++) {
stack_map_frame.stack[_i14] = this._readVerificationTypeInfo();
}
attribute.entries[entryIndex] = stack_map_frame;
}
return attribute;
}
}, {
key: "_readModuleAttribute",
value: function _readModuleAttribute(attribute) {
attribute.module_name_index = this.buf.readUint16();
attribute.module_flags = this.buf.readUint16();
attribute.module_version_index = this.buf.readUint16();
attribute.requires_count = this.buf.readUint16();
attribute.requires = new Array(attribute.requires_count);
for (var i = 0; i < attribute.requires_count; i++) {
attribute.requires[i] = {
requires_index: this.buf.readUint16(),
requires_flags: this.buf.readUint16(),
requires_version_index: this.buf.readUint16()
};
}
attribute.exports_count = this.buf.readUint16();
attribute.exports = new Array(attribute.exports_count);
for (var exportIndex = 0; exportIndex < attribute.exports_count; exportIndex++) {
var exportEntry = {
exports_index: this.buf.readUint16(),
exports_flags: this.buf.readUint16(),
exports_to_count: this.buf.readUint16()
};
exportEntry.exports_to_index = new Array(exportEntry.exports_to_count);
for (var exportsToIndex = 0; exportsToIndex < exportEntry.exports_to_count; exportsToIndex++) {
exportEntry.exports_to_index[exportsToIndex] = this.buf.readUint16();
}
attribute.exports[exportIndex] = exportEntry;
}
attribute.opens_count = this.buf.readUint16();
attribute.opens = new Array(attribute.opens_count);
for (var openIndex = 0; openIndex < attribute.opens_count; openIndex++) {
var openEntry = {
opens_index: this.buf.readUint16(),
opens_flags: this.buf.readUint16(),
opens_to_count: this.buf.readUint16()
};
openEntry.opens_to_index = new Array(openEntry.opens_to_count);
for (var opensToIndex = 0; opensToIndex < openEntry.opens_to_count; opensToIndex++) {
openEntry.opens_to_index[opensToIndex] = this.buf.readUint16();
}
attribute.opens[openIndex] = openEntry;
}
attribute.uses_count = this.buf.readUint16();
attribute.uses_index = new Array(attribute.uses_count);
;
for (var _i15 = 0; _i15 < attribute.uses_count; _i15++) {
attribute.uses_index[_i15] = this.buf.readUint16();
}
attribute.provides_count = this.buf.readUint16();
attribute.provides = new Array(attribute.provides_count);
for (var providesIndex = 0; providesIndex < attribute.provides_count; providesIndex++) {
var provideEntry = {
provides_index: this.buf.readUint16(),
provides_with_count: this.buf.readUint16()
};
provideEntry.provides_with_index = new Array(provideEntry.provides_with_count);
for (var providesWithIndex = 0; providesWithIndex < provideEntry.provides_with_count; providesWithIndex++) {
provideEntry.provides_with_index[providesWithIndex] = this.buf.readUint16();
}
attribute.provides[providesIndex] = provideEntry;
}
return attribute;
}
}, {
key: "_readModulePackagesAttribute",
value: function _readModulePackagesAttribute(attribute) {
attribute.package_count = this.buf.readUint16();
attribute.package_index = new Array(attribute.package_count);
for (var i = 0; i < attribute.package_count; i++) {
attribute.package_index[i] = this.buf.readUint16();
}
return attribute;
}
/**
* Reads the "annotation" structure
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16
*/
}, {
key: "_readAttributeAnnotation",
value: function _readAttributeAnnotation() {
var annotation = {
type_index: this.buf.readUint16(),
num_element_value_pairs: this.buf.readUint16()
};
annotation.element_value_pairs = new Array(annotation.num_element_value_pairs);
for (var i = 0; i < annotation.num_element_value_pairs; i++) {
annotation.element_value_pairs[i] = {
element_name_index: this.buf.readUint16(),
element_value: this._readElementValue()
};
}
return annotation;
}
/**
* Reads the "element_value" structure
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1
*/
}, {
key: "_readElementValue",
value: function _readElementValue() {
var element_value = {
tag: this.buf.readUint8(),
value: {}
};
/**
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1-130
*/
switch (element_value.tag) {
case 101:
// e
element_value.value.enum_const_value = {
type_name_index: this.buf.readUint16(),
const_name_index: this.buf.readUint16()
};
break;
case 99:
// c
element_value.value.class_info_index = this.buf.readUint16();
break;
case 91:
{
// [
var num_values = this.buf.readUint16();
var values = new Array(num_values);
for (var i = 0; i < num_values; i++) {
values[i] = this._readElementValue();
}
element_value.value.array_value = {
num_values: num_values,
values: values
};
break;
}
case 64:
// @
element_value.value.annotation = this._readAttributeAnnotation();
break;
case 66: // B
case 67: // C
case 68: // D
case 70: // F
case 73: // I
case 74: // J
case 83: // S
case 90: // Z
case 115:
// s
element_value.value.const_value_index = this.buf.readUint16();
break;
default:
throw Error("Unexpected tag: ".concat(element_value.tag));
}
return element_value;
}
}, {
key: "_readInterfaces",
value: function _readInterfaces(interfaceCount) {
var interfaces = new Array(interfaceCount);
for (var i = 0; i < interfaceCount; i++) {
interfaces[i] = this.buf.readUint16();
}
return interfaces;
}
/**
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4
*/
}, {
key: "_readConstantPool",
value: function _readConstantPool(poolCount) {
/**
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.1
* The constant_pool table is indexed from 1 to constant_pool_count-1.
*/
var pool = new Array(poolCount);
for (var i = 1; i <= poolCount; i++) {
var entry = this._readConstantPoolEntry();
pool[i] = entry;
/**
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.5
*
* All 8-byte constants take up two entries in the constant_pool table of the class file.
* If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pool table at index n,
* then the next usable item in the pool is located at index n+2.
* The constant_pool index n+ must be valid but is considered unusable.
*/
if (entry.tag === _constantType["default"].LONG || entry.tag === _constantType["default"].DOUBLE) {
pool[++i] = undefined;
}
}
return pool;
}
}, {
key: "_readUtf8PoolEntry",
value: function _readUtf8PoolEntry(tag) {
var length = this.buf.readUint16();
var bytes = new Array(length);
for (var i = 0; i < length; i++) {
bytes[i] = this.buf.readUint8();
}
return {
tag: tag,
length: length,
bytes: bytes
};
}
}, {
key: "_readConstantPoolEntry",
value: function _readConstantPoolEntry() {
var tag = this.buf.readUint8();
switch (tag) {
case _constantType["default"].UTF8:
return this._readUtf8PoolEntry(tag);
case _constantType["default"].INTEGER:
case _constantType["default"].FLOAT:
return {
tag: tag,
bytes: this.buf.readUint32()
};
case _constantType["default"].LONG:
case _constantType["default"].DOUBLE:
return {
tag: tag,
high_bytes: this.buf.readUint32(),
low_bytes: this.buf.readUint32()
};
case _constantType["default"].PACKAGE:
case _constantType["default"].MODULE:
case _constantType["default"].CLASS:
return {
tag: tag,
name_index: this.buf.readUint16()
};
case _constantType["default"].STRING:
return {
tag: tag,
string_index: this.buf.readUint16()
};
/**
* Fields, methods, and interface methods are represented by similar structures
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.2
*/
case _constantType["default"].FIELDREF:
case _constantType["default"].METHODREF:
case _constantType["default"].INTERFACE_METHODREF:
return {
tag: tag,
class_index: this.buf.readUint16(),
name_and_type_index: this.buf.readUint16()
};
case _constantType["default"].NAME_AND_TYPE:
return {
tag: tag,
name_index: this.buf.readUint16(),
descriptor_index: this.buf.readUint16()
};
case _constantType["default"].METHOD_HANDLE:
return {
tag: tag,
reference_kind: this.buf.readUint8(),
reference_index: this.buf.readUint16()
};
case _constantType["default"].METHOD_TYPE:
return {
tag: tag,
descriptor_index: this.buf.readUint16()
};
case _constantType["default"].DYNAMIC:
case _constantType["default"].INVOKE_DYNAMIC:
return {
tag: tag,
bootstrap_method_attr_index: this.buf.readUint16(),
name_and_type_index: this.buf.readUint16()
};
default:
throw Error("Unexpected tag: ".concat(tag));
}
}
}]);
return JavaClassFileReader;
}();
var _default = JavaClassFileReader;
exports["default"] = _default;