static bool dex_parse(RzBinDex *dex, ut64 base, RzBuffer *buf) {
	ut64 offset = 0;
	st64 read = 0;
	st64 buffer_size = rz_buf_size(buf);
	if (buffer_size < 116) {
		// 116 bytes is the smalled dex that can be built.
		RZ_LOG_ERROR("dex bin: invalid buffer size (size < 116)\n");
		goto dex_parse_bad;
	}

	dex->header_offset = base;
	dex->relocs_offset = base + RZ_DEX_RELOC_ADDRESS;
	rz_buf_read(buf, dex->magic, sizeof(dex->magic));
	rz_buf_read(buf, dex->version, sizeof(dex->version));
	dex->checksum_offset = rz_buf_tell(buf) + base;
	read_le32_or_fail(buf, dex->checksum, dex_parse_bad);
	dex->signature_offset = rz_buf_tell(buf) + base;
	rz_buf_read(buf, dex->signature, sizeof(dex->signature));
	read_le32_or_fail(buf, dex->file_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->header_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->endian_tag, dex_parse_bad);

	read_le32_or_fail(buf, dex->link_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->link_offset, dex_parse_bad);

	read_le32_or_fail(buf, dex->map_offset, dex_parse_bad);

	read_le32_or_fail(buf, dex->string_ids_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->string_ids_offset, dex_parse_bad);
	// string_ids points to an array of offsets.
	dex_fail_if_bad_ids(dex->string_ids, sizeof(ut32), buffer_size, dex_parse_bad);

	read_le32_or_fail(buf, dex->type_ids_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->type_ids_offset, dex_parse_bad);
	dex_fail_if_bad_ids(dex->type_ids, DEX_TYPE_ID_SIZE, buffer_size, dex_parse_bad);

	read_le32_or_fail(buf, dex->proto_ids_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->proto_ids_offset, dex_parse_bad);
	dex_fail_if_bad_ids(dex->proto_ids, DEX_PROTO_ID_SIZE, buffer_size, dex_parse_bad);

	read_le32_or_fail(buf, dex->field_ids_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->field_ids_offset, dex_parse_bad);
	dex_fail_if_bad_ids(dex->field_ids, DEX_FIELD_ID_SIZE, buffer_size, dex_parse_bad);

	read_le32_or_fail(buf, dex->method_ids_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->method_ids_offset, dex_parse_bad);
	dex_fail_if_bad_ids(dex->method_ids, DEX_METHOD_ID_SIZE, buffer_size, dex_parse_bad);

	read_le32_or_fail(buf, dex->class_defs_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->class_defs_offset, dex_parse_bad);

	read_le32_or_fail(buf, dex->data_size, dex_parse_bad);
	read_le32_or_fail(buf, dex->data_offset, dex_parse_bad);

	/* Strings */
	offset = dex->string_ids_offset;
	if (!rz_pvector_reserve(dex->strings, dex->string_ids_size)) {
		goto dex_parse_bad;
	}
	for (ut32 i = 0; i < dex->string_ids_size; ++i, offset += sizeof(ut32)) {
		ut32 string_offset = 0;
		read_le32_at_or_fail(buf, string_offset, offset, dex_parse_bad);

		if (rz_buf_seek(buf, string_offset, RZ_BUF_SET) < 0) {
			goto dex_parse_bad;
		}
		DexString *string = dex_string_new(buf, base + string_offset, &read);
		if (!string) {
			goto dex_parse_bad;
		}
		rz_pvector_push(dex->strings, string);
	}

	/* Type Ids */
	dex->types = RZ_NEWS0(DexTypeId, dex->type_ids_size);
	if (!dex->types) {
		goto dex_parse_bad;
	}
	if (rz_buf_seek(buf, dex->type_ids_offset, RZ_BUF_SET) < 0) {
		goto dex_parse_bad;
	}
	for (ut32 i = 0; i < dex->type_ids_size; ++i) {
		read_le32_or_fail(buf, dex->types[i], dex_parse_bad);
	}

	/* Proto Ids */
	offset = dex->proto_ids_offset;
	if (!rz_pvector_reserve(dex->proto_ids, dex->proto_ids_size)) {
		goto dex_parse_bad;
	}
	for (ut32 i = 0; i < dex->proto_ids_size; ++i, offset += DEX_PROTO_ID_SIZE) {
		if (rz_buf_seek(buf, offset, RZ_BUF_SET) < 0) {
			goto dex_parse_bad;
		}
		DexProtoId *proto_id = dex_proto_id_new(buf, base + offset);
		if (!proto_id) {
			goto dex_parse_bad;
		}
		rz_pvector_push(dex->proto_ids, proto_id);
	}

	/* Field Ids */
	offset = dex->field_ids_offset;
	if (!rz_pvector_reserve(dex->field_ids, dex->field_ids_size)) {
		goto dex_parse_bad;
	}
	for (ut32 i = 0; i < dex->field_ids_size; ++i, offset += DEX_FIELD_ID_SIZE) {
		if (rz_buf_seek(buf, offset, RZ_BUF_SET) < 0) {
			goto dex_parse_bad;
		}
		DexFieldId *field_id = dex_field_id_new(buf, base + offset);
		if (!field_id) {
			goto dex_parse_bad;
		}
		rz_pvector_push(dex->field_ids, field_id);
	}

	/* Method Ids */
	offset = dex->method_ids_offset;
	if (!rz_pvector_reserve(dex->method_ids, dex->method_ids_size)) {
		goto dex_parse_bad;
	}
	for (ut32 i = 0; i < dex->method_ids_size; ++i, offset += DEX_METHOD_ID_SIZE) {
		if (rz_buf_seek(buf, offset, RZ_BUF_SET) < 0) {
			goto dex_parse_bad;
		}
		DexMethodId *method_id = dex_method_id_new(buf, base + offset);
		if (!method_id) {
			goto dex_parse_bad;
		}
		rz_pvector_push(dex->method_ids, method_id);
	}

	/* Class Defs */
	offset = dex->class_defs_offset;
	if (!rz_pvector_reserve(dex->class_defs, dex->class_defs_size)) {
		goto dex_parse_bad;
	}
	for (ut32 i = 0; i < dex->class_defs_size; ++i, offset += DEX_CLASS_DEF_SIZE) {
		if (rz_buf_seek(buf, offset, RZ_BUF_SET) < 0) {
			goto dex_parse_bad;
		}
		DexClassDef *class_def = dex_class_def_new(buf, base + offset, base, dex->method_ids);
		if (!class_def) {
			goto dex_parse_bad;
		}
		rz_pvector_push(dex->class_defs, class_def);
	}

	/* Resolve all virtual methods */
	dex_resolve_all_virtual_methods(dex);

	/* generate relocation code buffer this buffer will contain a
	 * sequence of 0e00, i.e 'return-void', which will be used to
	 * resolve imports for the xrefs.
	 */
	if (!dex_create_relocations(dex)) {
		goto dex_parse_bad;
	}

	return true;

dex_parse_bad:
	rz_bin_dex_free(dex);
	return false;
}