UNPKG

java-class-tools

Version:

Read and write java class files in node or browser.

1,025 lines (836 loc) 35.2 kB
"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;