static void _parse_resource_directory(RBinPEObj *pe, Pe_image_resource_directory *dir, ut64 offDir, int type, int id, HtUU *dirs, const char *resource_name) {
	char *resourceEntryName = NULL;
	int index = 0;
	ut32 totalRes = dir->NumberOfNamedEntries + dir->NumberOfIdEntries;
	ut64 rsrc_base = pe->resource_directory_offset;
	ut64 off;
	if (totalRes > R_PE_MAX_RESOURCES) {
		return;
	}
	for (index = 0; index < totalRes; index++) {
		Pe_image_resource_directory_entry entry;
		off = rsrc_base + offDir + sizeof (*dir) + index * sizeof (entry);
		if (ht_uu_find (dirs, off, NULL)) {
			break;
		}
		ht_uu_insert (dirs, off, 1);
		if (off > pe->size || off + sizeof (entry) > pe->size) {
			break;
		}
		if (read_image_resource_directory_entry (pe->b, off, &entry) < 0) {
			eprintf ("Warning: read resource entry\n");
			break;
		}
		if (entry.u1.Name >> 31) {
			int i;
			ut16 buf;
			ut32 NameOffset = entry.u1.Name & 0x7fffffff;
			if (r_buf_read_at (pe->b, pe->resource_directory_offset + NameOffset, (ut8*)&buf, sizeof (ut16)) != sizeof (ut16)) {
				break;
			}
			ut16 resourceEntryNameLength = r_read_le16 (&buf);
			resourceEntryName = calloc (resourceEntryNameLength + 1, 1);
			if (resourceEntryName) {
				for (i = 0; i < resourceEntryNameLength; i++) { /* Convert Unicode to ASCII */
					ut8 byte;
					int r = r_buf_read_at (pe->b, pe->resource_directory_offset + NameOffset + 2 + (i*2), &byte, sizeof (ut8));
					if (r != sizeof (ut8) || !byte) {
						R_FREE (resourceEntryName);
						break;
					}
					resourceEntryName[i] = byte;
				}
			}
		}
		if (entry.u2.OffsetToData >> 31) {
			//detect here malicious file trying to making us infinite loop
			Pe_image_resource_directory identEntry;
			ut32 OffsetToDirectory = entry.u2.OffsetToData & 0x7fffffff;
			off = rsrc_base + OffsetToDirectory;
			int len = read_image_resource_directory (pe->b, off, &identEntry);
			if (len < 1 || len != sizeof (Pe_image_resource_directory)) {
				eprintf ("Warning: parsing resource directory\n");
			}
			_parse_resource_directory (pe, &identEntry, OffsetToDirectory, type, entry.u1.Name & 0xffff, dirs, resourceEntryName);
			R_FREE (resourceEntryName);
			continue;
		}
		R_FREE (resourceEntryName);

		Pe_image_resource_data_entry *data = R_NEW0 (Pe_image_resource_data_entry);
		if (!data) {
			break;
		}
		off = rsrc_base + entry.u2.OffsetToData;
		if (off > pe->size || off + sizeof (*data) > pe->size) {
			free (data);
			break;
		}
		if (read_image_resource_data_entry (pe->b, off, data) != sizeof (*data)) {
			eprintf ("Warning: read (resource data entry)\n");
			free (data);
			break;
		}
		if (type == PE_RESOURCE_ENTRY_VERSION) {
			char key[64];
			int counter = 0;
			Sdb *sdb = sdb_new0 ();
			if (!sdb) {
				free (data);
				sdb_free (sdb);
				continue;
			}
			PE_DWord data_paddr = PE_(va2pa) (pe, data->OffsetToData);
			if (!data_paddr) {
				pe_printf ("Warning: bad RVA in resource data entry\n");
				free (data);
				sdb_free (sdb);
				continue;
			}
			PE_DWord cur_paddr = data_paddr;
			if ((cur_paddr & 0x3) != 0) {
				pe_printf ("Warning: not aligned version info address\n");
				free (data);
				sdb_free (sdb);
				continue;
			}
			while (cur_paddr < (data_paddr + data->Size) && cur_paddr < pe->size) {
				PE_VS_VERSIONINFO* vs_VersionInfo = Pe_r_bin_pe_parse_version_info (pe, cur_paddr);
				if (!vs_VersionInfo) {
					break;
				}
				snprintf (key, 30, "VS_VERSIONINFO%d", counter++);
				sdb_ns_set (sdb, key, Pe_r_bin_store_resource_version_info (vs_VersionInfo));
				if (vs_VersionInfo->wLength < 1) {
					// Invalid version length
					break;
				}
				cur_paddr += vs_VersionInfo->wLength;
				free_VS_VERSIONINFO (vs_VersionInfo);
				align32 (cur_paddr);
			}
			sdb_ns_set (pe->kv, "vs_version_info", sdb);
		}
		r_pe_resource *rs = R_NEW0 (r_pe_resource);
		if (!rs) {
			free (data);
			break;
		}
		/* Compare compileTimeStamp to resource timestamp to figure out if DOS date or POSIX date */
		if (r_time_stamp_is_dos_format ((ut32) sdb_num_get (pe->kv, "image_file_header.TimeDateStamp", 0), dir->TimeDateStamp)) {
			rs->timestr = r_time_stamp_to_str ( r_time_dos_time_stamp_to_posix (dir->TimeDateStamp));
		} else {
			rs->timestr = r_time_stamp_to_str (dir->TimeDateStamp);
		}
		rs->type = _resource_type_str (type);
		rs->language = strdup (_resource_lang_str (entry.u1.Name & 0x3ff));
		rs->data = data;
		if (resource_name) {
			rs->name = strdup (resource_name);
		} else {
			rs->name = r_str_newf ("%d", id);
		}
		r_list_append (pe->resources, rs);
	}
}