use super::{
md::streams::{
tables_stream::{
coded_tokens::{CodedToken, ResolutionScopeToken, TypeDefOrRefToken},
FieldFlags, FieldTableRow, MethodFlags, MethodImplFlags, MethodTableRow,
ModulesTableRow, TypeAttributes, TypeDefTableRow, TypeRefTableRow, ParamTableOffset,
},
Signature,
},
module::{GetEntry, MaybeUninitEntries},
};
use crate::{
error::{HaoError, Result},
io::{EntryReader, ValueReadable},
};
use std::{cell::RefCell, fmt::Debug, rc::Rc};
#[derive(Copy, Clone, Debug)]
pub struct RowRange<T> {
pub start: T,
pub end: Option<T>,
}
impl<T> RowRange<T> {
pub fn new(start: T, end: Option<T>) -> Self {
Self { start, end }
}
}
#[derive(Clone)]
pub struct Ptr<T>(Rc<RefCell<Option<T>>>);
pub(crate) type EntList<T> = Vec<Ptr<T>>;
impl<T: Debug> Debug for Ptr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let v = self.0.as_ref().borrow();
match v.as_ref() {
Some(v) => v.fmt(f),
None => write!(f, "Ptr::new_unset()"),
}
}
}
pub trait ReadEntry<T>: Sized {
type RawRow;
fn from_row(&self, index: usize, row: &Self::RawRow, next_row: Option<&Self::RawRow>) -> Result<T>;
}
impl<T> Ptr<T> {
pub fn new_unset() -> Self {
Self(Rc::new(RefCell::new(None)))
}
pub fn set_value(&self, val: T) {
self.0.replace(Some(val));
}
pub fn value(&self) -> std::cell::Ref<Option<T>> {
self.0.borrow()
}
}
#[derive(Debug, Clone)]
pub struct ModuleDef {
pub generation: u16,
pub name: String,
pub mvid: uuid::Uuid,
pub enc_id: uuid::Uuid,
pub enc_base_id: uuid::Uuid,
}
impl<'a> ReadEntry<ModuleDef> for EntryReader<'a> {
type RawRow = ModulesTableRow;
fn from_row(&self, _: usize, row: &Self::RawRow, _next: Option<&Self::RawRow>) -> Result<ModuleDef> {
Ok(ModuleDef {
generation: self.read(row.generation)?,
name: self.read(row.name)?,
mvid: self.read(row.mvid)?,
enc_id: self.read(row.enc_id)?,
enc_base_id: self.read(row.enc_base_id)?,
})
}
}
#[derive(Debug, Clone)]
pub enum ResolutionScope {
Module(Ptr<ModuleDef>),
NotImplimented,
None,
}
impl<'a> GetEntry<CodedToken<ResolutionScopeToken>> for MaybeUninitEntries {
type EntryValue = ResolutionScope;
fn get_entry(&self, identifier: CodedToken<ResolutionScopeToken>) -> Result<Self::EntryValue> {
let index = match (identifier.rid as usize).checked_sub(1) {
Some(v) => v,
None => return Ok(ResolutionScope::None),
};
let val = match identifier.target {
ResolutionScopeToken::Module => self
.modules
.get(index)
.cloned()
.map(ResolutionScope::Module),
_ => Some(ResolutionScope::NotImplimented),
};
val.ok_or_else(|| HaoError::InvalidCodedTokenOffset(identifier.rid, "ResolutionScopeToken"))
}
}
#[derive(Debug, Clone)]
pub struct TypeRef {
pub resolution_scope: ResolutionScope,
pub name: String,
pub namespace: String,
}
impl<'a> ReadEntry<TypeRef> for EntryReader<'a> {
type RawRow = TypeRefTableRow;
fn from_row(&self, _: usize, row: &Self::RawRow, _next: Option<&Self::RawRow>) -> Result<TypeRef> {
Ok(TypeRef {
resolution_scope: self.read(row.resolution_scope)?,
name: self.read(row.name)?,
namespace: self.read(row.namespace)?,
})
}
}
#[derive(Debug, Clone)]
pub enum TypeDefOrRef {
TypeDef(Ptr<TypeDef>),
TypeRef(Ptr<TypeRef>),
NotImplimented,
None,
}
impl GetEntry<CodedToken<TypeDefOrRefToken>> for MaybeUninitEntries {
type EntryValue = TypeDefOrRef;
fn get_entry(&self, identifier: CodedToken<TypeDefOrRefToken>) -> Result<Self::EntryValue> {
let index = match (identifier.rid as usize).checked_sub(1) {
Some(v) => v,
None => return Ok(TypeDefOrRef::None),
};
let val = match identifier.target {
TypeDefOrRefToken::TypeDef => self
.type_defs
.get(index)
.cloned()
.map(TypeDefOrRef::TypeDef),
TypeDefOrRefToken::TypeRef => self
.type_refs
.get(index)
.cloned()
.map(TypeDefOrRef::TypeRef),
_ => Some(TypeDefOrRef::NotImplimented),
};
val.ok_or_else(|| HaoError::InvalidCodedTokenOffset(identifier.rid, "TypeDefOrRefToken"))
}
}
#[derive(Debug, Clone)]
pub struct TypeDef {
pub flags: TypeAttributes,
pub name: String,
pub namespace: String,
pub extends: TypeDefOrRef,
pub field_list: Vec<Ptr<Field>>,
pub method_list: Vec<Ptr<Method>>,
}
impl<'a> ReadEntry<TypeDef> for EntryReader<'a> {
type RawRow = TypeDefTableRow;
fn from_row(&self, _: usize, row: &Self::RawRow, _next: Option<&Self::RawRow>) -> Result<TypeDef> {
Ok(TypeDef {
flags: row.flags,
name: self.read(row.name)?,
namespace: self.read(row.namespace)?,
extends: self.read(row.extends)?,
field_list: self.read(RowRange::new(row.field_list, _next.map(|x| x.field_list)))?,
method_list: self.read(RowRange::new(row.method_list, _next.map(|x| x.method_list)))?,
})
}
}
#[derive(Debug, Clone)]
pub struct Field {
pub flags: FieldFlags,
pub name: String,
pub signature: Signature,
}
impl<'a> ReadEntry<Field> for EntryReader<'a> {
type RawRow = FieldTableRow;
fn from_row(&self, _: usize, row: &Self::RawRow, _next: Option<&Self::RawRow>) -> Result<Field> {
Ok(Field {
flags: row.flags,
name: self.read(row.name)?,
signature: self.read(row.signature)?,
})
}
}
#[derive(Debug, Clone)]
pub struct Method {
pub rva: u32,
pub impl_flags: MethodImplFlags,
pub flags: MethodFlags,
pub name: String,
pub signature: Signature,
pub param_list: ParamTableOffset,
}
impl<'a> ReadEntry<Method> for EntryReader<'a> {
type RawRow = MethodTableRow;
fn from_row(&self, _: usize, row: &Self::RawRow, _next: Option<&Self::RawRow>) -> Result<Method> {
Ok(Method {
rva: row.rva,
impl_flags: row.impl_flags,
flags: row.flags,
name: self.read(row.name)?,
signature: self.read(row.signature)?,
param_list: row.param_list
})
}
}