Skip to main content

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}