Skip to main content

windows_metadata/reader/
blob.rs

1use super::*;
2
3pub struct Blob<'a> {
4    index: &'a Index,
5    file: usize,
6    slice: &'a [u8],
7}
8
9impl Drop for Blob<'_> {
10    fn drop(&mut self) {
11        debug_assert_eq!(self.len(), 0);
12    }
13}
14
15impl std::fmt::Debug for Blob<'_> {
16    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
17        write!(f, "{:?}", self.slice)
18    }
19}
20
21impl std::ops::Deref for Blob<'_> {
22    type Target = [u8];
23
24    fn deref(&self) -> &[u8] {
25        self.slice
26    }
27}
28
29impl<'a> Blob<'a> {
30    pub fn new(index: &'a Index, file: usize, slice: &'a [u8]) -> Self {
31        Self { index, file, slice }
32    }
33
34    fn peek(&self) -> (usize, usize) {
35        if self[0] & 0x80 == 0 {
36            (self[0] as usize, 1)
37        } else if self[0] & 0xC0 == 0x80 {
38            ((((self[0] & 0x3F) as usize) << 8) | self[1] as usize, 2)
39        } else {
40            (
41                (((self[0] & 0x1F) as usize) << 24)
42                    | ((self[1] as usize) << 16)
43                    | ((self[2] as usize) << 8)
44                    | self[3] as usize,
45                4,
46            )
47        }
48    }
49
50    pub fn decode<D: Decode<'a>>(&mut self) -> D {
51        D::decode(self.index, self.file, self.read_compressed())
52    }
53
54    pub fn try_read(&mut self, expected: usize) -> bool {
55        let (value, offset) = self.peek();
56        if value == expected {
57            self.offset(offset);
58            true
59        } else {
60            false
61        }
62    }
63
64    pub fn read_modifiers(&mut self) -> Vec<TypeDefOrRef<'a>> {
65        let mut mods = vec![];
66        loop {
67            let (value, offset) = self.peek();
68            if value != ELEMENT_TYPE_CMOD_OPT as usize && value != ELEMENT_TYPE_CMOD_REQD as usize {
69                break;
70            } else {
71                self.offset(offset);
72                mods.push(TypeDefOrRef::decode(
73                    self.index,
74                    self.file,
75                    self.read_compressed(),
76                ));
77            }
78        }
79        mods
80    }
81
82    pub fn read_method_signature(&mut self, generics: &[Type]) -> Signature {
83        let flags = MethodCallAttributes(self.read_u8());
84        let param_count = self.read_compressed();
85        let return_type = self.read_type_signature(generics);
86
87        let mut types = vec![];
88
89        for _ in 0..param_count {
90            types.push(self.read_type_signature(generics));
91        }
92
93        Signature {
94            flags,
95            return_type,
96            types,
97        }
98    }
99
100    /// Reads a field or method type signature.
101    pub fn read_type_signature(&mut self, generics: &[Type]) -> Type {
102        let is_const = self.read_modifiers().iter().any(|def| {
103            def.namespace() == "System.Runtime.CompilerServices" && def.name() == "IsConst"
104        });
105
106        let is_ref = self.try_read(ELEMENT_TYPE_BYREF as usize);
107
108        if self.try_read(ELEMENT_TYPE_VOID as usize) {
109            return Type::Void;
110        }
111
112        let is_array = self.try_read(ELEMENT_TYPE_SZARRAY as usize);
113
114        let mut pointers = 0;
115
116        while self.try_read(ELEMENT_TYPE_PTR as usize) {
117            pointers += 1;
118        }
119
120        let ty = self.read_type_code(generics);
121
122        if pointers > 0 {
123            let ptr = if is_const {
124                Type::PtrConst(Box::new(ty), pointers)
125            } else {
126                Type::PtrMut(Box::new(ty), pointers)
127            };
128            if is_array {
129                Type::Array(Box::new(ptr))
130            } else {
131                ptr
132            }
133        } else if is_const {
134            Type::RefConst(Box::new(ty))
135        } else if is_array {
136            let ty = Type::Array(Box::new(ty));
137
138            if is_ref {
139                Type::RefMut(Box::new(ty))
140            } else {
141                ty
142            }
143        } else if is_ref {
144            Type::RefMut(Box::new(ty))
145        } else {
146            ty
147        }
148    }
149
150    pub fn read_type_code(&mut self, generics: &[Type]) -> Type {
151        match self.read_u8() {
152            ELEMENT_TYPE_VOID => Type::Void,
153            ELEMENT_TYPE_BOOLEAN => Type::Bool,
154            ELEMENT_TYPE_CHAR => Type::Char,
155            ELEMENT_TYPE_I1 => Type::I8,
156            ELEMENT_TYPE_U1 => Type::U8,
157            ELEMENT_TYPE_I2 => Type::I16,
158            ELEMENT_TYPE_U2 => Type::U16,
159            ELEMENT_TYPE_I4 => Type::I32,
160            ELEMENT_TYPE_U4 => Type::U32,
161            ELEMENT_TYPE_I8 => Type::I64,
162            ELEMENT_TYPE_U8 => Type::U64,
163            ELEMENT_TYPE_R4 => Type::F32,
164            ELEMENT_TYPE_R8 => Type::F64,
165            ELEMENT_TYPE_I => Type::ISize,
166            ELEMENT_TYPE_U => Type::USize,
167            ELEMENT_TYPE_STRING => Type::String,
168            ELEMENT_TYPE_OBJECT => Type::Object,
169            ELEMENT_TYPE_VALUETYPE => {
170                let tdr = self.decode::<TypeDefOrRef>();
171                if let TypeDefOrRef::TypeSpec(def) = tdr {
172                    def.ty(generics)
173                } else {
174                    Type::ValueName(TypeName::named(tdr.namespace(), tdr.name()))
175                }
176            }
177            ELEMENT_TYPE_CLASS => {
178                let tdr = self.decode::<TypeDefOrRef>();
179                if let TypeDefOrRef::TypeSpec(def) = tdr {
180                    def.ty(generics)
181                } else {
182                    Type::ClassName(TypeName::named(tdr.namespace(), tdr.name()))
183                }
184            }
185            ELEMENT_TYPE_VAR => generics[self.read_compressed()].clone(),
186            ELEMENT_TYPE_ARRAY => {
187                // See II.23.2.13 ArrayShape
188                let ty = self.read_type_signature(generics);
189                let rank = self.read_compressed();
190                debug_assert_eq!(rank, 1);
191                let num_sizes = self.read_compressed();
192                debug_assert_eq!(num_sizes, 1);
193                let size = self.read_compressed();
194                let num_lo_bounds = self.read_compressed();
195                debug_assert!(num_lo_bounds == 0 || num_lo_bounds == 1);
196
197                for _ in 0..num_lo_bounds {
198                    let lo_bounds = self.read_compressed();
199                    debug_assert_eq!(lo_bounds, 0);
200                }
201
202                Type::ArrayFixed(Box::new(ty), size)
203            }
204            ELEMENT_TYPE_GENERICINST => {
205                let type_code = self.read_u8();
206
207                debug_assert!(matches!(
208                    type_code,
209                    ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS
210                ));
211
212                let ty = self.decode::<TypeDefOrRef>();
213                let mut ty_generics = vec![];
214
215                for _ in 0..self.read_compressed() {
216                    ty_generics.push(self.read_type_code(generics));
217                }
218
219                let type_name = TypeName {
220                    namespace: ty.namespace().to_string(),
221                    name: ty.name().to_string(),
222                    generics: ty_generics,
223                };
224
225                if type_code == ELEMENT_TYPE_VALUETYPE {
226                    Type::ValueName(type_name)
227                } else {
228                    Type::ClassName(type_name)
229                }
230            }
231            0x55 => {
232                // SERIALIZATION_TYPE_ENUM in custom attribute named argument format
233                // (ECMA-335 II.23.1.16): followed by a SerString of the enum type name.
234                // Enums are always value types.
235                let name = self.read_utf8();
236                if let Some(dot) = name.rfind('.') {
237                    Type::ValueName(TypeName::named(&name[..dot], &name[dot + 1..]))
238                } else {
239                    Type::ValueName(TypeName::named("", &name))
240                }
241            }
242            rest => panic!("{rest:?}"),
243        }
244    }
245
246    pub fn read_compressed(&mut self) -> usize {
247        let (value, offset) = self.peek();
248        self.offset(offset);
249        value
250    }
251
252    pub fn read_utf8(&mut self) -> String {
253        let len = self.read_compressed();
254        let value = std::str::from_utf8(&self.slice[..len]).expect("expected valid UTF-8 string");
255        self.offset(len);
256        value.to_string()
257    }
258
259    pub fn read_utf16(&mut self) -> String {
260        let slice = self.slice;
261
262        let value = if cfg!(target_endian = "little") {
263            // SAFETY: `align_to::<u16>` is only used as an optimisation to view the
264            // already-aligned byte slice as `u16`s without copying. If any bytes fall
265            // in the prefix or suffix (i.e. the slice is not u16-aligned), we fall back
266            // to the byte-wise path below.
267            let (prefix, chars, suffix) = unsafe { slice.align_to::<u16>() };
268            if prefix.is_empty() && suffix.is_empty() {
269                String::from_utf16_lossy(chars)
270            } else {
271                let chars: Vec<u16> = slice
272                    .as_chunks::<2>()
273                    .0
274                    .iter()
275                    .map(|chunk| u16::from_le_bytes(*chunk))
276                    .collect();
277                String::from_utf16_lossy(&chars)
278            }
279        } else {
280            let chars: Vec<u16> = slice
281                .as_chunks::<2>()
282                .0
283                .iter()
284                .map(|chunk| u16::from_le_bytes(*chunk))
285                .collect();
286            String::from_utf16_lossy(&chars)
287        };
288
289        self.offset(slice.len());
290        value
291    }
292
293    pub fn read_bool(&mut self) -> bool {
294        // A bool is specified as "a single byte with value 0 (false) or 1 (true)".
295        match self.read_u8() {
296            0 => false,
297            1 => true,
298            _ => panic!(),
299        }
300    }
301
302    pub fn read_i8(&mut self) -> i8 {
303        let value = i8::from_le_bytes(self[..1].try_into().unwrap());
304        self.offset(1);
305        value
306    }
307
308    pub fn read_u8(&mut self) -> u8 {
309        let value = u8::from_le_bytes(self[..1].try_into().unwrap());
310        self.offset(1);
311        value
312    }
313
314    pub fn read_i16(&mut self) -> i16 {
315        let value = i16::from_le_bytes(self[..2].try_into().unwrap());
316        self.offset(2);
317        value
318    }
319
320    pub fn read_u16(&mut self) -> u16 {
321        let value = u16::from_le_bytes(self[..2].try_into().unwrap());
322        self.offset(2);
323        value
324    }
325
326    pub fn read_i32(&mut self) -> i32 {
327        let value = i32::from_le_bytes(self[..4].try_into().unwrap());
328        self.offset(4);
329        value
330    }
331
332    pub fn read_u32(&mut self) -> u32 {
333        let value = u32::from_le_bytes(self[..4].try_into().unwrap());
334        self.offset(4);
335        value
336    }
337
338    pub fn read_i64(&mut self) -> i64 {
339        let value = i64::from_le_bytes(self[..8].try_into().unwrap());
340        self.offset(8);
341        value
342    }
343
344    pub fn read_u64(&mut self) -> u64 {
345        let value = u64::from_le_bytes(self[..8].try_into().unwrap());
346        self.offset(8);
347        value
348    }
349
350    pub fn read_f32(&mut self) -> f32 {
351        let value = f32::from_le_bytes(self[..4].try_into().unwrap());
352        self.offset(4);
353        value
354    }
355
356    pub fn read_f64(&mut self) -> f64 {
357        let value = f64::from_le_bytes(self[..8].try_into().unwrap());
358        self.offset(8);
359        value
360    }
361
362    fn offset(&mut self, offset: usize) {
363        self.slice = &self.slice[offset..];
364    }
365}