diff options
Diffstat (limited to 'vendor/windows-metadata')
21 files changed, 1139 insertions, 1204 deletions
diff --git a/vendor/windows-metadata/.cargo-checksum.json b/vendor/windows-metadata/.cargo-checksum.json index 3055b9947..42d3edbcf 100644 --- a/vendor/windows-metadata/.cargo-checksum.json +++ b/vendor/windows-metadata/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c62bdf1f7590fca80f0bce1d57e44f066c061ab0af56869c5d1b0e354745b245","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","src/attributes.rs":"82fef5cd2f08624864139b9a3aef592ae2730c5cf185b06164b8db05314e81f3","src/blob.rs":"398f86e96c9bc5c35d3f2d0188e9183088b01f87d40f50fded1eceb3c4397723","src/codes.rs":"dd1a37c7417073c7f4d8682d0da4e5c3ac8897a8e92d902c0940658a26090603","src/file/mod.rs":"2b606c0216f82309e07c03d5a90dc2742a2aba6c5a9bdb4c0452c6ef9aaac3c7","src/file/reader.rs":"450a7c0935bb2089ce63abfa1fdb6f4827ea15a9b297b31baebe7f324998713a","src/file/table.rs":"906f304d744ec4d030160cdb25ba1c4e35965d38d77ff514db17ca760cdc7c58","src/file/view.rs":"def9bed45a3a6f12b501409b204d165ad5f8231359fc783cfcee9eaf1160bd59","src/filter.rs":"b6e77d22c996786af05287a562b8c4fe90f98a3ed2a180ad5f9854a4b68a0556","src/guid.rs":"069c5aa795b0858a012fe67f0fb8e5a4b1be17e1087283562ab51e68108a0e59","src/imp/bindings.rs":"c6fb2efdfb1ea133e47178a1de71c314021319e754ccf86a4639e6ce01920eab","src/imp/mod.rs":"7964e480c9a32a97735364b6386aa3d3b0ea5071c1ff43e6f8eaa786b49219f0","src/lib.rs":"4e2db9f8b2915f271bc4f3472fe497ad8467db56822262a7411c51f602b03f52","src/row.rs":"391b645ee0c7f034458c4fe49579bc1b60caf8d93c3b683ac96c1c7da2f2a9ab","src/type.rs":"920c260b597ef87984ebb3504134d6e915af7c4c6242fc50c0dd38e7d173df56","src/type_name.rs":"8414f7916932b7ed2a8d2a1cd48c14ad0c89c6d832fff5d5572734e1335131a6"},"package":"753135d996f9da437c0b31dbde3032489a61708361929bcc07d4fba0b161000e"}
\ No newline at end of file +{"files":{"Cargo.toml":"47ea9510176bee8b9ab0e08cc5dcf090b1f4aea4dbd1e7922a512022382826d7","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"c413987d2515509f71dc3f1f10362152b5ccd822d74896db1a3af152eae3b56a","src/attributes.rs":"64b6d61062a87a3df4b6c770e64f95f50a5d25a674caacc59474d21f60a8ed55","src/bindings.rs":"b8584035f0b26bbe4df8b9c5929b194eb895c7f02b7a03f60b36c82a873fc2f0","src/blob.rs":"c8505ed1164ca045fc95c75b07872ac81c7167b79ab3dc189de6ab67a852db66","src/codes.rs":"d778f8be69e28f403a3a5547e906d1228d11285269cc022d20544527619f27e4","src/column.rs":"95102b26fefd96a2c5ca1ec872a00ffdc9a774a90be1894a6b4320dbd90cd42b","src/file.rs":"cb210eba5a25b8fd7de388e955114c99a39a8cb6b9b2c35057744f3518ebf5d9","src/filter.rs":"1e94b3aa362954cb4c5cde344aa0b7ff58d56f2503d9df2f688587df9aeaf3d2","src/lib.rs":"efa0097044dbd950ef8ee2aad9679363decd8e2ec4ec9ea0617a27772648e6e2","src/reader.rs":"2d00969480a2517fa6e58a88a52c67b42c134376aa52a0f72ade9ed87c99190c","src/row.rs":"9cdbfe20a393f2c914e24adec4dc0fca91034f1998ec6478c0695fba84c86631","src/table.rs":"49021863fca609969ddf57816a0a3dd5f4b3b8c12eec6d5d8ece1d0fa9829dff","src/tables.rs":"14511b2b29b43df3963a83485373c06055825f1cb6e1ebac3bac34f04142bcf4","src/type.rs":"f1c71a8ccbd5fdfe3179b500873012e163ea968a87d371ff03a6d736f5275aad","src/type_name.rs":"1f37e1feffd83ed94775571f3bac0156f63673120737dab8b30495b483007137"},"package":"218fd59201e26acdbb894fa2b302d1de84bf3eec7d0eb894ac8e9c5a854ee4ef"}
\ No newline at end of file diff --git a/vendor/windows-metadata/Cargo.toml b/vendor/windows-metadata/Cargo.toml index e220f63d1..358588b84 100644 --- a/vendor/windows-metadata/Cargo.toml +++ b/vendor/windows-metadata/Cargo.toml @@ -11,10 +11,12 @@ [package] edition = "2021" +rust-version = "1.64" name = "windows-metadata" -version = "0.51.1" +version = "0.52.0" authors = ["Microsoft"] description = "Windows metadata reader" +readme = "readme.md" license = "MIT OR Apache-2.0" repository = "https://github.com/microsoft/windows-rs" diff --git a/vendor/windows-metadata/readme.md b/vendor/windows-metadata/readme.md new file mode 100644 index 000000000..e7960bdd0 --- /dev/null +++ b/vendor/windows-metadata/readme.md @@ -0,0 +1,37 @@ +## Windows metadata reader + +The [windows-metadata](https://crates.io/crates/windows-metadata) crate provides a fast reader for Windows metadata files based on the ECMA-335 file format. + +* [Getting started](https://kennykerr.ca/rust-getting-started/) +* [Samples](https://github.com/microsoft/windows-rs/tree/0.52.0/crates/samples) <!-- link to samples for upcoming release --> +* [Releases](https://github.com/microsoft/windows-rs/releases) + +Start by adding the following to your Cargo.toml file: + +```toml +[dependencies.windows-metadata] +version = "0.52" +``` + +Read metadata as needed: + +```rust,no_run +use windows_metadata::*; + +fn main() { + let bytes = std::fs::read(r#"C:\Windows\System32\WinMetadata\Windows.Foundation.winmd"#) + .expect("File not found"); + + let file = File::new(bytes).expect("Invalid metadata"); + + let reader = Reader::new(vec![file]); + + for def in reader.get_type_def("Windows.Foundation", "IAsyncInfo") { + println!("{}", def.name()); + + for method in def.methods() { + println!("{}", method.name()); + } + } +} +``` diff --git a/vendor/windows-metadata/src/attributes.rs b/vendor/windows-metadata/src/attributes.rs index 789214739..1bc2922da 100644 --- a/vendor/windows-metadata/src/attributes.rs +++ b/vendor/windows-metadata/src/attributes.rs @@ -2,7 +2,7 @@ macro_rules! flags { ($name:ident, $size:ty) => { - #[derive(Default, Copy, Clone, PartialEq, Eq, Debug)] + #[derive(Default, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)] pub struct $name(pub $size); impl $name { pub fn contains(&self, contains: Self) -> bool { diff --git a/vendor/windows-metadata/src/imp/bindings.rs b/vendor/windows-metadata/src/bindings.rs index abaebdd02..9f92aec78 100644 --- a/vendor/windows-metadata/src/imp/bindings.rs +++ b/vendor/windows-metadata/src/bindings.rs @@ -1,4 +1,4 @@ -// Bindings generated by `windows-bindgen` 0.51.1 +// Bindings generated by `windows-bindgen` 0.52.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] pub type CorElementType = u8; diff --git a/vendor/windows-metadata/src/blob.rs b/vendor/windows-metadata/src/blob.rs index a54336db1..398d5fb3b 100644 --- a/vendor/windows-metadata/src/blob.rs +++ b/vendor/windows-metadata/src/blob.rs @@ -1,11 +1,11 @@ use super::*; -pub struct Blob<'a> { - pub file: usize, - pub slice: &'a [u8], +pub struct Blob { + pub file: &'static File, + pub slice: &'static [u8], } -impl<'a> std::ops::Deref for Blob<'a> { +impl std::ops::Deref for Blob { type Target = [u8]; fn deref(&self) -> &[u8] { @@ -13,8 +13,8 @@ impl<'a> std::ops::Deref for Blob<'a> { } } -impl<'a> Blob<'a> { - pub fn new(file: usize, slice: &'a [u8]) -> Self { +impl Blob { + pub fn new(file: &'static File, slice: &'static [u8]) -> Self { Self { file, slice } } @@ -58,7 +58,7 @@ impl<'a> Blob<'a> { mods } - pub fn read_str(&mut self) -> &str { + pub fn read_str(&mut self) -> &'static str { let len = self.read_usize(); let value = unsafe { std::str::from_utf8_unchecked(&self.slice[..len]) }; self.offset(len); diff --git a/vendor/windows-metadata/src/codes.rs b/vendor/windows-metadata/src/codes.rs index d19f6e476..3171cb528 100644 --- a/vendor/windows-metadata/src/codes.rs +++ b/vendor/windows-metadata/src/codes.rs @@ -1,183 +1,91 @@ use super::*; pub trait Decode { - fn decode(file: usize, code: usize) -> Self; + fn decode(file: &'static File, code: usize) -> Self; } -pub enum AttributeType { - MemberRef(MemberRef), -} - -impl Decode for AttributeType { - fn decode(file: usize, code: usize) -> Self { - let (kind, row) = (code & ((1 << 3) - 1), (code >> 3) - 1); - match kind { - 3 => Self::MemberRef(MemberRef(Row::new(row, file))), - rest => unimplemented!("{rest:?}"), +macro_rules! code { + ($name:ident($size:literal) $(($table:ident, $code:literal))+) => { + #[derive(Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] + pub enum $name { + $($table($table),)* } - } -} - -pub enum HasAttribute { - MethodDef(MethodDef), - Field(Field), - TypeRef(TypeRef), - TypeDef(TypeDef), - Param(Param), - InterfaceImpl(InterfaceImpl), - MemberRef(MemberRef), - TypeSpec(TypeSpec), - GenericParam(GenericParam), -} - -impl HasAttribute { - pub fn encode(&self) -> usize { - match self { - Self::MethodDef(row) => (row.0.row + 1) << 5, - Self::Field(row) => ((row.0.row + 1) << 5) | 1, - Self::TypeRef(row) => ((row.0.row + 1) << 5) | 2, - Self::TypeDef(row) => ((row.0.row + 1) << 5) | 3, - Self::Param(row) => ((row.0.row + 1) << 5) | 4, - Self::InterfaceImpl(row) => ((row.0.row + 1) << 5) | 5, - Self::MemberRef(row) => ((row.0.row + 1) << 5) | 6, - Self::TypeSpec(row) => ((row.0.row + 1) << 5) | 13, - Self::GenericParam(row) => ((row.0.row + 1) << 5) | 19, + impl Decode for $name { + fn decode(file: &'static File, code: usize) -> Self { + let (kind, row) = (code & ((1 << $size) - 1), (code >> $size) - 1); + match kind { + $($code => Self::$table($table(Row::new(file, row))),)* + rest => unimplemented!("{rest:?}"), + } + } } - } -} - -impl From<MethodDef> for HasAttribute { - fn from(from: MethodDef) -> Self { - Self::MethodDef(from) - } -} -impl From<Field> for HasAttribute { - fn from(from: Field) -> Self { - Self::Field(from) - } -} -impl From<TypeRef> for HasAttribute { - fn from(from: TypeRef) -> Self { - Self::TypeRef(from) - } -} -impl From<TypeDef> for HasAttribute { - fn from(from: TypeDef) -> Self { - Self::TypeDef(from) - } -} -impl From<Param> for HasAttribute { - fn from(from: Param) -> Self { - Self::Param(from) - } -} -impl From<InterfaceImpl> for HasAttribute { - fn from(from: InterfaceImpl) -> Self { - Self::InterfaceImpl(from) - } -} -impl From<MemberRef> for HasAttribute { - fn from(from: MemberRef) -> Self { - Self::MemberRef(from) - } -} -impl From<TypeSpec> for HasAttribute { - fn from(from: TypeSpec) -> Self { - Self::TypeSpec(from) - } -} -impl From<GenericParam> for HasAttribute { - fn from(from: GenericParam) -> Self { - Self::GenericParam(from) - } -} - -#[derive(Clone)] -pub enum HasConstant { - Field(Field), -} - -impl HasConstant { - pub fn encode(&self) -> usize { - match self { - Self::Field(row) => (row.0.row + 1) << 2, + impl $name { + pub fn encode(&self) -> usize { + match self { + $(Self::$table(row) => (row.index() + 1) << $size | $code,)* + } + } } - } + $( + impl From<$table> for $name { + fn from(from: $table) -> Self { + Self::$table(from) + } + } + )* + }; } -#[derive(Clone)] -pub enum MemberForwarded { - MethodDef(MethodDef), +code! { AttributeType(3) + (MemberRef, 3) } -impl MemberForwarded { - pub fn encode(&self) -> usize { - match self { - Self::MethodDef(value) => ((value.0.row + 1) << 1) | 1, - } - } +code! { HasAttribute(5) + (MethodDef, 0) + (Field, 1) + (TypeRef, 2) + (TypeDef, 3) + (Param, 4) + (InterfaceImpl, 5) + (MemberRef, 6) + (TypeSpec, 13) + (GenericParam, 19) } -pub enum MemberRefParent { - TypeRef(TypeRef), +code! { HasConstant(2) + (Field, 0) } -impl Decode for MemberRefParent { - fn decode(file: usize, code: usize) -> Self { - let (kind, row) = (code & ((1 << 3) - 1), (code >> 3) - 1); - match kind { - 1 => Self::TypeRef(TypeRef(Row::new(row, file))), - rest => unimplemented!("{rest:?}"), - } - } +code! { MemberForwarded(1) + (MethodDef, 1) } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub enum TypeDefOrRef { - TypeDef(TypeDef), - TypeRef(TypeRef), - TypeSpec(TypeSpec), -} - -impl Decode for TypeDefOrRef { - fn decode(file: usize, code: usize) -> Self { - let (kind, row) = (code & ((1 << 2) - 1), (code >> 2) - 1); - match kind { - 0 => Self::TypeDef(TypeDef(Row::new(row, file))), - 1 => Self::TypeRef(TypeRef(Row::new(row, file))), - 2 => Self::TypeSpec(TypeSpec(Row::new(row, file))), - rest => unimplemented!("{rest:?}"), - } - } +code! { MemberRefParent(3) + (TypeRef, 1) } -pub enum TypeOrMethodDef { - TypeDef(TypeDef), +code! { TypeDefOrRef(2) + (TypeDef, 0) + (TypeRef, 1) + (TypeSpec, 2) } -impl TypeOrMethodDef { - pub fn encode(&self) -> usize { - match self { - Self::TypeDef(value) => (value.0.row + 1) << 1, - } - } +code! { TypeOrMethodDef(1) + (TypeDef, 0) } -pub enum ResolutionScope { - Module(Module), - ModuleRef(ModuleRef), - AssemblyRef(AssemblyRef), - TypeRef(TypeRef), +code! { ResolutionScope(2) + (Module, 0) + (ModuleRef, 1) + (AssemblyRef, 2) + (TypeRef, 3) } -impl Decode for ResolutionScope { - fn decode(file: usize, code: usize) -> Self { - let (kind, row) = (code & ((1 << 2) - 1), (code >> 2) - 1); - match kind { - 0 => Self::Module(Module(Row::new(row, file))), - 1 => Self::ModuleRef(ModuleRef(Row::new(row, file))), - 2 => Self::AssemblyRef(AssemblyRef(Row::new(row, file))), - 3 => Self::TypeRef(TypeRef(Row::new(row, file))), +impl TypeDefOrRef { + pub fn type_name(&self) -> TypeName { + match self { + Self::TypeDef(row) => row.type_name(), + Self::TypeRef(row) => row.type_name(), rest => unimplemented!("{rest:?}"), } } diff --git a/vendor/windows-metadata/src/column.rs b/vendor/windows-metadata/src/column.rs new file mode 100644 index 000000000..9a678daa8 --- /dev/null +++ b/vendor/windows-metadata/src/column.rs @@ -0,0 +1,11 @@ +#[derive(Default)] +pub struct Column { + pub offset: usize, + pub width: usize, +} + +impl Column { + pub fn new(offset: usize, width: usize) -> Self { + Self { offset, width } + } +} diff --git a/vendor/windows-metadata/src/file/mod.rs b/vendor/windows-metadata/src/file.rs index 41a6db920..e8867c1c9 100644 --- a/vendor/windows-metadata/src/file/mod.rs +++ b/vendor/windows-metadata/src/file.rs @@ -1,28 +1,55 @@ -mod reader; -mod table; -mod view; use super::*; -pub use reader::RowReader; -use std::cmp::Ordering; -use table::Table; -use view::View; type Result<T> = std::result::Result<T, ()>; -#[derive(Default)] pub struct File { - bytes: Vec<u8>, - strings: usize, - blobs: usize, - tables: [Table; 17], + pub reader: *const Reader, + pub bytes: Vec<u8>, + pub strings: usize, + pub blobs: usize, + pub tables: [Table; 17], } +impl std::fmt::Debug for File { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::write!(f, "{:?}", self.bytes.as_ptr()) + } +} + +impl std::hash::Hash for File { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.bytes.as_ptr().hash(state); + } +} + +impl PartialEq for File { + fn eq(&self, other: &Self) -> bool { + self.bytes.as_ptr() == other.bytes.as_ptr() + } +} + +impl Eq for File {} + +impl Ord for File { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.bytes.as_ptr().cmp(&other.bytes.as_ptr()) + } +} + +impl PartialOrd for File { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +unsafe impl Sync for File {} + impl File { pub fn new(bytes: Vec<u8>) -> Option<Self> { Self::ok(bytes).ok() } fn ok(bytes: Vec<u8>) -> Result<Self> { - let mut result = File { bytes, ..Default::default() }; + let mut result = File { bytes, reader: std::ptr::null(), strings: 0, blobs: 0, tables: Default::default() }; let dos = result.bytes.view_as::<IMAGE_DOS_HEADER>(0)?; @@ -282,7 +309,7 @@ impl File { Ok(result) } - fn usize(&self, row: usize, table: usize, column: usize) -> usize { + pub fn usize(&self, row: usize, table: usize, column: usize) -> usize { let table = &self.tables[table]; let column = &table.columns[column]; let offset = table.offset + row * table.width + column.offset; @@ -294,7 +321,7 @@ impl File { } } - fn lower_bound_of(&self, table: usize, mut first: usize, last: usize, column: usize, value: usize) -> usize { + pub fn lower_bound_of(&self, table: usize, mut first: usize, last: usize, column: usize, value: usize) -> usize { let mut count = last - first; while count > 0 { let count2 = count / 2; @@ -309,7 +336,7 @@ impl File { first } - fn upper_bound_of(&self, table: usize, mut first: usize, last: usize, column: usize, value: usize) -> usize { + pub fn upper_bound_of(&self, table: usize, mut first: usize, last: usize, column: usize, value: usize) -> usize { let mut count = last - first; while count > 0 { let count2 = count / 2; @@ -324,8 +351,8 @@ impl File { first } - pub fn table<R: AsRow>(&self, file: usize) -> RowIterator<R> { - RowIterator::new(file, 0..self.tables[R::TABLE].len) + pub fn table<R: AsRow>(&'static self) -> RowIterator<R> { + RowIterator::new(self, 0..self.tables[R::TABLE].len) } } @@ -336,3 +363,57 @@ fn section_from_rva(sections: &[IMAGE_SECTION_HEADER], rva: u32) -> Result<&IMAG fn offset_from_rva(section: &IMAGE_SECTION_HEADER, rva: u32) -> usize { (rva - section.VirtualAddress + section.PointerToRawData) as usize } + +trait View { + fn view_as<T>(&self, offset: usize) -> Result<&T>; + fn view_as_slice_of<T>(&self, offset: usize, len: usize) -> Result<&[T]>; + fn copy_as<T: Copy>(&self, offset: usize) -> Result<T>; + fn view_as_str(&self, offset: usize) -> Result<&[u8]>; + fn is_proper_length<T>(&self, offset: usize) -> Result<()>; + fn is_proper_length_and_alignment<T>(&self, offset: usize, count: usize) -> Result<*const T>; +} + +impl View for [u8] { + fn view_as<T>(&self, offset: usize) -> Result<&T> { + unsafe { Ok(&*self.is_proper_length_and_alignment(offset, 1)?) } + } + + fn view_as_slice_of<T>(&self, offset: usize, len: usize) -> Result<&[T]> { + unsafe { Ok(std::slice::from_raw_parts(self.is_proper_length_and_alignment(offset, len)?, len)) } + } + + fn copy_as<T>(&self, offset: usize) -> Result<T> { + self.is_proper_length::<T>(offset)?; + + unsafe { + let mut data = std::mem::MaybeUninit::zeroed().assume_init(); + std::ptr::copy_nonoverlapping(self[offset..].as_ptr(), &mut data as *mut T as *mut u8, std::mem::size_of::<T>()); + Ok(data) + } + } + + fn view_as_str(&self, offset: usize) -> Result<&[u8]> { + let buffer = &self[offset..]; + let index = buffer.iter().position(|c| *c == b'\0').ok_or(())?; + Ok(&self[offset..offset + index]) + } + + fn is_proper_length<T>(&self, offset: usize) -> Result<()> { + if offset + std::mem::size_of::<T>() <= self.len() { + Ok(()) + } else { + Err(()) + } + } + + fn is_proper_length_and_alignment<T>(&self, offset: usize, count: usize) -> Result<*const T> { + self.is_proper_length::<T>(offset * count)?; + let ptr = &self[offset] as *const u8 as *const T; + + if ptr.align_offset(std::mem::align_of::<T>()) == 0 { + Ok(ptr) + } else { + Err(()) + } + } +} diff --git a/vendor/windows-metadata/src/file/reader.rs b/vendor/windows-metadata/src/file/reader.rs deleted file mode 100644 index 571a06d5e..000000000 --- a/vendor/windows-metadata/src/file/reader.rs +++ /dev/null @@ -1,359 +0,0 @@ -use super::*; - -pub trait RowReader<'a> { - fn row_file<R: AsRow>(&self, row: R) -> &'a File; - - fn row_usize<R: AsRow>(&self, row: R, column: usize) -> usize { - let file = self.row_file(row); - let row = row.to_row(); - file.usize(row.row, R::TABLE, column) - } - - fn row_str<R: AsRow>(&self, row: R, column: usize) -> &'a str { - let file = self.row_file(row); - let offset = file.strings + self.row_usize(row, column); - let bytes = &file.bytes[offset..]; - let nul_pos = bytes.iter().position(|&c| c == 0).expect("expected null-terminated C-string"); - std::str::from_utf8(&bytes[..nul_pos]).expect("expected valid utf-8 C-string") - } - - fn row_blob<R: AsRow>(&self, row: R, column: usize) -> Blob<'a> { - let file = self.row_file(row); - let offset = file.blobs + self.row_usize(row, column); - let initial_byte = file.bytes[offset]; - - let (blob_size, blob_size_bytes) = match initial_byte >> 5 { - 0..=3 => (initial_byte & 0x7f, 1), - 4..=5 => (initial_byte & 0x3f, 2), - 6 => (initial_byte & 0x1f, 4), - rest => unimplemented!("{rest:?}"), - }; - - let mut blob_size = blob_size as usize; - - for byte in &file.bytes[offset + 1..offset + blob_size_bytes] { - blob_size = blob_size.checked_shl(8).unwrap_or(0) + (*byte as usize); - } - - let offset = offset + blob_size_bytes; - Blob::new(row.file(), &file.bytes[offset..offset + blob_size]) - } - - fn row_list<R: AsRow, L: AsRow>(&self, row: R, column: usize) -> RowIterator<L> { - let file = self.row_file(row); - let first = self.row_usize(row, column) - 1; - let next = row.next(); - let last = if next.index() < file.tables[R::TABLE].len { self.row_usize(next, column) - 1 } else { file.tables[L::TABLE].len }; - RowIterator::new(row.file(), first..last) - } - - fn row_equal_range<R: AsRow, L: AsRow>(&self, row: R, column: usize, value: usize) -> RowIterator<L> { - let file = self.row_file(row); - let mut first = 0; - let mut last = file.tables[L::TABLE].len; - let mut count = last; - - loop { - if count == 0 { - last = first; - break; - } - - let count2 = count / 2; - let middle = first + count2; - let middle_value = file.usize(middle, L::TABLE, column); - - match middle_value.cmp(&value) { - Ordering::Less => { - first = middle + 1; - count -= count2 + 1; - } - Ordering::Greater => count = count2, - Ordering::Equal => { - let first2 = file.lower_bound_of(L::TABLE, first, middle, column, value); - first += count; - last = file.upper_bound_of(L::TABLE, middle + 1, first, column, value); - first = first2; - break; - } - } - } - - RowIterator::new(row.file(), first..last) - } - - fn row_decode<R: AsRow, T: Decode>(&self, row: R, column: usize) -> T { - T::decode(row.file(), self.row_usize(row, column)) - } - - // - // Attribute - // - - fn attribute_name(&self, row: Attribute) -> &'a str { - let AttributeType::MemberRef(row) = self.row_decode(row, 1); - let MemberRefParent::TypeRef(row) = self.row_decode(row, 0); - self.type_ref_name(row) - } - - fn attributes<R: AsRow + Into<HasAttribute>>(&self, row: R) -> RowIterator<Attribute> { - self.row_equal_range(row, 0, row.into().encode()) - } - - fn find_attribute<R: AsRow + Into<HasAttribute>>(&self, row: R, name: &str) -> Option<Attribute> { - self.attributes(row).find(|attribute| self.attribute_name(*attribute) == name) - } - - fn has_attribute<R: AsRow + Into<HasAttribute>>(&self, row: R, name: &str) -> bool { - self.find_attribute(row, name).is_some() - } - - // - // Other - // - - fn type_def_or_ref(&self, code: TypeDefOrRef) -> TypeName<'a> { - match code { - TypeDefOrRef::TypeDef(row) => TypeName::new(self.type_def_namespace(row), self.type_def_name(row)), - TypeDefOrRef::TypeRef(row) => TypeName::new(self.type_ref_namespace(row), self.type_ref_name(row)), - rest => unimplemented!("{rest:?}"), - } - } - - // - // ClassLayout - // - - fn class_layout_packing_size(&self, row: ClassLayout) -> usize { - self.row_usize(row, 0) - } - - // - // Constant - // - - fn constant_type(&self, row: Constant) -> Type { - let code = self.row_usize(row, 0); - Type::from_code(code).expect("Constant type not found") - } - - fn constant_value(&self, row: Constant) -> Value { - let mut blob = self.row_blob(row, 2); - match self.constant_type(row) { - Type::I8 => Value::I8(blob.read_i8()), - Type::U8 => Value::U8(blob.read_u8()), - Type::I16 => Value::I16(blob.read_i16()), - Type::U16 => Value::U16(blob.read_u16()), - Type::I32 => Value::I32(blob.read_i32()), - Type::U32 => Value::U32(blob.read_u32()), - Type::I64 => Value::I64(blob.read_i64()), - Type::U64 => Value::U64(blob.read_u64()), - Type::F32 => Value::F32(blob.read_f32()), - Type::F64 => Value::F64(blob.read_f64()), - Type::String => Value::String(blob.read_string()), - rest => unimplemented!("{rest:?}"), - } - } - - // - // Field - // - - fn field_flags(&self, row: Field) -> FieldAttributes { - FieldAttributes(self.row_usize(row, 0) as u16) - } - - fn field_name(&self, row: Field) -> &'a str { - self.row_str(row, 1) - } - - fn field_constant(&self, row: Field) -> Option<Constant> { - self.row_equal_range(row, 1, HasConstant::Field(row).encode()).next() - } - - // - // GenericParam - // - - fn generic_param_number(&self, row: GenericParam) -> u16 { - self.row_usize(row, 0) as u16 - } - - fn generic_param_name(&self, row: GenericParam) -> &'a str { - self.row_str(row, 3) - } - - // - // ImplMap - // - - fn impl_map_flags(&self, row: ImplMap) -> PInvokeAttributes { - PInvokeAttributes(self.row_usize(row, 0)) - } - - fn impl_map_scope(&self, row: ImplMap) -> ModuleRef { - ModuleRef(Row::new(self.row_usize(row, 3) - 1, row.file())) - } - - fn impl_map_import_name(&self, row: ImplMap) -> &'a str { - self.row_str(row, 2) - } - - // - // MemberRef - // - - fn member_ref_parent(&self, row: MemberRef) -> MemberRefParent { - self.row_decode(row, 0) - } - - fn member_ref_signature(&self, row: MemberRef) -> Blob<'a> { - self.row_blob(row, 2) - } - - // - // MethodDef - // - - fn method_def_impl_flags(&self, row: MethodDef) -> MethodImplAttributes { - MethodImplAttributes(self.row_usize(row, 1) as u16) - } - - fn method_def_flags(&self, row: MethodDef) -> MethodAttributes { - MethodAttributes(self.row_usize(row, 2) as u16) - } - - fn method_def_name(&self, row: MethodDef) -> &'a str { - self.row_str(row, 3) - } - - fn method_def_params(&self, row: MethodDef) -> RowIterator<Param> { - self.row_list(row, 5) - } - - fn method_def_impl_map(&self, row: MethodDef) -> Option<ImplMap> { - self.row_equal_range(row, 1, MemberForwarded::MethodDef(row).encode()).next() - } - - fn method_def_module_name(&self, row: MethodDef) -> String { - // TODO: riddle should always lower case the module name to avoid allocating here - let Some(impl_map) = self.method_def_impl_map(row) else { - return String::new(); - }; - - self.module_ref_name(self.impl_map_scope(impl_map)).to_lowercase() - } - - // - // ModuleRef - // - - fn module_ref_name(&self, row: ModuleRef) -> &'a str { - self.row_str(row, 0) - } - - // - // NestedClass - // - - fn nested_class_inner(&self, row: NestedClass) -> TypeDef { - TypeDef(Row::new(self.row_usize(row, 0) - 1, row.file())) - } - - fn nested_class_outer(&self, row: NestedClass) -> TypeDef { - TypeDef(Row::new(self.row_usize(row, 1) - 1, row.file())) - } - - // - // Param - // - - fn param_flags(&self, row: Param) -> ParamAttributes { - ParamAttributes(self.row_usize(row, 0) as u16) - } - - fn param_sequence(&self, row: Param) -> u16 { - self.row_usize(row, 1) as u16 - } - - fn param_name(&self, row: Param) -> &'a str { - self.row_str(row, 2) - } - - // - // TypeDef - // - - fn type_def_flags(&self, row: TypeDef) -> TypeAttributes { - TypeAttributes(self.row_usize(row, 0) as u32) - } - - fn type_def_name(&self, row: TypeDef) -> &'a str { - self.row_str(row, 1) - } - - fn type_def_namespace(&self, row: TypeDef) -> &'a str { - self.row_str(row, 2) - } - - fn type_def_extends(&self, row: TypeDef) -> Option<TypeName<'a>> { - match self.row_usize(row, 3) { - 0 => None, - code => Some(self.type_def_or_ref(TypeDefOrRef::decode(row.file(), code))), - } - } - - fn type_def_methods(&self, row: TypeDef) -> RowIterator<MethodDef> { - self.row_list(row, 5) - } - - fn type_def_fields(&self, row: TypeDef) -> RowIterator<Field> { - self.row_list(row, 4) - } - - fn type_def_generics(&self, row: TypeDef) -> RowIterator<GenericParam> { - self.row_equal_range(row, 2, TypeOrMethodDef::TypeDef(row).encode()) - } - - fn type_def_interface_impls(&self, row: TypeDef) -> RowIterator<InterfaceImpl> { - self.row_equal_range(row, 0, row.0.row + 1) - } - - fn type_def_enclosing_type(&self, row: TypeDef) -> Option<TypeDef> { - self.row_equal_range::<TypeDef, NestedClass>(row, 0, row.0.row + 1).next().map(|row| TypeDef(Row::new(self.row_usize(row, 1) - 1, row.file()))) - } - - fn type_def_class_layout(&self, row: TypeDef) -> Option<ClassLayout> { - self.row_equal_range(row, 2, row.0.row + 1).next() - } - - // - // TypeRef - // - - fn type_ref_name(&self, row: TypeRef) -> &'a str { - self.row_str(row, 1) - } - - fn type_ref_namespace(&self, row: TypeRef) -> &'a str { - self.row_str(row, 2) - } - - fn type_ref_resolution_scope(&self, row: TypeRef) -> ResolutionScope { - self.row_decode(row, 0) - } - - // - // TypeSpec - // - - fn type_spec_signature(&self, row: TypeSpec) -> Blob<'a> { - self.row_blob(row, 0) - } -} - -impl<'a> RowReader<'a> for &'a [File] { - fn row_file<R: AsRow>(&self, row: R) -> &'a File { - &self[row.to_row().file] - } -} diff --git a/vendor/windows-metadata/src/file/view.rs b/vendor/windows-metadata/src/file/view.rs deleted file mode 100644 index 31eb1541b..000000000 --- a/vendor/windows-metadata/src/file/view.rs +++ /dev/null @@ -1,55 +0,0 @@ -type Result<T> = std::result::Result<T, ()>; - -pub trait View { - fn view_as<T>(&self, offset: usize) -> Result<&T>; - fn view_as_slice_of<T>(&self, offset: usize, len: usize) -> Result<&[T]>; - fn copy_as<T: Copy>(&self, offset: usize) -> Result<T>; - fn view_as_str(&self, offset: usize) -> Result<&[u8]>; - fn is_proper_length<T>(&self, offset: usize) -> Result<()>; - fn is_proper_length_and_alignment<T>(&self, offset: usize, count: usize) -> Result<*const T>; -} - -impl View for [u8] { - fn view_as<T>(&self, offset: usize) -> Result<&T> { - unsafe { Ok(&*self.is_proper_length_and_alignment(offset, 1)?) } - } - - fn view_as_slice_of<T>(&self, offset: usize, len: usize) -> Result<&[T]> { - unsafe { Ok(std::slice::from_raw_parts(self.is_proper_length_and_alignment(offset, len)?, len)) } - } - - fn copy_as<T>(&self, offset: usize) -> Result<T> { - self.is_proper_length::<T>(offset)?; - - unsafe { - let mut data = std::mem::MaybeUninit::zeroed().assume_init(); - std::ptr::copy_nonoverlapping(self[offset..].as_ptr(), &mut data as *mut T as *mut u8, std::mem::size_of::<T>()); - Ok(data) - } - } - - fn view_as_str(&self, offset: usize) -> Result<&[u8]> { - let buffer = &self[offset..]; - let index = buffer.iter().position(|c| *c == b'\0').ok_or(())?; - Ok(&self[offset..offset + index]) - } - - fn is_proper_length<T>(&self, offset: usize) -> Result<()> { - if offset + std::mem::size_of::<T>() <= self.len() { - Ok(()) - } else { - Err(()) - } - } - - fn is_proper_length_and_alignment<T>(&self, offset: usize, count: usize) -> Result<*const T> { - self.is_proper_length::<T>(offset * count)?; - let ptr = &self[offset] as *const u8 as *const T; - - if ptr.align_offset(std::mem::align_of::<T>()) == 0 { - Ok(ptr) - } else { - Err(()) - } - } -} diff --git a/vendor/windows-metadata/src/filter.rs b/vendor/windows-metadata/src/filter.rs index c13afda44..f9efcfe7e 100644 --- a/vendor/windows-metadata/src/filter.rs +++ b/vendor/windows-metadata/src/filter.rs @@ -1,18 +1,16 @@ -use super::*; - #[derive(Default)] -pub struct Filter<'a>(Vec<(&'a str, bool)>); +pub struct Filter(pub Vec<(String, bool)>); -impl<'a> Filter<'a> { - pub fn new(include: &[&'a str], exclude: &[&'a str]) -> Self { +impl Filter { + pub fn new(include: &[&str], exclude: &[&str]) -> Self { let mut rules = vec![]; for include in include { - rules.push((*include, true)); + rules.push((include.to_string(), true)); } for exclude in exclude { - rules.push((*exclude, false)); + rules.push((exclude.to_string(), false)); } rules.sort_unstable_by(|left, right| { @@ -25,7 +23,7 @@ impl<'a> Filter<'a> { } pub fn includes_namespace(&self, namespace: &str) -> bool { - if self.is_empty() { + if self.0.is_empty() { return true; } @@ -35,12 +33,12 @@ impl<'a> Filter<'a> { if rule.0.starts_with(namespace) { return true; } - if namespace.starts_with(rule.0) { + if namespace.starts_with(&rule.0) { return true; } } else { // exclude - if namespace.starts_with(rule.0) { + if namespace.starts_with(&rule.0) { return false; } } @@ -49,27 +47,19 @@ impl<'a> Filter<'a> { false } - pub fn includes_type_name(&self, type_name: TypeName) -> bool { - if self.is_empty() { + pub fn includes_type_name(&self, namespace: &str, name: &str) -> bool { + if self.0.is_empty() { return true; } for rule in &self.0 { - if match_type_name(rule.0, type_name.namespace, type_name.name) { + if match_type_name(&rule.0, namespace, name) { return rule.1; } } false } - - pub fn includes(&self) -> impl Iterator<Item = &str> + '_ { - self.0.iter().filter_map(|(name, include)| if *include { Some(*name) } else { None }) - } - - fn is_empty(&self) -> bool { - self.0.is_empty() - } } fn match_type_name(rule: &str, namespace: &str, name: &str) -> bool { @@ -92,8 +82,9 @@ fn match_type_name(rule: &str, namespace: &str, name: &str) -> bool { mod tests { use super::*; - fn includes_type_name(filter: &Filter, full_name: &str) -> bool { - filter.includes_type_name(TypeName::parse(full_name)) + fn includes_type_name(filter: &Filter, full_name: &'static str) -> bool { + let type_name = crate::TypeName::parse(full_name); + filter.includes_type_name(type_name.namespace, type_name.name) } #[test] @@ -116,8 +107,6 @@ mod tests { let exclude = ["N2", "N3.N4"]; let f = Filter::new(&include, &exclude); - assert!(!f.is_empty()); - assert!(!includes_type_name(&f, "NN.T")); assert!(includes_type_name(&f, "N1.T")); @@ -135,8 +124,6 @@ mod tests { let exclude = ["N.N3", "N.N4"]; let f = Filter::new(&include, &exclude); - assert!(!f.is_empty()); - assert!(includes_type_name(&f, "N.N1.T")); assert!(includes_type_name(&f, "N.N2.T")); @@ -150,8 +137,6 @@ mod tests { let exclude = ["N.T"]; let f = Filter::new(&include, &exclude); - assert!(!f.is_empty()); - assert!(!includes_type_name(&f, "N.T")); } } diff --git a/vendor/windows-metadata/src/guid.rs b/vendor/windows-metadata/src/guid.rs deleted file mode 100644 index a253530ba..000000000 --- a/vendor/windows-metadata/src/guid.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![allow(clippy::many_single_char_names)] - -use super::*; - -#[derive(Clone, PartialEq, Eq, Default)] -pub struct GUID(pub u32, pub u16, pub u16, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8); - -impl GUID { - pub fn from_args(args: &[(String, Value)]) -> Self { - fn unwrap_u32(value: &Value) -> u32 { - match value { - Value::U32(value) => *value, - rest => unimplemented!("{rest:?}"), - } - } - fn unwrap_u16(value: &Value) -> u16 { - match value { - Value::U16(value) => *value, - rest => unimplemented!("{rest:?}"), - } - } - fn unwrap_u8(value: &Value) -> u8 { - match value { - Value::U8(value) => *value, - rest => unimplemented!("{rest:?}"), - } - } - Self(unwrap_u32(&args[0].1), unwrap_u16(&args[1].1), unwrap_u16(&args[2].1), unwrap_u8(&args[3].1), unwrap_u8(&args[4].1), unwrap_u8(&args[5].1), unwrap_u8(&args[6].1), unwrap_u8(&args[7].1), unwrap_u8(&args[8].1), unwrap_u8(&args[9].1), unwrap_u8(&args[10].1)) - } - - pub fn from_string_args(args: &[&str]) -> Self { - Self(args[0].parse().unwrap(), args[1].parse().unwrap(), args[2].parse().unwrap(), args[3].parse().unwrap(), args[4].parse().unwrap(), args[5].parse().unwrap(), args[6].parse().unwrap(), args[7].parse().unwrap(), args[8].parse().unwrap(), args[9].parse().unwrap(), args[10].parse().unwrap()) - } -} - -impl std::fmt::Debug for GUID { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:08x?}-{:04x?}-{:04x?}-{:02x?}{:02x?}-{:02x?}{:02x?}{:02x?}{:02x?}{:02x?}{:02x?}", self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7, self.8, self.9, self.10) - } -} diff --git a/vendor/windows-metadata/src/imp/mod.rs b/vendor/windows-metadata/src/imp/mod.rs deleted file mode 100644 index 571d0f063..000000000 --- a/vendor/windows-metadata/src/imp/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -mod bindings; -pub use bindings::*; - -#[repr(C)] -#[derive(Default)] -pub struct METADATA_HEADER { - pub signature: u32, - pub major_version: u16, - pub minor_version: u16, - pub reserved: u32, - pub length: u32, - pub version: [u8; 20], - pub flags: u16, - pub streams: u16, -} - -pub const METADATA_SIGNATURE: u32 = 0x424A_5342; - -/// A coded index (see codes.rs) is a table index that may refer to different tables. The size of the column in memory -/// must therefore be large enough to hold an index for a row in the largest possible table. This function determines -/// this size for the given winmd file. -pub fn coded_index_size(tables: &[usize]) -> usize { - fn small(row_count: usize, bits: u8) -> bool { - (row_count as u64) < (1u64 << (16 - bits)) - } - - fn bits_needed(value: usize) -> u8 { - let mut value = value - 1; - let mut bits: u8 = 1; - while { - value >>= 1; - value != 0 - } { - bits += 1; - } - bits - } - - let bits_needed = bits_needed(tables.len()); - - if tables.iter().all(|table| small(*table, bits_needed)) { - 2 - } else { - 4 - } -} diff --git a/vendor/windows-metadata/src/lib.rs b/vendor/windows-metadata/src/lib.rs index 70a85c5b1..15220b178 100644 --- a/vendor/windows-metadata/src/lib.rs +++ b/vendor/windows-metadata/src/lib.rs @@ -1,36 +1,76 @@ -#[doc(hidden)] -pub mod imp; +use std::cmp::Ordering; +use std::collections::*; mod attributes; +mod bindings; mod blob; mod codes; +mod column; mod file; mod filter; -mod guid; +mod reader; mod row; +mod table; +mod tables; mod r#type; mod type_name; pub use attributes::*; -pub use blob::Blob; +pub use bindings::*; +pub use blob::*; pub use codes::*; +use column::*; pub use file::*; -pub use filter::Filter; -pub use guid::GUID; -use imp::*; -pub use r#type::Type; +use filter::*; +pub use r#type::*; +pub use reader::*; pub use row::*; -use std::collections::*; -pub use type_name::TypeName; +use table::*; +pub use tables::*; +pub use type_name::*; + +#[repr(C)] +#[derive(Default)] +pub struct METADATA_HEADER { + pub signature: u32, + pub major_version: u16, + pub minor_version: u16, + pub reserved: u32, + pub length: u32, + pub version: [u8; 20], + pub flags: u16, + pub streams: u16, +} -// TODO: move to riddle -#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)] -pub enum TypeKind { - Interface, - Class, - Enum, - Struct, - Delegate, +pub const METADATA_SIGNATURE: u32 = 0x424A_5342; + +/// A coded index (see codes.rs) is a table index that may refer to different tables. The size of the column in memory +/// must therefore be large enough to hold an index for a row in the largest possible table. This function determines +/// this size for the given winmd file. +pub fn coded_index_size(tables: &[usize]) -> usize { + fn small(row_count: usize, bits: u8) -> bool { + (row_count as u64) < (1u64 << (16 - bits)) + } + + fn bits_needed(value: usize) -> u8 { + let mut value = value - 1; + let mut bits: u8 = 1; + while { + value >>= 1; + value != 0 + } { + bits += 1; + } + bits + } + + let bits_needed = bits_needed(tables.len()); + + if tables.iter().all(|table| small(*table, bits_needed)) { + 2 + } else { + 4 + } } #[derive(Debug)] @@ -47,8 +87,7 @@ pub enum Value { F32(f32), F64(f64), String(String), - TypeName(String), - TypeRef(TypeDefOrRef), + TypeName(TypeName), EnumDef(TypeDef, Box<Self>), } @@ -58,406 +97,17 @@ pub struct MethodDefSig { pub params: Vec<Type>, } -#[derive(Clone, Debug)] -pub enum Item { - Type(TypeDef), - Const(Field), - // TODO: get rid of the trailing String - that's just a hack to get around a silly Win32 metadata deficiency where parsing method signatures - // requires knowing which namespace the method's surrounding interface was defined in. - Fn(MethodDef, String), -} - -pub struct Reader<'a> { - files: &'a [File], - items: BTreeMap<&'a str, BTreeMap<&'a str, Vec<Item>>>, - - // TODO: riddle should just avoid nested structs - nested: HashMap<TypeDef, BTreeMap<&'a str, TypeDef>>, -} - -impl<'a> Reader<'a> { - pub fn new(files: &'a [File]) -> Self { - let mut items = BTreeMap::<&'a str, BTreeMap<&'a str, Vec<Item>>>::new(); - let mut nested = HashMap::<TypeDef, BTreeMap<&'a str, TypeDef>>::new(); - for (file_index, file) in files.iter().enumerate() { - for def in file.table::<TypeDef>(file_index) { - let namespace = files.type_def_namespace(def); - if namespace.is_empty() { - continue; - } - let namespace_items = items.entry(namespace).or_default(); - let name = files.type_def_name(def); - if name == "Apis" { - for method in files.type_def_methods(def) { - let name = files.method_def_name(method); - namespace_items.entry(name).or_default().push(Item::Fn(method, namespace.to_string())); - } - for field in files.type_def_fields(def) { - let name = files.field_name(field); - namespace_items.entry(name).or_default().push(Item::Const(field)); - } - } else { - namespace_items.entry(trim_tick(name)).or_default().push(Item::Type(def)); - - // TODO: these should all be fields on the Apis class so we don't have to go looking for all of these as well. - if files.type_def_extends(def) == Some(TypeName::Enum) && !files.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) && !files.has_attribute(def, "ScopedEnumAttribute") { - for field in files.type_def_fields(def).filter(|field| files.field_flags(*field).contains(FieldAttributes::Literal)) { - let name = files.field_name(field); - namespace_items.entry(name).or_default().push(Item::Const(field)); - } - } - } - } - for key in file.table::<NestedClass>(file_index) { - let inner = files.nested_class_inner(key); - let outer = files.nested_class_outer(key); - let name = files.type_def_name(inner); - nested.entry(outer).or_default().insert(name, inner); - } - } - Self { files, items, nested } - } - - pub fn namespaces(&self) -> impl Iterator<Item = &str> + '_ { - self.items.keys().copied() - } - - pub fn items(&'a self, filter: &'a Filter) -> impl Iterator<Item = Item> + '_ { - self.items.iter().filter(move |(namespace, _)| filter.includes_namespace(namespace)).flat_map(move |(namespace, items)| items.iter().filter(move |(name, _)| filter.includes_type_name(TypeName::new(namespace, name)))).flat_map(move |(_, items)| items).cloned() - } - - pub fn namespace_items(&'a self, namespace: &str, filter: &'a Filter) -> impl Iterator<Item = Item> + '_ { - self.items.get_key_value(namespace).into_iter().flat_map(move |(namespace, items)| items.iter().filter(move |(name, _)| filter.includes_type_name(TypeName::new(namespace, name)))).flat_map(move |(_, items)| items).cloned() - } - - fn get_item(&self, type_name: TypeName) -> impl Iterator<Item = Item> + '_ { - if let Some(items) = self.items.get(type_name.namespace) { - if let Some(items) = items.get(type_name.name) { - return Some(items.iter().cloned()).into_iter().flatten(); - } - } - None.into_iter().flatten() - } - - pub fn get_type_def(&self, type_name: TypeName) -> impl Iterator<Item = TypeDef> + '_ { - self.get_item(type_name).filter_map(|item| if let Item::Type(def) = item { Some(def) } else { None }) - } - - pub fn get_method_def(&self, type_name: TypeName) -> impl Iterator<Item = (MethodDef, String)> + '_ { - self.get_item(type_name).filter_map(|item| if let Item::Fn(def, namespace) = item { Some((def, namespace)) } else { None }) - } - - pub fn nested_types(&self, type_def: TypeDef) -> impl Iterator<Item = TypeDef> + '_ { - self.nested.get(&type_def).map(|map| map.values().copied()).into_iter().flatten() - } - - pub fn attribute_args(&self, row: Attribute) -> Vec<(String, Value)> { - let AttributeType::MemberRef(member) = self.row_decode(row, 1); - let mut sig = self.member_ref_signature(member); - let mut values = self.row_blob(row, 2); - let _prolog = values.read_u16(); - let _this_and_gen_param_count = sig.read_usize(); - let fixed_arg_count = sig.read_usize(); - let _ret_type = sig.read_usize(); - let mut args: Vec<(String, Value)> = Vec::with_capacity(fixed_arg_count); - - for _ in 0..fixed_arg_count { - let arg = match self.type_from_blob(&mut sig, None, &[]) { - Type::Bool => Value::Bool(values.read_bool()), - Type::I8 => Value::I8(values.read_i8()), - Type::U8 => Value::U8(values.read_u8()), - Type::I16 => Value::I16(values.read_i16()), - Type::U16 => Value::U16(values.read_u16()), - Type::I32 => Value::I32(values.read_i32()), - Type::U32 => Value::U32(values.read_u32()), - Type::I64 => Value::I64(values.read_i64()), - Type::U64 => Value::U64(values.read_u64()), - Type::String => Value::String(values.read_str().to_string()), - Type::TypeName => Value::TypeName(values.read_str().to_string()), - Type::TypeDef(def, _) => Value::EnumDef(def, Box::new(values.read_integer(self.type_def_underlying_type(def)))), - rest => unimplemented!("{rest:?}"), - }; - - args.push((String::new(), arg)); - } - - let named_arg_count = values.read_u16(); - args.reserve(named_arg_count as usize); - - for _ in 0..named_arg_count { - let _id = values.read_u8(); - let arg_type = values.read_u8(); - let mut name = values.read_str().to_string(); - let arg = match arg_type { - ELEMENT_TYPE_BOOLEAN => Value::Bool(values.read_bool()), - ELEMENT_TYPE_I2 => Value::I16(values.read_i16()), - ELEMENT_TYPE_I4 => Value::I32(values.read_i32()), - ELEMENT_TYPE_U4 => Value::U32(values.read_u32()), - ELEMENT_TYPE_STRING => Value::String(values.read_str().to_string()), - 0x50 => Value::TypeName(values.read_str().to_string()), - 0x55 => { - let def = self.get_type_def(TypeName::parse(&name)).next().expect("Type not found"); - name = values.read_str().into(); - Value::EnumDef(def, Box::new(values.read_integer(self.type_def_underlying_type(def)))) - } - rest => unimplemented!("{rest:?}"), - }; - args.push((name, arg)); - } - - assert_eq!(sig.slice.len(), 0); - assert_eq!(values.slice.len(), 0); - - args - } - - // TODO: enclosing craziness is only needed for nested structs - get rid of those in riddle and this goes away. - pub fn field_type(&self, row: Field, enclosing: Option<TypeDef>) -> Type { - let mut blob = self.row_blob(row, 2); - blob.read_usize(); - blob.read_modifiers(); - let def = self.type_from_blob(&mut blob, enclosing, &[]); - - if self.has_attribute(row, "ConstAttribute") { - def.to_const_type().to_const_ptr() - } else { - def - } - } - - pub fn interface_impl_type(&self, row: InterfaceImpl, generics: &[Type]) -> Type { - self.type_from_ref(self.row_decode(row, 1), None, generics) - } - - pub fn method_def_signature(&self, method: MethodDef, generics: &[Type]) -> MethodDefSig { - let mut blob = self.row_blob(method, 4); - let call_flags = MethodCallAttributes(blob.read_usize() as u8); - let params = blob.read_usize(); - let return_type = self.type_from_blob(&mut blob, None, generics); - - MethodDefSig { call_flags, return_type, params: (0..params).map(|_| self.type_from_blob(&mut blob, None, generics)).collect() } - } - - pub fn method_def_size(&self, method: MethodDef) -> usize { - let sig = self.method_def_signature(method, &[]); - sig.params.iter().fold(0, |sum, param| sum + std::cmp::max(4, self.type_size(param))) - } - - pub fn type_def_type_name(&self, row: TypeDef) -> TypeName { - TypeName::new(self.type_def_namespace(row), self.type_def_name(row)) - } - - pub fn type_def_underlying_type(&self, row: TypeDef) -> Type { - let field = self.type_def_fields(row).next().expect("Field not found"); - if let Some(constant) = self.field_constant(field) { - self.constant_type(constant) - } else { - self.field_type(field, Some(row)) - } - } - - pub fn type_def_kind(&self, row: TypeDef) -> TypeKind { - match self.type_def_extends(row) { - None => TypeKind::Interface, - Some(TypeName::Enum) => TypeKind::Enum, - Some(TypeName::Delegate) => TypeKind::Delegate, - Some(TypeName::Struct) => TypeKind::Struct, - Some(_) => TypeKind::Class, - } - } - - pub fn type_def_size(&self, def: TypeDef) -> usize { - match self.type_def_kind(def) { - TypeKind::Struct => { - if self.type_def_flags(def).contains(TypeAttributes::ExplicitLayout) { - self.type_def_fields(def).map(|field| self.type_size(&self.field_type(field, Some(def)))).max().unwrap_or(1) - } else { - let mut sum = 0; - for field in self.type_def_fields(def) { - let size = self.type_size(&self.field_type(field, Some(def))); - let align = self.type_align(&self.field_type(field, Some(def))); - sum = (sum + (align - 1)) & !(align - 1); - sum += size; - } - sum - } - } - TypeKind::Enum => self.type_size(&self.type_def_underlying_type(def)), - _ => 4, - } - } - - fn type_def_align(&self, def: TypeDef) -> usize { - match self.type_def_kind(def) { - TypeKind::Struct => self.type_def_fields(def).map(|field| self.type_align(&self.field_type(field, Some(def)))).max().unwrap_or(1), - TypeKind::Enum => self.type_align(&self.type_def_underlying_type(def)), - _ => 4, - } - } - - fn type_align(&self, ty: &Type) -> usize { - match ty { - Type::I8 | Type::U8 => 1, - Type::I16 | Type::U16 => 2, - Type::I64 | Type::U64 | Type::F64 => 8, - Type::GUID => 4, - Type::TypeDef(def, _) => self.type_def_align(*def), - Type::Win32Array(ty, len) => self.type_align(ty) * len, - _ => 4, - } - } - - // TODO: this shouldn't be public - needed to work around Win32 metadata hackery. - pub fn type_size(&self, ty: &Type) -> usize { - match ty { - Type::I8 | Type::U8 => 1, - Type::I16 | Type::U16 => 2, - Type::I64 | Type::U64 | Type::F64 => 8, - Type::GUID => 16, - Type::TypeDef(def, _) => self.type_def_size(*def), - Type::Win32Array(ty, len) => self.type_size(ty) * len, - Type::PrimitiveOrEnum(ty, _) => self.type_size(ty), - _ => 4, - } - } - - pub fn type_def_or_ref(&self, code: TypeDefOrRef) -> TypeName { - match code { - TypeDefOrRef::TypeDef(row) => TypeName::new(self.type_def_namespace(row), self.type_def_name(row)), - TypeDefOrRef::TypeRef(row) => TypeName::new(self.type_ref_namespace(row), self.type_ref_name(row)), - rest => unimplemented!("{rest:?}"), - } - } - - fn type_from_ref(&self, code: TypeDefOrRef, enclosing: Option<TypeDef>, generics: &[Type]) -> Type { - if let TypeDefOrRef::TypeSpec(def) = code { - let mut blob = self.type_spec_signature(def); - return self.type_from_blob_impl(&mut blob, None, generics); - } - - let mut full_name = self.type_def_or_ref(code); - - // TODO: remove this - for (known_name, kind) in CORE_TYPES { - if full_name == known_name { - return kind; - } - } - - // TODO: remove this - for (from, to) in REMAP_TYPES { - if full_name == from { - full_name = to; - break; - } - } - - if let Some(outer) = enclosing { - if full_name.namespace.is_empty() { - let nested = &self.nested[&outer]; - let Some(inner) = nested.get(full_name.name) else { - panic!("Nested type not found: {}.{}", self.type_def_type_name(outer), full_name.name); - }; - return Type::TypeDef(*inner, Vec::new()); - } - } - - if let Some(def) = self.get_type_def(full_name).next() { - Type::TypeDef(def, Vec::new()) - } else { - Type::TypeRef(code) - } - } - - // TODO: this shouldn't be public - pub fn type_from_blob(&self, blob: &mut Blob, enclosing: Option<TypeDef>, generics: &[Type]) -> Type { - // Used by WinRT to indicate that a struct input parameter is passed by reference rather than by value on the ABI. - let is_const = blob.read_modifiers().iter().any(|def| self.type_def_or_ref(*def) == TypeName::IsConst); - - // Used by WinRT to indicate an output parameter, but there are other ways to determine this direction so here - // it is only used to distinguish between slices and heap-allocated arrays. - let is_ref = blob.read_expected(ELEMENT_TYPE_BYREF as usize); - - if blob.read_expected(ELEMENT_TYPE_VOID as usize) { - return Type::Void; - } - - let is_array = blob.read_expected(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array - - let mut pointers = 0; - - while blob.read_expected(ELEMENT_TYPE_PTR as usize) { - pointers += 1; - } - - let kind = self.type_from_blob_impl(blob, enclosing, generics); - - if pointers > 0 { - Type::MutPtr(Box::new(kind), pointers) - } else if is_const { - Type::ConstRef(Box::new(kind)) - } else if is_array { - if is_ref { - Type::WinrtArrayRef(Box::new(kind)) - } else { - Type::WinrtArray(Box::new(kind)) - } - } else { - kind - } - } - - fn type_from_blob_impl(&self, blob: &mut Blob, enclosing: Option<TypeDef>, generics: &[Type]) -> Type { - let code = blob.read_usize(); - - if let Some(code) = Type::from_code(code) { - return code; - } - - match code as u8 { - ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => self.type_from_ref(TypeDefOrRef::decode(blob.file, blob.read_usize()), enclosing, generics), - ELEMENT_TYPE_VAR => generics.get(blob.read_usize()).unwrap_or(&Type::Void).clone(), - ELEMENT_TYPE_ARRAY => { - let kind = self.type_from_blob(blob, enclosing, generics); - let _rank = blob.read_usize(); - let _count = blob.read_usize(); - let bounds = blob.read_usize(); - Type::Win32Array(Box::new(kind), bounds) - } - ELEMENT_TYPE_GENERICINST => { - blob.read_usize(); // ELEMENT_TYPE_VALUETYPE or ELEMENT_TYPE_CLASS - - let type_name = self.type_def_or_ref(TypeDefOrRef::decode(blob.file, blob.read_usize())); - let def = self.get_type_def(type_name).next().unwrap_or_else(|| panic!("Type not found: {}", type_name)); - let mut args = Vec::with_capacity(blob.read_usize()); - - for _ in 0..args.capacity() { - args.push(self.type_from_blob_impl(blob, enclosing, generics)); - } - - Type::TypeDef(def, args) - } - rest => unimplemented!("{rest:?}"), - } - } -} - -impl<'a> RowReader<'a> for Reader<'a> { - fn row_file<R: AsRow>(&self, row: R) -> &'a File { - &self.files[row.to_row().file] +impl MethodDefSig { + pub fn size(&self) -> usize { + self.params.iter().fold(0, |sum, param| sum + std::cmp::max(4, param.size())) } } -fn trim_tick(name: &str) -> &str { - if name.as_bytes().iter().rev().nth(1) == Some(&b'`') { - &name[..name.len() - 2] - } else { - name - } +#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)] +pub enum TypeKind { + Interface, + Class, + Enum, + Struct, + Delegate, } - -// TODO: this should be in riddle's Rust generator if at all - perhaps as convertible types rather than remapped types since there's already some precedent for that. -pub const REMAP_TYPES: [(TypeName, TypeName); 2] = [(TypeName::D2D_MATRIX_3X2_F, TypeName::Matrix3x2), (TypeName::D3DMATRIX, TypeName::Matrix4x4)]; - -// TODO: get rid of at least the second tuple if not the whole thing. -pub const CORE_TYPES: [(TypeName, Type); 11] = [(TypeName::GUID, Type::GUID), (TypeName::IUnknown, Type::IUnknown), (TypeName::HResult, Type::HRESULT), (TypeName::HRESULT, Type::HRESULT), (TypeName::HSTRING, Type::String), (TypeName::BSTR, Type::BSTR), (TypeName::IInspectable, Type::IInspectable), (TypeName::PSTR, Type::PSTR), (TypeName::PWSTR, Type::PWSTR), (TypeName::Type, Type::TypeName), (TypeName::CHAR, Type::U8)]; diff --git a/vendor/windows-metadata/src/reader.rs b/vendor/windows-metadata/src/reader.rs new file mode 100644 index 000000000..3445a7ad2 --- /dev/null +++ b/vendor/windows-metadata/src/reader.rs @@ -0,0 +1,255 @@ +use super::*; + +#[derive(Clone)] +pub enum Item { + Type(TypeDef), + Const(Field), + // TODO: get rid of the trailing String - that's just a hack to get around a silly Win32 metadata deficiency where parsing method signatures + // requires knowing which namespace the method's surrounding interface was defined in. + Fn(MethodDef, &'static str), +} + +pub struct Reader { + // TODO: get rid of inner Vec - that's just a hack to support multi-arch structs in Win32 metadata. + items: BTreeMap<&'static str, BTreeMap<&'static str, Vec<Item>>>, + + // TODO: riddle should just avoid nested structs + nested: HashMap<TypeDef, BTreeMap<&'static str, TypeDef>>, + + // The reader needs to store the filter since standalone code generation needs more than just the filtered items + // in order to chase dependencies automatically. This is why `Reader::filter` can't just filter everything up front. + filter: Filter, +} + +impl Reader { + pub fn new(files: Vec<File>) -> &'static Self { + Self::filter(files, &[], &[]) + } + + pub fn filter(files: Vec<File>, include: &[&str], exclude: &[&str]) -> &'static Self { + let reader: &'static mut Reader = Box::leak(Box::new(Self { items: Default::default(), nested: Default::default(), filter: Filter::new(include, exclude) })); + + for mut file in files { + file.reader = reader as *mut Reader; + let file = Box::leak(Box::new(file)); + + for def in file.table::<TypeDef>() { + let namespace = def.namespace(); + + if namespace.is_empty() { + continue; + } + + let namespace_items = reader.items.entry(namespace).or_default(); + let name = def.name(); + + if name == "Apis" { + for method in def.methods() { + namespace_items.entry(method.name()).or_default().push(Item::Fn(method, namespace)); + } + + for field in def.fields() { + namespace_items.entry(field.name()).or_default().push(Item::Const(field)); + } + } else { + namespace_items.entry(name).or_default().push(Item::Type(def)); + + // TODO: these should all be fields on the Apis class so we don't have to go looking for all of these as well. + if def.extends() == Some(TypeName::Enum) && !def.flags().contains(TypeAttributes::WindowsRuntime) && !def.has_attribute("ScopedEnumAttribute") { + for field in def.fields().filter(|field| field.flags().contains(FieldAttributes::Literal)) { + namespace_items.entry(field.name()).or_default().push(Item::Const(field)); + } + } + } + } + + for key in file.table::<NestedClass>() { + let inner = key.inner(); + reader.nested.entry(key.outer()).or_default().insert(inner.name(), inner); + } + } + + reader + } + + pub fn includes_namespace(&self, namespace: &str) -> bool { + self.filter.includes_namespace(namespace) + } + + pub fn namespaces(&self) -> impl Iterator<Item = &str> + '_ { + self.items.keys().copied() + } + + pub fn items(&self) -> impl Iterator<Item = Item> + '_ { + self.items.iter().filter(move |(namespace, _)| self.filter.includes_namespace(namespace)).flat_map(move |(namespace, items)| items.iter().filter(move |(name, _)| self.filter.includes_type_name(namespace, name))).flat_map(move |(_, items)| items).cloned() + } + + pub fn namespace_items(&self, namespace: &str) -> impl Iterator<Item = Item> + '_ { + self.items.get_key_value(namespace).into_iter().flat_map(move |(namespace, items)| items.iter().filter(move |(name, _)| self.filter.includes_type_name(namespace, name))).flat_map(move |(_, items)| items).cloned() + } + + pub fn unused(&self) -> impl Iterator<Item = &str> + '_ { + self.filter.0.iter().filter_map(|(name, _)| if self.is_unused(name) { Some(name.as_str()) } else { None }) + } + + fn is_unused(&self, filter: &str) -> bool { + // Match namespaces + if self.items.contains_key(filter) { + return false; + } + + // Match type names + if let Some((namespace, name)) = filter.rsplit_once('.') { + if self.items.get(namespace).is_some_and(|items| items.contains_key(name)) { + return false; + } + } + + // Match empty parent namespaces + for namespace in self.items.keys() { + if namespace.len() > filter.len() && namespace.starts_with(filter) && namespace.as_bytes()[filter.len()] == b'.' { + return false; + } + } + + true + } + + fn get_item(&self, namespace: &str, name: &str) -> impl Iterator<Item = Item> + '_ { + if let Some(items) = self.items.get(namespace) { + if let Some(items) = items.get(name) { + return Some(items.iter().cloned()).into_iter().flatten(); + } + } + None.into_iter().flatten() + } + + pub fn get_type_def(&self, namespace: &str, name: &str) -> impl Iterator<Item = TypeDef> + '_ { + self.get_item(namespace, name).filter_map(|item| if let Item::Type(def) = item { Some(def) } else { None }) + } + + pub fn get_method_def(&self, namespace: &str, name: &str) -> impl Iterator<Item = (MethodDef, &'static str)> + '_ { + self.get_item(namespace, name).filter_map(|item| if let Item::Fn(def, namespace) = item { Some((def, namespace)) } else { None }) + } + + pub fn nested_types(&self, type_def: TypeDef) -> impl Iterator<Item = TypeDef> + '_ { + self.nested.get(&type_def).map(|map| map.values().copied()).into_iter().flatten() + } + + pub fn type_from_ref(&self, code: TypeDefOrRef, enclosing: Option<TypeDef>, generics: &[Type]) -> Type { + if let TypeDefOrRef::TypeSpec(def) = code { + let mut blob = def.blob(0); + return self.type_from_blob_impl(&mut blob, None, generics); + } + + let mut full_name = code.type_name(); + + // TODO: remove this + for (known_name, kind) in CORE_TYPES { + if full_name == known_name { + return kind; + } + } + + // TODO: remove this + for (from, to) in REMAP_TYPES { + if full_name == from { + full_name = to; + break; + } + } + + if let Some(outer) = enclosing { + if full_name.namespace.is_empty() { + let nested = &self.nested[&outer]; + let Some(inner) = nested.get(full_name.name) else { + panic!("Nested type not found: {}.{}", outer.type_name(), full_name.name); + }; + return Type::TypeDef(*inner, Vec::new()); + } + } + + if let Some(def) = self.get_type_def(full_name.namespace, full_name.name).next() { + Type::TypeDef(def, Vec::new()) + } else { + Type::TypeRef(full_name) + } + } + + pub fn type_from_blob(&self, blob: &mut Blob, enclosing: Option<TypeDef>, generics: &[Type]) -> Type { + // Used by WinRT to indicate that a struct input parameter is passed by reference rather than by value on the ABI. + let is_const = blob.read_modifiers().iter().any(|def| def.type_name() == TypeName::IsConst); + + // Used by WinRT to indicate an output parameter, but there are other ways to determine this direction so here + // it is only used to distinguish between slices and heap-allocated arrays. + let is_ref = blob.read_expected(ELEMENT_TYPE_BYREF as usize); + + if blob.read_expected(ELEMENT_TYPE_VOID as usize) { + return Type::Void; + } + + let is_array = blob.read_expected(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array + + let mut pointers = 0; + + while blob.read_expected(ELEMENT_TYPE_PTR as usize) { + pointers += 1; + } + + let kind = self.type_from_blob_impl(blob, enclosing, generics); + + if pointers > 0 { + Type::MutPtr(Box::new(kind), pointers) + } else if is_const { + Type::ConstRef(Box::new(kind)) + } else if is_array { + if is_ref { + Type::WinrtArrayRef(Box::new(kind)) + } else { + Type::WinrtArray(Box::new(kind)) + } + } else { + kind + } + } + + fn type_from_blob_impl(&self, blob: &mut Blob, enclosing: Option<TypeDef>, generics: &[Type]) -> Type { + let code = blob.read_usize(); + + if let Some(code) = Type::from_code(code) { + return code; + } + + match code as u8 { + ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => self.type_from_ref(TypeDefOrRef::decode(blob.file, blob.read_usize()), enclosing, generics), + ELEMENT_TYPE_VAR => generics.get(blob.read_usize()).unwrap_or(&Type::Void).clone(), + ELEMENT_TYPE_ARRAY => { + let kind = self.type_from_blob(blob, enclosing, generics); + let _rank = blob.read_usize(); + let _count = blob.read_usize(); + let bounds = blob.read_usize(); + Type::Win32Array(Box::new(kind), bounds) + } + ELEMENT_TYPE_GENERICINST => { + blob.read_usize(); // ELEMENT_TYPE_VALUETYPE or ELEMENT_TYPE_CLASS + + let type_name = TypeDefOrRef::decode(blob.file, blob.read_usize()).type_name(); + let def = self.get_type_def(type_name.namespace, type_name.name).next().unwrap_or_else(|| panic!("Type not found: {}", type_name)); + let mut args = Vec::with_capacity(blob.read_usize()); + + for _ in 0..args.capacity() { + args.push(self.type_from_blob_impl(blob, enclosing, generics)); + } + + Type::TypeDef(def, args) + } + rest => unimplemented!("{rest:?}"), + } + } +} + +// TODO: this should be in riddle's Rust generator if at all - perhaps as convertible types rather than remapped types since there's already some precedent for that. +pub const REMAP_TYPES: [(TypeName, TypeName); 2] = [(TypeName::D2D_MATRIX_3X2_F, TypeName::Matrix3x2), (TypeName::D3DMATRIX, TypeName::Matrix4x4)]; + +// TODO: get rid of at least the second tuple if not the whole thing. +pub const CORE_TYPES: [(TypeName, Type); 11] = [(TypeName::GUID, Type::GUID), (TypeName::IUnknown, Type::IUnknown), (TypeName::HResult, Type::HRESULT), (TypeName::HRESULT, Type::HRESULT), (TypeName::HSTRING, Type::String), (TypeName::BSTR, Type::BSTR), (TypeName::IInspectable, Type::IInspectable), (TypeName::PSTR, Type::PSTR), (TypeName::PWSTR, Type::PWSTR), (TypeName::Type, Type::Type), (TypeName::CHAR, Type::U8)]; diff --git a/vendor/windows-metadata/src/row.rs b/vendor/windows-metadata/src/row.rs index 4e0c30593..4b99f5685 100644 --- a/vendor/windows-metadata/src/row.rs +++ b/vendor/windows-metadata/src/row.rs @@ -1,16 +1,18 @@ -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] +use super::*; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct Row { - pub row: usize, - pub file: usize, + pub file: &'static File, + pub index: usize, } impl Row { - pub fn new(row: usize, file: usize) -> Self { - Self { row, file } + pub fn new(file: &'static File, index: usize) -> Self { + Self { file, index } } fn next(&self) -> Self { - Self { row: self.row + 1, file: self.file } + Self { file: self.file, index: self.index + 1 } } } @@ -19,27 +21,117 @@ pub trait AsRow: Copy { fn to_row(&self) -> Row; fn from_row(row: Row) -> Self; - fn file(&self) -> usize { + fn file(&self) -> &'static File { self.to_row().file } + fn reader(&self) -> &'static Reader { + // Safety: At this point the File is already pointing to a valid Reader. + unsafe { &*self.file().reader } + } + fn index(&self) -> usize { - self.to_row().row + self.to_row().index } fn next(&self) -> Self { Self::from_row(self.to_row().next()) } + + fn usize(&self, column: usize) -> usize { + self.file().usize(self.index(), Self::TABLE, column) + } + + fn str(&self, column: usize) -> &'static str { + let file = self.file(); + let offset = file.strings + self.usize(column); + let bytes = &file.bytes[offset..]; + let nul_pos = bytes.iter().position(|&c| c == 0).expect("expected null-terminated C-string"); + std::str::from_utf8(&bytes[..nul_pos]).expect("expected valid utf-8 C-string") + } + + fn row(&self, column: usize) -> Row { + Row::new(self.file(), self.usize(column) - 1) + } + + fn decode<T: Decode>(&self, column: usize) -> T { + T::decode(self.file(), self.usize(column)) + } + + fn blob(&self, column: usize) -> Blob { + let file = self.file(); + let offset = file.blobs + self.usize(column); + let initial_byte = file.bytes[offset]; + + let (blob_size, blob_size_bytes) = match initial_byte >> 5 { + 0..=3 => (initial_byte & 0x7f, 1), + 4..=5 => (initial_byte & 0x3f, 2), + 6 => (initial_byte & 0x1f, 4), + rest => unimplemented!("{rest:?}"), + }; + + let mut blob_size = blob_size as usize; + + for byte in &file.bytes[offset + 1..offset + blob_size_bytes] { + blob_size = blob_size.checked_shl(8).unwrap_or(0) + (*byte as usize); + } + + let offset = offset + blob_size_bytes; + Blob::new(file, &file.bytes[offset..offset + blob_size]) + } + + fn list<R: AsRow>(&self, column: usize) -> RowIterator<R> { + let file = self.file(); + let first = self.usize(column) - 1; + let next = self.next(); + let last = if next.index() < file.tables[Self::TABLE].len { next.usize(column) - 1 } else { file.tables[R::TABLE].len }; + RowIterator::new(file, first..last) + } + + fn equal_range<L: AsRow>(&self, column: usize, value: usize) -> RowIterator<L> { + let file = self.file(); + let mut first = 0; + let mut last = file.tables[L::TABLE].len; + let mut count = last; + + loop { + if count == 0 { + last = first; + break; + } + + let count2 = count / 2; + let middle = first + count2; + let middle_value = file.usize(middle, L::TABLE, column); + + match middle_value.cmp(&value) { + Ordering::Less => { + first = middle + 1; + count -= count2 + 1; + } + Ordering::Greater => count = count2, + Ordering::Equal => { + let first2 = file.lower_bound_of(L::TABLE, first, middle, column, value); + first += count; + last = file.upper_bound_of(L::TABLE, middle + 1, first, column, value); + first = first2; + break; + } + } + } + + RowIterator::new(file, first..last) + } } pub struct RowIterator<R: AsRow> { - file: usize, + file: &'static File, rows: std::ops::Range<usize>, phantom: std::marker::PhantomData<R>, } impl<R: AsRow> RowIterator<R> { - pub fn new(file: usize, rows: std::ops::Range<usize>) -> Self { + pub fn new(file: &'static File, rows: std::ops::Range<usize>) -> Self { Self { file, rows, phantom: std::marker::PhantomData } } } @@ -48,44 +140,26 @@ impl<R: AsRow> Iterator for RowIterator<R> { type Item = R; fn next(&mut self) -> Option<Self::Item> { - self.rows.next().map(|row| R::from_row(Row::new(row, self.file))) + self.rows.next().map(|row| R::from_row(Row::new(self.file, row))) } } -macro_rules! tables { - ($(($name:ident, $table:literal))+) => { - $( - #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] - pub struct $name(pub(crate) Row); - impl AsRow for $name { - const TABLE: usize = $table; - fn to_row(&self) -> Row { - self.0 - } - fn from_row(row: Row) -> Self { - $name(row) - } - } - )* -}; +pub trait HasAttributes { + fn attributes(&self) -> RowIterator<Attribute>; + fn find_attribute(&self, name: &str) -> Option<Attribute>; + fn has_attribute(&self, name: &str) -> bool; } -tables! { - (Attribute, 1) - (ClassLayout, 16) - (Constant, 0) - (Field, 2) - (GenericParam, 3) - (ImplMap, 11) - (InterfaceImpl, 4) - (MemberRef, 5) - (MethodDef, 6) - (Module, 14) - (ModuleRef, 12) - (AssemblyRef, 15) - (Param, 7) - (TypeDef, 8) - (TypeRef, 9) - (TypeSpec, 10) - (NestedClass, 13) +impl<R: AsRow + Into<HasAttribute>> HasAttributes for R { + fn attributes(&self) -> RowIterator<Attribute> { + self.equal_range(0, Into::<HasAttribute>::into(*self).encode()) + } + + fn find_attribute(&self, name: &str) -> Option<Attribute> { + self.attributes().find(|attribute| attribute.name() == name) + } + + fn has_attribute(&self, name: &str) -> bool { + self.find_attribute(name).is_some() + } } diff --git a/vendor/windows-metadata/src/file/table.rs b/vendor/windows-metadata/src/table.rs index af9599c31..fd34b50b4 100644 --- a/vendor/windows-metadata/src/file/table.rs +++ b/vendor/windows-metadata/src/table.rs @@ -1,3 +1,5 @@ +use super::*; + #[derive(Default)] pub struct Table { pub offset: usize, @@ -6,12 +8,6 @@ pub struct Table { pub columns: [Column; 6], } -#[derive(Default)] -pub struct Column { - pub offset: usize, - pub width: usize, -} - impl Table { pub fn index_width(&self) -> usize { if self.len < (1 << 16) { @@ -49,9 +45,3 @@ impl Table { } } } - -impl Column { - fn new(offset: usize, width: usize) -> Self { - Self { offset, width } - } -} diff --git a/vendor/windows-metadata/src/tables.rs b/vendor/windows-metadata/src/tables.rs new file mode 100644 index 000000000..d7e3ad608 --- /dev/null +++ b/vendor/windows-metadata/src/tables.rs @@ -0,0 +1,420 @@ +use super::*; + +macro_rules! tables { + ($(($name:ident, $table:literal))+) => { + $( + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] + pub struct $name(pub Row); + impl AsRow for $name { + const TABLE: usize = $table; + fn to_row(&self) -> Row { + self.0 + } + fn from_row(row: Row) -> Self { + $name(row) + } + } + )* + }; +} + +tables! { + (AssemblyRef, 15) + (Attribute, 1) + (ClassLayout, 16) + (Constant, 0) + (Field, 2) + (GenericParam, 3) + (ImplMap, 11) + (InterfaceImpl, 4) + (MemberRef, 5) + (MethodDef, 6) + (Module, 14) + (ModuleRef, 12) + (NestedClass, 13) + (Param, 7) + (TypeDef, 8) + (TypeRef, 9) + (TypeSpec, 10) +} + +impl Attribute { + pub fn parent(&self) -> HasAttribute { + self.decode(0) + } + + pub fn ty(&self) -> AttributeType { + self.decode(1) + } + + pub fn name(&self) -> &'static str { + let AttributeType::MemberRef(ctor) = self.ty(); + let MemberRefParent::TypeRef(ty) = ctor.parent(); + ty.name() + } + + pub fn type_name(&self) -> TypeName { + let AttributeType::MemberRef(ctor) = self.ty(); + let MemberRefParent::TypeRef(ty) = ctor.parent(); + ty.type_name() + } + + pub fn args(&self) -> Vec<(&'static str, Value)> { + let AttributeType::MemberRef(member) = self.ty(); + let mut sig = member.blob(2); + let mut values = self.blob(2); + let _prolog = values.read_u16(); + let _this_and_gen_param_count = sig.read_usize(); + let fixed_arg_count = sig.read_usize(); + let _ret_type = sig.read_usize(); + let mut args = Vec::with_capacity(fixed_arg_count); + let reader = self.reader(); + + for _ in 0..fixed_arg_count { + let arg = match reader.type_from_blob(&mut sig, None, &[]) { + Type::Bool => Value::Bool(values.read_bool()), + Type::I8 => Value::I8(values.read_i8()), + Type::U8 => Value::U8(values.read_u8()), + Type::I16 => Value::I16(values.read_i16()), + Type::U16 => Value::U16(values.read_u16()), + Type::I32 => Value::I32(values.read_i32()), + Type::U32 => Value::U32(values.read_u32()), + Type::I64 => Value::I64(values.read_i64()), + Type::U64 => Value::U64(values.read_u64()), + Type::String => Value::String(values.read_str().to_string()), + Type::Type => Value::TypeName(TypeName::parse(values.read_str())), + Type::TypeDef(def, _) => Value::EnumDef(def, Box::new(values.read_integer(def.underlying_type()))), + rest => unimplemented!("{rest:?}"), + }; + + args.push(("", arg)); + } + + let named_arg_count = values.read_u16(); + args.reserve(named_arg_count as usize); + + for _ in 0..named_arg_count { + let _id = values.read_u8(); + let arg_type = values.read_u8(); + let mut name = values.read_str(); + let arg = match arg_type { + ELEMENT_TYPE_BOOLEAN => Value::Bool(values.read_bool()), + ELEMENT_TYPE_I2 => Value::I16(values.read_i16()), + ELEMENT_TYPE_I4 => Value::I32(values.read_i32()), + ELEMENT_TYPE_U4 => Value::U32(values.read_u32()), + ELEMENT_TYPE_STRING => Value::String(values.read_str().to_string()), + 0x50 => Value::TypeName(TypeName::parse(values.read_str())), + 0x55 => { + let type_name = TypeName::parse(name); + let def = reader.get_type_def(type_name.namespace, type_name.name).next().expect("Type not found"); + name = values.read_str(); + Value::EnumDef(def, Box::new(values.read_integer(def.underlying_type()))) + } + rest => unimplemented!("{rest:?}"), + }; + args.push((name, arg)); + } + + debug_assert_eq!(sig.slice.len(), 0); + debug_assert_eq!(values.slice.len(), 0); + + args + } +} + +impl ClassLayout { + pub fn packing_size(&self) -> usize { + self.usize(0) + } +} + +impl Constant { + pub fn ty(&self) -> Type { + Type::from_code(self.usize(0)).expect("Constant type not found") + } + + pub fn value(&self) -> Value { + let mut blob = self.blob(2); + + match self.ty() { + Type::I8 => Value::I8(blob.read_i8()), + Type::U8 => Value::U8(blob.read_u8()), + Type::I16 => Value::I16(blob.read_i16()), + Type::U16 => Value::U16(blob.read_u16()), + Type::I32 => Value::I32(blob.read_i32()), + Type::U32 => Value::U32(blob.read_u32()), + Type::I64 => Value::I64(blob.read_i64()), + Type::U64 => Value::U64(blob.read_u64()), + Type::F32 => Value::F32(blob.read_f32()), + Type::F64 => Value::F64(blob.read_f64()), + Type::String => Value::String(blob.read_string()), + rest => unimplemented!("{rest:?}"), + } + } +} + +impl Field { + pub fn flags(&self) -> FieldAttributes { + FieldAttributes(self.usize(0) as u16) + } + + pub fn name(&self) -> &'static str { + self.str(1) + } + + pub fn constant(&self) -> Option<Constant> { + self.equal_range(1, HasConstant::Field(*self).encode()).next() + } + + // TODO: enclosing craziness is only needed for nested structs - get rid of those in riddle and this goes away. + pub fn ty(&self, enclosing: Option<TypeDef>) -> Type { + let mut blob = self.blob(2); + blob.read_usize(); + blob.read_modifiers(); + let def = self.reader().type_from_blob(&mut blob, enclosing, &[]); + + if self.has_attribute("ConstAttribute") { + def.to_const_type().to_const_ptr() + } else { + def + } + } +} + +impl GenericParam { + pub fn number(&self) -> u16 { + self.usize(0) as u16 + } + + pub fn name(&self) -> &'static str { + self.str(3) + } +} + +impl ImplMap { + pub fn flags(&self) -> PInvokeAttributes { + PInvokeAttributes(self.usize(0)) + } + + pub fn scope(&self) -> ModuleRef { + ModuleRef(self.row(3)) + } + + pub fn import_name(&self) -> &'static str { + self.str(2) + } +} + +impl InterfaceImpl { + pub fn ty(&self, generics: &[Type]) -> Type { + self.reader().type_from_ref(self.decode(1), None, generics) + } +} + +impl MemberRef { + pub fn parent(&self) -> MemberRefParent { + self.decode(0) + } + + pub fn name(&self) -> &'static str { + self.str(1) + } +} + +impl MethodDef { + pub fn impl_flags(&self) -> MethodImplAttributes { + MethodImplAttributes(self.usize(1) as u16) + } + + pub fn flags(&self) -> MethodAttributes { + MethodAttributes(self.usize(2) as u16) + } + + pub fn name(&self) -> &'static str { + self.str(3) + } + + pub fn params(&self) -> RowIterator<Param> { + self.list(5) + } + + pub fn impl_map(&self) -> Option<ImplMap> { + self.equal_range(1, MemberForwarded::MethodDef(*self).encode()).next() + } + + pub fn module_name(&self) -> String { + // TODO: riddle should always lower case the module name to avoid allocating here + let Some(impl_map) = self.impl_map() else { + return String::new(); + }; + + impl_map.scope().name().to_lowercase() + } + + pub fn signature(&self, generics: &[Type]) -> MethodDefSig { + let reader = self.reader(); + let mut blob = self.blob(4); + let call_flags = MethodCallAttributes(blob.read_usize() as u8); + let params = blob.read_usize(); + let return_type = reader.type_from_blob(&mut blob, None, generics); + + MethodDefSig { call_flags, return_type, params: (0..params).map(|_| reader.type_from_blob(&mut blob, None, generics)).collect() } + } +} + +impl ModuleRef { + pub fn name(&self) -> &'static str { + self.str(0) + } +} + +impl NestedClass { + pub fn inner(&self) -> TypeDef { + TypeDef(self.row(0)) + } + + pub fn outer(&self) -> TypeDef { + TypeDef(self.row(1)) + } +} + +impl Param { + pub fn flags(&self) -> ParamAttributes { + ParamAttributes(self.usize(0) as u16) + } + + pub fn sequence(&self) -> u16 { + self.usize(1) as u16 + } + + pub fn name(&self) -> &'static str { + self.str(2) + } +} + +impl TypeDef { + pub fn flags(&self) -> TypeAttributes { + TypeAttributes(self.usize(0) as u32) + } + + pub fn name(&self) -> &'static str { + trim_tick(self.str(1)) + } + + pub fn namespace(&self) -> &'static str { + self.str(2) + } + + pub fn type_name(&self) -> TypeName { + TypeName::new(self.namespace(), self.name()) + } + + pub fn extends(&self) -> Option<TypeName> { + let extends = self.usize(3); + + if extends == 0 { + return None; + } + + Some(TypeDefOrRef::decode(self.file(), extends).type_name()) + } + + pub fn methods(&self) -> RowIterator<MethodDef> { + self.list(5) + } + + pub fn fields(&self) -> RowIterator<Field> { + self.list(4) + } + + pub fn generics(&self) -> RowIterator<GenericParam> { + self.equal_range(2, TypeOrMethodDef::TypeDef(*self).encode()) + } + + pub fn interface_impls(&self) -> RowIterator<InterfaceImpl> { + self.equal_range(0, self.index() + 1) + } + + pub fn enclosing_type(&self) -> Option<TypeDef> { + self.equal_range::<NestedClass>(0, self.index() + 1).next().map(|row| TypeDef(row.row(1))) + } + + pub fn class_layout(&self) -> Option<ClassLayout> { + self.equal_range(2, self.index() + 1).next() + } + + pub fn underlying_type(&self) -> Type { + let field = self.fields().next().expect("Field not found"); + if let Some(constant) = field.constant() { + constant.ty() + } else { + field.ty(Some(*self)) + } + } + + pub fn kind(&self) -> TypeKind { + match self.extends() { + None => TypeKind::Interface, + Some(TypeName::Enum) => TypeKind::Enum, + Some(TypeName::Delegate) => TypeKind::Delegate, + Some(TypeName::Struct) => TypeKind::Struct, + Some(_) => TypeKind::Class, + } + } + + pub fn size(&self) -> usize { + match self.kind() { + TypeKind::Struct => { + if self.flags().contains(TypeAttributes::ExplicitLayout) { + self.fields().map(|field| field.ty(Some(*self)).size()).max().unwrap_or(1) + } else { + let mut sum = 0; + for field in self.fields() { + let ty = field.ty(Some(*self)); + let size = ty.size(); + let align = ty.align(); + sum = (sum + (align - 1)) & !(align - 1); + sum += size; + } + sum + } + } + TypeKind::Enum => self.underlying_type().size(), + _ => 4, + } + } + + pub fn align(&self) -> usize { + match self.kind() { + TypeKind::Struct => self.fields().map(|field| field.ty(Some(*self)).align()).max().unwrap_or(1), + TypeKind::Enum => self.underlying_type().align(), + _ => 4, + } + } +} + +impl TypeRef { + pub fn name(&self) -> &'static str { + trim_tick(self.str(1)) + } + + pub fn namespace(&self) -> &'static str { + self.str(2) + } + + pub fn type_name(&self) -> TypeName { + TypeName::new(self.namespace(), self.name()) + } + + pub fn resolution_scope(&self) -> ResolutionScope { + self.decode(0) + } +} + +fn trim_tick(name: &str) -> &str { + if name.as_bytes().iter().rev().nth(1) == Some(&b'`') { + &name[..name.len() - 2] + } else { + name + } +} diff --git a/vendor/windows-metadata/src/type.rs b/vendor/windows-metadata/src/type.rs index b62faff78..5c2c24eb6 100644 --- a/vendor/windows-metadata/src/type.rs +++ b/vendor/windows-metadata/src/type.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] pub enum Type { // Primitives in ECMA-335 Void, @@ -23,12 +23,10 @@ pub enum Type { GUID, // Both Win32 and WinRT agree that this is represented by System.Guid String, // TODO: Win32 should use System.String when referring to an HSTRING IInspectable, // TODO: Win32 should use System.Object when referring to an IInspectable - - // Meta-type indicating type name in attribute blob. - TypeName, + Type, // System.Type is needed since WinRT attribute use this as a parameter type. // Regular ECMA-335 types that map to metadata - TypeRef(TypeDefOrRef), // Note: this ought to be a TypeName but that would require Type to have a lifetime reference. + TypeRef(TypeName), GenericParam(GenericParam), TypeDef(TypeDef, Vec<Self>), @@ -176,4 +174,29 @@ impl Type { _ => false, } } + + pub fn size(&self) -> usize { + match self { + Type::I8 | Type::U8 => 1, + Type::I16 | Type::U16 => 2, + Type::I64 | Type::U64 | Type::F64 => 8, + Type::GUID => 16, + Type::TypeDef(def, _) => def.size(), + Type::Win32Array(ty, len) => ty.size() * len, + Type::PrimitiveOrEnum(ty, _) => ty.size(), + _ => 4, + } + } + + pub fn align(&self) -> usize { + match self { + Type::I8 | Type::U8 => 1, + Type::I16 | Type::U16 => 2, + Type::I64 | Type::U64 | Type::F64 => 8, + Type::GUID => 4, + Type::TypeDef(def, _) => def.align(), + Type::Win32Array(ty, len) => ty.align() * len, + _ => 4, + } + } } diff --git a/vendor/windows-metadata/src/type_name.rs b/vendor/windows-metadata/src/type_name.rs index 750d58c3e..431e0f3f9 100644 --- a/vendor/windows-metadata/src/type_name.rs +++ b/vendor/windows-metadata/src/type_name.rs @@ -1,12 +1,12 @@ #![allow(non_upper_case_globals)] -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] -pub struct TypeName<'a> { - pub namespace: &'a str, - pub name: &'a str, +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] +pub struct TypeName { + pub namespace: &'static str, + pub name: &'static str, } -impl<'a> TypeName<'a> { +impl TypeName { pub const Enum: Self = Self::from_const("System", "Enum"); pub const Delegate: Self = Self::from_const("System", "MulticastDelegate"); pub const Struct: Self = Self::from_const("System", "ValueType"); @@ -30,7 +30,6 @@ impl<'a> TypeName<'a> { pub const IVectorView: Self = Self::from_const("Windows.Foundation.Collections", "IVectorView"); pub const IVector: Self = Self::from_const("Windows.Foundation.Collections", "IVector"); - pub const NTSTATUS: Self = Self::from_const("Windows.Win32.Foundation", "NTSTATUS"); pub const PWSTR: Self = Self::from_const("Windows.Win32.Foundation", "PWSTR"); pub const PSTR: Self = Self::from_const("Windows.Win32.Foundation", "PSTR"); pub const BSTR: Self = Self::from_const("Windows.Win32.Foundation", "BSTR"); @@ -52,17 +51,17 @@ impl<'a> TypeName<'a> { Self { namespace, name } } - pub fn new(namespace: &'a str, name: &'a str) -> Self { - Self { namespace, name: crate::trim_tick(name) } + pub fn new(namespace: &'static str, name: &'static str) -> Self { + Self { namespace, name } } - pub fn parse(full_name: &'a str) -> Self { + pub fn parse(full_name: &'static str) -> Self { let index = full_name.rfind('.').expect("Expected full name separated with `.`"); - Self { namespace: &full_name[0..index], name: &full_name[index + 1..] } + Self::new(&full_name[0..index], &full_name[index + 1..]) } } -impl<'a> std::fmt::Display for TypeName<'a> { +impl std::fmt::Display for TypeName { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(fmt, "{}.{}", self.namespace, self.name) } |