From 018c4950b9406055dec02ef0fb52f132e2bb1e2c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:25:56 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/windows-metadata/src/row.rs | 164 +++++++++++++++++++++++++++---------- 1 file changed, 119 insertions(+), 45 deletions(-) (limited to 'vendor/windows-metadata/src/row.rs') 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(&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(&self, column: usize) -> RowIterator { + 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(&self, column: usize, value: usize) -> RowIterator { + 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 { - file: usize, + file: &'static File, rows: std::ops::Range, phantom: std::marker::PhantomData, } impl RowIterator { - pub fn new(file: usize, rows: std::ops::Range) -> Self { + pub fn new(file: &'static File, rows: std::ops::Range) -> Self { Self { file, rows, phantom: std::marker::PhantomData } } } @@ -48,44 +140,26 @@ impl Iterator for RowIterator { type Item = R; fn next(&mut self) -> Option { - 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; + fn find_attribute(&self, name: &str) -> Option; + 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> HasAttributes for R { + fn attributes(&self) -> RowIterator { + self.equal_range(0, Into::::into(*self).encode()) + } + + fn find_attribute(&self, name: &str) -> Option { + self.attributes().find(|attribute| attribute.name() == name) + } + + fn has_attribute(&self, name: &str) -> bool { + self.find_attribute(name).is_some() + } } -- cgit v1.2.3