Skip to main content

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}