Struct TablesHeader
pub struct TablesHeader<'a> {
pub major_version: u8,
pub minor_version: u8,
pub valid: u64,
pub sorted: u64,
pub info: TableInfoRef,
/* private fields */
}Expand description
The TablesHeader structure represents the header in the ‘#’ stream. ‘#’ which contains all the metadata used
for reflection and execution of the CIL binary.
This structure provides efficient access to metadata tables, allowing reference-based parsing and traversal of .NET assemblies without loading the entire metadata into memory at once.
§Efficient Table Access Examples
§Basic Table Access
use dotscope::metadata::streams::{TablesHeader, TableId, TypeDefRaw, MethodDefRaw, FieldRaw};
// Check if a table is present before accessing it
if tables_header.has_table(TableId::TypeDef) {
// Get efficient access to the TypeDef table
if let Some(typedef_table) = tables_header.table::<TypeDefRaw>(TableId::TypeDef) {
println!("TypeDef table has {} rows", typedef_table.row_count());
// Access individual rows by index (0-based)
if let Some(first_type) = typedef_table.get(0) {
println!("First type: flags={}, name_idx={}, namespace_idx={}",
first_type.flags, first_type.type_name, first_type.type_namespace);
}
}
}§Iterating Over Table Rows
use dotscope::metadata::streams::{TablesHeader, TableId, MethodDefRaw};
// Iterate over all methods in the assembly
if let Some(method_table) = tables_header.table::<MethodDefRaw>(TableId::MethodDef) {
for (index, method) in method_table.iter().enumerate() {
println!("Method {}: RVA={:#x}, impl_flags={}, flags={}, name_idx={}",
index, method.rva, method.impl_flags, method.flags, method.name);
// Break after first 10 for demonstration
if index >= 9 { break; }
}
}§Parallel Processing with Rayon
use dotscope::metadata::streams::{TablesHeader, TableId, FieldRaw};
use rayon::prelude::*;
// Process field metadata in parallel
if let Some(field_table) = tables_header.table::<FieldRaw>(TableId::Field) {
let field_count = field_table.par_iter()
.filter(|field| field.flags & 0x0010 != 0) // FieldAttributes.Static
.count();
println!("Found {} static fields", field_count);
}§Cross-Table Analysis
use dotscope::metadata::streams::{TablesHeader, TableId, TypeDefRaw, MethodDefRaw};
// Analyze types and their methods together
if let (Some(typedef_table), Some(method_table)) = (
tables_header.table::<TypeDefRaw>(TableId::TypeDef),
tables_header.table::<MethodDefRaw>(TableId::MethodDef)
) {
for (type_idx, type_def) in typedef_table.iter().enumerate().take(5) {
println!("Type {}: methods {}-{}",
type_idx, type_def.method_list,
type_def.method_list.saturating_add(10)); // Simplified example
// In real usage, you'd calculate the actual method range
// by looking at the next type's method_list or using table bounds
}
}§Working with Table Summaries
use dotscope::metadata::streams::TablesHeader;
// Get overview of all present tables
let summaries = tables_header.table_summary();
for summary in summaries {
println!("Table {:?}: {} rows", summary.table_id, summary.row_count);
}
// Check for specific tables by ID
if tables_header.has_table_by_id(0x02) { // TypeDef table ID
println!("TypeDef table is present");
}
println!("Total metadata tables: {}", tables_header.table_count());§Memory-Efficient Pattern
use dotscope::metadata::streams::{TablesHeader, TableId, CustomAttributeRaw};
// Process large tables without loading all data at once
if let Some(ca_table) = tables_header.table::<CustomAttributeRaw>(TableId::CustomAttribute) {
println!("Processing {} custom attributes", ca_table.row_count());
// Process in chunks to manage memory usage
const CHUNK_SIZE: u32 = 100;
let total_rows = ca_table.row_count();
for chunk_start in (0..total_rows).step_by(CHUNK_SIZE as usize) {
let chunk_end = (chunk_start + CHUNK_SIZE).min(total_rows);
for i in chunk_start..chunk_end {
if let Some(attr) = ca_table.get(i) {
// Process individual custom attribute
// attr.parent, attr.type_def, attr.value are available
// without copying the entire table into memory
}
}
// Optional: yield control or log progress
println!("Processed chunk {}-{}", chunk_start, chunk_end);
}
}§Performance Notes
- All table access uses reference-based parsing - no data is duplicated in memory
- Row access via
get()and iteration is lazy - rows are parsed only when requested - Parallel iteration with
par_iter()can significantly speed up processing of large tables - The lifetime parameter
'aensures memory safety by tying table references to the original data
§Reference
- ‘https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf’ - II.24.2.6 && II.22
Fields§
§major_version: u8Major version of table schemeta, shall be 2
minor_version: u8Minor version of table schemata, shall be 0
valid: u64Bit vector of present tables, let n be the number of bits that are 1.
sorted: u64Bit vector of sorted tables
info: TableInfoRefInformation about specific tables, e.g their row count, and their reference index sizes
Implementations§
§impl<'a> TablesHeader<'a>
impl<'a> TablesHeader<'a>
pub fn from(data: &'a [u8]) -> Result<TablesHeader<'a>>
pub fn from(data: &'a [u8]) -> Result<TablesHeader<'a>>
pub fn table_count(&self) -> u32
pub fn table_count(&self) -> u32
Get the table count
pub fn table<T: RowDefinition<'a>>(
&self,
table_id: TableId,
) -> Option<&'a MetadataTable<'a, T>>
pub fn table<T: RowDefinition<'a>>( &self, table_id: TableId, ) -> Option<&'a MetadataTable<'a, T>>
Get a specific table for efficient access
This method provides type-safe access to metadata tables without copying data. The returned table reference allows efficient iteration and random access to rows.
§Arguments
table_id- The type of table to lookup
§Returns
Some(&MetadataTable<T>)- Reference to the table if presentNone- If the table is not present in this assembly
§Example
use dotscope::metadata::streams::{TablesHeader, TableId, TypeDefRaw};
// Safe access with type checking
if let Some(typedef_table) = tables.table::<TypeDefRaw>(TableId::TypeDef) {
// Efficient access to all type definitions
for type_def in typedef_table.iter().take(5) {
println!("Type: flags={:#x}, name_idx={}, namespace_idx={}",
type_def.flags, type_def.type_name, type_def.type_namespace);
}
// Random access to specific rows
if let Some(first_type) = typedef_table.get(0) {
println!("First type name index: {}", first_type.type_name);
}
}§Safety Note
The generic type parameter T must match the table type for table_id.
Using the wrong type will result in undefined behavior due to the internal cast.
Always use the corresponding *Raw types:
TableId::TypeDef→TypeDefRawTableId::MethodDef→MethodDefRawTableId::Field→FieldRaw- etc.
pub fn has_table(&self, table_id: TableId) -> bool
pub fn has_table(&self, table_id: TableId) -> bool
Check if a specific table is present
Use this method to safely check for table presence before accessing it. This avoids potential panics when working with assemblies that may not contain all possible metadata tables.
§Arguments
table_id- The table ID to check for presence
§Example
use dotscope::metadata::streams::{TablesHeader, TableId, EventRaw};
// Safe pattern: check before access
if tables.has_table(TableId::Event) {
if let Some(event_table) = tables.table::<EventRaw>(TableId::Event) {
println!("Assembly has {} events", event_table.row_count());
}
} else {
println!("No events defined in this assembly");
}pub fn has_table_by_id(&self, table_id: u8) -> bool
pub fn has_table_by_id(&self, table_id: u8) -> bool
Check if a table is present by its numeric ID
This method provides a way to check for table presence using the raw numeric table identifiers (0-63) as defined in the ECMA-335 specification.
§Arguments
table_id- The numeric table ID (0-63) to check for presence
§Returns
true- If the table is presentfalse- If the table is not present ortable_id> 63
§Example
use dotscope::metadata::streams::TablesHeader;
// Check for specific tables by their numeric IDs
if tables.has_table_by_id(0x02) { // TypeDef
println!("TypeDef table present");
}
if tables.has_table_by_id(0x06) { // MethodDef
println!("MethodDef table present");
}
if tables.has_table_by_id(0x04) { // Field
println!("Field table present");
}pub fn present_tables(&self) -> impl Iterator<Item = TableId> + '_
pub fn present_tables(&self) -> impl Iterator<Item = TableId> + '_
Get an iterator over all present tables
This method returns an iterator that yields TableId values for all tables
that are present in this assembly’s metadata. Useful for discovering what
metadata is available without having to check each table individually.
§Example
use dotscope::metadata::streams::TablesHeader;
println!("Present metadata tables:");
for table_id in tables.present_tables() {
let row_count = tables.table_row_count(table_id);
println!(" {:?}: {} rows", table_id, row_count);
}pub fn table_row_count(&self, table_id: TableId) -> u32
pub fn table_row_count(&self, table_id: TableId) -> u32
Get the row count for a specific table
Returns the number of rows in the specified table. This information is available even if you don’t access the table data itself.
§Arguments
table_id- The table to get the row count for
§Returns
- Row count (0 if table is not present)
§Example
use dotscope::metadata::streams::{TablesHeader, TableId};
let type_count = tables.table_row_count(TableId::TypeDef);
let method_count = tables.table_row_count(TableId::MethodDef);
let field_count = tables.table_row_count(TableId::Field);
println!("Assembly contains:");
println!(" {} types", type_count);
println!(" {} methods", method_count);
println!(" {} fields", field_count);pub fn table_summary(&self) -> Vec<TableSummary>
pub fn table_summary(&self) -> Vec<TableSummary>
Get a summary of all present tables with their row counts
Auto Trait Implementations§
impl<'a> Freeze for TablesHeader<'a>
impl<'a> RefUnwindSafe for TablesHeader<'a>
impl<'a> Send for TablesHeader<'a>
impl<'a> Sync for TablesHeader<'a>
impl<'a> Unpin for TablesHeader<'a>
impl<'a> UnwindSafe for TablesHeader<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more