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 272 : #[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 1456 : fn id(&self) -> u32 {
26 1456 : self.get_base().id()
27 1456 : }
28 :
29 : /// Current depth of the Node in the resource tree
30 224 : fn depth(&self) -> u32 {
31 224 : self.get_base().depth()
32 224 : }
33 :
34 : /// Iterator on node's children
35 1456 : fn children(&self) -> Children {
36 1456 : Children::new(self.get_base().childs())
37 1456 : }
38 : }
39 :
40 : impl std::fmt::Debug for &dyn NodeBase {
41 1456 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 1456 : f.debug_struct("NodeBase").field("id", &self.id()).finish()
43 1456 : }
44 : }
45 :
46 : impl<'a> FromFFI<ffi::PE_ResourceNode> for Node<'a> {
47 2864 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_ResourceNode>) -> Self {
48 2864 : unsafe {
49 2864 : let cmd_ref = ffi_entry.as_ref().unwrap();
50 2864 :
51 2864 : if ffi::PE_ResourceDirectory::classof(cmd_ref) {
52 1680 : let raw = {
53 1680 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
54 1680 : type To = cxx::UniquePtr<ffi::PE_ResourceDirectory>;
55 1680 : std::mem::transmute::<From, To>(ffi_entry)
56 1680 : };
57 1680 : Node::Directory(Directory::from_ffi(raw))
58 : } else {
59 1184 : assert!(
60 1184 : ffi::PE_ResourceData::classof(cmd_ref),
61 0 : "Must be a ResourceData node"
62 : );
63 :
64 1184 : let raw = {
65 1184 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
66 1184 : type To = cxx::UniquePtr<ffi::PE_ResourceData>;
67 1184 : std::mem::transmute::<From, To>(ffi_entry)
68 1184 : };
69 1184 : Node::Data(Data::from_ffi(raw))
70 : }
71 : }
72 2864 : }
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 1184 : pub fn code_page(&self) -> u32 {
84 1184 : self.ptr.code_page()
85 1184 : }
86 :
87 : /// Reserved value. Should be `0`
88 1184 : pub fn reserved(&self) -> u32 {
89 1184 : self.ptr.reserved()
90 1184 : }
91 :
92 : /// Offset of the content within the resource
93 : ///
94 : /// <div class="warning">this value may change when rebuilding resource table</div>
95 1184 : pub fn offset(&self) -> u32 {
96 1184 : self.ptr.offset()
97 1184 : }
98 :
99 : /// Resource content
100 1184 : pub fn content(&self) -> &[u8] {
101 1184 : to_slice!(self.ptr.content());
102 1184 : }
103 : }
104 :
105 : impl NodeBase for Data<'_> {
106 1184 : fn get_base(&self) -> &ffi::PE_ResourceNode {
107 1184 : self.ptr.as_ref().unwrap().as_ref()
108 1184 : }
109 : }
110 :
111 : impl fmt::Debug for Data<'_> {
112 1184 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 1184 : let base = self as &dyn NodeBase;
114 1184 : f.debug_struct("Data")
115 1184 : .field("base", &base)
116 1184 : .field("code_page", &self.code_page())
117 1184 : .field("reserved", &self.reserved())
118 1184 : .field("offset", &self.offset())
119 1184 : .finish()
120 1184 : }
121 : }
122 :
123 : impl<'a> FromFFI<ffi::PE_ResourceData> for Data<'a> {
124 1184 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceData>) -> Self {
125 1184 : Self {
126 1184 : ptr,
127 1184 : _owner: PhantomData,
128 1184 : }
129 1184 : }
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 272 : pub fn characteristics(&self) -> u32 {
142 272 : self.ptr.characteristics()
143 272 : }
144 :
145 : /// The time that the resource data was created by the
146 : /// resource compiler.
147 272 : pub fn time_date_stamp(&self) -> u32 {
148 272 : self.ptr.time_date_stamp()
149 272 : }
150 :
151 : /// The major version number, set by the user.
152 272 : pub fn major_version(&self) -> u32 {
153 272 : self.ptr.major_version()
154 272 : }
155 :
156 : /// The minor version number, set by the user.
157 272 : pub fn minor_version(&self) -> u32 {
158 272 : self.ptr.minor_version()
159 272 : }
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 272 : pub fn numberof_name_entries(&self) -> u32 {
165 272 : self.ptr.numberof_name_entries()
166 272 : }
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 272 : pub fn numberof_id_entries(&self) -> u32 {
173 272 : self.ptr.numberof_id_entries()
174 272 : }
175 : }
176 :
177 : impl NodeBase for Directory<'_> {
178 1952 : fn get_base(&self) -> &ffi::PE_ResourceNode {
179 1952 : self.ptr.as_ref().unwrap().as_ref()
180 1952 : }
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 272 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 272 : let base = self as &dyn NodeBase;
199 272 : f.debug_struct("Directory")
200 272 : .field("base", &base)
201 272 : .field("characteristics", &self.characteristics())
202 272 : .field("time_date_stamp", &self.time_date_stamp())
203 272 : .field("major_version", &self.major_version())
204 272 : .field("minor_version", &self.minor_version())
205 272 : .field("numberof_name_entries", &self.numberof_name_entries())
206 272 : .field("numberof_id_entries", &self.numberof_id_entries())
207 272 : .finish()
208 272 : }
209 : }
210 :
211 : impl<'a> FromFFI<ffi::PE_ResourceDirectory> for Directory<'a> {
212 1680 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>) -> Self {
213 1680 : Self {
214 1680 : ptr,
215 1680 : _owner: PhantomData,
216 1680 : }
217 1680 : }
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 48 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>) -> Self {
227 48 : Self {
228 48 : ptr,
229 48 : _owner: PhantomData,
230 48 : }
231 48 : }
232 : }
233 :
234 2768 : declare_iterator!(
235 2768 : Children,
236 2768 : Node<'a>,
237 2768 : ffi::PE_ResourceNode,
238 2768 : ffi::PE_Binary,
239 2768 : ffi::PE_ResourceNode_it_childs
240 2768 : );
|