Struct Blob
pub struct Blob<'a> { /* private fields */ }Expand description
ECMA-335 binary blob heap providing indexed access to variable-length data.
The Blob struct represents the #Blob metadata heap according to ECMA-335 Section II.24.2.4.
It provides safe, zero-copy access to binary data referenced by metadata table entries
such as method signatures, field types, custom attributes, and constant values.
§Blob Heap Properties
§Indexed Access Model
Blobs are accessed by offset rather than sequential iteration:
- Metadata tables store blob heap offsets as indices
- Each offset points to a size-prefixed binary chunk
- Size encoding uses compressed unsigned integers
- Random access enables efficient metadata parsing
§Size Encoding Details
The blob size prefix uses ECMA-335 compressed format:
Format | Size Range | Encoding
-----------------|-------------------|------------------
1-byte | 0-127 bytes | 0bbbbbbb
2-byte | 128-16,383 bytes | 10bbbbbb xxxxxxxx
4-byte | 16,384+ bytes | 110bbbbb xxxxxxxx yyyyyyyy zzzzzzzz§Memory Layout
Offset | Content
-------|------------------
0 | 0x00 (null blob)
1 | Size₁ | Data₁
N | Size₂ | Data₂
M | Size₃ | Data₃§Blob Content Categories
§Signature Blobs
Method, field, and property signatures:
- Calling conventions and parameter information
- Type specifications and generic parameters
- Custom modifiers and constraints
§Custom Attribute Blobs
Constructor arguments and named parameters:
- Primitive arrays and enum values
- Complex nested data structures
- String and object references
§Constant Value Blobs
Default values for fields and parameters:
- Primitive type constants
- String literals and null values
- Binary data for complex constants
§Safety and Error Handling
The Blob struct provides comprehensive safety guarantees:
- Bounds checking for all offset and size calculations
- Validation of compressed size encoding format
- Protection against integer overflow in size calculations
- Graceful handling of truncated or malformed data
§Examples
§Creating and Accessing Blobs
use dotscope::metadata::streams::Blob;
// Create blob heap with sample data
let heap_data = &[
0x00, // Required null blob at offset 0
0x04, 0x01, 0x02, 0x03, 0x04, // 4-byte blob at offset 1
0x02, 0xFF, 0xFE, // 2-byte blob at offset 6
];
let blob_heap = Blob::from(heap_data)?;
// Access specific blobs by offset (as referenced by metadata tables)
let first_blob = blob_heap.get(1)?;
assert_eq!(first_blob, &[0x01, 0x02, 0x03, 0x04]);
let second_blob = blob_heap.get(6)?;
assert_eq!(second_blob, &[0xFF, 0xFE]);§Handling Large Blobs
use dotscope::metadata::streams::Blob;
// Large blob with 2-byte size encoding
let mut heap_data = vec![0x00]; // Null blob
heap_data.push(0x81); // Size: 10000001 (2-byte format)
heap_data.push(0x00); // Size: 00000000 (total = 128)
heap_data.extend(std::iter::repeat(0xAA).take(128)); // 128 bytes of data
let blob_heap = Blob::from(&heap_data)?;
let large_blob = blob_heap.get(1)?;
assert_eq!(large_blob.len(), 128);
assert!(large_blob.iter().all(|&b| b == 0xAA));§Iterating Through All Blobs
use dotscope::metadata::streams::Blob;
let heap_data = &[0x00, 0x03, 0x41, 0x42, 0x43, 0x01, 0x44];
let blob_heap = Blob::from(heap_data)?;
for result in &blob_heap {
let (offset, data) = result?;
println!("Blob at offset {}: {:02X?}", offset, data);
}§ECMA-335 Compliance
This implementation fully supports ECMA-335 requirements:
- Correct handling of all three size encoding formats
- Mandatory null blob at offset 0
- Proper bounds checking and error handling
- Support for maximum blob sizes (up to 2^29 bytes)
§See Also
BlobIterator: For sequential access to all blobscrate::metadata::signatures: For parsing blob content as type signaturescrate::file::parser::Parser: For reading compressed integers- ECMA-335 II.24.2.4: Official specification
Implementations§
§impl<'a> Blob<'a>
impl<'a> Blob<'a>
pub fn from(data: &'a [u8]) -> Result<Blob<'a>>
pub fn from(data: &'a [u8]) -> Result<Blob<'a>>
Creates a new Blob heap accessor from raw metadata bytes.
Validates that the provided data represents a well-formed ECMA-335 #Blob heap
with the required null blob at offset 0. The blob heap stores variable-length
binary data referenced by metadata table entries.
§Parameters
data- Raw bytes containing the complete#Blobheap data
§Returns
A Blob instance providing safe access to the heap contents, or an error
if the data format is invalid.
§Errors
Returns crate::Error in the following cases:
- Empty data: The heap must contain at least one byte
- Missing null blob: First byte must be 0x00 per ECMA-335 requirements
- Invalid format: Data doesn’t conform to blob heap structure
§Examples
§Valid Blob Heap
use dotscope::metadata::streams::Blob;
let valid_data = &[
0x00, // Required null blob at offset 0
0x04, 0x01, 0x02, 0x03, 0x04, // 4-byte blob
0x02, 0xFF, 0xFE, // 2-byte blob
];
let blob_heap = Blob::from(valid_data)?;
assert_eq!(blob_heap.get(1)?, &[0x01, 0x02, 0x03, 0x04]);§Invalid Blob Heap
use dotscope::metadata::streams::Blob;
// Missing required null byte at offset 0
let invalid_data = &[0x01, 0x02, 0x03];
assert!(Blob::from(invalid_data).is_err());
// Empty data
let empty_data = &[];
assert!(Blob::from(empty_data).is_err());§Safety
This method performs minimal validation for performance. Individual blob
access via get provides comprehensive bounds checking.
§See Also
get: Access individual blobs by offsetiter: Iterate over all blobs in the heap- ECMA-335 II.24.2.4: Blob heap specification
pub fn get(&self, index: usize) -> Result<&'a [u8]>
pub fn get(&self, index: usize) -> Result<&'a [u8]>
Retrieves a blob from the heap by its offset.
Returns a zero-copy view of the binary data stored at the specified offset. The offset typically comes from metadata table entries that reference blob heap data such as method signatures, custom attributes, or constant values.
§Parameters
index- Byte offset within the blob heap (from metadata table references)
§Returns
A slice containing the blob data at the specified offset, or an error if the offset is invalid or the blob is malformed.
§Errors
Returns crate::Error in the following cases:
- Out of bounds:
indexexceeds the heap size - Invalid size encoding: Blob size header is malformed
- Truncated data: Blob extends beyond heap boundaries
- Integer overflow: Size calculations exceed platform limits
§Examples
§Basic Blob Access
use dotscope::metadata::streams::Blob;
let data = &[
0x00, // Null blob at offset 0
0x03, 0x41, 0x42, 0x43, // "ABC" at offset 1
0x81, 0x02, // 2-byte size encoding for 258 bytes
// ... 258 bytes of data would follow
];
let blob_heap = Blob::from(&data[..6])?; // Truncated for example
// Access null blob (always empty)
let null_blob = blob_heap.get(0)?;
assert_eq!(null_blob, &[]);
// Access first real blob
let first_blob = blob_heap.get(1)?;
assert_eq!(first_blob, b"ABC");§Error Handling
use dotscope::metadata::streams::Blob;
let data = &[0x00, 0x02, 0x41]; // Blob claims 2 bytes but only 1 available
let blob_heap = Blob::from(data)?;
// This will fail due to truncated data
assert!(blob_heap.get(1).is_err());
// Out of bounds access
assert!(blob_heap.get(100).is_err());§Size Encoding Details
The blob size is encoded using ECMA-335 compressed unsigned integers:
| Encoding | First Byte Pattern | Size Range |
|---|---|---|
| 1-byte | 0bbbbbbb | 0-127 |
| 2-byte | 10bbbbbb | 128-16,383 |
| 4-byte | 110bbbbb | 16,384+ |
§See Also
iter: Iterate over all blobs sequentiallycrate::file::parser::Parser: For compressed integer parsing- ECMA-335 II.23.2: Compressed integer format
pub fn iter(&self) -> BlobIterator<'_> ⓘ
pub fn iter(&self) -> BlobIterator<'_> ⓘ
Returns an iterator over all blobs in the heap.
Provides sequential access to every blob stored in the heap, yielding both the offset and binary data for each entry. This is useful for comprehensive analysis, validation, or debugging of blob heap contents.
§Returns
A BlobIterator that yields Result<(usize, &[u8])> tuples containing:
- Offset: Byte position of the blob within the heap
- Data: Zero-copy slice of the blob’s binary content
§Iteration Behavior
- Sequential access: Blobs returned in heap order (not offset order)
- Skips null blob: Iterator starts at offset 1, skipping the null blob at 0
- Error handling: Returns errors for malformed blobs but continues iteration
- Zero-copy: Each blob is a direct slice reference to heap data
§Examples
§Basic Iteration
use dotscope::metadata::streams::Blob;
let data = &[
0x00, // Null blob (skipped by iterator)
0x03, 0x41, 0x42, 0x43, // "ABC" blob at offset 1
0x02, 0x44, 0x45, // "DE" blob at offset 5
0x00, // Empty blob at offset 8
];
let blob_heap = Blob::from(data)?;
for result in blob_heap.iter() {
let (offset, blob_data) = result?;
println!("Blob at offset {}: {} bytes", offset, blob_data.len());
}§Error Handling During Iteration
use dotscope::metadata::streams::Blob;
let data = &[0x00, 0x05, 0x41, 0x42]; // Claims 5 bytes but only 2 available
let blob_heap = Blob::from(data)?;
for result in blob_heap.iter() {
match result {
Ok((offset, blob_data)) => {
println!("Valid blob at {}: {:02X?}", offset, blob_data);
}
Err(e) => {
eprintln!("Malformed blob: {}", e);
break; // Stop on first error
}
}
}§Collecting All Valid Blobs
use dotscope::metadata::streams::Blob;
let data = &[0x00, 0x02, 0x41, 0x42, 0x01, 0x43];
let blob_heap = Blob::from(data)?;
let blobs: Result<Vec<_>, _> = blob_heap.iter().collect();
let blobs = blobs?;
assert_eq!(blobs.len(), 2);
assert_eq!(blobs[0], (1, &[0x41, 0x42][..]));
assert_eq!(blobs[1], (4, &[0x43][..]));§Error Recovery
If a malformed blob is encountered, the iterator returns an error but can potentially continue with subsequent blobs if the heap structure allows recovery. This design enables partial processing of corrupted metadata.
§See Also
BlobIterator: The iterator implementation detailsget: Direct access to specific blobs by offset- ECMA-335 II.24.2.4: Blob heap specification
Trait Implementations§
Auto Trait Implementations§
impl<'a> Freeze for Blob<'a>
impl<'a> RefUnwindSafe for Blob<'a>
impl<'a> Send for Blob<'a>
impl<'a> Sync for Blob<'a>
impl<'a> Unpin for Blob<'a>
impl<'a> UnwindSafe for Blob<'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