///|
pub fn PEImage::resources(self : Self) -> Array[ResourceEntry] raise PeError {
let directory = match self.directory(2) {
Some(directory) if directory.virtual_address != 0UL && directory.size > 0 =>
directory
_ => return []
}
let entries = []
self.walk_resource_directory(
directory.virtual_address,
directory.virtual_address,
0,
"",
entries,
)
entries
}
///|
fn PEImage::walk_resource_directory(
self : Self,
resource_base : UInt64,
directory_rva : UInt64,
depth : Int32,
parent_path : String,
output : Array[ResourceEntry],
) -> Unit raise PeError {
if depth > 4 || output.length() >= 4096 {
return
}
let offset = self.rva_to_offset(directory_rva)
ensure_range(self.data, offset, 16)
let named_count = read_u16(self.data, offset + 12)
let id_count = read_u16(self.data, offset + 14)
let count = named_count + id_count
if count > 4096 {
raise PeError(offset + 12, "resource entry count exceeds the safety limit")
}
ensure_range(self.data, offset + 16, count * 8)
for index in 0.. None
}
output.push({
path,
type_id: if depth == 0 {
Some(name_value.to_int())
} else {
None
},
name_id: if depth == 1 {
Some(name_value.to_int())
} else {
None
},
language_id: if depth == 2 {
Some(name_value.to_int())
} else {
None
},
data_rva,
file_offset,
size,
code_page,
})
}
}
}
///|
fn PEImage::read_resource_string(
self : Self,
string_rva : UInt64,
) -> String raise PeError {
let offset = self.rva_to_offset(string_rva)
ensure_range(self.data, offset, 2)
let length = read_u16(self.data, offset)
if length > 2048 {
raise PeError(offset, "resource string exceeds the safety limit")
}
ensure_range(self.data, offset + 2, length * 2)
let builder = StringBuilder()
for index in 0..= 0x20 && code <= 0x7e {
builder.write_char(code.unsafe_to_char())
} else {
builder.write_char('?')
}
}
builder.to_string()
}
///|
fn resource_type_name(id : Int32) -> String {
match id {
1 => "cursor"
2 => "bitmap"
3 => "icon"
4 => "menu"
5 => "dialog"
6 => "string-table"
9 => "accelerator"
10 => "rcdata"
11 => "message-table"
12 => "group-cursor"
14 => "group-icon"
16 => "version"
17 => "dlginclude"
19 => "plugplay"
20 => "vxd"
21 => "anicursor"
22 => "aniicon"
23 => "html"
24 => "manifest"
_ => "#\{id}"
}
}