msft_typelib/lib.rs
1//! Allocation-free parser for MSFT-format type library (`.tlb`) files.
2//!
3//! MSFT is the binary format used by Microsoft COM type libraries since
4//! the late 1990s. A type library describes the interfaces, coclasses,
5//! enumerations, and constants exposed by a COM component so that tools
6//! and languages can use them at compile time or runtime.
7//!
8//! Record types borrow directly from the input `&[u8]` and carry a
9//! lifetime that ties them to the original buffer. Parsing requires no
10//! heap allocations beyond what the caller performs to load the file;
11//! individual accessor methods return small scalar values by copy.
12//!
13//! # Quick start
14//!
15//! ```no_run
16//! # fn main() -> Result<(), msft_typelib::Error> {
17//! let data = std::fs::read("library.tlb").unwrap();
18//! let lib = msft_typelib::TypeLib::parse(&data)?;
19//! println!("TypeLib: {} ({} typeinfos)",
20//! lib.lib_name().unwrap_or("?"), lib.typeinfo_count());
21//! # Ok(())
22//! # }
23//! ```
24//!
25//! # Binary format overview
26//!
27//! An MSFT file begins with a 0x54-byte header (magic `"MSFT"`, version,
28//! GUID offset, LCID, flags, etc.), followed by:
29//!
30//! 1. **Offset table** -- one `i32` per TypeInfo, giving its byte offset
31//! inside the TypeInfo segment.
32//! 2. **Extra field** (4 bytes) -- help-string-DLL offset when the
33//! `HELPDLLFLAG` is set; empirically always present.
34//! 3. **Segment directory** -- 15 entries of 16 bytes each
35//! (`offset: i32, length: i32, res08, res0c`), pointing to the data
36//! segments that follow.
37//!
38//! The 15 segments are:
39//!
40//! | Index | Contents |
41//! |------:|----------|
42//! | 0 | TypeInfo table -- fixed-size (0x64 byte) entries |
43//! | 1 | Import-info table -- 12-byte entries referencing external typelibs |
44//! | 2 | Import-files table -- variable-length entries with library name, GUID, version |
45//! | 3 | Reference table -- 16-byte linked-list entries for coclass impl-types |
46//! | 4 | GUID hash table -- bucket array for fast GUID lookup |
47//! | 5 | GUID table -- 24-byte entries (16-byte GUID + hreftype + hash chain) |
48//! | 6 | Name hash table -- bucket array for fast name lookup |
49//! | 7 | Name table -- variable-length entries (12-byte header + name bytes) |
50//! | 8 | String table -- variable-length entries (2-byte length + string bytes) |
51//! | 9 | Type-descriptor table -- 8-byte entries encoding `TYPEDESC` trees |
52//! | 10 | Array-descriptor table -- variable-length `ARRAYDESC` entries |
53//! | 11 | Custom-data table -- variant-tagged values (2-byte VT + payload) |
54//! | 12 | Custom-data GUID directory -- 12-byte linked-list entries mapping GUIDs to custom data |
55//! | 13--14 | Reserved (always empty) |
56//!
57//! Each TypeInfo has a func/var data block at an absolute file offset.
58//! The block starts with a 4-byte size, followed by variable-length
59//! function and variable records, then **auxiliary arrays** containing
60//! MEMBERIDs and name-table offsets for each member.
61//!
62//! # Public types
63//!
64//! | Type | Description |
65//! |------|-------------|
66//! | [`TypeLib`] | Main entry point and all lookup / iteration methods |
67//! | [`TypeInfoEntry`] | One type description (enum, struct, interface, ...) |
68//! | [`FuncRecord`] | One function or property accessor |
69//! | [`VarRecord`] | One variable or constant |
70//! | [`ParameterInfo`] | One function parameter |
71//! | [`GuidEntry`] | One GUID-table entry |
72//! | [`RefRecord`] | One coclass-implements reference |
73//! | [`ImpInfo`] | One imported-typelib reference |
74//! | [`ImpFile`] | One imported-library file entry (name, version, GUID) |
75//! | [`ArrayDesc`], [`SafeArrayBound`] | Array descriptor with per-dimension bounds |
76//! | [`CustDataEntry`] | One entry in the custom data GUID directory |
77//! | [`ResolvedHreftype`] | Result of resolving an hreftype (internal or external) |
78//! | [`TypeKind`], [`ConstValue`], [`vt_name`] | Shared enumerations and helpers |
79//! | [`Guid`] | 16-byte GUID display wrapper |
80//! | [`NameEntry`] | A decoded entry from the name table |
81//! | [`Error`] | Parse error type |
82
83#![deny(missing_docs, unsafe_code)]
84
85mod arraydesc;
86mod custdata;
87mod error;
88mod func;
89mod guid;
90mod guidentry;
91mod impfile;
92mod impinfo;
93mod iterators;
94mod name;
95mod param;
96mod refrecord;
97mod typeinfo;
98mod typelib;
99mod types;
100pub(crate) mod util;
101mod var;
102
103pub use arraydesc::{ArrayDesc, SafeArrayBound};
104pub use custdata::CustDataEntry;
105pub use error::Error;
106pub use func::FuncRecord;
107pub use guid::Guid;
108pub use guidentry::GuidEntry;
109pub use impfile::ImpFile;
110pub use impinfo::ImpInfo;
111pub use iterators::{
112 CustDataIter, FuncIter, GuidEntryIter, ImpFileIter, ImpInfoIter, ImplTypeIter, NameIter,
113 ParamIter, TypeInfoIter, VarIter,
114};
115pub use name::NameEntry;
116pub use param::ParameterInfo;
117pub use refrecord::RefRecord;
118pub use typeinfo::TypeInfoEntry;
119pub use typelib::{ResolvedHreftype, TypeLib};
120pub use types::{ConstValue, TypeKind, vt_name};
121pub use var::VarRecord;
122
123#[cfg(test)]
124mod tests;