msft_typelib/impfile.rs
1//! [`ImpFile`] -- zero-copy view of an import-file entry in segment 2.
2//!
3//! The import-files table (segment 2) stores one variable-length entry per
4//! external type library that this library depends on. Each entry contains
5//! the library's GUID (as an offset into the GUID table), its LCID and
6//! version, and its filename.
7//!
8//! The entry layout is:
9//!
10//! ```text
11//! [GuidOffset: i32] [LCID: i32] [MajVer: u16] [MinVer: u16] [SizeField: u16]
12//! [filename bytes, padded to 4-byte alignment]
13//! ```
14//!
15//! The filename length is `SizeField >> 2`; the low 2 bits of `SizeField`
16//! are flags.
17
18use crate::util::{read_i32_le, read_u16_le};
19
20/// Zero-copy view of a variable-length import-file entry.
21///
22/// Each entry describes one imported type library: its GUID, locale,
23/// version, and filename.
24#[derive(Clone, Copy, Debug)]
25pub struct ImpFile<'a> {
26 bytes: &'a [u8],
27}
28
29impl<'a> ImpFile<'a> {
30 /// Minimum header size before the filename (GUID offset + LCID + version + size field).
31 pub const HEADER_SIZE: usize = 0x0E;
32
33 /// Wraps a variable-length slice as an `ImpFile`.
34 pub(crate) fn new(bytes: &'a [u8]) -> Self {
35 Self { bytes }
36 }
37
38 /// Offset into the GUID table for this imported library's GUID.
39 #[inline]
40 pub fn guid_offset(&self) -> i32 {
41 read_i32_le(self.bytes, 0x00).unwrap_or(-1)
42 }
43
44 /// Locale identifier (LCID) of the imported library.
45 #[inline]
46 pub fn lcid(&self) -> i32 {
47 read_i32_le(self.bytes, 0x04).unwrap_or(0)
48 }
49
50 /// Major version of the imported library.
51 #[inline]
52 pub fn major_version(&self) -> u16 {
53 read_u16_le(self.bytes, 0x08).unwrap_or(0)
54 }
55
56 /// Minor version of the imported library.
57 #[inline]
58 pub fn minor_version(&self) -> u16 {
59 read_u16_le(self.bytes, 0x0A).unwrap_or(0)
60 }
61
62 /// Raw size field at offset 0x0C.
63 ///
64 /// The filename length in bytes is `size_field >> 2`.
65 /// The low 2 bits are flags.
66 #[inline]
67 pub fn size_field(&self) -> u16 {
68 read_u16_le(self.bytes, 0x0C).unwrap_or(0)
69 }
70
71 /// The filename of the imported library.
72 pub fn filename(&self) -> Option<&'a str> {
73 let name_len = (self.size_field() >> 2) as usize;
74 let name_bytes = self
75 .bytes
76 .get(Self::HEADER_SIZE..Self::HEADER_SIZE + name_len)?;
77 std::str::from_utf8(name_bytes).ok()
78 }
79
80 /// Total size of this entry in bytes (header + name, padded to 4-byte alignment).
81 pub fn entry_size(&self) -> usize {
82 let name_len = (self.size_field() >> 2) as usize;
83 let unpadded = Self::HEADER_SIZE + name_len;
84 (unpadded + 3) & !3
85 }
86}