Line data Source code
1 : //! This module contains the different structures involved in the PE's resource tree
2 :
3 : use lief_ffi as ffi;
4 :
5 : use std::{fmt, marker::PhantomData};
6 :
7 : use crate::to_slice;
8 : use crate::{common::FromFFI, declare_iterator};
9 :
10 340 : #[derive(Debug)]
11 : pub enum Node<'a> {
12 : /// A *data* node (i.e. a leaf)
13 : Data(Data<'a>),
14 : /// A directory node
15 : Directory(Directory<'a>),
16 : }
17 :
18 : /// Trait that is shared by both [`Node::Data`] and [`Node::Directory`].
19 : pub trait NodeBase {
20 : #[doc(hidden)]
21 : fn get_base(&self) -> &ffi::PE_ResourceNode;
22 :
23 : /// Integer that identifies the Type, Name, or Language ID of the entry
24 : /// depending on its [`NodeBase::depth`] in the tree
25 1820 : fn id(&self) -> u32 {
26 1820 : self.get_base().id()
27 1820 : }
28 :
29 : /// Current depth of the Node in the resource tree
30 280 : fn depth(&self) -> u32 {
31 280 : self.get_base().depth()
32 280 : }
33 :
34 : /// Iterator on node's children
35 1820 : fn children(&self) -> Children {
36 1820 : Children::new(self.get_base().childs())
37 1820 : }
38 : }
39 :
40 : impl std::fmt::Debug for &dyn NodeBase {
41 1820 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 1820 : f.debug_struct("NodeBase").field("id", &self.id()).finish()
43 1820 : }
44 : }
45 :
46 : impl<'a> FromFFI<ffi::PE_ResourceNode> for Node<'a> {
47 3580 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_ResourceNode>) -> Self {
48 3580 : unsafe {
49 3580 : let cmd_ref = ffi_entry.as_ref().unwrap();
50 3580 :
51 3580 : if ffi::PE_ResourceDirectory::classof(cmd_ref) {
52 2100 : let raw = {
53 2100 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
54 2100 : type To = cxx::UniquePtr<ffi::PE_ResourceDirectory>;
55 2100 : std::mem::transmute::<From, To>(ffi_entry)
56 2100 : };
57 2100 : Node::Directory(Directory::from_ffi(raw))
58 : } else {
59 1480 : assert!(
60 1480 : ffi::PE_ResourceData::classof(cmd_ref),
61 0 : "Must be a ResourceData node"
62 : );
63 :
64 1480 : let raw = {
65 1480 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
66 1480 : type To = cxx::UniquePtr<ffi::PE_ResourceData>;
67 1480 : std::mem::transmute::<From, To>(ffi_entry)
68 1480 : };
69 1480 : Node::Data(Data::from_ffi(raw))
70 : }
71 : }
72 3580 : }
73 : }
74 :
75 : pub struct Data<'a> {
76 : ptr: cxx::UniquePtr<ffi::PE_ResourceData>,
77 : _owner: PhantomData<&'a Node<'a>>,
78 : }
79 :
80 : impl Data<'_> {
81 : /// Return the code page that is used to decode code point
82 : /// values within the resource data. Typically, the code page is the unicode code page.
83 1480 : pub fn code_page(&self) -> u32 {
84 1480 : self.ptr.code_page()
85 1480 : }
86 :
87 : /// Reserved value. Should be `0`
88 1480 : pub fn reserved(&self) -> u32 {
89 1480 : self.ptr.reserved()
90 1480 : }
91 :
92 : /// Offset of the content within the resource
93 : ///
94 : /// <div class="warning">this value may change when rebuilding resource table</div>
95 1480 : pub fn offset(&self) -> u32 {
96 1480 : self.ptr.offset()
97 1480 : }
98 :
99 : /// Resource content
100 1480 : pub fn content(&self) -> &[u8] {
101 1480 : to_slice!(self.ptr.content());
102 1480 : }
103 : }
104 :
105 : impl NodeBase for Data<'_> {
106 1480 : fn get_base(&self) -> &ffi::PE_ResourceNode {
107 1480 : self.ptr.as_ref().unwrap().as_ref()
108 1480 : }
109 : }
110 :
111 : impl fmt::Debug for Data<'_> {
112 1480 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 1480 : let base = self as &dyn NodeBase;
114 1480 : f.debug_struct("Data")
115 1480 : .field("base", &base)
116 1480 : .field("code_page", &self.code_page())
117 1480 : .field("reserved", &self.reserved())
118 1480 : .field("offset", &self.offset())
119 1480 : .finish()
120 1480 : }
121 : }
122 :
123 : impl<'a> FromFFI<ffi::PE_ResourceData> for Data<'a> {
124 1480 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceData>) -> Self {
125 1480 : Self {
126 1480 : ptr,
127 1480 : _owner: PhantomData,
128 1480 : }
129 1480 : }
130 : }
131 :
132 : pub struct Directory<'a> {
133 : ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>,
134 : _owner: PhantomData<&'a Node<'a>>,
135 : }
136 :
137 : impl Directory<'_> {
138 :
139 : /// Resource characteristics. This field is reserved for future use.
140 : /// It is currently set to zero.
141 340 : pub fn characteristics(&self) -> u32 {
142 340 : self.ptr.characteristics()
143 340 : }
144 :
145 : /// The time that the resource data was created by the
146 : /// resource compiler.
147 340 : pub fn time_date_stamp(&self) -> u32 {
148 340 : self.ptr.time_date_stamp()
149 340 : }
150 :
151 : /// The major version number, set by the user.
152 340 : pub fn major_version(&self) -> u32 {
153 340 : self.ptr.major_version()
154 340 : }
155 :
156 : /// The minor version number, set by the user.
157 340 : pub fn minor_version(&self) -> u32 {
158 340 : self.ptr.minor_version()
159 340 : }
160 :
161 : /// The number of directory entries immediately
162 : /// following the table that use strings to identify Type,
163 : /// Name, or Language entries (depending on the level of the table).
164 340 : pub fn numberof_name_entries(&self) -> u32 {
165 340 : self.ptr.numberof_name_entries()
166 340 : }
167 :
168 :
169 : /// The number of directory entries immediately
170 : /// following the Name entries that use numeric IDs for
171 : /// Type, Name, or Language entries.
172 340 : pub fn numberof_id_entries(&self) -> u32 {
173 340 : self.ptr.numberof_id_entries()
174 340 : }
175 : }
176 :
177 : impl NodeBase for Directory<'_> {
178 2440 : fn get_base(&self) -> &ffi::PE_ResourceNode {
179 2440 : self.ptr.as_ref().unwrap().as_ref()
180 2440 : }
181 : }
182 :
183 : impl NodeBase for Node<'_> {
184 0 : fn get_base(&self) -> &ffi::PE_ResourceNode {
185 0 : match &self {
186 0 : Node::Data(n) => {
187 0 : n.get_base()
188 : }
189 0 : Node::Directory(n) => {
190 0 : n.get_base()
191 : }
192 : }
193 0 : }
194 : }
195 :
196 : impl fmt::Debug for Directory<'_> {
197 340 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 340 : let base = self as &dyn NodeBase;
199 340 : f.debug_struct("Directory")
200 340 : .field("base", &base)
201 340 : .field("characteristics", &self.characteristics())
202 340 : .field("time_date_stamp", &self.time_date_stamp())
203 340 : .field("major_version", &self.major_version())
204 340 : .field("minor_version", &self.minor_version())
205 340 : .field("numberof_name_entries", &self.numberof_name_entries())
206 340 : .field("numberof_id_entries", &self.numberof_id_entries())
207 340 : .finish()
208 340 : }
209 : }
210 :
211 : impl<'a> FromFFI<ffi::PE_ResourceDirectory> for Directory<'a> {
212 2100 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>) -> Self {
213 2100 : Self {
214 2100 : ptr,
215 2100 : _owner: PhantomData,
216 2100 : }
217 2100 : }
218 : }
219 :
220 : pub struct Manager<'a> {
221 : ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>,
222 : _owner: PhantomData<&'a Node<'a>>,
223 : }
224 :
225 : impl<'a> FromFFI<ffi::PE_ResourcesManager> for Manager<'a> {
226 60 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>) -> Self {
227 60 : Self {
228 60 : ptr,
229 60 : _owner: PhantomData,
230 60 : }
231 60 : }
232 : }
233 :
234 3460 : declare_iterator!(
235 3460 : Children,
236 3460 : Node<'a>,
237 3460 : ffi::PE_ResourceNode,
238 3460 : ffi::PE_Binary,
239 3460 : ffi::PE_ResourceNode_it_childs
240 3460 : );
|