msft_typelib/arraydesc.rs
1//! [`ArrayDesc`] -- zero-copy view of an array descriptor in segment 10.
2//!
3//! When a type descriptor has `VT_CARRAY` (28), the `extra` field is an
4//! offset into the array-descriptor table (segment 10). Each descriptor
5//! stores the element type, the number of dimensions, and per-dimension
6//! bounds (`count` and `lower_bound`).
7//!
8//! ```text
9//! [element_type: i32] [num_dims: u16] [flags: u16]
10//! [SafeArrayBound * num_dims] -- each: [cElements: u32] [lLbound: i32]
11//! ```
12
13use crate::util::{read_i32_le, read_u16_le, read_u32_le};
14
15/// Zero-copy view of a `VT_CARRAY` array descriptor.
16///
17/// Describes a fixed-size array: its element type, number of dimensions,
18/// and bounds for each dimension.
19pub struct ArrayDesc<'a> {
20 bytes: &'a [u8],
21}
22
23impl<'a> ArrayDesc<'a> {
24 /// Wraps a variable-length slice as an `ArrayDesc`.
25 pub(crate) fn new(bytes: &'a [u8]) -> Self {
26 Self { bytes }
27 }
28
29 /// Element type descriptor at offset 0x00.
30 ///
31 /// Negative values encode simple `VT_*` types inline.
32 /// Non-negative values are offsets into the type descriptor table.
33 #[inline]
34 pub fn element_type(&self) -> i32 {
35 read_i32_le(self.bytes, 0x00).unwrap_or(-1)
36 }
37
38 /// Number of array dimensions.
39 #[inline]
40 pub fn num_dims(&self) -> u16 {
41 read_u16_le(self.bytes, 0x04).unwrap_or(0)
42 }
43
44 /// Flags / extra field at offset 0x06.
45 #[inline]
46 pub fn flags(&self) -> u16 {
47 read_u16_le(self.bytes, 0x06).unwrap_or(0)
48 }
49
50 /// Returns the bounds for dimension `index`.
51 ///
52 /// Each bound has a count (number of elements) and a lower bound.
53 /// Returns `None` if `index >= num_dims` or the data is too short.
54 pub fn bound(&self, index: usize) -> Option<SafeArrayBound> {
55 if index >= self.num_dims() as usize {
56 return None;
57 }
58 let base = 0x08 + index * 8;
59 let c_elements = read_u32_le(self.bytes, base)?;
60 let l_lbound = read_i32_le(self.bytes, base + 4)?;
61 Some(SafeArrayBound {
62 c_elements,
63 l_lbound,
64 })
65 }
66
67 /// Total size of this descriptor in bytes.
68 #[inline]
69 pub fn size(&self) -> usize {
70 0x08 + (self.num_dims() as usize) * 8
71 }
72}
73
74/// One dimension of a SAFEARRAY descriptor.
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub struct SafeArrayBound {
77 c_elements: u32,
78 l_lbound: i32,
79}
80
81impl SafeArrayBound {
82 /// Number of elements in this dimension.
83 #[inline]
84 pub fn count(&self) -> u32 {
85 self.c_elements
86 }
87
88 /// Lower bound of this dimension (starting index).
89 #[inline]
90 pub fn lower_bound(&self) -> i32 {
91 self.l_lbound
92 }
93}