diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:25:56 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:25:56 +0000 |
commit | 018c4950b9406055dec02ef0fb52f132e2bb1e2c (patch) | |
tree | a835ebdf2088ef88fa681f8fad45f09922c1ae9a /vendor/windows-metadata/src/lib.rs | |
parent | Adding debian version 1.75.0+dfsg1-5. (diff) | |
download | rustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.tar.xz rustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/windows-metadata/src/lib.rs')
-rw-r--r-- | vendor/windows-metadata/src/lib.rs | 488 |
1 files changed, 69 insertions, 419 deletions
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)]; |