cilium 0.0.0

An experimental Rust library for interfacing with Microsoft's CLI assembly format.
Documentation
use std::io::{Cursor, ErrorKind, Read};
use std::fmt::{Debug, Formatter};
use std::sync::Arc;

pub use crate::raw::heaps::blob::BlobHeap;
pub use crate::raw::heaps::guid::GuidHeap;
pub use crate::raw::heaps::string::{StringHeap, UserStringHeap};

use crate::raw::heaps::table::TableHeap;
use crate::raw::indices::metadata_token;
use crate::raw::indices::sizes::IndexSizes;
use crate::utilities::{FromByteStream, read_string_from_stream_into};

pub mod table;
pub mod guid;
pub mod string;
pub mod blob;

#[derive(Debug)]
pub enum MetadataHeap<'l> {
	Blob(BlobHeap<'l>),
	Guid(GuidHeap<'l>),
	Table(TableHeap<'l>),
	String(StringHeap<'l>),
	UserString(UserStringHeap<'l>),
}

impl<'l> MetadataHeap<'l> {
	#[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
	pub fn read(stream: &mut Cursor<&'l [u8]>, data: &'l [u8]) -> std::io::Result<Arc<Self>> {
		if stream.get_ref().as_ptr() != data.as_ptr() {
			return Err(ErrorKind::InvalidInput.into());
		}

		let offset = u32::read(stream, &())? as usize;
		let size = u32::read(stream, &())? as usize;

		let mut name = [0u8; 32];
		let name = read_string_from_stream_into::<4>(stream, name.as_mut_slice())?;
		let data = &data[offset..offset + size];

		match name {
			"#Blob" => Ok(Arc::new(Self::Blob(BlobHeap::from(data)))),
			"#US" => Ok(Arc::new(Self::UserString(UserStringHeap::from(data)))),
			"#~" => Ok(Arc::new(Self::Table(TableHeap::try_from(data)?))),
			"#GUID" => Ok(Arc::new(Self::Guid(GuidHeap::try_from(data)?))),
			"#Strings" => Ok(Arc::new(Self::String(StringHeap::try_from(data)?))),
			_ => unimplemented!("Unimplemented MetadataHeap kind {:?}", name),
		}
	}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct StringIndex(pub usize);

impl FromByteStream for StringIndex {
	type Deps = IndexSizes;
	fn read(stream: &mut Cursor<&[u8]>, sizes: &Self::Deps) -> std::io::Result<Self> {
		let mut value = 0usize.to_ne_bytes();
		stream.read_exact(&mut value[..sizes.string])?;
		Ok(Self(usize::from_le_bytes(value)))
	}
}

impl From<StringIndex> for metadata_token::String {
	#[inline]
	fn from(value: StringIndex) -> Self {
		Self(value.0)
	}
}

impl From<StringIndex> for metadata_token::MetadataToken {
	#[inline]
	fn from(value: StringIndex) -> Self {
		metadata_token::String(value.0).into()
	}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct BlobIndex(pub usize);

impl FromByteStream for BlobIndex {
	type Deps = IndexSizes;
	fn read(stream: &mut Cursor<&[u8]>, sizes: &Self::Deps) -> std::io::Result<Self> {
		let mut value = 0usize.to_ne_bytes();
		stream.read_exact(&mut value[..sizes.blob])?;
		Ok(Self(usize::from_le_bytes(value)))
	}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct GuidIndex(pub usize);

impl FromByteStream for GuidIndex {
	type Deps = IndexSizes;
	fn read(stream: &mut Cursor<&[u8]>, sizes: &Self::Deps) -> std::io::Result<Self> {
		let mut value = 0usize.to_ne_bytes();
		stream.read_exact(&mut value[..sizes.guid])?;
		Ok(Self(usize::from_le_bytes(value)))
	}
}

pub(crate) struct SizeDebugWrapper(usize);
impl Debug for SizeDebugWrapper {
	#[inline]
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		f.write_str("[u8; ")?;
		Debug::fmt(&self.0, f)?;
		f.write_str("]")
	}
}