Skip to main content

msft_typelib/
typeinfo.rs

1//! [`TypeInfoEntry`] -- zero-copy view of an `MSFT_TypeInfoBase` (0x64 bytes).
2//!
3//! Each TypeInfo describes one top-level type in the library: an enum,
4//! record (struct), module, COM interface, dispatch interface, coclass,
5//! alias (typedef), or union.  The 0x64-byte structure contains the type
6//! kind, function/variable counts, a GUID, flags, offsets into the name
7//! and string tables, version, custom data offset, and more.
8
9use crate::{
10    TypeKind,
11    util::{read_i16_le, read_i32_le, read_u32_le},
12};
13
14/// Zero-copy view of an `MSFT_TypeInfoBase` structure (0x64 bytes).
15///
16/// Each TypeInfo describes one type in the library: an enum, struct,
17/// module, COM interface, dispatch interface, coclass, alias, or union.
18///
19/// Constructed by [`TypeLib::typeinfo`](crate::TypeLib::typeinfo);
20/// the backing slice is guaranteed to be at least [`SIZE`](Self::SIZE) bytes.
21#[derive(Clone, Copy, Debug)]
22pub struct TypeInfoEntry<'a> {
23    bytes: &'a [u8],
24}
25
26impl<'a> TypeInfoEntry<'a> {
27    /// Wraps a 0x64-byte slice as a `TypeInfoEntry`.
28    pub(crate) fn new(bytes: &'a [u8]) -> Self {
29        Self { bytes }
30    }
31
32    /// Size of the fixed `MSFT_TypeInfoBase` structure in bytes.
33    pub const SIZE: usize = 0x64;
34
35    /// Returns the raw backing bytes.
36    #[inline]
37    pub fn as_bytes(&self) -> &'a [u8] {
38        self.bytes
39    }
40
41    /// Type kind (low 4 bits of the `typekind` field).
42    #[inline]
43    pub fn typekind(&self) -> TypeKind {
44        let raw = read_u32_le(self.bytes, 0x00).unwrap_or(0);
45        TypeKind::from_raw((raw & 0x0F) as u8)
46    }
47
48    /// Raw `typekind` field (includes alignment in bits 11-15).
49    #[inline]
50    pub fn typekind_raw(&self) -> u32 {
51        read_u32_le(self.bytes, 0x00).unwrap_or(0)
52    }
53
54    /// Absolute file offset to the func/var data block.
55    ///
56    /// Returns a negative value when no data block exists.
57    #[inline]
58    pub fn memoffset(&self) -> i32 {
59        read_i32_le(self.bytes, 0x04).unwrap_or(-1)
60    }
61
62    /// First reference offset in `pRefTab` (for coclasses), or `-1`.
63    #[inline]
64    pub fn res2(&self) -> i32 {
65        read_i32_le(self.bytes, 0x08).unwrap_or(-1)
66    }
67
68    /// Raw `cElement` field.
69    ///
70    /// Low 16 bits = function count, high 16 bits = variable count.
71    #[inline]
72    pub fn celement(&self) -> u32 {
73        read_u32_le(self.bytes, 0x18).unwrap_or(0)
74    }
75
76    /// Number of functions (low 16 bits of `cElement`).
77    #[inline]
78    pub fn func_count(&self) -> u16 {
79        (self.celement() & 0xFFFF) as u16
80    }
81
82    /// Number of variables (high 16 bits of `cElement`).
83    #[inline]
84    pub fn var_count(&self) -> u16 {
85        (self.celement() >> 16) as u16
86    }
87
88    /// Offset into the GUID table, or `-1` if this type has no GUID.
89    #[inline]
90    pub fn guid_offset(&self) -> i32 {
91        read_i32_le(self.bytes, 0x2C).unwrap_or(-1)
92    }
93
94    /// `TYPEFLAG_*` flags.
95    #[inline]
96    pub fn flags(&self) -> u32 {
97        read_u32_le(self.bytes, 0x30).unwrap_or(0)
98    }
99
100    /// Offset into the name table for this type's name.
101    #[inline]
102    pub fn name_offset(&self) -> i32 {
103        read_i32_le(self.bytes, 0x34).unwrap_or(-1)
104    }
105
106    /// Element version (set with `SetVersion`).
107    #[inline]
108    pub fn version(&self) -> u32 {
109        read_u32_le(self.bytes, 0x38).unwrap_or(0)
110    }
111
112    /// Offset into the string table for the doc string, or `-1`.
113    #[inline]
114    pub fn docstring_offset(&self) -> i32 {
115        read_i32_le(self.bytes, 0x3C).unwrap_or(-1)
116    }
117
118    /// Number of implemented interfaces (for coclasses).
119    #[inline]
120    pub fn cimpltypes(&self) -> i16 {
121        read_i16_le(self.bytes, 0x4C).unwrap_or(0)
122    }
123
124    /// Virtual function table size in bytes.
125    #[inline]
126    pub fn cb_size_vft(&self) -> i16 {
127        read_i16_le(self.bytes, 0x4E).unwrap_or(0)
128    }
129
130    /// Instance size in bytes.
131    #[inline]
132    pub fn size(&self) -> i32 {
133        read_i32_le(self.bytes, 0x50).unwrap_or(0)
134    }
135
136    /// For `ALIAS` types: the aliased type descriptor. Otherwise `-1`.
137    #[inline]
138    pub fn datatype1(&self) -> i32 {
139        read_i32_le(self.bytes, 0x54).unwrap_or(-1)
140    }
141
142    /// For `ALIAS` types: secondary aliased type descriptor. Otherwise `-1`.
143    #[inline]
144    pub fn datatype2(&self) -> i32 {
145        read_i32_le(self.bytes, 0x58).unwrap_or(-1)
146    }
147
148    /// Help string context at offset 0x40.
149    #[inline]
150    pub fn helpstringcontext(&self) -> i32 {
151        read_i32_le(self.bytes, 0x40).unwrap_or(0)
152    }
153
154    /// Help context at offset 0x44.
155    #[inline]
156    pub fn helpcontext(&self) -> i32 {
157        read_i32_le(self.bytes, 0x44).unwrap_or(0)
158    }
159
160    /// Offset into the CDGuids directory for this type's custom data, or `-1`.
161    #[inline]
162    pub fn cust_data_offset(&self) -> i32 {
163        read_i32_le(self.bytes, 0x48).unwrap_or(-1)
164    }
165
166    /// Reserved field at offset 0x0C (`-1` if no element, else `(N-1)*0x38`).
167    #[inline]
168    pub fn res3(&self) -> i32 {
169        read_i32_le(self.bytes, 0x0C).unwrap_or(-1)
170    }
171
172    /// Reserved field at offset 0x5C (always 0).
173    #[inline]
174    pub fn res18(&self) -> i32 {
175        read_i32_le(self.bytes, 0x5C).unwrap_or(0)
176    }
177
178    /// Reserved field at offset 0x60 (always `-1`).
179    #[inline]
180    pub fn res19(&self) -> i32 {
181        read_i32_le(self.bytes, 0x60).unwrap_or(-1)
182    }
183}