dotscope 0.6.0

A high-performance, cross-platform framework for analyzing and reverse engineering .NET PE executables
Documentation
//! # `StandAloneSig` Raw Implementation
//!
//! This module provides the raw variant of `StandAloneSig` table entries with unresolved
//! indexes for initial parsing and memory-efficient storage.

use std::sync::Arc;

use crate::{
    metadata::{
        customattributes::CustomAttributeValueList,
        signatures::{
            parse_field_signature, parse_local_var_signature, parse_method_signature,
            CALLING_CONVENTION, SIGNATURE_HEADER,
        },
        streams::Blob,
        tables::{StandAloneSig, StandAloneSigRc, StandAloneSignature},
        tables::{TableInfoRef, TableRow},
        token::Token,
    },
    Result,
};

/// Raw representation of a `StandAloneSig` table entry from the .NET metadata.
///
/// The `StandAloneSig` table contains standalone signatures that are not directly associated
/// with specific methods, fields, or properties but are referenced from CIL instructions
/// or used in complex signature scenarios. Each entry points to a signature blob that
/// contains the actual signature data.
///
/// ## Metadata Table Information
/// - **Table ID**: `0x11` (17 decimal)
/// - **Token Type**: `0x11000000` + RID
/// - **Purpose**: Stores standalone signatures for various metadata scenarios
///
/// ## Structure Layout
/// The table entry contains a single field that references the signature blob
/// in the metadata blob heap. This indirection enables:
/// - **Signature Reuse**: Multiple references to the same signature blob
/// - **Complex Signatures**: Support for method pointers and local variable signatures
/// - **Dynamic Signatures**: Runtime signature generation and manipulation
///
/// ## Signature Types
/// `StandAloneSig` entries can contain various signature types:
/// - **Method Signatures**: Function pointer signatures with calling conventions
/// - **Local Variable Signatures**: Method local variable type declarations
/// - **Field Signatures**: Standalone field type specifications
/// - **Generic Signatures**: Generic type and method instantiation signatures
///
/// ## See Also
/// - [`StandAloneSig`](crate::metadata::tables::StandAloneSig) - Resolved owned variant
/// - [ECMA-335 §II.22.39](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/) - `StandAloneSig` table specification
#[derive(Clone, Debug)]
pub struct StandAloneSigRaw {
    /// The 1-based row identifier within the `StandAloneSig` table.
    pub rid: u32,

    /// The metadata token for this `StandAloneSig` entry.
    pub token: Token,

    /// The byte offset of this entry within the metadata stream.
    pub offset: usize,

    /// Index into the Blob heap containing the signature data.
    ///
    /// This field points to the signature blob that contains the actual signature
    /// information including calling conventions, parameter types, return types,
    /// and other signature-specific data. The blob format depends on the signature type.
    pub signature: u32,
}

impl StandAloneSigRaw {
    /// Converts this raw `StandAloneSig` entry into an owned representation.
    ///
    /// Creates a fully-owned [`crate::metadata::tables::StandAloneSig`] instance from this raw entry,
    /// parsing the signature blob and resolving all type references within
    /// the signature data.
    ///
    /// The signature type is determined by examining the first byte of the blob:
    /// - `0x07` (`LOCAL_SIG`): Local variable signature
    /// - `0x06` (`FIELD`): Field signature
    /// - `0x00`-`0x05` (with optional `HASTHIS`/`GENERIC` flags): Method signature
    ///
    /// ## Arguments
    ///
    /// * `blob` - The blob heap containing the signature data
    ///
    /// ## Returns
    ///
    /// * `Ok(StandAloneSigRc)` - Successfully converted owned entry
    /// * `Err(_)` - Conversion failed due to invalid signature or missing blob data
    ///
    /// ## Errors
    ///
    /// Returns an error if:
    /// - The signature blob index is invalid
    /// - The signature data is malformed or truncated
    /// - An unknown signature type is encountered
    pub fn to_owned(&self, blob: &Blob) -> Result<StandAloneSigRc> {
        let sig_data = blob.get(self.signature as usize)?;

        if sig_data.is_empty() {
            return Err(malformed_error!(
                "StandAloneSig blob is empty at index {}",
                self.signature
            ));
        }

        let first_byte = sig_data[0];
        let parsed_signature = match first_byte {
            SIGNATURE_HEADER::LOCAL_SIG => {
                let locals = parse_local_var_signature(sig_data)?;
                StandAloneSignature::LocalVariables(locals)
            }
            SIGNATURE_HEADER::FIELD => {
                let field = parse_field_signature(sig_data)?;
                StandAloneSignature::Field(field)
            }
            _ => {
                // Check if this is a method signature by examining calling convention
                // Method signatures have calling convention in low 4 bits (0x00-0x05)
                // with optional HASTHIS (0x20), EXPLICITTHIS (0x40), or GENERIC (0x10) flags
                let calling_conv = first_byte & CALLING_CONVENTION::KIND_MASK;
                if calling_conv <= CALLING_CONVENTION::VARARG {
                    let method = parse_method_signature(sig_data)?;
                    StandAloneSignature::Method(method)
                } else {
                    return Err(malformed_error!(
                        "Unknown StandAloneSig signature type: 0x{:02X}",
                        first_byte
                    ));
                }
            }
        };

        Ok(Arc::new(StandAloneSig {
            rid: self.rid,
            token: self.token,
            offset: self.offset,
            signature: self.signature,
            custom_attributes: CustomAttributeValueList::default(),
            parsed_signature,
        }))
    }

    /// Applies this `StandAloneSig` entry to update related metadata structures.
    ///
    /// `StandAloneSig` entries define standalone signatures that can be referenced
    /// by other metadata elements, but they do not directly modify other metadata
    /// structures during the loading process. The signatures serve as reference
    /// targets for CIL instructions and method definitions.
    ///
    /// ## Returns
    ///
    /// * `Ok(())` - Entry application completed (always succeeds)
    ///
    /// ## Errors
    ///
    /// This function does not currently return an error, but the signature is present for future compatibility.
    pub fn apply(&self) -> Result<()> {
        Ok(())
    }
}

impl TableRow for StandAloneSigRaw {
    /// Calculates the byte size of a `StandAloneSig` table row.
    ///
    /// The row size depends on the blob heap size:
    /// - 2 bytes if blob heap has ≤ 65535 entries
    /// - 4 bytes if blob heap has > 65535 entries
    ///
    /// ## Arguments
    ///
    /// * `sizes` - Table size information for index size calculation
    ///
    /// ## Returns
    ///
    /// The size in bytes required for a single `StandAloneSig` table row
    #[rustfmt::skip]
    fn row_size(sizes: &TableInfoRef) -> u32 {
        u32::from(
            /* signature */ sizes.blob_bytes()
        )
    }
}