struct r_bin_pe_lib_t* PE_(r_bin_pe_get_libs)(struct PE_(r_bin_pe_obj_t)* bin) {
	if (!bin) {
		return NULL;
	}
	struct r_bin_pe_lib_t* libs = NULL;
	PE_(image_import_directory) * curr_import_dir = NULL;
	PE_(image_delay_import_directory) * curr_delay_import_dir = NULL;
	PE_DWord name_off = 0;
	SdbHash* lib_map = NULL;
	ut64 off; //cache value
	int index = 0;
	int len = 0;
	int max_libs = 20;
	libs = calloc (max_libs + 1, sizeof(struct r_bin_pe_lib_t));
	if (!libs) {
		r_sys_perror ("malloc (libs)");
		return NULL;
	}

	if (bin->import_directory_offset + bin->import_directory_size > bin->size) {
		bprintf ("import directory offset bigger than file\n");
		goto out_error;
	}
	lib_map = sdb_ht_new ();
	off = bin->import_directory_offset;
	if (off < bin->size && off > 0) {
		void* last = NULL;
		// normal imports
		if (off + sizeof (PE_(image_import_directory)) > bin->size) {
			goto out_error;
		}
		curr_import_dir = (PE_(image_import_directory)*)(bin->b->buf + off);
		last = (char*) curr_import_dir + bin->import_directory_size;
		while ((void*) (curr_import_dir + 1) <= last && (
			curr_import_dir->FirstThunk || curr_import_dir->Name ||
			curr_import_dir->TimeDateStamp || curr_import_dir->Characteristics ||
			curr_import_dir->ForwarderChain)) {
			name_off = bin_pe_rva_to_paddr (bin, curr_import_dir->Name);
			len = r_buf_read_at (bin->b, name_off, (ut8*) libs[index].name, PE_STRING_LENGTH);
			if (!libs[index].name[0]) { // minimum string length
				goto next;
			}
			if (len < 2 || libs[index].name[0] == 0) { // minimum string length
				bprintf ("Warning: read (libs - import dirs) %d\n", len);
				break;
			}
			libs[index].name[len - 1] = '\0';
			r_str_case (libs[index].name, 0);
			if (!sdb_ht_find (lib_map, libs[index].name, NULL)) {
				sdb_ht_insert (lib_map, libs[index].name, "a");
				libs[index++].last = 0;
				if (index >= max_libs) {
					libs = realloc (libs, (max_libs * 2) * sizeof (struct r_bin_pe_lib_t));
					if (!libs) {
						r_sys_perror ("realloc (libs)");
						goto out_error;
					}
					max_libs *= 2;
				}
			}
next:
			curr_import_dir++;
		}
	}
	off = bin->delay_import_directory_offset;
	if (off < bin->size && off > 0) {
		if (off + sizeof(PE_(image_delay_import_directory)) > bin->size) {
			goto out_error;
		}
		curr_delay_import_dir = (PE_(image_delay_import_directory)*)(bin->b->buf + off);
		while (curr_delay_import_dir->Name != 0 && curr_delay_import_dir->DelayImportNameTable != 0) {
			name_off = bin_pe_rva_to_paddr (bin, curr_delay_import_dir->Name);
			if (name_off > bin->size || name_off + PE_STRING_LENGTH > bin->size) {
				goto out_error;
			}
			len = r_buf_read_at (bin->b, name_off, (ut8*) libs[index].name, PE_STRING_LENGTH);
			if (len != PE_STRING_LENGTH) {
				bprintf ("Warning: read (libs - delay import dirs)\n");
				break;
			}
			libs[index].name[len - 1] = '\0';
			r_str_case (libs[index].name, 0);
			if (!sdb_ht_find (lib_map, libs[index].name, NULL)) {
				sdb_ht_insert (lib_map, libs[index].name, "a");
				libs[index++].last = 0;
				if (index >= max_libs) {
					libs = realloc (libs, (max_libs * 2) * sizeof (struct r_bin_pe_lib_t));
					if (!libs) {
						sdb_ht_free (lib_map);
						r_sys_perror ("realloc (libs)");
						return NULL;
					}
					max_libs *= 2;
				}
			}
			curr_delay_import_dir++;
			if ((const ut8*) (curr_delay_import_dir + 1) >= (const ut8*) (bin->b->buf + bin->size)) {
				break;
			}
		}
	}
	sdb_ht_free (lib_map);
	libs[index].last = 1;
	return libs;
out_error:
	sdb_ht_free (lib_map);
	free (libs);
	return NULL;
}