R_API RBinJavaElementValue *r_bin_java_element_value_new(ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	ut64 offset = 0;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaElementValue *element_value = R_NEW0 (RBinJavaElementValue);
	if (!element_value) {
		return NULL;
	}
	RBinJavaElementValuePair *evps = NULL;
	element_value->metas = R_NEW0 (RBinJavaMetaInfo);
	if (!element_value->metas) {
		R_FREE (element_value);
		return NULL;
	}
	element_value->file_offset = buf_offset;
	element_value->tag = buffer[offset];
	element_value->size += 1;
	offset += 1;
	element_value->metas->type_info = (void *) r_bin_java_get_ev_meta_from_tag (element_value->tag);
	switch (element_value->tag) {
	case R_BIN_JAVA_EV_TAG_BYTE:
	case R_BIN_JAVA_EV_TAG_CHAR:
	case R_BIN_JAVA_EV_TAG_DOUBLE:
	case R_BIN_JAVA_EV_TAG_FLOAT:
	case R_BIN_JAVA_EV_TAG_INT:
	case R_BIN_JAVA_EV_TAG_LONG:
	case R_BIN_JAVA_EV_TAG_SHORT:
	case R_BIN_JAVA_EV_TAG_BOOLEAN:
	case R_BIN_JAVA_EV_TAG_STRING:
		// look up value in bin->cp_list
		// (ut16) read and set const_value.const_value_idx
		element_value->value.const_value.const_value_idx = R_BIN_JAVA_USHORT (buffer, offset);
		element_value->size += 2;
		// look-up, deep copy, and set const_value.const_value_cp_obj
		element_value->value.const_value.const_value_cp_obj = r_bin_java_clone_cp_idx (R_BIN_JAVA_GLOBAL_BIN, element_value->value.const_value.const_value_idx);
		break;
	case R_BIN_JAVA_EV_TAG_ENUM:
		// (ut16) read and set enum_const_value.type_name_idx
		element_value->value.enum_const_value.type_name_idx = R_BIN_JAVA_USHORT (buffer, offset);
		element_value->size += 2;
		offset += 2;
		// (ut16) read and set enum_const_value.const_name_idx
		element_value->value.enum_const_value.const_name_idx = R_BIN_JAVA_USHORT (buffer, offset);
		element_value->size += 2;
		offset += 2;
		// look up type_name_index in bin->cp_list
		// look-up, deep copy, and set enum_const_value.const_name_cp_obj
		element_value->value.enum_const_value.const_name_cp_obj = r_bin_java_clone_cp_idx (R_BIN_JAVA_GLOBAL_BIN, element_value->value.enum_const_value.const_name_idx);
		// look-up, deep copy, and set enum_const_value.type_name_cp_obj
		element_value->value.enum_const_value.type_name_cp_obj = r_bin_java_clone_cp_idx (R_BIN_JAVA_GLOBAL_BIN, element_value->value.enum_const_value.type_name_idx);
		break;
	case R_BIN_JAVA_EV_TAG_CLASS:
		// (ut16) read and set class_value.class_info_idx
		element_value->value.class_value.class_info_idx = R_BIN_JAVA_USHORT (buffer, offset);
		element_value->size += 2;
		offset += 2;
		// look up type_name_index in bin->cp_list
		// look-up, deep copy, and set class_value.class_info_cp_obj
		element_value->value.class_value.class_info_cp_obj = r_bin_java_clone_cp_idx (R_BIN_JAVA_GLOBAL_BIN, element_value->value.class_value.class_info_idx);
		break;
	case R_BIN_JAVA_EV_TAG_ARRAY:
		// (ut16) read and set array_value.num_values
		element_value->value.array_value.num_values = R_BIN_JAVA_USHORT (buffer, offset);
		element_value->size += 2;
		offset += 2;
		element_value->value.array_value.values = r_list_new ();
		for (i = 0; i < element_value->value.array_value.num_values; i++) {
			if (offset >= sz) {
				break;
			}
			RBinJavaElementValue *ev_element = r_bin_java_element_value_new (buffer + offset, sz - offset, buf_offset + offset);
			if (ev_element) {
				element_value->size += ev_element->size;
				offset += ev_element->size;
				// read array_value.num_values, and append to array_value.values
				r_list_append (element_value->value.array_value.values, (void *) ev_element);
			}
		}
		break;
	case R_BIN_JAVA_EV_TAG_ANNOTATION:
		// annotation new is not used here.
		// (ut16) read and set annotation_value.type_idx;
		if (offset + 8 < sz) {
			element_value->value.annotation_value.type_idx = R_BIN_JAVA_USHORT (buffer, offset);
			element_value->size += 2;
			offset += 2;
			// (ut16) read and set annotation_value.num_element_value_pairs;
			element_value->value.annotation_value.num_element_value_pairs = R_BIN_JAVA_USHORT (buffer, offset);
			element_value->size += 2;
			offset += 2;
		}
		element_value->value.annotation_value.element_value_pairs = r_list_newf (r_bin_java_element_pair_free);
		// read annotation_value.num_element_value_pairs, and append to annotation_value.element_value_pairs
		for (i = 0; i < element_value->value.annotation_value.num_element_value_pairs; i++) {
			if (offset > sz) {
				break;
			}
			evps = r_bin_java_element_pair_new (buffer + offset, sz - offset, buf_offset + offset);
			if (evps) {
				element_value->size += evps->size;
				offset += evps->size;
			}
			if (evps == NULL) {
				// TODO: eprintf error when reading element pair
			}
			r_list_append (element_value->value.annotation_value.element_value_pairs, (void *) evps);
		}
		break;
	default:
		// eprintf unable to handle tag
		break;
	}
	return element_value;
}


Fix oobread in java parser ##crash

* Reported by @bet4it via @huntrdev
* BountyID c8f4c2de-7d96-4ad4-857a-c099effca2d6
* Reproducer: bootstrap.class

R_API void r_bin_java_print_code_exceptions_attr_summary(RBinJavaExceptionEntry *exc_entry) {
	if (exc_entry == NULL) {
		eprintf ("Attempting to print an invalid RBinJavaExceptionEntry *.\n");
		return;
	}
	printf ("  Exception Table Entry Information\n");
	printf ("    offset:	0x%08"PFMT64x"\n", exc_entry->file_offset);
	printf ("    catch_type: %d\n", exc_entry->catch_type);
	printf ("    start_pc:   0x%04x\n", exc_entry->start_pc);
	printf ("    end_pc:	0x%04x\n", exc_entry->end_pc);
	printf ("    handler_pc: 0x%04x\n", exc_entry->handler_pc);
}

Out-of-bounds Read in r_bin_java_bootstrap_methods_attr_new function in GitHub repository radareorg/radare2 prior to 5.7.0. The bug causes the program reads data past the end 2f the intented buffer. Typically, this can allow attackers to read sensitive information from other memory locations or cause a crash. More details see [CWE-125: Out-of-bounds read](https://cwe.mitre.org/data/definitions/125.html).


R_API void r_bin_java_print_annotation_summary(RBinJavaAnnotation *annotation) {
	RListIter *iter = NULL, *iter_tmp = NULL;
	RBinJavaElementValuePair *evp = NULL;
	if (!annotation) {
		// TODO eprintf invalid annotation
		return;
	}
	printf ("  Annotation Type Index: 0x%02x\n", annotation->type_idx);
	printf ("  Annotation Number of EV Pairs: 0x%04x\n", annotation->num_element_value_pairs);
	printf ("  Annotation EV Pair Values:\n");
	if (annotation->element_value_pairs) {
		r_list_foreach_safe (annotation->element_value_pairs, iter, iter_tmp, evp) {
			r_bin_java_print_element_pair_summary (evp);
		}
	}
}


R_API int r_bin_java_check_reset_cp_obj(RBinJavaCPTypeObj *cp_obj, ut8 tag) {
	bool res = false;
	if (tag < R_BIN_JAVA_CP_METAS_SZ) {
		if (tag != cp_obj->tag) {
			if (cp_obj->tag == R_BIN_JAVA_CP_UTF8) {
				R_FREE (cp_obj->info.cp_utf8.bytes);
				cp_obj->info.cp_utf8.length = 0;
				R_FREE (cp_obj->name);
			}
			cp_obj->tag = tag;
			cp_obj->metas->type_info = (void *) &R_BIN_JAVA_CP_METAS[tag];
			cp_obj->name = strdup (R_BIN_JAVA_CP_METAS[tag].name);
			res = true;
		} else {
			eprintf ("Invalid tag\n");
		}
	} else {
		eprintf ("Invalid tag '%d'.\n", tag);
	}
	return res;
}


R_API int r_bin_java_extract_reference_name(const char *input_str, char **ref_str, ut8 array_cnt) {
	char *new_str = NULL;
	ut32 str_len = array_cnt ? (array_cnt + 1) * 2 : 0;
	const char *str_pos = input_str;
	int consumed = 0, len = 0;
	if (!str_pos || *str_pos != 'L' || !*str_pos) {
		return -1;
	}
	consumed++;
	str_pos++;
	while (*str_pos && *str_pos != ';') {
		str_pos++;
		len++;
		consumed++;
	}
	str_pos = input_str + 1;
	free (*ref_str);
	str_len += len;
	*ref_str = malloc (str_len + 1);
	new_str = *ref_str;
	memcpy (new_str, str_pos, str_len);
	new_str[str_len] = 0;
	while (*new_str) {
		if (*new_str == '/') {
			*new_str = '.';
		}
		new_str++;
	}
	return len + 2;
}


R_API RBinJavaVerificationObj *r_bin_java_verification_info_from_type(RBinJavaObj *bin, R_BIN_JAVA_STACKMAP_TYPE type, ut32 value) {
	RBinJavaVerificationObj *se = R_NEW0 (RBinJavaVerificationObj);
	if (se) {
		se->tag = type;
		if (se->tag == R_BIN_JAVA_STACKMAP_OBJECT) {
			se->info.obj_val_cp_idx = (ut16) value;
		} else if (se->tag == R_BIN_JAVA_STACKMAP_UNINIT) {
			se->info.uninit_offset = (ut16) value;
		}
	}
	return se;
}


R_API void r_bin_java_print_utf8_cp_summary(RBinJavaCPTypeObj *obj) {
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  Utf8.\n");
		return;
	}
	char *str = convert_string ((const char *) obj->info.cp_utf8.bytes, obj->info.cp_utf8.length);
	eprintf ("UTF8 ConstantPool Type (%d) ", obj->metas->ord);
	eprintf ("	Offset: 0x%08"PFMT64x"", obj->file_offset);
	eprintf ("	length = %d\n", obj->info.cp_utf8.length);
	eprintf ("	utf8 = %s\n", str);
	free (str);
}


R_API ut64 r_bin_java_annotation_array_calc_size(RBinJavaAnnotationsArray *annotation_array) {
	ut64 size = 0;
	RListIter *iter = NULL, *iter_tmp = NULL;
	RBinJavaAnnotation *annotation;
	if (!annotation_array->annotations) {
		// TODO eprintf
		return size;
	}
	// annotation_array->num_annotations = R_BIN_JAVA_USHORT (buffer, offset);
	size += 2;
	r_list_foreach_safe (annotation_array->annotations, iter, iter_tmp, annotation) {
		size += r_bin_java_annotation_calc_size (annotation);
	}
	return size;
}


R_API void r_bin_java_print_methodhandle_cp_summary(RBinJavaCPTypeObj *obj) {
	ut8 ref_kind;
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  RBinJavaCPTypeMethodHandle.\n");
		return;
	}
	ref_kind = obj->info.cp_method_handle.reference_kind;
	eprintf ("MethodHandle ConstantPool Type (%d) ", obj->metas->ord);
	eprintf ("	Offset: 0x%08"PFMT64x"", obj->file_offset);
	eprintf ("	Reference Kind = (0x%02x) %s\n", ref_kind, R_BIN_JAVA_REF_METAS[ref_kind].name);
	eprintf ("	Reference Index = %d\n", obj->info.cp_method_handle.reference_index);
}


R_API RBinJavaAttrInfo *r_bin_java_bootstrap_methods_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	RBinJavaBootStrapMethod *bsm = NULL;
	ut64 offset = 0;
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	offset += 6;
	if (attr) {
		attr->type = R_BIN_JAVA_ATTR_TYPE_BOOTSTRAP_METHODS_ATTR;
		if (offset + 8 > sz)  {
			free (attr);
			return NULL;
		}
		attr->info.bootstrap_methods_attr.num_bootstrap_methods = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		attr->info.bootstrap_methods_attr.bootstrap_methods = r_list_newf (r_bin_java_bootstrap_method_free);
		for (i = 0; i < attr->info.bootstrap_methods_attr.num_bootstrap_methods; i++) {
			// bsm = r_bin_java_bootstrap_method_new (bin, bin->b->cur);
			if (offset >= sz) {
				break;
			}
			bsm = r_bin_java_bootstrap_method_new (buffer + offset, sz - offset, buf_offset + offset);
			if (bsm) {
				offset += bsm->size;
				r_list_append (attr->info.bootstrap_methods_attr.bootstrap_methods, (void *) bsm);
			} else {
				// TODO eprintf Failed to read the %d boot strap method.
			}
		}
		attr->size = offset;
	}
	return attr;
}


R_API char *r_bin_java_print_name_and_type_cp_stringify(RBinJavaCPTypeObj *obj) {
	ut32 size = 255, consumed = 0;
	char *value = malloc (size);
	if (value) {
		memset (value, 0, size);
		consumed = snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%d.%d",
			obj->metas->ord, obj->file_offset + obj->loadaddr, ((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
			obj->info.cp_name_and_type.name_idx,
			obj->info.cp_name_and_type.descriptor_idx);
		if (consumed >= size - 1) {
			free (value);
			size += size >> 1;
			value = malloc (size);
			if (value) {
				memset (value, 0, size);
				(void)snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%d.%d",
					obj->metas->ord, obj->file_offset + obj->loadaddr, ((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
					obj->info.cp_name_and_type.name_idx,
					obj->info.cp_name_and_type.descriptor_idx);
			}
		}
	}
	return value;
}


R_API RList *r_bin_java_enum_class_methods(RBinJavaObj *bin, ut16 class_idx) {
	RList *methods = r_list_newf (free);
	RListIter *iter;
	RBinJavaField *field;
	r_list_foreach (bin->methods_list, iter, field) {
		if (field->field_ref_cp_obj && 0) {
			if ((field && field->field_ref_cp_obj->metas->ord == class_idx)) {
				RBinSymbol *sym = r_bin_java_create_new_symbol_from_ref (
						bin, field->field_ref_cp_obj, bin->loadaddr);
				if (sym) {
					r_list_append (methods, sym);
				}
			}
		} else {
			RBinSymbol *sym = R_NEW0 (RBinSymbol);
			sym->name = strdup (field->name);
			// func defintion
			// sym->paddr = field->file_offset + bin->loadaddr;
			// code implementation
			sym->paddr = r_bin_java_get_method_code_offset (field);
			sym->vaddr = sym->paddr; // + bin->loadaddr;
			r_list_append (methods, sym);
		}
	}
	return methods;
}


R_API RList *r_bin_java_get_method_num_name(RBinJavaObj *bin_obj) {
	ut32 i = 0;
	RListIter *iter;
	RBinJavaField *fm_type;
	RList *res = r_list_newf (free);
	r_list_foreach (bin_obj->methods_list, iter, fm_type) {
		char *str = r_str_newf ("%d %s", i, fm_type->name);
		r_list_append (res, str);
		i++;
	}
	return res;
}


R_API RBinSymbol *r_bin_java_create_new_symbol_from_cp_idx(ut32 cp_idx, ut64 baddr) {
	RBinSymbol *sym = NULL;
	RBinJavaCPTypeObj *obj = r_bin_java_get_item_from_bin_cp_list (
		R_BIN_JAVA_GLOBAL_BIN, cp_idx);
	if (obj) {
		switch (obj->tag) {
		case R_BIN_JAVA_CP_METHODREF:
		case R_BIN_JAVA_CP_FIELDREF:
		case R_BIN_JAVA_CP_INTERFACEMETHOD_REF:
			sym = r_bin_java_create_new_symbol_from_ref (R_BIN_JAVA_GLOBAL_BIN, obj, baddr);
			break;
		case R_BIN_JAVA_CP_INVOKEDYNAMIC:
			sym = r_bin_java_create_new_symbol_from_invoke_dynamic (obj, baddr);
			break;
		default:
			break;
		}
	}
	return sym;
}


R_API void r_bin_java_print_inner_classes_attr_summary(RBinJavaAttrInfo *attr) {
	RBinJavaClassesAttribute *icattr;
	RListIter *iter, *iter_tmp;
	if (!attr) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *InnerClasses.\n");
		return;
	}
	printf ("Inner Classes Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
	r_list_foreach_safe (attr->info.inner_classes_attr.classes, iter, iter_tmp, icattr) {
		r_bin_java_print_classes_attr_summary (icattr);
	}
}


R_API RBinJavaStackMapFrame *r_bin_java_default_stack_frame(void) {
	RBinJavaStackMapFrame *sf = R_NEW0 (RBinJavaStackMapFrame);
	if (!sf) {
		return NULL;
	}
	sf->metas = R_NEW0 (RBinJavaMetaInfo);
	if (!sf->metas) {
		free (sf);
		return NULL;
	}
	sf->metas->type_info = (void *) &R_BIN_JAVA_STACK_MAP_FRAME_METAS[R_BIN_JAVA_STACK_FRAME_IMPLICIT];
	sf->type = ((RBinJavaStackMapFrameMetas *) sf->metas->type_info)->type;
	sf->local_items = r_list_newf (r_bin_java_verification_info_free);
	sf->stack_items = r_list_newf (r_bin_java_verification_info_free);
	sf->number_of_stack_items = 0;
	sf->number_of_locals = 0;
	return sf;
}


R_API void r_bin_java_get_method_json_definition(RBinJavaObj *bin, RBinJavaField *fm_type, PJ *pj) {
	r_bin_java_get_fm_type_definition_json (bin, fm_type, pj, 1);
}


R_API void r_bin_java_print_float_cp_summary(RBinJavaCPTypeObj *obj) {
	ut8 *b = NULL;
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  Double.\n");
		return;
	}
	b = obj->info.cp_float.bytes.raw;
	printf ("Float ConstantPool Type (%d) ", obj->metas->ord);
	printf ("  Offset: 0x%08"PFMT64x "", obj->file_offset);
	printf ("  Bytes = %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3]);
	printf ("  Float = %f\n", R_BIN_JAVA_FLOAT (obj->info.cp_float.bytes.raw, 0));
}


R_API RBinSymbol *r_bin_java_create_new_symbol_from_fm_type_meta(RBinJavaField *fm_type, ut64 baddr) {
	RBinSymbol *sym = R_NEW0 (RBinSymbol);
	if (!sym || !fm_type || !fm_type->field_ref_cp_obj || fm_type->field_ref_cp_obj == &R_BIN_JAVA_NULL_TYPE) {
		free (sym);
		return NULL;
	}
	// ut32 new_name_len = strlen (fm_type->name) + strlen ("_meta") + 1;
	// char *new_name = malloc (new_name_len);
	sym->name = r_str_newf ("meta_%s", fm_type->name);
	if (fm_type->type == R_BIN_JAVA_FIELD_TYPE_METHOD) {
		sym->type = "FUNC_META";
	} else {
		sym->type = "FIELD_META";
	}
	if (r_bin_java_is_fm_type_protected (fm_type)) {
		sym->bind = R_BIN_BIND_LOCAL_STR;
	} else if (r_bin_java_is_fm_type_private (fm_type)) {
		sym->bind = R_BIN_BIND_LOCAL_STR;
	} else if (r_bin_java_is_fm_type_protected (fm_type)) {
		sym->bind = R_BIN_BIND_GLOBAL_STR;
	}
	sym->forwarder = "NONE";
	if (fm_type->class_name) {
		sym->classname = strdup (fm_type->class_name);
	} else {
		sym->classname = strdup ("UNKNOWN");
	}
	sym->paddr = fm_type->file_offset;// r_bin_java_get_method_code_offset (fm_type);
	sym->vaddr = fm_type->file_offset + baddr;
	sym->ordinal = fm_type->metas->ord;
	sym->size = fm_type->size;
	sym->visibility = fm_type->flags;
	if (fm_type->flags_str) {
		sym->visibility_str = strdup (fm_type->flags_str);
	}
	return sym;
}


R_API RList *r_bin_java_get_sections(RBinJavaObj *bin) {
	RBinSection *section = NULL;
	RList *sections = r_list_newf (free);
	ut64 baddr = bin->loadaddr;
	RBinJavaField *fm_type;
	RListIter *iter = NULL;
	if (bin->cp_count > 0) {
		section = R_NEW0 (RBinSection);
		if (section) {
			section->name = strdup ("constant_pool");
			section->paddr = bin->cp_offset + baddr;
			section->size = bin->cp_size;
#if 0
			section->vsize = section->size;
			section->vaddr = 0x10; // XXX // bin->cp_offset; //  + baddr;
#endif
			section->vaddr = baddr;
			// section->vaddr = section->paddr;
			// section->vsize = section->size;
			section->perm = R_PERM_R;
			section->add = true;
			r_list_append (sections, section);
		}
		section = NULL;
	}
	if (bin->fields_count > 0) {
		section = R_NEW0 (RBinSection);
		if (section) {
			section->name = strdup ("fields");
			section->size = bin->fields_size;
			section->paddr = bin->fields_offset + baddr;
#if 0
			section->vsize = section->size;
			section->vaddr = section->paddr;
#endif
			section->perm = R_PERM_R;
			section->add = true;
			r_list_append (sections, section);
			section = NULL;
			r_list_foreach (bin->fields_list, iter, fm_type) {
				if (fm_type->attr_offset == 0) {
					continue;
				}
				section = R_NEW0 (RBinSection);
				if (section) {
					section->name = r_str_newf ("attrs.%s", fm_type->name);
					section->size = fm_type->size - (fm_type->file_offset - fm_type->attr_offset);
#if 0
					section->vsize = section->size;
					section->vaddr = section->paddr;
#endif
					section->paddr = fm_type->attr_offset + baddr;
					section->perm = R_PERM_R;
					section->add = true;
					r_list_append (sections, section);
				}
			}
		}
	}
	if (bin->methods_count > 0) {
		section = R_NEW0 (RBinSection);
		if (section) {
			section->name = strdup ("methods");
			section->paddr = bin->methods_offset + baddr;
			section->size = bin->methods_size;
			// section->vaddr = section->paddr;
			// section->vsize = section->size;
			section->perm = R_PERM_RX;
			section->add = true;
			r_list_append (sections, section);
			section = NULL;
			r_list_foreach (bin->methods_list, iter, fm_type) {
				if (fm_type->attr_offset == 0) {
					continue;
				}
				section = R_NEW0 (RBinSection);
				if (section) {
					section->name = r_str_newf ("attrs.%s", fm_type->name);
					section->size = fm_type->size - (fm_type->file_offset - fm_type->attr_offset);
					// section->vsize = section->size;
					// section->vaddr = section->paddr;
					section->paddr = fm_type->attr_offset + baddr;
					section->perm = R_PERM_R | R_PERM_X;
					section->add = true;
					r_list_append (sections, section);
				}
			}
		}
	}
	if (bin->interfaces_count > 0) {
		section = R_NEW0 (RBinSection);
		if (section) {
			section->name = strdup ("interfaces");
			section->paddr = bin->interfaces_offset + baddr;
			section->size = bin->interfaces_size;
			// section->vaddr = section->paddr;
			// section->vsize = section->size;
			section->perm = R_PERM_R;
			section->add = true;
			r_list_append (sections, section);
		}
		section = NULL;
	}
	if (bin->attrs_count > 0) {
		section = R_NEW0 (RBinSection);
		if (section) {
			section->name = strdup ("attributes");
			section->paddr = bin->attrs_offset + baddr;
			section->size = bin->attrs_size;
			// section->vaddr = section->paddr;
			// section->vsize = section->size;
			section->perm = R_PERM_R;
			section->perm = R_PERM_R;
			section->add = true;
			r_list_append (sections, section);
		}
		section = NULL;
	}
	return sections;
}


R_API char *r_bin_java_print_null_cp_stringify(RBinJavaCPTypeObj *obj) {
	return r_str_newf ("%d.0x%04"PFMT64x ".%s",
		obj->metas->ord,
		obj->file_offset + obj->loadaddr,
		((RBinJavaCPTypeMetas *) obj->metas->type_info)->name);
}


R_API RBinJavaAttrInfo *r_bin_java_inner_classes_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	RBinJavaClassesAttribute *icattr;
	RBinJavaCPTypeObj *obj;
	ut32 i = 0;
	ut64 offset = 0, curpos;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!attr) {
		return NULL;
	}
	offset += 6;
	attr->type = R_BIN_JAVA_ATTR_TYPE_INNER_CLASSES_ATTR;
	attr->info.inner_classes_attr.number_of_classes = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	attr->info.inner_classes_attr.classes = r_list_newf (r_bin_java_inner_classes_attr_entry_free);
	for (i = 0; i < attr->info.inner_classes_attr.number_of_classes; i++) {
		curpos = buf_offset + offset;
		if (offset + 8 > sz) {
			eprintf ("Invalid amount of inner classes\n");
			break;
		}
		icattr = R_NEW0 (RBinJavaClassesAttribute);
		if (!icattr) {
			break;
		}
		icattr->inner_class_info_idx = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		icattr->outer_class_info_idx = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		icattr->inner_name_idx = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		icattr->inner_class_access_flags = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		icattr->flags_str = retrieve_class_method_access_string (icattr->inner_class_access_flags);
		icattr->file_offset = curpos;
		icattr->size = 8;

		obj = r_bin_java_get_item_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, icattr->inner_name_idx);
		if (!obj) {
			eprintf ("BINCPLIS IS HULL %d\n", icattr->inner_name_idx);
		}
		icattr->name = r_bin_java_get_item_name_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, obj);
		if (!icattr->name) {
			obj = r_bin_java_get_item_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, icattr->inner_class_info_idx);
			if (!obj) {
				eprintf ("BINCPLIST IS NULL %d\n", icattr->inner_class_info_idx);
			}
			icattr->name = r_bin_java_get_item_name_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, obj);
			if (!icattr->name) {
				icattr->name = r_str_dup (NULL, "NULL");
				eprintf ("r_bin_java_inner_classes_attr: Unable to find the name for %d index.\n", icattr->inner_name_idx);
				free (icattr);
				break;
			}
		}

		IFDBG eprintf ("r_bin_java_inner_classes_attr: Inner class name %d is %s.\n", icattr->inner_name_idx, icattr->name);
		r_list_append (attr->info.inner_classes_attr.classes, (void *) icattr);
	}
	attr->size = offset;
	// IFDBG r_bin_java_print_inner_classes_attr_summary(attr);
	return attr;
}


R_API void r_bin_java_print_method_summary(RBinJavaField *field) {
	RBinJavaAttrInfo *attr;
	RListIter *iter, *iter_tmp;
	if (field == NULL) {
		eprintf ("Attempting to print an invalid RBinJavaField* Method.\n");
		return;
	}
	printf ("Method Summary Information:\n");
	printf ("  File Offset: 0x%08"PFMT64x "\n", field->file_offset);
	printf ("  Name Index: %d (%s)\n", field->name_idx, field->name);
	printf ("  Descriptor Index: %d (%s)\n", field->descriptor_idx, field->descriptor);
	printf ("  Access Flags: 0x%02x (%s)\n", field->flags, field->flags_str);
	printf ("  Method Attributes Count: %d\n", field->attr_count);
	printf ("  Method Attributes:\n");
	r_list_foreach_safe (field->attributes, iter, iter_tmp, attr) {
		r_bin_java_print_attr_summary (attr);
	}
}


R_API void r_bin_java_print_methodref_cp_summary(RBinJavaCPTypeObj *obj) {
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  MethodRef.\n");
		return;
	}
	eprintf ("MethodRef ConstantPool Type (%d) ", obj->metas->ord);
	eprintf ("	Offset: 0x%08"PFMT64x"", obj->file_offset);
	eprintf ("	Class Index = %d\n", obj->info.cp_method.class_idx);
	eprintf ("	Name and type Index = %d\n", obj->info.cp_method.name_and_type_idx);
}


R_API void r_bin_java_element_pair_free(void /*RBinJavaElementValuePair*/ *e) {
	RBinJavaElementValuePair *evp = e;
	if (evp) {
		free (evp->name);
		r_bin_java_element_value_free (evp->value);
		free (evp);
	}
	evp = NULL;
}


R_API ut64 r_bin_java_parse_fields(RBinJavaObj *bin, const ut64 offset, const ut8 *buf, const ut64 len) {
	int i = 0;
	ut64 adv = 0;
	RBinJavaField *field;
	const ut8 *fm_buf = buf + offset;
	r_list_free (bin->fields_list);
	bin->fields_list = r_list_newf (r_bin_java_fmtype_free);
	bin->fields_offset = offset;
	if (offset + 2 >= len) {
		return UT64_MAX;
	}
	bin->fields_count = R_BIN_JAVA_USHORT (fm_buf, 0);
	adv += 2;
	IFDBG eprintf ("Fields count: %d 0x%"PFMT64x "\n", bin->fields_count, bin->fields_offset);
	if (bin->fields_count > 0) {
		for (i = 0; i < bin->fields_count; i++, bin->field_idx++) {
			field = r_bin_java_read_next_field (bin, offset + adv, buf, len);
			if (field) {
				adv += field->size;
				r_list_append (bin->fields_list, field);
				IFDBG r_bin_java_print_field_summary(field);
				if (adv + offset > len) {
					eprintf ("[X] r_bin_java: Error unable to parse remainder of classfile after Field: %d.\n", i);
					break;
				}
			} else {
				IFDBG eprintf ("Failed to read Field %d\n", i);
				break;
			}
		}
	}
	bin->fields_size = adv;
	return adv;
}


R_API void r_bin_java_print_double_cp_summary(RBinJavaCPTypeObj *obj) {
	ut8 *b = NULL;
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  Double.\n");
		return;
	}
	b = obj->info.cp_double.bytes.raw;
	printf ("Double ConstantPool Type (%d) ", obj->metas->ord);
	printf ("  Offset: 0x%08"PFMT64x "", obj->file_offset);
	printf ("  High-Bytes = %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3]);
	printf ("  Low-Bytes = %02x %02x %02x %02x\n", b[4], b[5], b[6], b[7]);
	printf ("  Double = %f\n", r_bin_java_raw_to_double (obj->info.cp_double.bytes.raw, 0));
}


R_API RBinJavaAttrInfo *r_bin_java_exceptions_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0, offset = 0;
	ut64 size;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	offset += 6;
	if (!attr) {
		return attr;
	}
	attr->type = R_BIN_JAVA_ATTR_TYPE_LINE_NUMBER_TABLE_ATTR;
	attr->info.exceptions_attr.number_of_exceptions = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	size = sizeof (ut16) * attr->info.exceptions_attr.number_of_exceptions;
	if (size < attr->info.exceptions_attr.number_of_exceptions) {
		free (attr);
		return NULL;
	}
	attr->info.exceptions_attr.exception_idx_table = (ut16 *) malloc (size);
	if (!attr->info.exceptions_attr.exception_idx_table) {
		free (attr);
		return NULL;
	}
	for (i = 0; i < attr->info.exceptions_attr.number_of_exceptions; i++) {
		if (offset + 2 > sz) {
			break;
		}
		attr->info.exceptions_attr.exception_idx_table[i] = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
	}
	attr->size = offset;
	// IFDBG r_bin_java_print_exceptions_attr_summary(attr);
	return attr;
}


R_API RBinJavaAnnotation *r_bin_java_annotation_new(ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	RBinJavaElementValuePair *evps = NULL;
	ut64 offset = 0;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAnnotation *annotation = R_NEW0 (RBinJavaAnnotation);
	if (!annotation) {
		return NULL;
	}
	// (ut16) read and set annotation_value.type_idx;
	annotation->type_idx = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	// (ut16) read and set annotation_value.num_element_value_pairs;
	annotation->num_element_value_pairs = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	annotation->element_value_pairs = r_list_newf (r_bin_java_element_pair_free);
	// read annotation_value.num_element_value_pairs, and append to annotation_value.element_value_pairs
	for (i = 0; i < annotation->num_element_value_pairs; i++) {
		if (offset > sz) {
			break;
		}
		evps = r_bin_java_element_pair_new (buffer + offset, sz - offset, buf_offset + offset);
		if (evps) {
			offset += evps->size;
			r_list_append (annotation->element_value_pairs, (void *) evps);
		}
	}
	annotation->size = offset;
	return annotation;
}


R_API void r_bin_java_print_enclosing_methods_attr_summary(RBinJavaAttrInfo *attr) {
	if (!attr) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *Deperecated.\n");
		return;
	}
	printf ("Enclosing Method Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
	printf ("  Class Info Index : 0x%02x\n", attr->info.enclosing_method_attr.class_idx);
	printf ("  Method Name and Type Index : 0x%02x\n", attr->info.enclosing_method_attr.method_idx);
	printf ("  Class Name : %s\n", attr->info.enclosing_method_attr.class_name);
	printf ("  Method Name and Desc : %s %s\n", attr->info.enclosing_method_attr.method_name, attr->info.enclosing_method_attr.method_descriptor);
}


R_API RBinJavaAttrInfo *r_bin_java_local_variable_table_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	RBinJavaLocalVariableAttribute *lvattr;
	ut64 curpos = 0, offset = 6;
	ut32 i = 0;
	if (!bin || !buffer || sz < 8) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!attr) {
		return NULL;
	}
	attr->type = R_BIN_JAVA_ATTR_TYPE_LOCAL_VARIABLE_TABLE_ATTR;
	attr->info.local_variable_table_attr.table_length = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	attr->info.local_variable_table_attr.local_variable_table =\
		r_list_newf (r_bin_java_local_variable_table_attr_entry_free);
	for (i = 0; i < attr->info.local_variable_table_attr.table_length; i++) {
		if (offset + 10 > sz) {
			break;
		}
		curpos = buf_offset + offset;
		lvattr = R_NEW0 (RBinJavaLocalVariableAttribute);
		if (!lvattr) {
			break;
		}
		lvattr->start_pc = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lvattr->length = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lvattr->name_idx = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lvattr->descriptor_idx = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lvattr->index = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lvattr->file_offset = curpos;
		lvattr->name = r_bin_java_get_utf8_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, lvattr->name_idx);
		lvattr->size = 10;
		if (!lvattr->name) {
			lvattr->name = strdup ("NULL");
			eprintf ("r_bin_java_local_variable_table_attr_new: Unable to find the name for %d index.\n", lvattr->name_idx);
		}
		lvattr->descriptor = r_bin_java_get_utf8_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, lvattr->descriptor_idx);
		if (!lvattr->descriptor) {
			lvattr->descriptor = strdup ("NULL");
			eprintf ("r_bin_java_local_variable_table_attr_new: Unable to find the descriptor for %d index.\n", lvattr->descriptor_idx);
		}
		r_list_append (attr->info.local_variable_table_attr.local_variable_table, lvattr);
	}
	attr->size = offset;
	// IFDBG r_bin_java_print_local_variable_table_attr_summary(attr);
	return attr;
}


R_API void U(add_field_infos_to_sdb)(RBinJavaObj * bin) {
	/*
	*** Experimental and May Change ***
	Add field information to an Array
	the key for this info variable depenedent on addr, method ordinal, etc.
	Key 1, mapping to method key:
	java.<file_offset> = <field_key>
	Key 3, method description
	<field_key>.info = [<access str>, <class_name>, <name>, <signature>]
	key 4, method meta
	<field_key>.meta = [<file_offset>, ?]
	*/
	RListIter *iter = NULL, *iter_tmp = NULL;
	RBinJavaField *fm_type;
	ut32 key_size = 255,
	value_buffer_size = 1024,
	class_name_inheap = 1;
	char *field_key = NULL,
	*field_key_value = NULL,
	*value_buffer = NULL;
	char *class_name = r_bin_java_get_this_class_name (bin);
	if (!class_name) {
		class_name = "unknown";
		class_name_inheap = 0;
	}
	key_size += strlen (class_name);
	value_buffer_size += strlen (class_name);
	field_key = malloc (key_size);
	value_buffer = malloc (value_buffer_size);
	field_key_value = malloc (key_size);
	snprintf (field_key, key_size, "%s.methods", class_name);
	field_key[key_size - 1] = 0;
	r_list_foreach_safe (bin->fields_list, iter, iter_tmp, fm_type) {
		char number_buffer[80];
		ut64 file_offset = fm_type->file_offset + bin->loadaddr;
		snprintf (number_buffer, sizeof (number_buffer), "0x%04"PFMT64x, file_offset);
		IFDBG eprintf ("Inserting: []%s = %s\n", field_key, number_buffer);
		sdb_array_push (bin->kv, field_key, number_buffer, 0);
	}
	r_list_foreach_safe (bin->fields_list, iter, iter_tmp, fm_type) {
		ut64 field_offset = fm_type->file_offset + bin->loadaddr;
		// generate method specific key & value
		snprintf (field_key, key_size, "%s.0x%04"PFMT64x, class_name, field_offset);
		field_key[key_size - 1] = 0;
		snprintf (field_key_value, key_size, "%s.0x%04"PFMT64x ".field", class_name, field_offset);
		field_key_value[key_size - 1] = 0;
		sdb_set (bin->kv, field_key, field_key_value, 0);
		IFDBG eprintf ("Inserting: %s = %s\n", field_key, field_key_value);
		// generate info key, and place values in method info array
		snprintf (field_key, key_size, "%s.info", field_key_value);
		field_key[key_size - 1] = 0;
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->flags_str);
		value_buffer[value_buffer_size - 1] = 0;
		sdb_array_push (bin->kv, field_key, value_buffer, 0);
		IFDBG eprintf ("Inserting: []%s = %s\n", field_key, value_buffer);
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->class_name);
		value_buffer[value_buffer_size - 1] = 0;
		sdb_array_push (bin->kv, field_key, value_buffer, 0);
		IFDBG eprintf ("Inserting: []%s = %s\n", field_key, value_buffer);
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->name);
		value_buffer[value_buffer_size - 1] = 0;
		sdb_array_push (bin->kv, field_key, value_buffer, 0);
		IFDBG eprintf ("Inserting: []%s = %s\n", field_key, value_buffer);
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->descriptor);
		value_buffer[value_buffer_size - 1] = 0;
		sdb_array_push (bin->kv, field_key, value_buffer, 0);
		IFDBG eprintf ("Inserting: []%s = %s\n", field_key, value_buffer);
	}
	free (field_key);
	free (field_key_value);
	free (value_buffer);
	if (class_name_inheap) {
		free (class_name);
	}
}


R_API RList *r_bin_java_get_entrypoints(RBinJavaObj *bin) {
	RListIter *iter = NULL, *iter_tmp = NULL;
	RBinJavaField *fm_type;
	RList *ret = r_list_newf (free);
	if (!ret) {
		return NULL;
	}
	r_list_foreach_safe (bin->methods_list, iter, iter_tmp, fm_type) {
		if (!strcmp (fm_type->name, "main")
		|| !strcmp (fm_type->name, "<init>")
		|| !strcmp (fm_type->name, "<clinit>")
		|| strstr (fm_type->flags_str, "static")) {
			RBinAddr *addr = R_NEW0 (RBinAddr);
			if (addr) {
				addr->vaddr = addr->paddr = \
					r_bin_java_get_method_code_offset (fm_type) + bin->loadaddr;
				addr->hpaddr = fm_type->file_offset;
				r_list_append (ret, addr);
			}
		}
	}
	return ret;
}


R_API void r_bin_java_get_method_json_definitions(RBinJavaObj *bin, PJ *pj) {
	r_return_if_fail (pj);
	RBinJavaField *fm_type = NULL;
	RListIter *iter = NULL;

	pj_ka (pj, "methods");
	if (!bin) {
		pj_end (pj);
		return;
	}

	r_list_foreach (bin->methods_list, iter, fm_type) {
		r_bin_java_get_method_json_definition (bin, fm_type, pj);
	}
	pj_end (pj);
}


R_API void r_bin_java_print_fieldref_cp_summary(RBinJavaCPTypeObj *obj) {
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  FieldRef.\n");
		return;
	}
	eprintf ("FieldRef ConstantPool Type (%d) ", obj->metas->ord);
	eprintf ("	Offset: 0x%08"PFMT64x"", obj->file_offset);
	eprintf ("	Class Index = %d\n", obj->info.cp_field.class_idx);
	eprintf ("	Name and type Index = %d\n", obj->info.cp_field.name_and_type_idx);
}


R_API char *r_bin_java_get_item_name_from_cp_item_list(RList *cp_list, RBinJavaCPTypeObj *obj, int depth) {
	/*
	Given a constant pool object Class, FieldRef, MethodRef, or InterfaceMethodRef
	return the actual descriptor string.
	@param cp_list: RList of RBinJavaCPTypeObj *
	@param obj object to look up the name for
	@rvalue ut8* (user frees) or NULL
	*/
	if (!obj || !cp_list || depth < 0) {
		return NULL;
	}
	switch (obj->tag) {
	case R_BIN_JAVA_CP_NAMEANDTYPE:
		return r_bin_java_get_utf8_from_cp_item_list (
			cp_list, obj->info.cp_name_and_type.name_idx);
	case R_BIN_JAVA_CP_CLASS:
		return r_bin_java_get_utf8_from_cp_item_list (
			cp_list, obj->info.cp_class.name_idx);
	// XXX - Probably not good form, but they are the same memory structure
	case R_BIN_JAVA_CP_FIELDREF:
	case R_BIN_JAVA_CP_INTERFACEMETHOD_REF:
	case R_BIN_JAVA_CP_METHODREF:
		obj = r_bin_java_get_item_from_cp_item_list (
			cp_list, obj->info.cp_method.name_and_type_idx);
		return r_bin_java_get_item_name_from_cp_item_list (
			cp_list, obj, depth - 1);
	default:
		return NULL;
	case 0:
		IFDBG eprintf ("Invalid 0 tag in the constant pool\n");
		return NULL;
	}
	return NULL;
}


R_API RBinJavaField *r_bin_java_read_next_field(RBinJavaObj *bin, const ut64 offset, const ut8 *buffer, const ut64 len) {
	RBinJavaAttrInfo *attr;
	ut32 i, idx;
	ut8 buf[8];
	RBinJavaCPTypeObj *item = NULL;
	const ut8 *f_buf = buffer + offset;
	ut64 adv = 0;
	if (!bin || offset + 8 >= len) {
		return NULL;
	}
	RBinJavaField *field = (RBinJavaField *) R_NEW0 (RBinJavaField);
	if (!field) {
		eprintf ("Unable to allocate memory for field information\n");
		return NULL;
	}
	field->metas = (RBinJavaMetaInfo *) R_NEW0 (RBinJavaMetaInfo);
	if (!field->metas) {
		eprintf ("Unable to allocate memory for meta information\n");
		free (field);
		return NULL;
	}
	memcpy (buf, f_buf, 8);
	field->file_offset = offset;
	field->flags = R_BIN_JAVA_USHORT (buf, 0);
	field->flags_str = retrieve_field_access_string (field->flags);
	field->name_idx = R_BIN_JAVA_USHORT (buf, 2);
	field->descriptor_idx = R_BIN_JAVA_USHORT (buf, 4);
	field->attr_count = R_BIN_JAVA_USHORT (buf, 6);
	field->attributes = r_list_newf (r_bin_java_attribute_free);
	field->type = R_BIN_JAVA_FIELD_TYPE_FIELD;
	adv += 8;
	field->metas->ord = bin->field_idx;

	idx = field->name_idx;
	item = r_bin_java_get_item_from_bin_cp_list (bin, idx);
	field->name = r_bin_java_get_utf8_from_bin_cp_list (bin, (ut32) (field->name_idx));
	IFDBG eprintf ("Field name_idx: %d, which is: ord: %d, name: %s, value: %s\n", idx, item->metas->ord, ((RBinJavaCPTypeMetas *)item->metas->type_info)->name, field->name);
	if (!field->name) {
		field->name = (char *) malloc (21);
		snprintf ((char *) field->name, 20, "sym.field_%08x", field->metas->ord);
		IFDBG eprintf ("r_bin_java_read_next_field: Unable to find the name for 0x%02x index.\n", field->name_idx);
	}
	idx = field->descriptor_idx;
	item = r_bin_java_get_item_from_bin_cp_list (bin, idx);
	field->descriptor = r_bin_java_get_utf8_from_bin_cp_list (bin, (ut32) field->descriptor_idx);
	IFDBG eprintf ("Field descriptor_idx: %d, which is: ord: %d, name: %s, value: %s\n", idx, item->metas->ord, ((RBinJavaCPTypeMetas *)item->metas->type_info)->name, field->descriptor);
	if (!field->descriptor) {
		field->descriptor = r_str_dup (NULL, "NULL");
		IFDBG eprintf ("r_bin_java_read_next_field: Unable to find the descriptor for 0x%02x index.\n", field->descriptor_idx);
	}
	IFDBG eprintf ("Looking for a NameAndType CP with name_idx: %d descriptor_idx: %d\n", field->name_idx, field->descriptor_idx);
	field->field_ref_cp_obj = r_bin_java_find_cp_ref_info_from_name_and_type (bin, field->name_idx, field->descriptor_idx);
	if (field->field_ref_cp_obj) {
		IFDBG eprintf ("Found the obj.\n");
		item = r_bin_java_get_item_from_bin_cp_list (bin, field->field_ref_cp_obj->info.cp_field.class_idx);
		IFDBG eprintf ("Field class reference value: %d, which is: ord: %d, name: %s\n", field->field_ref_cp_obj->info.cp_field.class_idx, item->metas->ord, ((RBinJavaCPTypeMetas *)item->metas->type_info)->name);
		field->class_name = r_bin_java_get_item_name_from_bin_cp_list (bin, item);
		IFDBG eprintf ("Field requesting ref_cp_obj the following which is: ord: %d, name: %s\n", field->field_ref_cp_obj->metas->ord, ((RBinJavaCPTypeMetas *)field->field_ref_cp_obj->metas->type_info)->name);
		IFDBG eprintf ("FieldRef class name resolves to: %s\n", field->class_name);
		if (!field->class_name) {
			field->class_name = r_str_dup (NULL, "NULL");
		}
	} else {
		// XXX - default to this class?
		field->field_ref_cp_obj = r_bin_java_get_item_from_bin_cp_list (bin, bin->cf2.this_class);
		field->class_name = r_bin_java_get_item_name_from_bin_cp_list (bin, field->field_ref_cp_obj);
	}
	IFDBG eprintf ("Parsing %s(%s)", field->name, field->descriptor);
	if (field->attr_count > 0) {
		field->attr_offset = adv + offset;
		for (i = 0; i < field->attr_count && offset + adv < len; i++) {
			attr = r_bin_java_read_next_attr (bin, offset + adv, buffer, len);
			if (!attr) {
				eprintf ("[X] r_bin_java: Error unable to parse remainder of classfile after Field Attribute: %d.\n", i);
				free (field->metas);
				free (field);
				return NULL;
			}
			if ((r_bin_java_get_attr_type_by_name (attr->name))->type == R_BIN_JAVA_ATTR_TYPE_CODE_ATTR) {
				// This is necessary for determing the appropriate number of bytes when readin
				// uoffset, ustack, ulocalvar values
				bin->cur_method_code_length = attr->info.code_attr.code_length;
				bin->offset_sz = 2;// (attr->info.code_attr.code_length > 65535) ? 4 : 2;
				bin->ustack_sz = 2;// (attr->info.code_attr.max_stack > 65535) ? 4 : 2;
				bin->ulocalvar_sz = 2;// (attr->info.code_attr.max_locals > 65535) ? 4 : 2;
			}
			r_list_append (field->attributes, attr);
			adv += attr->size;
			if (adv + offset >= len) {
				eprintf ("[X] r_bin_java: Error unable to parse remainder of classfile after Field Attribute: %d.\n", i);
				r_bin_java_fmtype_free (field);
				return NULL;
			}
		}
	}
	field->size = adv;
	return field;
}


R_API void U(deinit_java_type_null)(void) {
	free (R_BIN_JAVA_NULL_TYPE.metas);
}


R_API void r_bin_java_print_local_variable_table_attr_summary(RBinJavaAttrInfo *attr) {
	RBinJavaLocalVariableAttribute *lvattr;
	RListIter *iter, *iter_tmp;
	if (attr == NULL) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *LocalVariableTable.\n");
		return;
	}
	printf ("Local Variable Table Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
	r_list_foreach_safe (attr->info.local_variable_table_attr.local_variable_table, iter, iter_tmp, lvattr) {
		r_bin_java_print_local_variable_attr_summary (lvattr);
	}
}


R_API RList *retrieve_all_field_access_string_and_value(void) {
	return retrieve_all_access_string_and_value (FIELD_ACCESS_FLAGS);
}


R_API void U(add_method_infos_to_sdb)(RBinJavaObj * bin) {
	/*
	*** Experimental and May Change ***
	Add Mehtod information to an Array
	the key for this info variable depenedent on addr, method ordinal, etc.
	Key 1, mapping to method key:
	java.<file_offset> = <method_key>
	Key 2, basic code information
	<method_key>.code = [<addr>, <size>]
	Key 3, method description
	<method_key>.info = [<access str>, <class_name>, <name>, <signature>,]
	key 4, method meta
	<method_key>.meta = [<file_offset>, ?]
	// TODO in key 3 add <class_name>?
	e.g. <access str>.<name>.<signature>
	Note: method name not used because of collisions with operator overloading
	also take note that code offset and the method offset are not the same
	values.
	*/
	RListIter *iter = NULL, *iter_tmp = NULL;
	RBinJavaField *fm_type;
	ut32 key_size = 255,
	value_buffer_size = 1024,
	class_name_inheap = 1;
	char *method_key = NULL,
	*method_key_value = NULL,
	*value_buffer = NULL;
	char *class_name = r_bin_java_get_this_class_name (bin);
	ut64 baddr = bin->loadaddr;
	if (!class_name) {
		class_name = "unknown";
		class_name_inheap = 0;
	}
	key_size += strlen (class_name);
	value_buffer_size += strlen (class_name);
	method_key = malloc (key_size);
	value_buffer = malloc (value_buffer_size);
	method_key_value = malloc (key_size);
	snprintf (method_key, key_size, "%s.methods", class_name);
	method_key[key_size - 1] = 0;
	r_list_foreach_safe (bin->methods_list, iter, iter_tmp, fm_type) {
		char number_buffer[80];
		ut64 file_offset = fm_type->file_offset + baddr;
		snprintf (number_buffer, sizeof (number_buffer), "0x%04"PFMT64x, file_offset);
		sdb_array_push (bin->kv, method_key, number_buffer, 0);
	}
	r_list_foreach_safe (bin->methods_list, iter, iter_tmp, fm_type) {
		ut64 code_offset = r_bin_java_get_method_code_offset (fm_type) + baddr,
		code_size = r_bin_java_get_method_code_size (fm_type),
		method_offset = fm_type->file_offset + baddr;
		// generate method specific key & value
		snprintf (method_key, key_size, "%s.0x%04"PFMT64x, class_name, code_offset);
		method_key[key_size - 1] = 0;
		snprintf (method_key_value, key_size, "%s.0x%04"PFMT64x ".method", class_name, method_offset);
		method_key_value[key_size - 1] = 0;
		IFDBG eprintf ("Adding %s to sdb_array: %s\n", method_key_value, method_key);
		sdb_set (bin->kv, method_key, method_key_value, 0);
		// generate code key and values
		snprintf (method_key, key_size, "%s.code", method_key_value);
		method_key[key_size - 1] = 0;
		snprintf (value_buffer, value_buffer_size, "0x%04"PFMT64x, code_offset);
		value_buffer[value_buffer_size - 1] = 0;
		sdb_array_push (bin->kv, method_key, value_buffer, 0);
		snprintf (value_buffer, value_buffer_size, "0x%04"PFMT64x, code_size);
		value_buffer[value_buffer_size - 1] = 0;
		sdb_array_push (bin->kv, method_key, value_buffer, 0);
		// generate info key, and place values in method info array
		snprintf (method_key, key_size, "%s.info", method_key_value);
		method_key[key_size - 1] = 0;
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->flags_str);
		value_buffer[value_buffer_size - 1] = 0;
		IFDBG eprintf ("Adding %s to sdb_array: %s\n", value_buffer, method_key);
		sdb_array_push (bin->kv, method_key, value_buffer, 0);
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->class_name);
		value_buffer[value_buffer_size - 1] = 0;
		IFDBG eprintf ("Adding %s to sdb_array: %s\n", value_buffer, method_key);
		sdb_array_push (bin->kv, method_key, value_buffer, 0);
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->name);
		value_buffer[value_buffer_size - 1] = 0;
		IFDBG eprintf ("Adding %s to sdb_array: %s\n", value_buffer, method_key);
		sdb_array_push (bin->kv, method_key, value_buffer, 0);
		snprintf (value_buffer, value_buffer_size, "%s", fm_type->descriptor);
		value_buffer[value_buffer_size - 1] = 0;
		IFDBG eprintf ("Adding %s to sdb_array: %s\n", value_buffer, method_key);
		sdb_array_push (bin->kv, method_key, value_buffer, 0);
	}
	free (method_key);
	free (method_key_value);
	free (value_buffer);
	if (class_name_inheap) {
		free (class_name);
	}
}


R_API char *r_bin_java_resolve(RBinJavaObj *BIN_OBJ, int idx, ut8 space_bn_name_type) {
	// TODO XXX FIXME add a size parameter to the str when it is passed in
	RBinJavaCPTypeObj *item = NULL, *item2 = NULL;
	char *class_str = NULL,
	*name_str = NULL,
	*desc_str = NULL,
	*string_str = NULL,
	*empty = "",
	*cp_name = NULL,
	*str = NULL;
	if (BIN_OBJ && BIN_OBJ->cp_count < 1) {
		// r_bin_java_new_bin(BIN_OBJ);
		return NULL;
	}
	item = (RBinJavaCPTypeObj *) r_bin_java_get_item_from_bin_cp_list (BIN_OBJ, idx);
	if (item) {
		cp_name = ((RBinJavaCPTypeMetas *) item->metas->type_info)->name;
		IFDBG eprintf ("java_resolve Resolved: (%d) %s\n", idx, cp_name);
	} else {
		str = malloc (512);
		if (str) {
			snprintf (str, 512, "(%d) INVALID CP_OBJ", idx);
		}
		return str;
	}
	if (strcmp (cp_name, "Class") == 0) {
		item2 = (RBinJavaCPTypeObj *) r_bin_java_get_item_from_bin_cp_list (BIN_OBJ, idx);
		// str = r_bin_java_get_name_from_bin_cp_list (BIN_OBJ, idx-1);
		class_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item);
		if (!class_str) {
			class_str = empty;
		}
		name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item2);
		if (!name_str) {
			name_str = empty;
		}
		desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item2);
		if (!desc_str) {
			desc_str = empty;
		}
		str = r_str_newf ("%s%s%s", name_str,
			space_bn_name_type ? " " : "", desc_str);
		if (class_str != empty) {
			free (class_str);
		}
		if (name_str != empty) {
			free (name_str);
		}
		if (desc_str != empty) {
			free (desc_str);
		}
	} else if (!strcmp (cp_name, "MethodRef") ||
	!strcmp (cp_name, "FieldRef") ||
	!strcmp (cp_name, "InterfaceMethodRef")) {
		/*
		*  The MethodRef, FieldRef, and InterfaceMethodRef structures
		*/
		class_str = r_bin_java_get_name_from_bin_cp_list (BIN_OBJ, item->info.cp_method.class_idx);
		if (!class_str) {
			class_str = empty;
		}
		name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item);
		if (!name_str) {
			name_str = empty;
		}
		desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item);
		if (!desc_str) {
			desc_str = empty;
		}
		str = r_str_newf ("%s/%s%s%s", class_str, name_str,
			space_bn_name_type ? " " : "", desc_str);
		if (class_str != empty) {
			free (class_str);
		}
		if (name_str != empty) {
			free (name_str);
		}
		if (desc_str != empty) {
			free (desc_str);
		}
	} else if (!strcmp (cp_name, "String")) {
		string_str = r_bin_java_get_utf8_from_bin_cp_list (BIN_OBJ, item->info.cp_string.string_idx);
		str = NULL;
		IFDBG eprintf ("java_resolve String got: (%d) %s\n", item->info.cp_string.string_idx, string_str);
		if (!string_str) {
			string_str = empty;
		}
		str = r_str_newf ("\"%s\"", string_str);
		IFDBG eprintf ("java_resolve String return: %s\n", str);
		if (string_str != empty) {
			free (string_str);
		}

	} else if (!strcmp (cp_name, "Utf8")) {
		char *tmp_str = convert_string ((const char *) item->info.cp_utf8.bytes, item->info.cp_utf8.length);
		ut32 tmp_str_len = tmp_str ? strlen (tmp_str) + 4 : 0;
		if (tmp_str) {
			str = malloc (tmp_str_len + 4);
			snprintf (str, tmp_str_len + 4, "\"%s\"", tmp_str);
		}
		free (tmp_str);
	} else if (!strcmp (cp_name, "Long")) {
		str = r_str_newf ("0x%"PFMT64x, r_bin_java_raw_to_long (item->info.cp_long.bytes.raw, 0));
	} else if (!strcmp (cp_name, "Double")) {
		str = r_str_newf ("%f", r_bin_java_raw_to_double (item->info.cp_double.bytes.raw, 0));
	} else if (!strcmp (cp_name, "Integer")) {
		str = r_str_newf ("0x%08x", R_BIN_JAVA_UINT (item->info.cp_integer.bytes.raw, 0));
	} else if (!strcmp (cp_name, "Float")) {
		str = r_str_newf ("%f", R_BIN_JAVA_FLOAT (item->info.cp_float.bytes.raw, 0));
	} else if (!strcmp (cp_name, "NameAndType")) {
		name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item);
		if (!name_str) {
			name_str = empty;
		}
		desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item);
		if (!desc_str) {
			desc_str = empty;
		}
		str = r_str_newf ("%s%s%s", name_str, space_bn_name_type ? " " : "", desc_str);
		if (name_str != empty) {
			free (name_str);
		}
		if (desc_str != empty) {
			free (desc_str);
		}
	} else {
		str = strdup ("(null)");
	}
	return str;
}


R_API RBinJavaAttrInfo *r_bin_java_line_number_table_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	ut64 curpos, offset = 0;
	if (sz < 6) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!attr) {
		return NULL;
	}
	offset += 6;
	attr->type = R_BIN_JAVA_ATTR_TYPE_LINE_NUMBER_TABLE_ATTR;
	attr->info.line_number_table_attr.line_number_table_length = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	attr->info.line_number_table_attr.line_number_table = r_list_newf (free);

	ut32 linenum_len = attr->info.line_number_table_attr.line_number_table_length;
	RList *linenum_list = attr->info.line_number_table_attr.line_number_table;
	for (i = 0; i < linenum_len; i++) {
		curpos = buf_offset + offset;
		// eprintf ("%"PFMT64x" %"PFMT64x"\n", curpos, sz);
		// XXX if (curpos + 8 >= sz) break;
		RBinJavaLineNumberAttribute *lnattr = R_NEW0 (RBinJavaLineNumberAttribute);
		if (!lnattr) {
			break;
		}
		// wtf it works
		if (offset - 2 > sz) {
			R_FREE (lnattr);
			break;
		}
		lnattr->start_pc = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lnattr->line_number = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		lnattr->file_offset = curpos;
		lnattr->size = 4;
		r_list_append (linenum_list, lnattr);
	}
	attr->size = offset;
	return attr;
}


R_API RBinJavaAttrInfo *r_bin_java_source_debug_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut64 offset = 6;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!attr) {
		return NULL;
	}
	attr->type = R_BIN_JAVA_ATTR_TYPE_SOURCE_DEBUG_EXTENTSION_ATTR;
	if (attr->length == 0) {
		eprintf ("r_bin_java_source_debug_attr_new: Attempting to allocate 0 bytes for debug_extension.\n");
		attr->info.debug_extensions.debug_extension = NULL;
		return attr;
	} else if ((attr->length + offset) > sz) {
		eprintf ("r_bin_java_source_debug_attr_new: Expected %d byte(s) got %"
			PFMT64d " bytes for debug_extension.\n", attr->length, (offset + sz));
	}
	attr->info.debug_extensions.debug_extension = (ut8 *) malloc (attr->length);
	if (attr->info.debug_extensions.debug_extension && (attr->length > (sz - offset))) {
		memcpy (attr->info.debug_extensions.debug_extension, buffer + offset, sz - offset);
	} else if (attr->info.debug_extensions.debug_extension) {
		memcpy (attr->info.debug_extensions.debug_extension, buffer + offset, attr->length);
	} else {
		eprintf ("r_bin_java_source_debug_attr_new: Unable to allocate the data for the debug_extension.\n");
	}
	offset += attr->length;
	attr->size = offset;
	return attr;
}


R_API char *r_bin_java_print_string_cp_stringify(RBinJavaCPTypeObj *obj) {
	ut32 size = 255, consumed = 0;
	char *value = malloc (size);
	if (value) {
		memset (value, 0, size);
		consumed = snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%d",
			obj->metas->ord, obj->file_offset + obj->loadaddr, ((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
			obj->info.cp_string.string_idx);
		if (consumed >= size - 1) {
			free (value);
			size += size >> 1;
			value = malloc (size);
			if (value) {
				memset (value, 0, size);
				(void)snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%d",
					obj->metas->ord, obj->file_offset,
					((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
					obj->info.cp_string.string_idx);
			}
		}
	}
	return value;
}


R_API void r_bin_java_print_long_cp_summary(RBinJavaCPTypeObj *obj) {
	ut8 *b = NULL;
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  Long.\n");
		return;
	}
	b = obj->info.cp_long.bytes.raw;
	printf ("Long ConstantPool Type (%d) ", obj->metas->ord);
	printf ("  Offset: 0x%08"PFMT64x "", obj->file_offset);
	printf ("  High-Bytes = %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3]);
	printf ("  Low-Bytes = %02x %02x %02x %02x\n", b[4], b[5], b[6], b[7]);
	printf ("  Long = %08"PFMT64x "\n", r_bin_java_raw_to_long (obj->info.cp_long.bytes.raw, 0));
}


R_API RBinJavaAttrInfo *r_bin_java_rti_annotations_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	ut64 offset = 0;
	if (buf_offset + 32 >= sz) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	offset += 6;
	if (attr) {
		attr->type = R_BIN_JAVA_ATTR_TYPE_RUNTIME_INVISIBLE_ANNOTATION_ATTR;
		attr->info.annotation_array.num_annotations = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		attr->info.annotation_array.annotations = r_list_newf (r_bin_java_annotation_free);
		for (i = 0; i < attr->info.rtv_annotations_attr.num_annotations; i++) {
			if (offset >= sz) {
				break;
			}
			RBinJavaAnnotation *annotation = r_bin_java_annotation_new (buffer + offset, sz - offset, buf_offset + offset);
			if (annotation) {
				offset += annotation->size;
			}
			r_list_append (attr->info.annotation_array.annotations, (void *) annotation);
		}
		attr->size = offset;
	}
	return attr;
}


R_API void r_bin_java_print_constant_value_attr_summary(RBinJavaAttrInfo *attr) {
	if (!attr) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *ConstantValue.\n");
		return;
	}
	printf ("Constant Value Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
	printf ("  ConstantValue Index: %d\n", attr->info.constant_value_attr.constantvalue_idx);
}


R_API void r_bin_add_import(RBinJavaObj *bin, RBinJavaCPTypeObj *obj, const char *type) {
	RBinImport *imp = R_NEW0 (RBinImport);
	char *class_name = r_bin_java_get_name_from_bin_cp_list (bin, obj->info.cp_method.class_idx);
	char *name = r_bin_java_get_name_from_bin_cp_list (bin, obj->info.cp_method.name_and_type_idx);
	char *descriptor = r_bin_java_get_desc_from_bin_cp_list (bin, obj->info.cp_method.name_and_type_idx);
	class_name = class_name ? class_name : strdup ("INVALID CLASS NAME INDEX");
	name = name ? name : strdup ("InvalidNameIndex");
	descriptor = descriptor ? descriptor : strdup ("INVALID DESCRIPTOR INDEX");
	imp->classname = class_name;
	imp->name = name;
	imp->bind = "NONE";
	imp->type = r_str_constpool_get (&bin->constpool, type);
	imp->descriptor = descriptor;
	imp->ordinal = obj->idx;
	r_list_append (bin->imports_list, imp);
}


R_API char *r_bin_java_print_double_cp_stringify(RBinJavaCPTypeObj *obj) {
	ut32 size = 255, consumed = 0;
	char *value = malloc (size);
	if (value) {
		memset (value, 0, size);
		consumed = snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%f",
			obj->metas->ord,
			obj->file_offset,
			((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
			r_bin_java_raw_to_double (obj->info.cp_double.bytes.raw, 0));
		if (consumed >= size - 1) {
			free (value);
			size += size >> 1;
			value = malloc (size);
			if (value) {
				memset (value, 0, size);
				(void)snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%f",
					obj->metas->ord,
					obj->file_offset,
					((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
					r_bin_java_raw_to_double (obj->info.cp_double.bytes.raw, 0));
			}
		}
	}
	return value;
}


R_API void r_bin_java_get_fm_type_definition_json(RBinJavaObj *bin, RBinJavaField *fm_type, PJ *pj, int is_method) {
	r_return_if_fail (bin && fm_type && pj);

	ut64 addr = UT64_MAX;
	char *prototype = NULL, *fq_name = NULL;
	bool is_native = ((fm_type->flags & R_BIN_JAVA_METHOD_ACC_NATIVE) != 0);
	bool is_static = ((fm_type->flags & R_BIN_JAVA_METHOD_ACC_STATIC) != 0);
	bool is_synthetic = ((fm_type->flags & R_BIN_JAVA_METHOD_ACC_SYNTHETIC) != 0);
	bool is_private = ((fm_type->flags & R_BIN_JAVA_METHOD_ACC_PRIVATE) != 0);
	bool is_public = ((fm_type->flags & R_BIN_JAVA_METHOD_ACC_PUBLIC) != 0);
	bool is_protected = ((fm_type->flags & R_BIN_JAVA_METHOD_ACC_PROTECTED) != 0);
	bool is_super = ((fm_type->flags & R_BIN_JAVA_CLASS_ACC_SUPER) != 0);

	pj_o (pj);
	pj_ki (pj, "access_flags", fm_type->flags);
	pj_ki (pj, "is_method", is_method);
	pj_ki (pj, "is_native", is_native);
	pj_ki (pj, "is_synthetic", is_synthetic);
	pj_ki (pj, "is_private", is_private);
	pj_ki (pj, "is_public", is_public);
	pj_ki (pj, "is_static", is_static);
	pj_ki (pj, "is_protected", is_protected);
	pj_ki (pj, "is_super", is_super);

	addr = r_bin_java_get_method_code_offset (fm_type);
	if (addr == 0) {
		addr = fm_type->file_offset;
	}
	addr += bin->loadaddr;

	pj_ki (pj, "addr", addr);
	pj_ki (pj, "offset", fm_type->file_offset + bin->loadaddr);
	pj_ks (pj, "class_name", fm_type->class_name);
	pj_ks (pj, "signature", fm_type->descriptor);
	pj_ks (pj, "name", fm_type->name);

	if (is_method) {
		fq_name = r_bin_java_create_method_fq_str (fm_type->class_name, fm_type->name, fm_type->descriptor);
	} else {
		fq_name = r_bin_java_create_field_fq_str (fm_type->class_name, fm_type->name, fm_type->descriptor);
	}
	pj_ks (pj, "fq_name", fq_name);
	free (fq_name);

	prototype = r_bin_java_unmangle (fm_type->flags_str, fm_type->name, fm_type->descriptor);
	pj_ks (pj, "prototype", prototype);
	free (prototype);

	pj_end (pj);
}


R_API RBinJavaAttrInfo *r_bin_java_read_next_attr_from_buffer(RBinJavaObj *bin, ut8 *buffer, st64 sz, st64 buf_offset) {
	RBinJavaAttrInfo *attr = NULL;
	st64 nsz;

	if (!buffer || ((int) sz) < 4 || buf_offset < 0) {
		eprintf ("r_bin_Java_read_next_attr_from_buffer: invalid buffer size %d\n", (int) sz);
		return NULL;
	}
	ut16 name_idx = R_BIN_JAVA_USHORT (buffer, 0);
	ut64 offset = 2;
	nsz = R_BIN_JAVA_UINT (buffer, offset);
	// DEAD INCREMENT offset += 4;

	char *name = r_bin_java_get_utf8_from_bin_cp_list (R_BIN_JAVA_GLOBAL_BIN, name_idx);
	if (!name) {
		name = strdup ("unknown");
	}
	IFDBG eprintf ("r_bin_java_read_next_attr: name_idx = %d is %s\n", name_idx, name);
	RBinJavaAttrMetas *type_info = r_bin_java_get_attr_type_by_name (name);
	if (type_info) {
		IFDBG eprintf ("Typeinfo: %s, was %s\n", type_info->name, name);
		// printf ("SZ %d %d %d\n", nsz, sz, buf_offset);
		if (nsz > sz) {
			free (name);
			return NULL;
		}
		if ((attr = type_info->allocs->new_obj (bin, buffer, nsz, buf_offset))) {
			attr->metas->ord = (R_BIN_JAVA_GLOBAL_BIN->attr_idx++);
		}
	} else {
		eprintf ("r_bin_java_read_next_attr_from_buffer: Cannot find type_info for %s\n", name);
	}
	free (name);
	return attr;
}


R_API char *r_bin_java_build_obj_key(RBinJavaObj *bin) {
	char *cname = r_bin_java_get_this_class_name (bin);
	char *jvcname = cname?
		r_str_newf ("%d.%s.class", bin->id, cname)
		: r_str_newf ("%d._unknown_.class", bin->id);
	free (cname);
	return jvcname;
}


R_API void r_bin_java_print_bootstrap_method_argument_summary(RBinJavaBootStrapArgument *bsm_arg) {
	if (!bsm_arg) {
		eprintf ("Attempting to print an invalid RBinJavaBootStrapArgument *.\n");
		return;
	}
	eprintf ("Bootstrap Method Argument Information:\n");
	eprintf ("	Offset: 0x%08"PFMT64x"", bsm_arg->file_offset);
	eprintf ("	Name_And_Type Index = (0x%02x)\n", bsm_arg->argument_info_idx);
	if (bsm_arg->argument_info_cp_obj) {
		eprintf ("	Bootstrap Method Argument Type and Name Info:\n");
		((RBinJavaCPTypeMetas *) bsm_arg->argument_info_cp_obj)->allocs->print_summary (bsm_arg->argument_info_cp_obj);
	} else {
		eprintf ("	Bootstrap Method Argument Type and Name Info: INVALID\n");
	}
}


R_API RBinJavaAttrInfo *r_bin_java_code_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	RBinJavaAttrInfo *_attr = NULL;
	ut32 k = 0, curpos;
	ut64 offset = 0;
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!attr) {
		return NULL;
	}
	if (sz < 16 || sz > buf_offset) {// sz > buf_offset) {
		free (attr);
		return NULL;
	}
	offset += 6;
	attr->type = R_BIN_JAVA_ATTR_TYPE_CODE_ATTR;
	attr->info.code_attr.max_stack = attr->is_attr_in_old_format ? buffer[offset] : R_BIN_JAVA_USHORT (buffer, offset);
	offset += attr->is_attr_in_old_format ? 1 : 2;
	attr->info.code_attr.max_locals = attr->is_attr_in_old_format ? buffer[offset] : R_BIN_JAVA_USHORT (buffer, offset);
	offset += attr->is_attr_in_old_format ? 1 : 2;
	attr->info.code_attr.code_length = attr->is_attr_in_old_format ? R_BIN_JAVA_USHORT(buffer, offset) : R_BIN_JAVA_UINT (buffer, offset);
	offset += attr->is_attr_in_old_format ? 2 : 4;
	// BUG: possible unsigned integer overflow here
	attr->info.code_attr.code_offset = buf_offset + offset;
	attr->info.code_attr.code = (ut8 *) malloc (attr->info.code_attr.code_length);
	if (!attr->info.code_attr.code) {
		eprintf ("Handling Code Attributes: Unable to allocate memory "
			"(%u bytes) for a code.\n", attr->info.code_attr.code_length);
		return attr;
	}
	R_BIN_JAVA_GLOBAL_BIN->current_code_attr = attr;
	{
		int len = attr->info.code_attr.code_length;
		memset (attr->info.code_attr.code, 0, len);
		if (offset + len >= sz) {
			return attr;
		}
		memcpy (attr->info.code_attr.code, buffer + offset, len);
		offset += len;
	}
	attr->info.code_attr.exception_table_length = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	attr->info.code_attr.exception_table = r_list_newf (free);
	for (k = 0; k < attr->info.code_attr.exception_table_length; k++) {
		curpos = buf_offset + offset;
		if (curpos + 8 > sz) {
			return attr;
		}
		RBinJavaExceptionEntry *e = R_NEW0 (RBinJavaExceptionEntry);
		if (!e) {
			free (attr);
			return NULL;
		}
		e->file_offset = curpos;
		e->start_pc = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		e->end_pc = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		e->handler_pc = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		e->catch_type = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		r_list_append (attr->info.code_attr.exception_table, e);
		e->size = 8;
	}
	attr->info.code_attr.attributes_count = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	// IFDBG eprintf ("	code Attributes_count: %d\n", attr->info.code_attr.attributes_count);
	// XXX - attr->info.code_attr.attributes is not freed because one of the code attributes is improperly parsed.
	attr->info.code_attr.attributes = r_list_newf (r_bin_java_attribute_free);
	if (attr->info.code_attr.attributes_count > 0) {
		for (k = 0; k < attr->info.code_attr.attributes_count; k++) {
			int size = (offset < sz) ? sz - offset : 0;
			if (size > sz || size <= 0) {
				break;
			}
			_attr = r_bin_java_read_next_attr_from_buffer (bin, buffer + offset, size, buf_offset + offset);
			if (!_attr) {
				eprintf ("[X] r_bin_java_code_attr_new: Error unable to parse remainder of classfile after Method's Code Attribute: %d.\n", k);
				break;
			}
			IFDBG eprintf ("Parsing @ 0x%"PFMT64x " (%s) = 0x%"PFMT64x " bytes, %p\n", _attr->file_offset, _attr->name, _attr->size, _attr);
			offset += _attr->size;
			r_list_append (attr->info.code_attr.attributes, _attr);
			if (_attr->type == R_BIN_JAVA_ATTR_TYPE_LOCAL_VARIABLE_TABLE_ATTR) {
				IFDBG eprintf ("Parsed the LocalVariableTable, preparing the implicit mthod frame.\n");
				// r_bin_java_print_attr_summary(_attr);
				attr->info.code_attr.implicit_frame = r_bin_java_build_stack_frame_from_local_variable_table (R_BIN_JAVA_GLOBAL_BIN, _attr);
				attr->info.code_attr.implicit_frame->file_offset = buf_offset;
				IFDBG r_bin_java_print_stack_map_frame_summary(attr->info.code_attr.implicit_frame);
				// r_list_append (attr->info.code_attr.attributes, attr->info.code_attr.implicit_frame);
			}
			// if (offset > sz) {
			// eprintf ("[X] r_bin_java: Error unable to parse remainder of classfile after Attribute: %d.\n", k);
			// break;
			// }

		}
	}
	if (attr->info.code_attr.implicit_frame == NULL) {
		// build a default implicit_frame
		attr->info.code_attr.implicit_frame = r_bin_java_default_stack_frame ();
		// r_list_append (attr->info.code_attr.attributes, attr->info.code_attr.implicit_frame);
	}
	attr->size = offset;
	return attr;
}


R_API bool r_bin_java_is_old_format(RBinJavaObj *bin) {
	return bin->cf.major[1] == 45 && bin->cf.minor[1] <= 2;
}


R_API RList *r_bin_java_get_args(RBinJavaField *fm_type) {
	RList *the_list = r_bin_java_extract_type_values (fm_type->descriptor);
	RList *arg_list = r_list_new ();
	ut8 in_args = 0;
	RListIter *desc_iter;
	char *str;
	r_list_foreach (the_list, desc_iter, str) {
		if (str && *str == '(') {
			in_args = 1;
			continue;
		}
		if (str && *str == ')') {
			break;
		}
		if (in_args && str) {
			r_list_append (arg_list, strdup (str));
		}
	}
	r_list_free (the_list);
	return arg_list;
}


R_API void r_bin_java_print_bootstrap_methods_attr_summary(RBinJavaAttrInfo *attr) {
	RListIter *iter, *iter_tmp;
	RBinJavaBootStrapMethod *obj = NULL;
	if (!attr || attr->type == R_BIN_JAVA_ATTR_TYPE_BOOTSTRAP_METHODS_ATTR) {
		eprintf ("Unable to print attribue summary for RBinJavaAttrInfo *RBinJavaBootstrapMethodsAttr");
		return;
	}
	eprintf ("Bootstrap Methods Attribute Information Information:\n");
	eprintf ("	Attribute Offset: 0x%08"PFMT64x"", attr->file_offset);
	eprintf ("	Length: 0x%08x", attr->length);
	eprintf ("	Number of Method Arguments = (0x%02x)\n", attr->info.bootstrap_methods_attr.num_bootstrap_methods);
	if (attr->info.bootstrap_methods_attr.bootstrap_methods) {
		r_list_foreach_safe (attr->info.bootstrap_methods_attr.bootstrap_methods, iter, iter_tmp, obj) {
			if (obj) {
				r_bin_java_print_bootstrap_method_summary (obj);
			}
		}
	} else {
		eprintf ("	Bootstrap Methods: NONE \n");
	}
}


R_API void r_bin_java_get_class_info_json(RBinJavaObj *bin, PJ *pj) {
	r_return_if_fail (bin && pj);
	RList *classes = r_bin_java_get_classes (bin);
	RBinClass *class_ = r_list_get_n (classes, 0);

	// pj dict already opened

	if (class_) {
		int dummy = 0;
		RListIter *iter;
		RBinClass *class_v = NULL;
		// add access flags like in methods
		bool is_public = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_PUBLIC) != 0);
		bool is_final = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_FINAL) != 0);
		bool is_super = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_SUPER) != 0);
		bool is_interface = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_INTERFACE) != 0);
		bool is_abstract = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_ABSTRACT) != 0);
		bool is_synthetic = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_SYNTHETIC) != 0);
		bool is_annotation = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_ANNOTATION) != 0);
		bool is_enum = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_ENUM) != 0);

		pj_ki (pj, "access_flags", class_->visibility);
		pj_ki (pj, "is_public", is_public);
		pj_ki (pj, "is_final", is_final);
		pj_ki (pj, "is_super", is_super);
		pj_ki (pj, "is_interface", is_interface);
		pj_ki (pj, "is_abstract", is_abstract);
		pj_ki (pj, "is_synthetic", is_synthetic);
		pj_ki (pj, "is_annotation", is_annotation);
		pj_ki (pj, "is_enum", is_enum);
		pj_ks (pj, "name", class_->name);

		pj_ks (pj, "super", r_str_get (class_->super));

		pj_ka (pj, "interfaces");

		r_list_foreach (classes, iter, class_v) {
			if (!dummy) {
				dummy++;
				continue;
			}
			// enumerate all interface classes and append them to the interfaces
			if ((class_v->visibility & R_BIN_JAVA_CLASS_ACC_INTERFACE) != 0) {
				pj_s (pj, class_v->name);
			}
		}

		pj_end (pj);
	}
	r_list_free (classes);
}


R_API char *r_bin_java_print_long_cp_stringify(RBinJavaCPTypeObj *obj) {
	ut32 size = 255, consumed = 0;
	char *value = malloc (size);
	if (value) {
		memset (value, 0, size);
		consumed = snprintf (value, size, "%d.0x%04"PFMT64x ".%s.0x%08"PFMT64x "",
			obj->metas->ord,
			obj->file_offset,
			((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
			r_bin_java_raw_to_long (obj->info.cp_long.bytes.raw, 0));
		if (consumed >= size - 1) {
			free (value);
			size += size >> 1;
			value = malloc (size);
			if (value) {
				memset (value, 0, size);
				(void)snprintf (value, size, "%d.0x%04"PFMT64x ".%s.0x%08"PFMT64x "",
					obj->metas->ord,
					obj->file_offset,
					((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
					r_bin_java_raw_to_long (obj->info.cp_long.bytes.raw, 0));
			}
		}
	}
	return value;
}


R_API RBinJavaObj *r_bin_java_new(const char *file, ut64 loadaddr, Sdb *kv) {
	RBinJavaObj *bin = R_NEW0 (RBinJavaObj);
	if (!bin) {
		return NULL;
	}
	bin->file = strdup (file);
	size_t sz;
	ut8 *buf = (ut8 *)r_file_slurp (file, &sz);
	bin->size = sz;
	if (!buf) {
		return r_bin_java_free (bin);
	}
	if (!r_bin_java_new_bin (bin, loadaddr, kv, buf, bin->size)) {
		r_bin_java_free (bin);
		bin = NULL;
	}
	free (buf);
	return bin;
}


R_API RBinJavaCPTypeObj *r_bin_java_utf8_cp_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz) {
	ut8 tag = buffer[0];
	RBinJavaCPTypeObj *obj;
	int quick_check = r_bin_java_quick_check (R_BIN_JAVA_CP_UTF8, tag, sz, "Utf8");
	if (quick_check > 0) {
		return NULL;
	}
	if ((obj = R_NEW0 (RBinJavaCPTypeObj))) {
		obj->tag = tag;
		obj->metas = R_NEW0 (RBinJavaMetaInfo);
		obj->metas->type_info = (void *) &R_BIN_JAVA_CP_METAS[tag];
		obj->name = r_str_dup (NULL, (const char *) R_BIN_JAVA_CP_METAS[tag].name);
		obj->info.cp_utf8.length = R_BIN_JAVA_USHORT (buffer, 1);
		obj->info.cp_utf8.bytes = (ut8 *) malloc (obj->info.cp_utf8.length + 1);
		if (obj->info.cp_utf8.bytes) {
			memset (obj->info.cp_utf8.bytes, 0, obj->info.cp_utf8.length + 1);
			if (obj->info.cp_utf8.length < (sz - 3)) {
				memcpy (obj->info.cp_utf8.bytes, buffer + 3, (sz - 3));
				obj->info.cp_utf8.length = sz - 3;
			} else {
				memcpy (obj->info.cp_utf8.bytes, buffer + 3, obj->info.cp_utf8.length);
			}
			obj->value = obj->info.cp_utf8.bytes;
		} else {
			r_bin_java_obj_free (obj);
			obj = NULL;
		}
	}
	return obj;
}


R_API RBinJavaObj *r_bin_java_new_buf(RBuffer *buf, ut64 loadaddr, Sdb *kv) {
	RBinJavaObj *bin = R_NEW0 (RBinJavaObj);
	if (!bin) {
		return NULL;
	}
	ut64 tmpsz;
	const ut8 *tmp = r_buf_data (buf, &tmpsz);
	if (!r_bin_java_new_bin (bin, loadaddr, kv, tmp, tmpsz)) {
		return r_bin_java_free (bin);
	}
	return bin;
}


R_API char *r_bin_java_print_float_cp_stringify(RBinJavaCPTypeObj *obj) {
	ut32 size = 255, consumed = 0;
	char *value = malloc (size);
	if (value) {
		memset (value, 0, size);
		consumed = snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%f",
			obj->metas->ord, obj->file_offset + obj->loadaddr, ((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
			R_BIN_JAVA_FLOAT (obj->info.cp_float.bytes.raw, 0));
		if (consumed >= size - 1) {
			free (value);
			size += size >> 1;
			value = malloc (size);
			if (value) {
				memset (value, 0, size);
				(void)snprintf (value, size, "%d.0x%04"PFMT64x ".%s.%f",
					obj->metas->ord, obj->file_offset + obj->loadaddr, ((RBinJavaCPTypeMetas *) obj->metas->type_info)->name,
					R_BIN_JAVA_FLOAT (obj->info.cp_float.bytes.raw, 0));
			}
		}
	}
	return value;
}


R_API char *r_bin_java_get_item_desc_from_cp_item_list(RList *cp_list, RBinJavaCPTypeObj *obj, int depth) {
	/*
	Given a constant pool object FieldRef, MethodRef, or InterfaceMethodRef
	return the actual descriptor string.
	@rvalue ut8* (user frees) or NULL
	*/
	if (!obj || !cp_list || depth < 0) {
		return NULL;
	}
	switch (obj->tag) {
	case R_BIN_JAVA_CP_NAMEANDTYPE:
		return r_bin_java_get_utf8_from_cp_item_list (cp_list,
			obj->info.cp_name_and_type.descriptor_idx);
	// XXX - Probably not good form, but they are the same memory structure
	case R_BIN_JAVA_CP_FIELDREF:
	case R_BIN_JAVA_CP_INTERFACEMETHOD_REF:
	case R_BIN_JAVA_CP_METHODREF:
		obj = r_bin_java_get_item_from_cp_item_list (cp_list,
			obj->info.cp_method.name_and_type_idx);
		return r_bin_java_get_item_desc_from_cp_item_list (
			cp_list, obj, depth - 1);
	default:
		return NULL;
	}
	return NULL;
}


R_API void r_bin_java_print_local_variable_attr_summary(RBinJavaLocalVariableAttribute *lvattr) {
	if (!lvattr) {
		eprintf ("Attempting to print an invalid RBinJavaLocalVariableAttribute *.\n");
		return;
	}
	printf ("  Local Variable Attribute offset: 0x%08"PFMT64x "\n", lvattr->file_offset);
	printf ("  Local Variable Attribute start_pc: %d\n", lvattr->start_pc);
	printf ("  Local Variable Attribute Length: %d\n", lvattr->length);
	printf ("  Local Variable Attribute name_idx: %d\n", lvattr->name_idx);
	printf ("  Local Variable Attribute name: %s\n", lvattr->name);
	printf ("  Local Variable Attribute descriptor_idx: %d\n", lvattr->descriptor_idx);
	printf ("  Local Variable Attribute descriptor: %s\n", lvattr->descriptor);
	printf ("  Local Variable Attribute index: %d\n", lvattr->index);
}


R_API RBinJavaAttrInfo *r_bin_java_rtv_annotations_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	ut64 offset = 0;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	offset += 6;
	if (attr) {
		attr->type = R_BIN_JAVA_ATTR_TYPE_RUNTIME_VISIBLE_ANNOTATION_ATTR;
		attr->info.annotation_array.num_annotations = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		attr->info.annotation_array.annotations = r_list_newf (r_bin_java_annotation_free);
		for (i = 0; i < attr->info.annotation_array.num_annotations; i++) {
			if (offset >= sz) {
				break;
			}
			RBinJavaAnnotation *annotation = r_bin_java_annotation_new (buffer + offset, sz - offset, buf_offset + offset);
			if (annotation) {
				offset += annotation->size;
				r_list_append (attr->info.annotation_array.annotations, (void *) annotation);
			}
		}
		attr->size = offset;
	}
	return attr;
}


R_API RBinJavaField *r_bin_java_get_method_code_attribute_with_addr(RBinJavaObj *bin, ut64 addr) {
	RListIter *iter = NULL, *iter_tmp = NULL;
	RBinJavaField *fm_type, *res = NULL;
	if (!bin && R_BIN_JAVA_GLOBAL_BIN) {
		bin = R_BIN_JAVA_GLOBAL_BIN;
	}
	if (!bin) {
		eprintf ("Attempting to analyse function when the R_BIN_JAVA_GLOBAL_BIN has not been set.\n");
		return NULL;
	}
	r_list_foreach_safe (bin->methods_list, iter, iter_tmp, fm_type) {
		ut64 offset = r_bin_java_get_method_code_offset (fm_type) + bin->loadaddr,
		size = r_bin_java_get_method_code_size (fm_type);
		if (addr >= offset && addr <= size + offset) {
			res = fm_type;
		}
	}
	return res;
}


R_API char *r_bin_java_get_item_name_from_bin_cp_list(RBinJavaObj *bin, RBinJavaCPTypeObj *obj) {
	char *res = NULL;
	/*
	Given a constant pool object Class, FieldRef, MethodRef, or InterfaceMethodRef
	return the actual descriptor string.
	@param cp_list: RList of RBinJavaCPTypeObj *
	@param obj object to look up the name for
	@rvalue char* (user frees) or NULL
	*/
	if (bin && obj) {
		res = r_bin_java_get_item_name_from_cp_item_list (
			bin->cp_list, obj, MAX_CPITEMS);
	}
	return res;
}


R_API char *r_bin_java_get_desc_from_cp_item_list(RList *cp_list, ut64 idx) {
	/*
	Given a constant pool object FieldRef, MethodRef, or InterfaceMethodRef
	return the actual descriptor string.
	@rvalue ut8* (user frees) or NULL
	*/
	RBinJavaCPTypeObj *obj = r_bin_java_get_item_from_cp_item_list (cp_list, idx);
	if (!cp_list) {
		return NULL;
	}
	return r_bin_java_get_item_desc_from_cp_item_list (cp_list, obj, MAX_CPITEMS);
}


static bool char_must_be_escaped(ut8 c) {
	switch (c) {
	case 0x7f:
	case 0x81:
	case 0x8f:
	case 0x90:
	case 0x9d:
	case 0xa0:
	case 0xad:
		return true;
	default:
		if (c < 0x20) {
			return true;
		}
		return false;
	}
}


R_API void r_bin_java_attribute_free(void /*RBinJavaAttrInfo*/ *a) {
	RBinJavaAttrInfo *attr = a;
	if (attr) {
		IFDBG eprintf ("Deleting attr %s, %p\n", attr->name, attr);
		if (attr && attr->metas && attr->metas->type_info) {
			RBinJavaAttrMetas *a = attr->metas->type_info;
			if (a && a->allocs && a->allocs->delete_obj) {
				a->allocs->delete_obj (attr);
			}
		}
		// free (attr->metas);
		// free (attr);
	}
}


R_API RBinJavaAttrInfo *r_bin_java_stack_map_table_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
	ut32 i = 0;
	ut64 offset = 0;
	if (sz < 8) {
		return NULL;
	}
	RBinJavaStackMapFrame *stack_frame = NULL, *new_stack_frame = NULL;
	if (sz < 10) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	offset += 6;
	IFDBG eprintf ("r_bin_java_stack_map_table_attr_new: New stack map allocated.\n");
	if (!attr) {
		return NULL;
	}
	attr->info.stack_map_table_attr.stack_map_frame_entries = r_list_newf (r_bin_java_stack_frame_free);
	// IFDBG r_bin_java_print_source_code_file_attr_summary(attr);
	// Current spec does not call for variable sizes.
	attr->info.stack_map_table_attr.number_of_entries = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	IFDBG eprintf ("r_bin_java_stack_map_table_attr_new: Processing stack map, summary is:\n");
	IFDBG r_bin_java_print_stack_map_table_attr_summary(attr);
	for (i = 0; i < attr->info.stack_map_table_attr.number_of_entries; i++) {
		// read next stack frame
		IFDBG eprintf ("Reading StackMap Entry #%d @ 0x%08"PFMT64x "\n", i, buf_offset + offset);
		if (stack_frame == NULL && R_BIN_JAVA_GLOBAL_BIN && R_BIN_JAVA_GLOBAL_BIN->current_code_attr) {
			IFDBG eprintf ("Setting an implicit frame at #%d @ 0x%08"PFMT64x "\n", i, buf_offset + offset);
			stack_frame = R_BIN_JAVA_GLOBAL_BIN->current_code_attr->info.code_attr.implicit_frame;
		}
		IFDBG eprintf ("Reading StackMap Entry #%d @ 0x%08"PFMT64x ", current stack_frame: %p\n", i, buf_offset + offset, stack_frame);
		if (offset >= sz) {
			r_bin_java_stack_map_table_attr_free (attr);
			return NULL;
		}
		new_stack_frame = r_bin_java_stack_map_frame_new (buffer + offset, sz - offset, stack_frame, buf_offset + offset);
		if (new_stack_frame) {
			offset += new_stack_frame->size;
			// append stack frame to the list
			r_list_append (attr->info.stack_map_table_attr.stack_map_frame_entries, (void *) new_stack_frame);
			stack_frame = new_stack_frame;
		} else {
			eprintf ("r_bin_java_stack_map_table_attr_new: Unable to parse the stack frame for the stack map table.\n");
			r_bin_java_stack_map_table_attr_free (attr);
			attr = NULL;
			break;
		}
	}
	if (attr) {
		attr->size = offset;
	}
	return attr;
}


R_API RBinJavaAnnotationsArray *r_bin_java_annotation_array_new(ut8 *buffer, ut64 sz, ut64 buf_offset) {
	RBinJavaAnnotation *annotation;
	RBinJavaAnnotationsArray *annotation_array;
	ut32 i;
	ut64 offset = 0;
	annotation_array = (RBinJavaAnnotationsArray *) malloc (sizeof (RBinJavaAnnotationsArray));
	if (!annotation_array) {
		// TODO eprintf
		return NULL;
	}
	annotation_array->num_annotations = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	annotation_array->annotations = r_list_new ();
	for (i = 0; i < annotation_array->num_annotations; i++) {
		if (offset > sz) {
			break;
		}
		annotation = r_bin_java_annotation_new (buffer + offset, sz - offset, buf_offset + offset);
		if (annotation) {
			offset += annotation->size;
			r_list_append (annotation_array->annotations, (void *) annotation);
		}
	}
	annotation_array->size = offset;
	return annotation_array;
}


R_API RBinSymbol *r_bin_java_create_new_symbol_from_field(RBinJavaField *fm_type, ut64 baddr) {
	RBinSymbol *sym = R_NEW0 (RBinSymbol);
	if (!fm_type || !fm_type->field_ref_cp_obj || fm_type->field_ref_cp_obj == &R_BIN_JAVA_NULL_TYPE) {
		R_FREE (sym);
	}
	if (sym) {
		sym->name = strdup (fm_type->name);
		// strncpy (sym->type, fm_type->descriptor, R_BIN_SIZEOF_STRINGS);
		if (fm_type->type == R_BIN_JAVA_FIELD_TYPE_METHOD) {
			sym->type = R_BIN_TYPE_FUNC_STR;
			sym->paddr = r_bin_java_get_method_code_offset (fm_type);
			sym->vaddr = r_bin_java_get_method_code_offset (fm_type) + baddr;
			sym->size = r_bin_java_get_method_code_size (fm_type);
		} else {
			sym->type = "FIELD";
			sym->paddr = fm_type->file_offset;// r_bin_java_get_method_code_offset (fm_type);
			sym->vaddr = fm_type->file_offset + baddr;
			sym->size = fm_type->size;
		}
		if (r_bin_java_is_fm_type_protected (fm_type)) {
			sym->bind = R_BIN_BIND_LOCAL_STR;
		} else if (r_bin_java_is_fm_type_private (fm_type)) {
			sym->bind = R_BIN_BIND_LOCAL_STR;
		} else if (r_bin_java_is_fm_type_protected (fm_type)) {
			sym->bind = R_BIN_BIND_GLOBAL_STR;
		}
		sym->forwarder = "NONE";
		if (fm_type->class_name) {
			sym->classname = strdup (fm_type->class_name);
		} else {
			sym->classname = strdup ("UNKNOWN"); // dupped names?
		}
		sym->ordinal = fm_type->metas->ord;
		sym->visibility = fm_type->flags;
		if (fm_type->flags_str) {
			sym->visibility_str = strdup (fm_type->flags_str);
		}
	}
	return sym;
}


R_API void r_bin_java_reset_bin_info(RBinJavaObj *bin) {
	free (bin->cf2.flags_str);
	free (bin->cf2.this_class_name);
	r_list_free (bin->imports_list);
	r_list_free (bin->methods_list);
	r_list_free (bin->fields_list);
	r_list_free (bin->attrs_list);
	r_list_free (bin->cp_list);
	r_list_free (bin->interfaces_list);
	r_str_constpool_fini (&bin->constpool);
	r_str_constpool_init (&bin->constpool);
	bin->cf2.flags_str = strdup ("unknown");
	bin->cf2.this_class_name = strdup ("unknown");
	bin->imports_list = r_list_newf (free);
	bin->methods_list = r_list_newf (r_bin_java_fmtype_free);
	bin->fields_list = r_list_newf (r_bin_java_fmtype_free);
	bin->attrs_list = r_list_newf (r_bin_java_attribute_free);
	bin->cp_list = r_list_newf (r_bin_java_constant_pool);
	bin->interfaces_list = r_list_newf (r_bin_java_interface_free);
}


R_API void r_bin_java_print_interfacemethodref_cp_summary(RBinJavaCPTypeObj *obj) {
	if (!obj) {
		eprintf ("Attempting to print an invalid RBinJavaCPTypeObj*  InterfaceMethodRef.\n");
		return;
	}
	eprintf ("InterfaceMethodRef ConstantPool Type (%d) ", obj->metas->ord);
	eprintf ("	Offset: 0x%08"PFMT64x"", obj->file_offset);
	eprintf ("	Class Index = %d\n", obj->info.cp_interface.class_idx);
	eprintf ("	Name and type Index = %d\n", obj->info.cp_interface.name_and_type_idx);
}


R_API void U(r_bin_java_print_stack_map_append_frame_summary)(RBinJavaStackMapFrame * obj) {
	RListIter *iter, *iter_tmp;
	RList *ptrList;
	RBinJavaVerificationObj *ver_obj;
	printf ("Stack Map Frame Information\n");
	printf ("  Tag Value = 0x%02x Name: %s\n", obj->tag, ((RBinJavaStackMapFrameMetas *) obj->metas->type_info)->name);
	printf ("  Offset: 0x%08"PFMT64x "\n", obj->file_offset);
	printf ("  Local Variable Count = 0x%04x\n", obj->number_of_locals);
	printf ("  Local Variables:\n");
	ptrList = obj->local_items;
	r_list_foreach_safe (ptrList, iter, iter_tmp, ver_obj) {
		r_bin_java_print_verification_info_summary (ver_obj);
	}
	printf ("  Stack Items Count = 0x%04x\n", obj->number_of_stack_items);
	printf ("  Stack Items:\n");
	ptrList = obj->stack_items;
	r_list_foreach_safe (ptrList, iter, iter_tmp, ver_obj) {
		r_bin_java_print_verification_info_summary (ver_obj);
	}
}


R_API void r_bin_java_get_import_json_definitions(RBinJavaObj *bin, PJ *pj) {
	r_return_if_fail (pj);
	RList *the_list;
	RListIter *iter = NULL;
	char *new_str;

	pj_ka (pj, "imports");

	if (!bin || !(the_list = r_bin_java_get_lib_names (bin))) {
		pj_end (pj);
		return;
	}

	r_list_foreach (the_list, iter, new_str) {
		char *tmp = new_str;
		while (*tmp) {
			if (*tmp == '/') {
				*tmp = '.';
			}
			tmp++;
		}
		pj_s (pj, new_str);
	}
	r_list_free (the_list);
	pj_end (pj);
	return;
}


R_API ut64 r_bin_java_rti_annotations_attr_calc_size(RBinJavaAttrInfo *attr) {
	ut64 size = 0;
	if (!attr) {
		// TODO eprintf allocation fail
		return size;
	}
	size += (6 + r_bin_java_annotation_array_calc_size (&(attr->info.annotation_array)));
	return size;
}


R_API void r_bin_java_print_synthetic_attr_summary(RBinJavaAttrInfo *attr) {
	if (attr == NULL) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *Synthetic.\n");
		return;
	}
	printf ("Synthetic Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
	printf ("  Attribute Index: %d\n", attr->info.source_file_attr.sourcefile_idx);
}


R_API void r_bin_java_print_deprecated_attr_summary(RBinJavaAttrInfo *attr) {
	if (!attr) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *Deperecated.\n");
		return;
	}
	printf ("Deperecated Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
}


R_API void r_bin_java_print_line_number_table_attr_summary(RBinJavaAttrInfo *attr) {
	RBinJavaLineNumberAttribute *lnattr;
	RListIter *iter, *iter_tmp;
	if (!attr) {
		eprintf ("Attempting to print an invalid RBinJavaAttrInfo *LineNumberTable.\n");
		return;
	}
	printf ("Line Number Table Attribute Information:\n");
	printf ("  Attribute Offset: 0x%08"PFMT64x "\n", attr->file_offset);
	printf ("  Attribute Name Index: %d (%s)\n", attr->name_idx, attr->name);
	printf ("  Attribute Length: %d\n", attr->length);
	r_list_foreach_safe (attr->info.line_number_table_attr.line_number_table, iter, iter_tmp, lnattr) {
		r_bin_java_print_line_number_attr_summary (lnattr);
	}
}


R_API void r_bin_java_print_element_value_summary(RBinJavaElementValue *element_value) {
	RBinJavaCPTypeObj *obj;
	RBinJavaElementValue *ev_element = NULL;
	RListIter *iter = NULL, *iter_tmp = NULL;
	char *name;
	if (!element_value) {
		eprintf ("Attempting to print an invalid RBinJavaElementValuePair *pair.\n");
		return;
	}
	name = ((RBinJavaElementValueMetas *) element_value->metas->type_info)->name;
	eprintf ("Element Value information:\n");
	eprintf ("   EV Pair File Offset: 0x%08"PFMT64x "\n", element_value->file_offset);
	eprintf ("   EV Value Type (%d): %s\n", element_value->tag, name);
	switch (element_value->tag) {
	case R_BIN_JAVA_EV_TAG_BYTE:
	case R_BIN_JAVA_EV_TAG_CHAR:
	case R_BIN_JAVA_EV_TAG_DOUBLE:
	case R_BIN_JAVA_EV_TAG_FLOAT:
	case R_BIN_JAVA_EV_TAG_INT:
	case R_BIN_JAVA_EV_TAG_LONG:
	case R_BIN_JAVA_EV_TAG_SHORT:
	case R_BIN_JAVA_EV_TAG_BOOLEAN:
	case R_BIN_JAVA_EV_TAG_STRING:
		eprintf ("   EV Value Constant Value index: 0x%02x\n", element_value->value.const_value.const_value_idx);
		eprintf ("   EV Value Constant Value Information:\n");
		obj = element_value->value.const_value.const_value_cp_obj;
		if (obj && obj->metas && obj->metas->type_info) {
			((RBinJavaCPTypeMetas *) obj->metas->type_info)->allocs->print_summary (obj);
		}
		break;
	case R_BIN_JAVA_EV_TAG_ENUM:
		eprintf ("   EV Value Enum Constant Value Const Name Index: 0x%02x\n", element_value->value.enum_const_value.const_name_idx);
		eprintf ("   EV Value Enum Constant Value Type Name Index: 0x%02x\n", element_value->value.enum_const_value.type_name_idx);
		eprintf ("   EV Value Enum Constant Value Const CP Information:\n");
		obj = element_value->value.enum_const_value.const_name_cp_obj;
		if (obj && obj->metas && obj->metas->type_info) {
			((RBinJavaCPTypeMetas *) obj->metas->type_info)->allocs->print_summary (obj);
		}
		eprintf ("   EV Value Enum Constant Value Type CP Information:\n");
		obj = element_value->value.enum_const_value.type_name_cp_obj;
		if (obj && obj->metas && obj->metas->type_info) {
			((RBinJavaCPTypeMetas *) obj->metas->type_info)->allocs->print_summary (obj);
		}
		break;
	case R_BIN_JAVA_EV_TAG_CLASS:
		eprintf ("   EV Value Class Info Index: 0x%02x\n", element_value->value.class_value.class_info_idx);
		eprintf ("   EV Value Class Info CP Information:\n");
		obj = element_value->value.class_value.class_info_cp_obj;
		if (obj && obj->metas && obj->metas->type_info) {
			((RBinJavaCPTypeMetas *) obj->metas->type_info)->allocs->print_summary (obj);
		}
		break;
	case R_BIN_JAVA_EV_TAG_ARRAY:
		eprintf ("   EV Value Array Value Number of Values: 0x%04x\n", element_value->value.array_value.num_values);
		eprintf ("   EV Value Array Values\n");
		r_list_foreach_safe (element_value->value.array_value.values, iter, iter_tmp, ev_element) {
			r_bin_java_print_element_value_summary (ev_element);
		}
		break;
	case R_BIN_JAVA_EV_TAG_ANNOTATION:
		eprintf ("   EV Annotation Information:\n");
		r_bin_java_print_annotation_summary (&element_value->value.annotation_value);
		break;
	default:
		// eprintf unable to handle tag
		break;
	}
}


R_API void r_bin_java_get_field_json_definitions(RBinJavaObj *bin, PJ *pj) {
	r_return_if_fail (pj);
	RBinJavaField *fm_type = NULL;
	RListIter *iter = NULL;

	pj_ka (pj, "fields");
	if (!bin) {
		pj_end (pj);
		return;
	}

	r_list_foreach (bin->fields_list, iter, fm_type) {
		r_bin_java_get_field_json_definition (bin, fm_type, pj);
	}
	pj_end (pj);
}


R_API void U(copy_type_info_to_stack_frame_list)(RList * type_list, RList * sf_list) {
	RListIter *iter, *iter_tmp;
	RBinJavaVerificationObj *ver_obj, *new_ver_obj;
	if (!type_list || !sf_list) {
		return;
	}
	r_list_foreach_safe (type_list, iter, iter_tmp, ver_obj) {
		new_ver_obj = (RBinJavaVerificationObj *) malloc (sizeof (RBinJavaVerificationObj));
		// FIXME: how to handle failed memory allocation?
		if (new_ver_obj && ver_obj) {
			memcpy (new_ver_obj, ver_obj, sizeof (RBinJavaVerificationObj));
			if (!r_list_append (sf_list, (void *) new_ver_obj)) {
				R_FREE (new_ver_obj);
			}
		} else {
			R_FREE (new_ver_obj);
		}
	}
}


R_API RList *retrieve_all_class_access_string_and_value(void) {
	return retrieve_all_access_string_and_value (CLASS_ACCESS_FLAGS);
}


R_API ut64 r_bin_java_parse_methods(RBinJavaObj *bin, const ut64 offset, const ut8 *buf, const ut64 len) {
	int i = 0;
	ut64 adv = 0;
	RBinJavaField *method;
	const ut8 *fm_buf = buf + offset;
	r_list_free (bin->methods_list);
	bin->methods_list = r_list_newf (r_bin_java_fmtype_free);

	if (offset + 2 >= len) {
		return 0LL;
	}
	bin->methods_offset = offset;
	bin->methods_count = R_BIN_JAVA_USHORT (fm_buf, 0);
	adv += 2;
	IFDBG eprintf ("Methods count: %d 0x%"PFMT64x "\n", bin->methods_count, bin->methods_offset);
	bin->main = NULL;
	bin->entrypoint = NULL;
	bin->main_code_attr = NULL;
	bin->entrypoint_code_attr = NULL;
	for (i = 0; i < bin->methods_count; i++, bin->method_idx++) {
		method = r_bin_java_read_next_method (bin, offset + adv, buf, len);
		if (method) {
			adv += method->size;
			r_list_append (bin->methods_list, method);
		}
		// Update Main, Init, or Class Init
		if (method && !strcmp ((const char *) method->name, "main")) {
			bin->main = method;
			// get main code attr
			bin->main_code_attr = r_bin_java_get_attr_from_field (method, R_BIN_JAVA_ATTR_TYPE_CODE_ATTR, 0);
		} else if (method && (!strcmp ((const char *) method->name, "<init>") || !strcmp ((const char *) method->name, "init")))   {
			IFDBG eprintf ("Found an init function.\n");
			bin->entrypoint = method;
			bin->entrypoint_code_attr = r_bin_java_get_attr_from_field (method, R_BIN_JAVA_ATTR_TYPE_CODE_ATTR, 0);
		} else if (method && (!strcmp ((const char *) method->name, "<cinit>") || !strcmp ((const char *) method->name, "cinit")))   {
			bin->cf2.this_class_entrypoint = method;
			bin->cf2.this_class_entrypoint_code_attr = r_bin_java_get_attr_from_field (method, R_BIN_JAVA_ATTR_TYPE_CODE_ATTR, 0);
		}
		if (adv + offset > len) {
			eprintf ("[X] r_bin_java: Error unable to parse remainder of classfile after Method: %d.\n", i);
			break;
		}
		IFDBG r_bin_java_print_field_summary(method);
	}
	bin->methods_size = adv;
	return adv;
}


R_API ConstJavaValue *U(r_bin_java_resolve_to_const_value)(RBinJavaObj * BIN_OBJ, int idx) {
	// TODO XXX FIXME add a size parameter to the str when it is passed in
	RBinJavaCPTypeObj *item = NULL, *item2 = NULL;
	ConstJavaValue *result = R_NEW0 (ConstJavaValue);
	if (!result) {
		return NULL;
	}
	char *class_str = NULL,
	*name_str = NULL,
	*desc_str = NULL,
	*string_str = NULL,
	*empty = "",
	*cp_name = NULL;
	result->type = "unknown";
	if (BIN_OBJ && BIN_OBJ->cp_count < 1) {
		// r_bin_java_new_bin(BIN_OBJ);
		return result;
	}
	item = (RBinJavaCPTypeObj *) r_bin_java_get_item_from_bin_cp_list (BIN_OBJ, idx);
	if (!item) {
		return result;
	}
	cp_name = ((RBinJavaCPTypeMetas *) item->metas->type_info)->name;
	IFDBG eprintf ("java_resolve Resolved: (%d) %s\n", idx, cp_name);
	if (strcmp (cp_name, "Class") == 0) {
		item2 = (RBinJavaCPTypeObj *) r_bin_java_get_item_from_bin_cp_list (BIN_OBJ, idx);
		// str = r_bin_java_get_name_from_bin_cp_list (BIN_OBJ, idx-1);
		class_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item);
		if (!class_str) {
			class_str = empty;
		}
		name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item2);
		if (!name_str) {
			name_str = empty;
		}
		desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item2);
		if (!desc_str) {
			desc_str = empty;
		}
		result->value._ref = R_NEW0 (_JavaRef);
		result->type = "ref";
		result->value._ref->class_name = strdup (class_str);
		result->value._ref->name = strdup (name_str);
		result->value._ref->desc = strdup (desc_str);
		if (class_str != empty) {
			free (class_str);
		}
		if (name_str != empty) {
			free (name_str);
		}
		if (desc_str != empty) {
			free (desc_str);
		}
	} else if (strcmp (cp_name, "MethodRef") == 0 ||
	strcmp (cp_name, "FieldRef") == 0 ||
	strcmp (cp_name, "InterfaceMethodRef") == 0) {
		/*
		*  The MethodRef, FieldRef, and InterfaceMethodRef structures
		*/
		class_str = r_bin_java_get_name_from_bin_cp_list (BIN_OBJ, item->info.cp_method.class_idx);
		if (!class_str) {
			class_str = empty;
		}
		name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item);
		if (!name_str) {
			name_str = empty;
		}
		desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item);
		if (!desc_str) {
			desc_str = empty;
		}
		result->value._ref = R_NEW0 (_JavaRef);
		result->type = "ref";
		result->value._ref->class_name = strdup (class_str);
		result->value._ref->name = strdup (name_str);
		result->value._ref->desc = strdup (desc_str);
		if (class_str != empty) {
			free (class_str);
		}
		if (name_str != empty) {
			free (name_str);
		}
		if (desc_str != empty) {
			free (desc_str);
		}
	} else if (strcmp (cp_name, "String") == 0) {
		ut32 length = r_bin_java_get_utf8_len_from_bin_cp_list (BIN_OBJ, item->info.cp_string.string_idx);
		string_str = r_bin_java_get_utf8_from_bin_cp_list (BIN_OBJ, item->info.cp_string.string_idx);
		IFDBG eprintf ("java_resolve String got: (%d) %s\n", item->info.cp_string.string_idx, string_str);
		if (!string_str) {
			string_str = empty;
			length = strlen (empty);
		}
		result->type = "str";
		result->value._str = R_NEW0 (struct  java_const_value_str_t);
		result->value._str->len = length;
		if (length > 0) {
			result->value._str->str = r_str_ndup (string_str, length);
		} else {
			result->value._str->str = strdup ("");
		}
		if (string_str != empty) {
			free (string_str);
		}
	} else if (strcmp (cp_name, "Utf8") == 0) {
		result->type = "str";
		result->value._str = R_NEW0 (struct java_const_value_str_t);
		result->value._str->str = malloc (item->info.cp_utf8.length);
		result->value._str->len = item->info.cp_utf8.length;
		memcpy (result->value._str->str, item->info.cp_utf8.bytes, item->info.cp_utf8.length);
	} else if (strcmp (cp_name, "Long") == 0) {
		result->type = "long";
		result->value._long = r_bin_java_raw_to_long (item->info.cp_long.bytes.raw, 0);
	} else if (strcmp (cp_name, "Double") == 0) {
		result->type = "double";
		result->value._double = r_bin_java_raw_to_double (item->info.cp_double.bytes.raw, 0);
	} else if (strcmp (cp_name, "Integer") == 0) {
		result->type = "int";
		result->value._int = R_BIN_JAVA_UINT (item->info.cp_integer.bytes.raw, 0);
	} else if (strcmp (cp_name, "Float") == 0) {
		result->type = "float";
		result->value._float = R_BIN_JAVA_FLOAT (item->info.cp_float.bytes.raw, 0);
	} else if (strcmp (cp_name, "NameAndType") == 0) {
		result->value._ref = R_NEW0 (struct java_const_value_ref_t);
		result->type = "ref";
		name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item);
		if (!name_str) {
			name_str = empty;
		}
		desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item);
		if (!desc_str) {
			desc_str = empty;
		}
		result->value._ref->class_name = strdup (empty);
		result->value._ref->name = strdup (name_str);
		result->value._ref->desc = strdup (desc_str);
		if (name_str != empty) {
			free (name_str);
		}
		if (desc_str != empty) {
			free (desc_str);
		}
		result->value._ref->is_method = r_bin_java_does_cp_idx_ref_method (BIN_OBJ, idx);
		result->value._ref->is_field = r_bin_java_does_cp_idx_ref_field (BIN_OBJ, idx);
	}
	return result;
}