windows-metadata 0.34.0

Code gen support for the windows crate
Documentation
use super::{Decode, File, TypeDefOrRef};
use core::convert::TryInto;

pub struct Blob {
    pub file: &'static File,
    pub offset: usize,
    pub size: usize,
}

impl Blob {
    fn bytes(&self) -> &'static [u8] {
        &self.file.bytes[self.offset..]
    }

    pub fn peek_unsigned(&self) -> (u32, usize) {
        let bytes = self.bytes();

        if bytes[0] & 0x80 == 0 {
            (bytes[0] as u32, 1)
        } else if bytes[0] & 0xC0 == 0x80 {
            ((((bytes[0] & 0x3F) as u32) << 8) | bytes[1] as u32, 2)
        } else {
            ((((bytes[0] & 0x1F) as u32) << 24) | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 | bytes[3] as u32, 4)
        }
    }

    pub fn read_unsigned(&mut self) -> u32 {
        let (value, offset) = self.peek_unsigned();
        self.offset += offset;
        value
    }

    pub fn read_expected(&mut self, expected: u32) -> bool {
        let (value, offset) = self.peek_unsigned();
        if value == expected {
            self.offset += offset;
            true
        } else {
            false
        }
    }

    pub fn read_modifiers(&mut self) -> Vec<TypeDefOrRef> {
        let mut mods = vec![];

        loop {
            let (value, offset) = self.peek_unsigned();
            if value != 32 && value != 31 {
                break;
            } else {
                self.offset += offset;
                mods.push(TypeDefOrRef::decode(self.file, self.read_unsigned()))
            }
        }

        mods
    }

    pub fn read_str(&mut self) -> &'static str {
        let len = self.read_unsigned() as usize;
        self.offset += len;
        core::str::from_utf8(&self.file.bytes[self.offset - len..self.offset]).unwrap()
    }

    pub fn read_utf16(&self) -> String {
        let bytes = &self.file.bytes[self.offset..];
        if bytes.as_ptr().align_offset(core::mem::align_of::<u16>()) > 0 {
            let bytes = bytes.chunks_exact(2).take(self.size / 2).map(|chunk| u16::from_le_bytes(chunk.try_into().unwrap())).collect::<Vec<u16>>();
            String::from_utf16(&bytes).unwrap()
        } else {
            assert!(bytes.len() >= self.size, "Attempt to read from end of memory");
            let bytes = unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *const u16, self.size / 2) };
            String::from_utf16(bytes).unwrap()
        }
    }

    pub fn read_i8(&mut self) -> i8 {
        let value = i8::from_le_bytes(self.bytes()[..1].try_into().unwrap());
        self.offset += 1;
        value
    }

    pub fn read_u8(&mut self) -> u8 {
        let value = u8::from_le_bytes(self.bytes()[..1].try_into().unwrap());
        self.offset += 1;
        value
    }

    pub fn read_i16(&mut self) -> i16 {
        let value = i16::from_le_bytes(self.bytes()[..2].try_into().unwrap());
        self.offset += 2;
        value
    }

    pub fn read_u16(&mut self) -> u16 {
        let value = u16::from_le_bytes(self.bytes()[..2].try_into().unwrap());
        self.offset += 2;
        value
    }

    pub fn read_i32(&mut self) -> i32 {
        let value = i32::from_le_bytes(self.bytes()[..4].try_into().unwrap());
        self.offset += 4;
        value
    }

    pub fn read_u32(&mut self) -> u32 {
        let value = u32::from_le_bytes(self.bytes()[..4].try_into().unwrap());
        self.offset += 4;
        value
    }

    pub fn read_i64(&mut self) -> i64 {
        let value = i64::from_le_bytes(self.bytes()[..8].try_into().unwrap());
        self.offset += 8;
        value
    }

    pub fn read_u64(&mut self) -> u64 {
        let value = u64::from_le_bytes(self.bytes()[..8].try_into().unwrap());
        self.offset += 8;
        value
    }

    pub fn read_f32(&mut self) -> f32 {
        let value = f32::from_le_bytes(self.bytes()[..4].try_into().unwrap());
        self.offset += 4;
        value
    }

    pub fn read_f64(&mut self) -> f64 {
        let value = f64::from_le_bytes(self.bytes()[..8].try_into().unwrap());
        self.offset += 8;
        value
    }
}