struct r_bin_pe_lib_t* PE_(r_bin_pe_get_libs)(RBinPEObj* pe) {
	if (!pe) {
		return NULL;
	}
	struct r_bin_pe_lib_t* libs = NULL;
	struct r_bin_pe_lib_t* new_libs = NULL;
	PE_(image_import_directory) curr_import_dir;
	PE_(image_delay_import_directory) curr_delay_import_dir;
	PE_DWord name_off = 0;
	HtPP *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 (pe->import_directory_offset + pe->import_directory_size > pe->size) {
		pe_printf ("import directory offset bigger than file\n");
		goto out_error;
	}
	lib_map = sdb_ht_new ();
	off = pe->import_directory_offset;
	if (off < pe->size && off > 0) {
		ut64 last;
		int iidi = 0;
		// normal imports
		if (off + sizeof (PE_(image_import_directory)) > pe->size) {
			goto out_error;
		}
		int r = read_image_import_directory (pe->b, off + iidi * sizeof (curr_import_dir),
			&curr_import_dir);
		last = off + pe->import_directory_size;
		while (r == sizeof (curr_import_dir) && off + (iidi + 1) * sizeof (curr_import_dir) <= last && (
			curr_import_dir.FirstThunk || curr_import_dir.Name ||
			curr_import_dir.TimeDateStamp || curr_import_dir.Characteristics ||
			curr_import_dir.ForwarderChain)) {
			name_off = PE_(va2pa) (pe, curr_import_dir.Name);
			len = r_buf_read_at (pe->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
				pe_printf ("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) {
					new_libs = realloc (libs, (max_libs * 2) * sizeof (struct r_bin_pe_lib_t));
					if (!new_libs) {
						r_sys_perror ("realloc (libs)");
						goto out_error;
					}
					libs = new_libs;
					new_libs = NULL;
					max_libs *= 2;
				}
			}
next:
			iidi++;
			r = read_image_import_directory (pe->b, off + iidi * sizeof (curr_import_dir),
				&curr_import_dir);
		}
	}
	off = pe->delay_import_directory_offset;
	if (off < pe->size && off > 0) {
		ut64 did = 0;
		if (off + sizeof (PE_(image_delay_import_directory)) > pe->size) {
			goto out_error;
		}
		int r = read_image_delay_import_directory (pe->b, off, &curr_delay_import_dir);
		if (r != sizeof (curr_delay_import_dir)) {
			goto out_error;
		}
		while (r == sizeof (curr_delay_import_dir) &&
			curr_delay_import_dir.Name != 0 && curr_delay_import_dir.DelayImportNameTable != 0) {
			name_off = PE_(va2pa) (pe, curr_delay_import_dir.Name);
			if (name_off > pe->size || name_off + PE_STRING_LENGTH > pe->size) {
				goto out_error;
			}
			len = r_buf_read_at (pe->b, name_off, (ut8*) libs[index].name, PE_STRING_LENGTH);
			if (len != PE_STRING_LENGTH) {
				pe_printf ("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) {
					new_libs = realloc (libs, (max_libs * 2) * sizeof (struct r_bin_pe_lib_t));
					if (!new_libs) {
						r_sys_perror ("realloc (libs)");
						goto out_error;
					}
					libs = new_libs;
					new_libs = NULL;
					max_libs *= 2;
				}
			}
			did++;
			r = read_image_delay_import_directory (pe->b, off + did * sizeof (curr_delay_import_dir),
				&curr_delay_import_dir);
		}
	}
	sdb_ht_free (lib_map);
	libs[index].last = 1;
	return libs;
out_error:
	sdb_ht_free (lib_map);
	free (libs);
	return NULL;
}