Line data Source code
1 : //! This module contains the different structures involved in the PE's resource tree
2 : //!
3 : //! One can access this tree using either: [`crate::pe::Binary::resources`] or by parsing raw bytes
4 : //! with [`Node::from_slice`]. The [`Manager`] provides a logical API over the resource tree
5 : //! to access specifics parts of the tree.
6 :
7 : use lief_ffi as ffi;
8 :
9 : use std::pin::Pin;
10 : use std::{fmt, marker::PhantomData};
11 :
12 : use crate::common::into_optional;
13 : use crate::to_slice;
14 : use crate::{common::FromFFI, declare_iterator};
15 :
16 : /// This enum represents a node in the resource tree which can be either: a **directory** node
17 : /// or a data (leaf) node.
18 598 : #[derive(Debug)]
19 : pub enum Node<'a> {
20 : /// A *data* node (i.e. a leaf)
21 : Data(Data<'a>),
22 : /// A directory node
23 : Directory(Directory<'a>),
24 : }
25 :
26 : impl Node<'_> {
27 : /// Parse a resource tree from the provided slice. The original RVA must be provided
28 : /// to resolve the content of the data nodes.
29 130 : pub fn from_slice(content: &[u8], rva: u64) -> Option<Node<'_>> {
30 130 : unsafe {
31 130 : let ptr = ffi::PE_ResourceNode::from_slice(content.as_ptr(), content.len(), rva);
32 130 : if ptr.is_null() {
33 0 : return None;
34 130 : }
35 130 : Some(Node::from_ffi(ptr))
36 : }
37 130 : }
38 : }
39 :
40 : /// Trait that is shared by both [`Node::Data`] and [`Node::Directory`].
41 : pub trait NodeBase {
42 : #[doc(hidden)]
43 : fn get_base(&self) -> &ffi::PE_ResourceNode;
44 :
45 : #[doc(hidden)]
46 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode>;
47 :
48 : /// Integer that identifies the Type, Name, or Language ID of the entry
49 : /// depending on its [`NodeBase::depth`] in the tree
50 2626 : fn id(&self) -> u32 {
51 2626 : self.get_base().id()
52 2626 : }
53 :
54 : /// Current depth of the Node in the resource tree
55 468 : fn depth(&self) -> u32 {
56 468 : self.get_base().depth()
57 468 : }
58 :
59 : /// Iterator on node's children
60 2678 : fn children(&self) -> Children<'_> {
61 2678 : Children::new(self.get_base().childs())
62 2678 : }
63 :
64 : /// Name of the node (if any)
65 0 : fn name(&self) -> Option<String> {
66 0 : if !self.get_base().has_name() {
67 0 : return None;
68 0 : }
69 0 : Some(self.get_base().name().to_string())
70 0 : }
71 :
72 : /// Add a new child node to the current and return the newly-added node
73 0 : fn add_child(&mut self, node: &Node) -> Node<'_> {
74 0 : Node::from_ffi(self.base_as_pin_mut().add_child(node.get_base()))
75 0 : }
76 :
77 : /// Delete the child node with the given id
78 0 : fn delete_child(&mut self, id: u32) {
79 0 : self.base_as_pin_mut().delete_child(id);
80 0 : }
81 : }
82 :
83 : impl std::fmt::Debug for &dyn NodeBase {
84 2626 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 2626 : f.debug_struct("NodeBase").field("id", &self.id()).finish()
86 2626 : }
87 : }
88 :
89 : impl std::fmt::Display for &dyn NodeBase {
90 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
91 0 : write!(f, "{}", self.get_base().print())
92 0 : }
93 : }
94 :
95 : impl<'a> FromFFI<ffi::PE_ResourceNode> for Node<'a> {
96 5304 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_ResourceNode>) -> Self {
97 5304 : unsafe {
98 5304 : let cmd_ref = ffi_entry.as_ref().unwrap();
99 5304 :
100 5304 : if ffi::PE_ResourceDirectory::classof(cmd_ref) {
101 3276 : let raw = {
102 3276 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
103 3276 : type To = cxx::UniquePtr<ffi::PE_ResourceDirectory>;
104 3276 : std::mem::transmute::<From, To>(ffi_entry)
105 3276 : };
106 3276 : Node::Directory(Directory::from_ffi(raw))
107 : } else {
108 2028 : assert!(
109 2028 : ffi::PE_ResourceData::classof(cmd_ref),
110 0 : "Must be a ResourceData node"
111 : );
112 :
113 2028 : let raw = {
114 2028 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
115 2028 : type To = cxx::UniquePtr<ffi::PE_ResourceData>;
116 2028 : std::mem::transmute::<From, To>(ffi_entry)
117 2028 : };
118 2028 : Node::Data(Data::from_ffi(raw))
119 : }
120 : }
121 5304 : }
122 : }
123 :
124 : pub struct Data<'a> {
125 : ptr: cxx::UniquePtr<ffi::PE_ResourceData>,
126 : _owner: PhantomData<&'a Node<'a>>,
127 : }
128 :
129 : impl Data<'_> {
130 : /// Create a new Data node with the provided payload
131 0 : pub fn with_buffer(buffer: &[u8]) -> Data<'static> {
132 0 : unsafe {
133 0 : Data::from_ffi(ffi::PE_ResourceData::create_from_data(
134 0 : buffer.as_ptr(),
135 0 : buffer.len(),
136 0 : ))
137 0 : }
138 0 : }
139 :
140 : /// Create a new Data node
141 0 : pub fn new() -> Data<'static> {
142 0 : Data::from_ffi(ffi::PE_ResourceData::create())
143 0 : }
144 :
145 : /// Return the code page that is used to decode code point
146 : /// values within the resource data. Typically, the code page is the unicode code page.
147 2028 : pub fn code_page(&self) -> u32 {
148 2028 : self.ptr.code_page()
149 2028 : }
150 :
151 : /// Reserved value. Should be `0`
152 2028 : pub fn reserved(&self) -> u32 {
153 2028 : self.ptr.reserved()
154 2028 : }
155 :
156 : /// Offset of the content within the resource
157 : ///
158 : /// <div class="warning">this value may change when rebuilding resource table</div>
159 2028 : pub fn offset(&self) -> u32 {
160 2028 : self.ptr.offset()
161 2028 : }
162 :
163 : /// Resource content
164 2028 : pub fn content(&self) -> &[u8] {
165 2028 : to_slice!(self.ptr.content());
166 2028 : }
167 :
168 : /// Change or set the raw data associated with this node
169 0 : pub fn set_content(&mut self, content: &[u8]) -> &mut Self {
170 0 : unsafe {
171 0 : self.ptr
172 0 : .pin_mut()
173 0 : .set_content(content.as_ptr(), content.len());
174 0 : }
175 0 : self
176 0 : }
177 :
178 : /// Change or set the code page
179 0 : pub fn set_code_page(&mut self, code_page: u32) -> &mut Self {
180 0 : self.ptr.pin_mut().set_code_page(code_page);
181 0 : self
182 0 : }
183 :
184 : /// Change or set the *reserved* field
185 0 : pub fn set_reserved(&mut self, reserved: u32) -> &mut Self {
186 0 : self.ptr.pin_mut().set_reserved(reserved);
187 0 : self
188 0 : }
189 : }
190 :
191 : impl NodeBase for Data<'_> {
192 2028 : fn get_base(&self) -> &ffi::PE_ResourceNode {
193 2028 : self.ptr.as_ref().unwrap().as_ref()
194 2028 : }
195 :
196 0 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode> {
197 0 : unsafe {
198 0 : Pin::new_unchecked({
199 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::PE_ResourceNode
200 0 : as *mut ffi::PE_ResourceNode)
201 0 : .as_mut()
202 0 : .unwrap()
203 0 : })
204 0 : }
205 0 : }
206 : }
207 :
208 : impl fmt::Debug for Data<'_> {
209 2028 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 2028 : let base = self as &dyn NodeBase;
211 2028 : f.debug_struct("Data")
212 2028 : .field("base", &base)
213 2028 : .field("code_page", &self.code_page())
214 2028 : .field("reserved", &self.reserved())
215 2028 : .field("offset", &self.offset())
216 2028 : .finish()
217 2028 : }
218 : }
219 :
220 : impl<'a> FromFFI<ffi::PE_ResourceData> for Data<'a> {
221 2028 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceData>) -> Self {
222 2028 : Self {
223 2028 : ptr,
224 2028 : _owner: PhantomData,
225 2028 : }
226 2028 : }
227 : }
228 :
229 : pub struct Directory<'a> {
230 : ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>,
231 : _owner: PhantomData<&'a Node<'a>>,
232 : }
233 :
234 : impl Directory<'_> {
235 : /// Create a new Directory node with the given d
236 0 : pub fn with_id(id: u32) -> Directory<'static> {
237 0 : Directory::from_ffi(ffi::PE_ResourceDirectory::create_from_id(id))
238 0 : }
239 :
240 : /// Create a new Directory node
241 0 : pub fn new() -> Directory<'static> {
242 0 : Directory::from_ffi(ffi::PE_ResourceDirectory::create())
243 0 : }
244 :
245 : /// Resource characteristics. This field is reserved for future use.
246 : /// It is currently set to zero.
247 598 : pub fn characteristics(&self) -> u32 {
248 598 : self.ptr.characteristics()
249 598 : }
250 :
251 : /// The time that the resource data was created by the
252 : /// resource compiler.
253 598 : pub fn time_date_stamp(&self) -> u32 {
254 598 : self.ptr.time_date_stamp()
255 598 : }
256 :
257 : /// The major version number, set by the user.
258 598 : pub fn major_version(&self) -> u32 {
259 598 : self.ptr.major_version()
260 598 : }
261 :
262 : /// The minor version number, set by the user.
263 598 : pub fn minor_version(&self) -> u32 {
264 598 : self.ptr.minor_version()
265 598 : }
266 :
267 : /// The number of directory entries immediately
268 : /// following the table that use strings to identify Type,
269 : /// Name, or Language entries (depending on the level of the table).
270 598 : pub fn numberof_name_entries(&self) -> u32 {
271 598 : self.ptr.numberof_name_entries()
272 598 : }
273 :
274 : /// The number of directory entries immediately
275 : /// following the Name entries that use numeric IDs for
276 : /// Type, Name, or Language entries.
277 598 : pub fn numberof_id_entries(&self) -> u32 {
278 598 : self.ptr.numberof_id_entries()
279 598 : }
280 : }
281 :
282 : impl NodeBase for Directory<'_> {
283 3744 : fn get_base(&self) -> &ffi::PE_ResourceNode {
284 3744 : self.ptr.as_ref().unwrap().as_ref()
285 3744 : }
286 :
287 0 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode> {
288 0 : unsafe {
289 0 : Pin::new_unchecked({
290 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::PE_ResourceNode
291 0 : as *mut ffi::PE_ResourceNode)
292 0 : .as_mut()
293 0 : .unwrap()
294 0 : })
295 0 : }
296 0 : }
297 : }
298 :
299 : impl NodeBase for Node<'_> {
300 0 : fn get_base(&self) -> &ffi::PE_ResourceNode {
301 0 : match &self {
302 0 : Node::Data(n) => n.get_base(),
303 0 : Node::Directory(n) => n.get_base(),
304 : }
305 0 : }
306 :
307 0 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode> {
308 0 : match self {
309 0 : Node::Data(n) => n.base_as_pin_mut(),
310 0 : Node::Directory(n) => n.base_as_pin_mut(),
311 : }
312 0 : }
313 : }
314 :
315 : impl fmt::Debug for Directory<'_> {
316 598 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 598 : let base = self as &dyn NodeBase;
318 598 : f.debug_struct("Directory")
319 598 : .field("base", &base)
320 598 : .field("characteristics", &self.characteristics())
321 598 : .field("time_date_stamp", &self.time_date_stamp())
322 598 : .field("major_version", &self.major_version())
323 598 : .field("minor_version", &self.minor_version())
324 598 : .field("numberof_name_entries", &self.numberof_name_entries())
325 598 : .field("numberof_id_entries", &self.numberof_id_entries())
326 598 : .finish()
327 598 : }
328 : }
329 :
330 : impl<'a> FromFFI<ffi::PE_ResourceDirectory> for Directory<'a> {
331 3276 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>) -> Self {
332 3276 : Self {
333 3276 : ptr,
334 3276 : _owner: PhantomData,
335 3276 : }
336 3276 : }
337 : }
338 :
339 : /// This manager abstracts the tree representation to provide a comprehensive API over
340 : /// the information wrapped by the resources tree.
341 : pub struct Manager<'a> {
342 : ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>,
343 : _owner: PhantomData<&'a Node<'a>>,
344 : }
345 :
346 : impl<'a> FromFFI<ffi::PE_ResourcesManager> for Manager<'a> {
347 130 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>) -> Self {
348 130 : Self {
349 130 : ptr,
350 130 : _owner: PhantomData,
351 130 : }
352 130 : }
353 : }
354 :
355 : #[allow(non_camel_case_types)]
356 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
357 : pub enum Types {
358 : CURSOR,
359 : BITMAP,
360 : ICON,
361 : MENU,
362 : DIALOG,
363 : STRING,
364 : FONTDIR,
365 : FONT,
366 : ACCELERATOR,
367 : RCDATA,
368 : MESSAGETABLE,
369 : GROUP_CURSOR,
370 : GROUP_ICON,
371 : VERSION,
372 : DLGINCLUDE,
373 : PLUGPLAY,
374 : VXD,
375 : ANICURSOR,
376 : ANIICON,
377 : HTML,
378 : MANIFEST,
379 : UNKNOWN(u32),
380 : }
381 :
382 : impl From<u32> for Types {
383 0 : fn from(value: u32) -> Self {
384 0 : match value {
385 0 : 0x00000001 => Types::CURSOR,
386 0 : 0x00000002 => Types::BITMAP,
387 0 : 0x00000003 => Types::ICON,
388 0 : 0x00000004 => Types::MENU,
389 0 : 0x00000005 => Types::DIALOG,
390 0 : 0x00000006 => Types::STRING,
391 0 : 0x00000007 => Types::FONTDIR,
392 0 : 0x00000008 => Types::FONT,
393 0 : 0x00000009 => Types::ACCELERATOR,
394 0 : 0x0000000a => Types::RCDATA,
395 0 : 0x0000000b => Types::MESSAGETABLE,
396 0 : 0x0000000c => Types::GROUP_CURSOR,
397 0 : 0x0000000e => Types::GROUP_ICON,
398 0 : 0x00000010 => Types::VERSION,
399 0 : 0x00000011 => Types::DLGINCLUDE,
400 0 : 0x00000013 => Types::PLUGPLAY,
401 0 : 0x00000014 => Types::VXD,
402 0 : 0x00000015 => Types::ANICURSOR,
403 0 : 0x00000016 => Types::ANIICON,
404 0 : 0x00000017 => Types::HTML,
405 0 : 0x00000018 => Types::MANIFEST,
406 0 : _ => Types::UNKNOWN(value),
407 : }
408 0 : }
409 : }
410 : impl From<Types> for u32 {
411 0 : fn from(value: Types) -> u32 {
412 0 : match value {
413 0 : Types::CURSOR => 0x00000001,
414 0 : Types::BITMAP => 0x00000002,
415 0 : Types::ICON => 0x00000003,
416 0 : Types::MENU => 0x00000004,
417 0 : Types::DIALOG => 0x00000005,
418 0 : Types::STRING => 0x00000006,
419 0 : Types::FONTDIR => 0x00000007,
420 0 : Types::FONT => 0x00000008,
421 0 : Types::ACCELERATOR => 0x00000009,
422 0 : Types::RCDATA => 0x0000000a,
423 0 : Types::MESSAGETABLE => 0x0000000b,
424 0 : Types::GROUP_CURSOR => 0x0000000c,
425 0 : Types::GROUP_ICON => 0x0000000e,
426 0 : Types::VERSION => 0x00000010,
427 0 : Types::DLGINCLUDE => 0x00000011,
428 0 : Types::PLUGPLAY => 0x00000013,
429 0 : Types::VXD => 0x00000014,
430 0 : Types::ANICURSOR => 0x00000015,
431 0 : Types::ANIICON => 0x00000016,
432 0 : Types::HTML => 0x00000017,
433 0 : Types::MANIFEST => 0x00000018,
434 0 : Types::UNKNOWN(value) => value,
435 : }
436 0 : }
437 : }
438 :
439 : impl Manager<'_> {
440 : /// Return the manifest as a string. This manifest matches the node associated with
441 : /// the type: [`Types::MANIFEST`].
442 0 : pub fn manifest(&self) -> String {
443 0 : self.ptr.manifest().to_string()
444 0 : }
445 :
446 : /// Change or set the manifest. If the manifest node path does not exist,
447 : /// all required nodes are created.
448 0 : pub fn set_manifest(&mut self, content: &str) {
449 0 : self.ptr.pin_mut().set_manifest(content);
450 0 : }
451 :
452 : /// Try to find the node associated with the given [`Types`]
453 : ///
454 : /// This type corresponds to the [`Node::id`] at the **level 1** of the
455 : /// resource tree.
456 0 : pub fn find_by_type(&self, res_type: Types) -> Option<Node<'_>> {
457 0 : into_optional(self.ptr.find_node_type(res_type.into()))
458 0 : }
459 :
460 : /// Return the list of [`Types`] exposed by the resource tree.
461 0 : pub fn types(&self) -> Vec<Types> {
462 0 : self.ptr
463 0 : .get_types()
464 0 : .iter()
465 0 : .map(|v| Types::from(*v))
466 0 : .collect()
467 0 : }
468 :
469 : /// Return the HTML resources as a list of strings
470 0 : pub fn html(&self) -> Vec<String> {
471 0 : self.ptr.html().iter().map(|s| s.to_string()).collect()
472 0 : }
473 :
474 : /// Return an iterator over the resource icons
475 0 : pub fn icons(&self) -> Icons<'_> {
476 0 : Icons::new(self.ptr.icons())
477 0 : }
478 :
479 : /// Return an iterator over the resource version entries
480 0 : pub fn version(&self) -> Versions<'_> {
481 0 : Versions::new(self.ptr.version())
482 0 : }
483 :
484 : /// Return an iterator over the resource accelerator entries
485 0 : pub fn accelerator(&self) -> Accelerators<'_> {
486 0 : Accelerators::new(self.ptr.accelerator())
487 0 : }
488 :
489 : /// Return an iterator over the string table entries
490 0 : pub fn string_table(&self) -> StringTableEntries<'_> {
491 0 : StringTableEntries::new(self.ptr.string_table())
492 0 : }
493 :
494 : /// Print the current resources a tree in a pretty representation.
495 : ///
496 : /// ```text
497 : /// │ ├── Directory ID: 0016 (0x0010) type: VERSION
498 : /// │ │ └── Directory ID: 0001 (0x0001)
499 : /// │ │ └── Data ID: 1033 (0x0409) [...]
500 : /// │ │ ├── Hex: c0:03:34:00:00:00:[...]
501 : /// │ │ └── Str: ..4...V.S._.V.E.R.S.
502 : /// │ └── Directory ID: 0024 (0x0018) type: MANIFEST
503 : /// │ └── Directory ID: 0001 (0x0001)
504 : /// │ └── Data ID: 1033 (0x0409) [...]
505 : /// │ ├── Hex: 3c:3f:78:6d:6c:20:[...]
506 : /// │ └── Str: <?xml version="1.0"
507 : /// ```
508 0 : pub fn print_tree(&self) -> String {
509 0 : self.ptr.print_tree().to_string()
510 0 : }
511 :
512 : /// Same as [`Manager::print_tree`] but with a maximal depth provided in the
513 : /// first parameter.
514 0 : pub fn print_tree_with_depth(&self, depth: u32) -> String {
515 0 : self.ptr.print_tree_with_depth(depth).to_string()
516 0 : }
517 : }
518 :
519 : /// Represents a PE icon resource
520 : pub struct Icon<'a> {
521 : ptr: cxx::UniquePtr<ffi::PE_ResourceIcon>,
522 : _owner: PhantomData<&'a ffi::PE_ResourcesManager>,
523 : }
524 :
525 : impl Icon<'_> {
526 : /// ID of the icon
527 0 : pub fn id(&self) -> u32 {
528 0 : self.ptr.id()
529 0 : }
530 :
531 : /// Language of the icon
532 0 : pub fn lang(&self) -> u32 {
533 0 : self.ptr.lang()
534 0 : }
535 :
536 : /// Sublanguage of the icon
537 0 : pub fn sublang(&self) -> u32 {
538 0 : self.ptr.sublang()
539 0 : }
540 :
541 : /// Width in pixels
542 0 : pub fn width(&self) -> u8 {
543 0 : self.ptr.width()
544 0 : }
545 :
546 : /// Height in pixels
547 0 : pub fn height(&self) -> u8 {
548 0 : self.ptr.height()
549 0 : }
550 :
551 : /// Number of colors in the palette (0 if more than 256)
552 0 : pub fn color_count(&self) -> u8 {
553 0 : self.ptr.color_count()
554 0 : }
555 :
556 : /// Reserved (should be 0)
557 0 : pub fn reserved(&self) -> u8 {
558 0 : self.ptr.reserved()
559 0 : }
560 :
561 : /// Number of color planes
562 0 : pub fn planes(&self) -> u16 {
563 0 : self.ptr.planes()
564 0 : }
565 :
566 : /// Bits per pixel
567 0 : pub fn bit_count(&self) -> u16 {
568 0 : self.ptr.bit_count()
569 0 : }
570 :
571 : /// Size of the icon pixel data
572 0 : pub fn size(&self) -> u32 {
573 0 : self.ptr.size()
574 0 : }
575 :
576 : /// Raw pixel data of the icon
577 0 : pub fn pixels(&self) -> &[u8] {
578 0 : to_slice!(self.ptr.pixels());
579 0 : }
580 : }
581 :
582 : impl fmt::Debug for Icon<'_> {
583 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
584 0 : f.debug_struct("Icon")
585 0 : .field("id", &self.id())
586 0 : .field("width", &self.width())
587 0 : .field("height", &self.height())
588 0 : .field("color_count", &self.color_count())
589 0 : .field("bit_count", &self.bit_count())
590 0 : .finish()
591 0 : }
592 : }
593 :
594 : impl<'a> FromFFI<ffi::PE_ResourceIcon> for Icon<'a> {
595 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceIcon>) -> Self {
596 0 : Self {
597 0 : ptr,
598 0 : _owner: PhantomData,
599 0 : }
600 0 : }
601 : }
602 :
603 : /// Represents fixed file information from a version resource
604 0 : #[derive(Debug, Clone)]
605 : pub struct FixedFileInfo {
606 : /// Contains the value `0xFEEF04BD`. This is used with the `szKey` member of
607 : /// the `VS_VERSIONINFO` structure when searching a file for the
608 : /// `VS_FIXEDFILEINFO` structure.
609 : pub signature: u32,
610 :
611 : /// The binary version number of this structure. The high-order word of
612 : /// this member contains the major version number, and the low-order word
613 : /// contains the minor version number.
614 : pub struct_version: u32,
615 :
616 : /// The most significant 32 bits of the file's binary version number.
617 : /// This member is used with file_version_ls to form a 64-bit value used
618 : /// for numeric comparisons.
619 : pub file_version_ms: u32,
620 :
621 : /// The least significant 32 bits of the file's binary version number.
622 : /// This member is used with file_version_ms to form a 64-bit value used for
623 : /// numeric comparisons.
624 : pub file_version_ls: u32,
625 :
626 : /// The most significant 32 bits of the binary version number of the product
627 : /// with which this file was distributed. This member is used with
628 : /// product_version_ls to form a 64-bit value used for numeric comparisons.
629 : pub product_version_ms: u32,
630 :
631 : /// The least significant 32 bits of the binary version number of the product
632 : /// with which this file was distributed. This member is used with
633 : /// product_version_ms to form a 64-bit value used for numeric comparisons.
634 : pub product_version_ls: u32,
635 :
636 : /// Contains a bitmask that specifies the valid bits in file_flags.
637 : /// A bit is valid only if it was defined when the file was created.
638 : pub file_flags_mask: u32,
639 :
640 : /// Contains a bitmask that specifies the Boolean attributes of the file.
641 : /// This member can include one or more of the values specified in FILE_FLAGS
642 : pub file_flags: u32,
643 :
644 : /// The operating system for which this file was designed. This member can
645 : /// be one of the values specified in VERSION_OS.
646 : pub file_os: u32,
647 :
648 : /// The general type of file. This member can be one of the values specified
649 : /// in FILE_TYPE. All other values are reserved.
650 : pub file_type: u32,
651 :
652 : /// The function of the file. The possible values depend on the value of
653 : /// file_type.
654 : pub file_subtype: u32,
655 :
656 : /// The most significant 32 bits of the file's 64-bit binary creation date
657 : /// and time stamp.
658 : pub file_date_ms: u32,
659 :
660 : /// The least significant 32 bits of the file's 64-bit binary creation date
661 : /// and time stamp.
662 : pub file_date_ls: u32,
663 : }
664 :
665 : /// Represents a string table entry (key/value) from a StringFileInfo
666 0 : #[derive(Debug, Clone)]
667 : pub struct VersionStringTableEntry {
668 : /// Key of the entry
669 : pub key: String,
670 : /// Value of the entry
671 : pub value: String,
672 : }
673 :
674 : impl FromFFI<ffi::PE_ResourceStringTable_entry_t> for VersionStringTableEntry {
675 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceStringTable_entry_t>) -> Self {
676 0 : Self {
677 0 : key: ptr.key().to_string(),
678 0 : value: ptr.value().to_string(),
679 0 : }
680 0 : }
681 : }
682 :
683 : /// Represents a string table within a StringFileInfo
684 : pub struct VersionStringTable<'a> {
685 : ptr: cxx::UniquePtr<ffi::PE_ResourceStringTable>,
686 : _owner: PhantomData<&'a ffi::PE_ResourceVersion>,
687 : }
688 :
689 : impl VersionStringTable<'_> {
690 : /// Type of the string table
691 0 : pub fn get_type(&self) -> u16 {
692 0 : self.ptr.get_type()
693 0 : }
694 :
695 : /// Key identifying the string table (typically a language/codepage pair)
696 0 : pub fn key(&self) -> String {
697 0 : self.ptr.key().to_string()
698 0 : }
699 :
700 : /// Return an iterator over the key/value entries
701 0 : pub fn entries(&self) -> VersionStringTableEntries<'_> {
702 0 : VersionStringTableEntries::new(self.ptr.entries())
703 0 : }
704 : }
705 :
706 : impl fmt::Debug for VersionStringTable<'_> {
707 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708 0 : f.debug_struct("VersionStringTable")
709 0 : .field("key", &self.key())
710 0 : .finish()
711 0 : }
712 : }
713 :
714 : impl<'a> FromFFI<ffi::PE_ResourceStringTable> for VersionStringTable<'a> {
715 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceStringTable>) -> Self {
716 0 : Self {
717 0 : ptr,
718 0 : _owner: PhantomData,
719 0 : }
720 0 : }
721 : }
722 :
723 : /// Represents a Var entry within VarFileInfo
724 : pub struct ResourceVar<'a> {
725 : ptr: cxx::UniquePtr<ffi::PE_ResourceVar>,
726 : _owner: PhantomData<&'a ffi::PE_ResourceVersion>,
727 : }
728 :
729 : impl ResourceVar<'_> {
730 : /// Type of the var entry
731 0 : pub fn get_type(&self) -> u16 {
732 0 : self.ptr.get_type()
733 0 : }
734 :
735 : /// Key of the var entry
736 0 : pub fn key(&self) -> String {
737 0 : self.ptr.key().to_string()
738 0 : }
739 :
740 : /// Values of the var entry (language/codepage pairs)
741 0 : pub fn values(&self) -> Vec<u32> {
742 0 : self.ptr.values().iter().map(|&v| v as u32).collect()
743 0 : }
744 : }
745 :
746 : impl fmt::Debug for ResourceVar<'_> {
747 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
748 0 : f.debug_struct("ResourceVar")
749 0 : .field("key", &self.key())
750 0 : .field("values", &self.values())
751 0 : .finish()
752 0 : }
753 : }
754 :
755 : impl<'a> FromFFI<ffi::PE_ResourceVar> for ResourceVar<'a> {
756 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceVar>) -> Self {
757 0 : Self {
758 0 : ptr,
759 0 : _owner: PhantomData,
760 0 : }
761 0 : }
762 : }
763 :
764 : /// Represents a StringFileInfo structure from a version resource
765 : pub struct StringFileInfo<'a> {
766 : ptr: cxx::UniquePtr<ffi::PE_ResourceStringFileInfo>,
767 : _owner: PhantomData<&'a ffi::PE_ResourceVersion>,
768 : }
769 :
770 : impl StringFileInfo<'_> {
771 : /// Type of the StringFileInfo
772 0 : pub fn get_type(&self) -> u16 {
773 0 : self.ptr.get_type()
774 0 : }
775 :
776 : /// Key of the StringFileInfo
777 0 : pub fn key(&self) -> String {
778 0 : self.ptr.key().to_string()
779 0 : }
780 :
781 : /// Return an iterator over the child string tables
782 0 : pub fn children(&self) -> StringFileInfoChildren<'_> {
783 0 : StringFileInfoChildren::new(self.ptr.children())
784 0 : }
785 : }
786 :
787 : impl fmt::Debug for StringFileInfo<'_> {
788 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
789 0 : f.debug_struct("StringFileInfo")
790 0 : .field("key", &self.key())
791 0 : .finish()
792 0 : }
793 : }
794 :
795 : impl<'a> FromFFI<ffi::PE_ResourceStringFileInfo> for StringFileInfo<'a> {
796 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceStringFileInfo>) -> Self {
797 0 : Self {
798 0 : ptr,
799 0 : _owner: PhantomData,
800 0 : }
801 0 : }
802 : }
803 :
804 : /// Represents a VarFileInfo structure from a version resource
805 : pub struct VarFileInfo<'a> {
806 : ptr: cxx::UniquePtr<ffi::PE_ResourceVarFileInfo>,
807 : _owner: PhantomData<&'a ffi::PE_ResourceVersion>,
808 : }
809 :
810 : impl VarFileInfo<'_> {
811 : /// Type of the VarFileInfo
812 0 : pub fn get_type(&self) -> u16 {
813 0 : self.ptr.get_type()
814 0 : }
815 :
816 : /// Key of the VarFileInfo
817 0 : pub fn key(&self) -> String {
818 0 : self.ptr.key().to_string()
819 0 : }
820 :
821 : /// Return an iterator over the Var entries
822 0 : pub fn vars(&self) -> VarFileInfoVars<'_> {
823 0 : VarFileInfoVars::new(self.ptr.vars())
824 0 : }
825 : }
826 :
827 : impl fmt::Debug for VarFileInfo<'_> {
828 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
829 0 : f.debug_struct("VarFileInfo")
830 0 : .field("key", &self.key())
831 0 : .finish()
832 0 : }
833 : }
834 :
835 : impl<'a> FromFFI<ffi::PE_ResourceVarFileInfo> for VarFileInfo<'a> {
836 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceVarFileInfo>) -> Self {
837 0 : Self {
838 0 : ptr,
839 0 : _owner: PhantomData,
840 0 : }
841 0 : }
842 : }
843 :
844 : /// Represents a PE version resource
845 : pub struct Version<'a> {
846 : ptr: cxx::UniquePtr<ffi::PE_ResourceVersion>,
847 : _owner: PhantomData<&'a ffi::PE_ResourcesManager>,
848 : }
849 :
850 : impl Version<'_> {
851 : /// Type of the version resource
852 0 : pub fn get_type(&self) -> u16 {
853 0 : self.ptr.get_type()
854 0 : }
855 :
856 : /// Key of the version resource
857 0 : pub fn key(&self) -> String {
858 0 : self.ptr.key().to_string()
859 0 : }
860 :
861 : /// Return the fixed file information if present
862 0 : pub fn file_info(&self) -> FixedFileInfo {
863 0 : FixedFileInfo {
864 0 : signature: self.ptr.file_info_signature(),
865 0 : struct_version: self.ptr.file_info_struct_version(),
866 0 : file_version_ms: self.ptr.file_info_file_version_ms(),
867 0 : file_version_ls: self.ptr.file_info_file_version_ls(),
868 0 : product_version_ms: self.ptr.file_info_product_version_ms(),
869 0 : product_version_ls: self.ptr.file_info_product_version_ls(),
870 0 : file_flags_mask: self.ptr.file_info_file_flags_mask(),
871 0 : file_flags: self.ptr.file_info_file_flags(),
872 0 : file_os: self.ptr.file_info_file_os(),
873 0 : file_type: self.ptr.file_info_file_type(),
874 0 : file_subtype: self.ptr.file_info_file_subtype(),
875 0 : file_date_ms: self.ptr.file_info_file_date_ms(),
876 0 : file_date_ls: self.ptr.file_info_file_date_ls(),
877 0 : }
878 0 : }
879 :
880 : /// Return the StringFileInfo if present
881 0 : pub fn string_file_info(&self) -> Option<StringFileInfo<'_>> {
882 0 : into_optional(self.ptr.string_file_info())
883 0 : }
884 :
885 : /// Return the VarFileInfo if present
886 0 : pub fn var_file_info(&self) -> Option<VarFileInfo<'_>> {
887 0 : into_optional(self.ptr.var_file_info())
888 0 : }
889 : }
890 :
891 : impl fmt::Debug for Version<'_> {
892 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893 0 : f.debug_struct("Version").field("key", &self.key()).finish()
894 0 : }
895 : }
896 :
897 : impl<'a> FromFFI<ffi::PE_ResourceVersion> for Version<'a> {
898 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceVersion>) -> Self {
899 0 : Self {
900 0 : ptr,
901 0 : _owner: PhantomData,
902 0 : }
903 0 : }
904 : }
905 :
906 : /// Represents a PE accelerator resource entry
907 : pub struct Accelerator<'a> {
908 : ptr: cxx::UniquePtr<ffi::PE_ResourceAccelerator>,
909 : _owner: PhantomData<&'a ffi::PE_ResourcesManager>,
910 : }
911 :
912 : impl Accelerator<'_> {
913 : /// Flags for the accelerator
914 0 : pub fn flags(&self) -> i16 {
915 0 : self.ptr.flags()
916 0 : }
917 :
918 : /// ANSI code of the accelerator key
919 0 : pub fn ansi(&self) -> i16 {
920 0 : self.ptr.ansi()
921 0 : }
922 :
923 : /// ID of the accelerator
924 0 : pub fn id(&self) -> u16 {
925 0 : self.ptr.id()
926 0 : }
927 :
928 : /// Padding value
929 0 : pub fn padding(&self) -> i16 {
930 0 : self.ptr.padding()
931 0 : }
932 :
933 : /// Return the ANSI string representation of the accelerator key
934 0 : pub fn ansi_str(&self) -> String {
935 0 : self.ptr.ansi_str().to_string()
936 0 : }
937 : }
938 :
939 : impl fmt::Debug for Accelerator<'_> {
940 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
941 0 : f.debug_struct("Accelerator")
942 0 : .field("id", &self.id())
943 0 : .field("flags", &self.flags())
944 0 : .field("ansi", &self.ansi())
945 0 : .finish()
946 0 : }
947 : }
948 :
949 : impl<'a> FromFFI<ffi::PE_ResourceAccelerator> for Accelerator<'a> {
950 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceAccelerator>) -> Self {
951 0 : Self {
952 0 : ptr,
953 0 : _owner: PhantomData,
954 0 : }
955 0 : }
956 : }
957 :
958 : /// Represents a string table entry from the ResourcesManager
959 : pub struct StringEntry<'a> {
960 : ptr: cxx::UniquePtr<ffi::PE_ResourcesManager_string_entry_t>,
961 : _owner: PhantomData<&'a ffi::PE_ResourcesManager>,
962 : }
963 :
964 : impl StringEntry<'_> {
965 : /// The string value
966 0 : pub fn string(&self) -> String {
967 0 : self.ptr.string().to_string()
968 0 : }
969 :
970 : /// The ID associated with this string
971 0 : pub fn id(&self) -> u32 {
972 0 : self.ptr.id()
973 0 : }
974 : }
975 :
976 : impl fmt::Debug for StringEntry<'_> {
977 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978 0 : f.debug_struct("StringEntry")
979 0 : .field("id", &self.id())
980 0 : .field("string", &self.string())
981 0 : .finish()
982 0 : }
983 : }
984 :
985 : impl<'a> FromFFI<ffi::PE_ResourcesManager_string_entry_t> for StringEntry<'a> {
986 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourcesManager_string_entry_t>) -> Self {
987 0 : Self {
988 0 : ptr,
989 0 : _owner: PhantomData,
990 0 : }
991 0 : }
992 : }
993 :
994 4914 : declare_iterator!(
995 4914 : Children,
996 4914 : Node<'a>,
997 4914 : ffi::PE_ResourceNode,
998 4914 : ffi::PE_Binary,
999 4914 : ffi::PE_ResourceNode_it_childs
1000 4914 : );
1001 :
1002 0 : declare_iterator!(
1003 0 : Icons,
1004 0 : Icon<'a>,
1005 0 : ffi::PE_ResourceIcon,
1006 0 : ffi::PE_ResourcesManager,
1007 0 : ffi::PE_ResourcesManager_it_icons
1008 0 : );
1009 :
1010 0 : declare_iterator!(
1011 0 : Versions,
1012 0 : Version<'a>,
1013 0 : ffi::PE_ResourceVersion,
1014 0 : ffi::PE_ResourcesManager,
1015 0 : ffi::PE_ResourcesManager_it_version
1016 0 : );
1017 :
1018 0 : declare_iterator!(
1019 0 : Accelerators,
1020 0 : Accelerator<'a>,
1021 0 : ffi::PE_ResourceAccelerator,
1022 0 : ffi::PE_ResourcesManager,
1023 0 : ffi::PE_ResourcesManager_it_accelerator
1024 0 : );
1025 :
1026 0 : declare_iterator!(
1027 0 : StringTableEntries,
1028 0 : StringEntry<'a>,
1029 0 : ffi::PE_ResourcesManager_string_entry_t,
1030 0 : ffi::PE_ResourcesManager,
1031 0 : ffi::PE_ResourcesManager_it_string_table_entry
1032 0 : );
1033 :
1034 0 : declare_iterator!(
1035 0 : VersionStringTableEntries,
1036 0 : VersionStringTableEntry,
1037 0 : ffi::PE_ResourceStringTable_entry_t,
1038 0 : ffi::PE_ResourceStringTable,
1039 0 : ffi::PE_ResourceStringTable_it_entries
1040 0 : );
1041 :
1042 0 : declare_iterator!(
1043 0 : StringFileInfoChildren,
1044 0 : VersionStringTable<'a>,
1045 0 : ffi::PE_ResourceStringTable,
1046 0 : ffi::PE_ResourceStringFileInfo,
1047 0 : ffi::PE_ResourceStringFileInfo_it_children
1048 0 : );
1049 :
1050 0 : declare_iterator!(
1051 0 : VarFileInfoVars,
1052 0 : ResourceVar<'a>,
1053 0 : ffi::PE_ResourceVar,
1054 0 : ffi::PE_ResourceVarFileInfo,
1055 0 : ffi::PE_ResourceVarFileInfo_it_vars
1056 0 : );
|