use common::*;
use super::constants::*;
use super::primitive::*;
#[derive(Debug,Clone,PartialEq,Eq)]
pub enum TypeData<'t> {
Primitive(PrimitiveType),
Class(ClassType<'t>),
Member(MemberType<'t>),
MemberFunction(MemberFunctionType),
OverloadedMethod(OverloadedMethodType<'t>),
Method(MethodType<'t>),
StaticMember(StaticMemberType<'t>),
Nested(NestedType<'t>),
BaseClass(BaseClassType),
VirtualBaseClass(VirtualBaseClassType),
VirtualFunctionTablePointer(VirtualFunctionTablePointerType),
Procedure(ProcedureType),
Pointer(PointerType),
Modifier(ModifierType),
Enumeration(EnumerationType<'t>),
Enumerate(EnumerateType<'t>),
Array(ArrayType),
Union(UnionType<'t>),
Bitfield(BitfieldType),
FieldList(FieldList<'t>),
ArgumentList(ArgumentList),
MethodList(MethodList),
}
impl<'t> TypeData<'t> {
pub fn name(&self) -> Option<RawString<'t>> {
let name = match *self {
TypeData::Class(ClassType { ref name, .. }) |
TypeData::Member(MemberType { ref name, .. }) |
TypeData::OverloadedMethod(OverloadedMethodType { ref name, .. }) |
TypeData::StaticMember(StaticMemberType { ref name, .. }) |
TypeData::Nested(NestedType { ref name, .. }) |
TypeData::Enumeration(EnumerationType { ref name, .. }) |
TypeData::Enumerate(EnumerateType { ref name, .. }) |
TypeData::Union(UnionType { ref name, .. }) => name,
_ => { return None }
};
Some(name.clone())
}
}
pub(crate) fn parse_type_data<'t>(mut buf: &mut ParseBuffer<'t>) -> Result<TypeData<'t>> {
let leaf = buf.parse_u16()?;
match leaf {
LF_CLASS | LF_CLASS_ST |
LF_STRUCTURE | LF_STRUCTURE_ST |
LF_INTERFACE => {
Ok(TypeData::Class(ClassType {
kind: match leaf {
LF_CLASS | LF_CLASS_ST => ClassKind::Class,
LF_STRUCTURE | LF_STRUCTURE_ST => ClassKind::Struct,
LF_INTERFACE => ClassKind::Interface,
_ => unreachable!()
},
count: buf.parse_u16()?,
properties: TypeProperties(buf.parse_u16()?),
fields: parse_optional_type_index(&mut buf)?,
derived_from: parse_optional_type_index(&mut buf)?,
vtable_shape: parse_optional_type_index(&mut buf)?,
size: parse_unsigned(&mut buf)? as u16,
name: parse_string(leaf, buf)?,
}))
},
LF_MEMBER | LF_MEMBER_ST => {
Ok(TypeData::Member(MemberType {
attributes: FieldAttributes(buf.parse_u16()?),
field_type: buf.parse_u32()? as TypeIndex,
offset: parse_unsigned(&mut buf)? as u16,
name: parse_string(leaf, &mut buf)?,
}))
},
LF_NESTTYPE | LF_NESTTYPE_ST |
LF_NESTTYPEEX | LF_NESTTYPEEX_ST => {
let raw_attr = match leaf {
LF_NESTTYPEEX | LF_NESTTYPEEX_ST => {
buf.parse_u16()?
}
_ => {
buf.parse_u16()?;
0
}
};
Ok(TypeData::Nested(NestedType {
attributes: FieldAttributes(raw_attr),
nested_type: buf.parse_u32()? as TypeIndex,
name: parse_string(leaf, &mut buf)?,
}))
},
LF_MFUNCTION => {
Ok(TypeData::MemberFunction(MemberFunctionType {
return_type: buf.parse_u32()? as TypeIndex,
class_type: buf.parse_u32()? as TypeIndex,
this_pointer_type: parse_optional_type_index(&mut buf)?,
attributes: FunctionAttributes(buf.parse_u16()?),
parameter_count: buf.parse_u16()?,
argument_list: buf.parse_u32()? as TypeIndex,
this_adjustment: buf.parse_u32()?,
}))
}
LF_METHOD | LF_METHOD_ST => {
Ok(TypeData::OverloadedMethod(OverloadedMethodType {
count: buf.parse_u16()?,
method_list: buf.parse_u32()? as TypeIndex,
name: parse_string(leaf, &mut buf)?,
}))
},
LF_ONEMETHOD | LF_ONEMETHOD_ST => {
let attr = FieldAttributes(buf.parse_u16()?);
Ok(TypeData::Method(MethodType {
attributes: attr,
method_type: buf.parse_u32()? as TypeIndex,
vtable_offset: if attr.is_intro_virtual() {
Some(buf.parse_u32()? as u32)
} else {
None
},
name: parse_string(leaf, &mut buf)?,
}))
},
LF_BCLASS | LF_BINTERFACE => {
Ok(TypeData::BaseClass(BaseClassType {
kind: match leaf {
LF_BCLASS => ClassKind::Class,
LF_BINTERFACE => ClassKind::Interface,
_ => unreachable!(),
},
attributes: FieldAttributes(buf.parse_u16()?),
base_class: buf.parse_u32()? as TypeIndex,
offset: parse_unsigned(&mut buf)? as u32,
}))
},
LF_VFUNCTAB => {
buf.parse_u16()?;
Ok(TypeData::VirtualFunctionTablePointer(VirtualFunctionTablePointerType {
table: buf.parse_u32()? as TypeIndex,
}))
},
LF_STMEMBER | LF_STMEMBER_ST => {
Ok(TypeData::StaticMember(StaticMemberType {
attributes: FieldAttributes(buf.parse_u16()?),
field_type: buf.parse_u32()? as TypeIndex,
name: parse_string(leaf, &mut buf)?,
}))
},
LF_POINTER => {
Ok(TypeData::Pointer(PointerType {
underlying_type: buf.parse_u32()? as TypeIndex,
attributes: PointerAttributes(buf.parse_u32()?),
}))
},
LF_PROCEDURE => {
Ok(TypeData::Procedure(ProcedureType {
return_type: parse_optional_type_index(&mut buf)?,
attributes: FunctionAttributes(buf.parse_u16()?),
parameter_count: buf.parse_u16()?,
argument_list: buf.parse_u32()? as TypeIndex,
}))
},
LF_MODIFIER => {
let type_index = buf.parse_u32()? as TypeIndex;
let flags = buf.parse_u16()?;
Ok(TypeData::Modifier(ModifierType {
underlying_type: type_index,
constant: (flags & 0x01) != 0,
volatile: (flags & 0x02) != 0,
unaligned: (flags & 0x04) != 0,
}))
},
LF_ENUM | LF_ENUM_ST => {
Ok(TypeData::Enumeration(EnumerationType {
count: buf.parse_u16()?,
properties: TypeProperties(buf.parse_u16()?),
underlying_type: buf.parse_u32()? as TypeIndex,
fields: buf.parse_u32()? as TypeIndex,
name: parse_string(leaf, &mut buf)?,
}))
},
LF_ENUMERATE | LF_ENUMERATE_ST => {
Ok(TypeData::Enumerate(EnumerateType {
attributes: FieldAttributes(buf.parse_u16()?),
value: buf.parse_variant()?,
name: parse_string(leaf, &mut buf)?,
}))
}
LF_ARRAY | LF_ARRAY_ST | LF_STRIDED_ARRAY => {
let element_type = buf.parse_u32()? as TypeIndex;
let indexing_type = buf.parse_u32()? as TypeIndex;
let stride: Option<u32> = if leaf == LF_STRIDED_ARRAY {
Some(buf.parse_u32()?)
} else {
None
};
let mut dimensions: Vec<u32> = Vec::new();
loop {
let dim = parse_unsigned(&mut buf)?;
if dim > u32::max_value() as u64 {
return Err(Error::UnimplementedFeature("u64 array sizes"));
}
dimensions.push(dim as u32);
if buf.len() == 0 {
return Err(Error::UnexpectedEof);
}
if buf.peek_u8()? == 0x00 {
buf.parse_u8()?;
break
}
}
parse_padding(&mut buf)?;
assert!(buf.len() == 0);
Ok(TypeData::Array(ArrayType {
element_type: element_type,
indexing_type: indexing_type,
stride: stride,
dimensions: dimensions,
}))
}
LF_UNION | LF_UNION_ST => {
Ok(TypeData::Union(UnionType {
count: buf.parse_u16()?,
properties: TypeProperties(buf.parse_u16()?),
fields: buf.parse_u32()? as TypeIndex,
size: parse_unsigned(&mut buf)? as u32,
name: parse_string(leaf, &mut buf)?,
}))
},
LF_BITFIELD => {
Ok(TypeData::Bitfield(BitfieldType {
underlying_type: buf.parse_u32()? as TypeIndex,
length: buf.parse_u8()?,
position: buf.parse_u8()?,
}))
},
LF_VTSHAPE => {
Err(Error::UnimplementedTypeKind(leaf))
},
LF_VFTABLE => {
Err(Error::UnimplementedTypeKind(leaf))
}
LF_VBCLASS | LF_IVBCLASS => {
Ok(TypeData::VirtualBaseClass(VirtualBaseClassType {
direct: leaf == LF_VBCLASS,
attributes: FieldAttributes(buf.parse_u16()?),
base_class: buf.parse_u32()? as TypeIndex,
base_pointer: buf.parse_u32()? as TypeIndex,
base_pointer_offset: parse_unsigned(&mut buf)? as u32,
virtual_base_offset: parse_unsigned(&mut buf)? as u32,
}))
},
LF_FIELDLIST => {
let mut fields: Vec<TypeData<'t>> = Vec::new();
let mut continuation: Option<TypeIndex> = None;
while buf.len() > 0 {
match buf.peek_u16()? {
LF_INDEX => {
buf.parse_u16()?;
continuation = Some(buf.parse_u32()? as TypeIndex);
}
_ => {
fields.push(parse_type_data(&mut buf)?);
}
}
parse_padding(&mut buf)?;
}
Ok(TypeData::FieldList(FieldList { fields: fields, continuation: continuation }))
},
LF_ARGLIST => {
let count = buf.parse_u32()?;
let mut arglist: Vec<TypeIndex> = Vec::with_capacity(count as usize);
for _ in 0..count {
arglist.push(buf.parse_u32()? as TypeIndex);
}
Ok(TypeData::ArgumentList(ArgumentList {
arguments: arglist,
}))
},
LF_METHODLIST => {
let mut methods: Vec<MethodListEntry> = Vec::new();
while buf.len() > 0 {
let attr = FieldAttributes(buf.parse_u16()?);
buf.parse_u16()?;
methods.push(MethodListEntry {
attributes: attr,
method_type: buf.parse_u32()?,
vtable_offset: if attr.is_intro_virtual() {
Some(buf.parse_u32()?)
} else {
None
},
});
}
Ok(TypeData::MethodList(MethodList {
methods: methods,
}))
},
_ => Err(Error::UnimplementedTypeKind(leaf)),
}
}
#[inline]
fn parse_optional_type_index<'t>(buf: &mut ParseBuffer<'t>) -> Result<Option<TypeIndex>> {
let index = buf.parse_u32()? as TypeIndex;
if index == 0 || index == 0xffff {
Ok(None)
} else {
Ok(Some(index))
}
}
#[inline]
fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>> {
if leaf > LF_ST_MAX {
buf.parse_cstring()
} else {
buf.parse_u8_pascal_string()
}
}
#[inline]
fn parse_padding<'t>(buf: &mut ParseBuffer<'t>) -> Result<()> {
while buf.len() > 0 && buf.peek_u8()? >= 0xf0 {
let padding = buf.parse_u8()?;
if padding > 0xf0 {
buf.take((padding & 0x0f) as usize - 1)?;
}
}
Ok(())
}
fn parse_unsigned<'t>(buf: &mut ParseBuffer<'t>) -> Result<u64> {
let leaf = buf.parse_u16()?;
if leaf < LF_NUMERIC {
return Ok(leaf as u64);
}
match leaf {
LF_CHAR => { Ok(buf.parse_u8()? as u64) },
LF_USHORT => { Ok(buf.parse_u16()? as u64) },
LF_ULONG => { Ok(buf.parse_u32()? as u64) },
LF_UQUADWORD => { Ok(buf.parse_u64()? as u64) },
_ => {
debug_assert!(false);
Err(Error::UnexpectedNumericPrefix(leaf))
}
}
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct TypeProperties(u16);
impl TypeProperties {
pub fn packed(&self) -> bool { self.0 & 0x0001 != 0 }
pub fn constructors(&self) -> bool { self.0 & 0x0002 != 0 }
pub fn overloaded_operators(&self) -> bool { self.0 & 0x0004 != 0 }
pub fn is_nested_type(&self) -> bool { self.0 & 0x0008 != 0 }
pub fn contains_nested_types(&self) -> bool { self.0 & 0x0010 != 0 }
pub fn overloaded_assignment(&self) -> bool { self.0 & 0x0020 != 0 }
pub fn overloaded_casting(&self) -> bool { self.0 & 0x0040 != 0 }
pub fn forward_reference(&self) -> bool { self.0 & 0x0080 != 0 }
pub fn scoped_definition(&self) -> bool { self.0 & 0x0100 != 0 }
pub fn has_unique_name(&self) -> bool { self.0 & 0x0200 != 0 }
pub fn sealed(&self) -> bool { self.0 & 0x0400 != 0 }
pub fn hfa(&self) -> u8 { ((self.0 & 0x1800) >> 11) as u8 }
pub fn intrinsic_type(&self) -> bool { self.0 & 0x1000 != 0 }
pub fn mocom(&self) -> u8 { ((self.0 & 0x6000) >> 14) as u8 }
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct FieldAttributes(u16);
impl FieldAttributes {
#[inline]
pub fn access(&self) -> u8 { (self.0 & 0x0003) as u8 }
#[inline]
fn method_properties(&self) -> u8 { ((self.0 & 0x001c) >> 2) as u8 }
#[inline]
pub fn is_static(&self) -> bool {
self.method_properties() == 0x02
}
#[inline]
pub fn is_virtual(&self) -> bool {
self.method_properties() == 0x01
}
#[inline]
pub fn is_pure_virtual(&self) -> bool {
self.method_properties() == 0x05
}
#[inline]
pub fn is_intro_virtual(&self) -> bool {
match self.method_properties() {
0x04 | 0x06 => true,
_ => false,
}
}
}
#[allow(dead_code)]
#[repr(u8)]
enum Access {
None = 0x00,
Private = 0x01,
Protected = 0x02,
Public = 0x03,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct FunctionAttributes(u16);
impl FunctionAttributes {
pub fn calling_convention(&self) -> u8 { (self.0 & 0xff) as u8 }
pub fn cxx_return_udt(&self) -> bool { (self.0 & 0x0100) > 0 }
pub fn is_constructor(&self) -> bool { (self.0 & 0x0200) > 0 }
pub fn is_constructor_with_virtual_bases(&self) -> bool { (self.0 & 0x0400) > 0 }
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct PointerAttributes(u32);
impl PointerAttributes {
pub fn pointer_type(&self) -> u8 {
(self.0 & 0x1f) as u8
}
pub fn is_const(&self) -> bool { (self.0 & 0x40) != 0 }
pub fn is_reference(&self) -> bool {
match (self.0 >> 5) & 0x07 {
0x01 | 0x04 => true,
_ => false,
}
}
pub fn size(&self) -> u8 {
let size = ((self.0 >> 13) & 0x3f) as u8;
if size != 0 {
return size;
}
match self.pointer_type() {
0x0a => 4,
0x0c => 8,
_ => 0
}
}
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct ClassType<'t> {
pub kind: ClassKind,
pub count: u16,
pub properties: TypeProperties,
pub fields: Option<TypeIndex>,
pub derived_from: Option<TypeIndex>,
pub vtable_shape: Option<TypeIndex>,
pub size: u16,
pub name: RawString<'t>,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum ClassKind { Class, Struct, Interface }
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct MemberType<'t> {
pub attributes: FieldAttributes,
pub field_type: TypeIndex,
pub offset: u16,
pub name: RawString<'t>,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct MemberFunctionType {
pub return_type: TypeIndex,
pub class_type: TypeIndex,
pub this_pointer_type: Option<TypeIndex>,
pub attributes: FunctionAttributes,
pub parameter_count: u16,
pub argument_list: TypeIndex,
pub this_adjustment: u32,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct OverloadedMethodType<'t> {
pub count: u16,
pub method_list: TypeIndex,
pub name: RawString<'t>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct MethodType<'t> {
pub attributes: FieldAttributes,
pub method_type: TypeIndex,
pub vtable_offset: Option<u32>,
pub name: RawString<'t>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct StaticMemberType<'t> {
pub attributes: FieldAttributes,
pub field_type: TypeIndex,
pub name: RawString<'t>
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct NestedType<'t> {
pub attributes: FieldAttributes,
pub nested_type: TypeIndex,
pub name: RawString<'t>,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct BaseClassType {
pub kind: ClassKind,
pub attributes: FieldAttributes,
pub base_class: TypeIndex,
pub offset: u32,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct VirtualBaseClassType {
pub direct: bool,
pub attributes: FieldAttributes,
pub base_class: TypeIndex,
pub base_pointer: TypeIndex,
pub base_pointer_offset: u32,
pub virtual_base_offset: u32,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct VirtualFunctionTablePointerType {
pub table: TypeIndex
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct ProcedureType {
pub return_type: Option<TypeIndex>,
pub attributes: FunctionAttributes,
pub parameter_count: u16,
pub argument_list: TypeIndex,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct PointerType {
pub underlying_type: TypeIndex,
pub attributes: PointerAttributes,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct ModifierType {
pub underlying_type: TypeIndex,
pub constant: bool,
pub volatile: bool,
pub unaligned: bool,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct EnumerationType<'t> {
pub count: u16,
pub properties: TypeProperties,
pub underlying_type: TypeIndex,
pub fields: TypeIndex,
pub name: RawString<'t>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct EnumerateType<'t> {
pub attributes: FieldAttributes,
pub value: Variant,
pub name: RawString<'t>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct ArrayType {
pub element_type: TypeIndex,
pub indexing_type: TypeIndex,
pub stride: Option<u32>,
pub dimensions: Vec<u32>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct UnionType<'t> {
pub count: u16,
pub properties: TypeProperties,
pub fields: TypeIndex,
pub size: u32,
pub name: RawString<'t>,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct BitfieldType {
pub underlying_type: TypeIndex,
pub length: u8,
pub position: u8,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct FieldList<'t> {
pub fields: Vec<TypeData<'t>>,
pub continuation: Option<TypeIndex>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct ArgumentList {
pub arguments: Vec<TypeIndex>,
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct MethodList {
pub methods: Vec<MethodListEntry>,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct MethodListEntry {
pub attributes: FieldAttributes,
pub method_type: TypeIndex,
pub vtable_offset: Option<u32>,
}