1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 18:24:05 +02:00

some error refactoring

This commit is contained in:
Robin Appelman 2019-08-23 12:31:51 +02:00
commit 77180520ef
12 changed files with 1671 additions and 1298 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,10 @@
use bitstream_reader::BitRead;
use crate::{ParseError, Result};
use crate::{MalformedDemoError, ParseError, Result};
pub use super::gameevent_gen::{GameEvent, GameEventType};
use crate::demo::message::gameevent::GameEventTypeId;
use std::fmt;
#[derive(Debug)]
pub struct GameEventDefinition {
@ -32,6 +33,21 @@ pub enum GameEventValueType {
Local = 7,
}
impl fmt::Display for GameEventValueType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
GameEventValueType::None => write!(f, "None"),
GameEventValueType::String => write!(f, "String"),
GameEventValueType::Float => write!(f, "Float"),
GameEventValueType::Long => write!(f, "Long"),
GameEventValueType::Short => write!(f, "Short"),
GameEventValueType::Byte => write!(f, "Byte"),
GameEventValueType::Boolean => write!(f, "Boolean"),
GameEventValueType::Local => write!(f, "Local"),
}
}
}
#[derive(Debug, Clone)]
pub enum GameEventValue {
String(String),
@ -43,6 +59,20 @@ pub enum GameEventValue {
Local,
}
impl GameEventValue {
pub fn get_type(&self) -> GameEventValueType {
match self {
GameEventValue::String(_) => GameEventValueType::String,
GameEventValue::Float(_) => GameEventValueType::Float,
GameEventValue::Long(_) => GameEventValueType::Long,
GameEventValue::Short(_) => GameEventValueType::Short,
GameEventValue::Byte(_) => GameEventValueType::Byte,
GameEventValue::Boolean(_) => GameEventValueType::Boolean,
GameEventValue::Local => GameEventValueType::Local,
}
}
}
pub trait FromGameEventValue: Sized {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self>;
}
@ -51,11 +81,12 @@ impl FromGameEventValue for String {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::String(val) => Ok(val),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::String,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}
@ -64,11 +95,12 @@ impl FromGameEventValue for f32 {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::Float(val) => Ok(val),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::Float,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}
@ -77,11 +109,12 @@ impl FromGameEventValue for u32 {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::Long(val) => Ok(val),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::Long,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}
@ -90,11 +123,12 @@ impl FromGameEventValue for u16 {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::Short(val) => Ok(val),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::Short,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}
@ -103,11 +137,12 @@ impl FromGameEventValue for u8 {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::Byte(val) => Ok(val),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::Byte,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}
@ -116,11 +151,12 @@ impl FromGameEventValue for bool {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::Boolean(val) => Ok(val),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::Boolean,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}
@ -129,11 +165,12 @@ impl FromGameEventValue for () {
fn from_value(value: GameEventValue, name: &'static str) -> Result<Self> {
match value {
GameEventValue::Local => Ok(()),
_ => Err(ParseError::InvalidGameEvent {
_ => Err(MalformedDemoError::InvalidGameEvent {
expected_type: GameEventValueType::Local,
name,
value,
}),
found_type: value.get_type(),
}
.into()),
}
}
}

View file

@ -9,7 +9,9 @@ use crate::demo::gamevent::{
RawGameEvent,
};
use crate::demo::parser::ParseBitSkip;
use crate::{GameEventError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::{
GameEventError, MalformedDemoError, Parse, ParseError, ParserState, ReadResult, Result, Stream,
};
fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<GameEventValue> {
Ok(match definition.kind {
@ -20,9 +22,7 @@ fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<
GameEventValueType::Byte => GameEventValue::Byte(stream.read()?),
GameEventValueType::Boolean => GameEventValue::Boolean(stream.read()?),
GameEventValueType::Local => GameEventValue::Local,
GameEventValueType::None => {
return Err(ParseError::MalformedGameEvent(GameEventError::NoneValue))
}
GameEventValueType::None => return Err(GameEventError::NoneValue.into()),
})
}
@ -48,7 +48,11 @@ impl Parse for GameEventMessage {
values,
}
}
None => return Err(ParseError::MalformedGameEvent(GameEventError::UnknownType)),
None => {
return Err(
MalformedDemoError::MalformedGameEvent(GameEventError::UnknownType).into(),
)
}
};
let event = GameEvent::from_raw_event(raw_event)?;
Ok(GameEventMessage { event })

View file

@ -15,7 +15,7 @@ use crate::demo::message::tempentities::*;
use crate::demo::message::usermessage::*;
use crate::demo::message::voice::*;
use crate::demo::parser::ParseBitSkip;
use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::{MalformedDemoError, Parse, ParseError, ParserState, Result, Stream};
pub mod bspdecal;
pub mod classinfo;
@ -65,7 +65,7 @@ impl Parse for MessageType {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
let raw = stream.read_int(6)?;
let prop_type: Option<MessageType> = MessageType::from_u8(raw);
prop_type.ok_or(ParseError::InvalidMessageType(raw))
prop_type.ok_or(MalformedDemoError::InvalidMessageType(raw).into())
}
}

View file

@ -3,10 +3,10 @@ use num_traits::{PrimInt, Unsigned};
use snap::Decoder;
use crate::demo::packet::stringtable::{
ExtraData, FixedUserdataSize, StringTable, StringTableEntry,
ExtraData, FixedUserDataSize, StringTable, StringTableEntry,
};
use crate::demo::parser::ParseBitSkip;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::{MalformedDemoError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(Debug)]
pub struct CreateStringTableMessage {
@ -16,14 +16,14 @@ pub struct CreateStringTableMessage {
#[derive(Debug)]
pub struct StringTableMeta {
pub max_entries: u16,
pub fixed_userdata_size: Option<FixedUserdataSize>,
pub fixed_userdata_size: Option<FixedUserDataSize>,
}
impl From<&StringTable> for StringTableMeta {
fn from(table: &StringTable) -> Self {
StringTableMeta {
max_entries: table.max_entries,
fixed_userdata_size: table.fixed_userdata_size,
fixed_userdata_size: table.fixed_user_data_size,
}
}
}
@ -80,7 +80,7 @@ impl Parse for CreateStringTableMessage {
let table = StringTable {
entries,
max_entries,
fixed_userdata_size,
fixed_user_data_size: fixed_userdata_size,
client_entries: None,
compressed,
name,
@ -97,7 +97,7 @@ impl ParseBitSkip for CreateStringTableMessage {
let _: u16 = stream.read_sized(encode_bits as usize + 1)?;
let length = read_var_int(stream)?;
let _: Option<FixedUserdataSize> = stream.read()?;
let _: Option<FixedUserDataSize> = stream.read()?;
let _: bool = stream.read()?;
@ -122,7 +122,7 @@ impl Parse for UpdateStringTableMessage {
let entries = match state.string_tables.get(table_id as usize) {
Some(table) => parse_string_table_update(&mut data, table, changed),
None => return Err(ParseError::StringTableNotFound(table_id)),
None => return Err(MalformedDemoError::StringTableNotFound(table_id).into()),
}?;
Ok(UpdateStringTableMessage { table_id, entries })

View file

@ -1,7 +1,8 @@
use bitstream_reader::{BitRead, LittleEndian};
use crate::demo::parser::MalformedSendPropDefinitionError;
use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropName, SendPropType};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::{MalformedDemoError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
use serde::{Deserialize, Serialize};
use std::cell::{Cell, RefCell};
use std::fmt;
@ -63,16 +64,12 @@ impl Parse for ParseSendTable {
let prop: SendPropDefinition = SendPropDefinition::read(stream, name.clone())?;
if prop.flags.contains(SendPropFlag::InsideArray) {
if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) {
return Err(ParseError::InvalidSendProp(
"Array contents can't have the 'ChangesOften' flag",
));
return Err(MalformedSendPropDefinitionError::ArrayChangesOften.into());
}
array_element_prop = Some(prop);
} else if let Some(array_element) = array_element_prop {
if prop.prop_type != SendPropType::Array {
return Err(ParseError::InvalidSendProp(
"Array contents can without array",
));
return Err(MalformedSendPropDefinitionError::UntypedArray.into());
}
array_element_prop = None;
props.push(prop.with_array_property(array_element));
@ -222,7 +219,7 @@ impl Parse for DataTablePacket {
let server_classes = packet_data.read_sized(server_class_count)?;
if packet_data.bits_left() > 7 {
Err(ParseError::DataRemaining(packet_data.bits_left()))
Err(MalformedDemoError::DataRemaining(packet_data.bits_left()).into())
} else {
Ok(DataTablePacket {
tick,

View file

@ -3,10 +3,10 @@ use std::fmt;
use bitstream_reader::{BitRead, LittleEndian};
use crate::demo::message::stringtable::StringTableMeta;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::{MalformedDemoError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(BitRead, Clone, Copy, Debug)]
pub struct FixedUserdataSize {
pub struct FixedUserDataSize {
#[size = 12]
pub size: u16,
#[size = 4]
@ -18,7 +18,7 @@ pub struct StringTable {
pub name: String,
pub entries: Vec<(u16, StringTableEntry)>,
pub max_entries: u16,
pub fixed_userdata_size: Option<FixedUserdataSize>,
pub fixed_user_data_size: Option<FixedUserDataSize>,
pub client_entries: Option<Vec<StringTableEntry>>,
pub compressed: bool,
}
@ -26,7 +26,7 @@ pub struct StringTable {
impl StringTable {
pub fn get_table_meta(&self) -> StringTableMeta {
StringTableMeta {
fixed_userdata_size: self.fixed_userdata_size,
fixed_userdata_size: self.fixed_user_data_size,
max_entries: self.max_entries,
}
}
@ -53,7 +53,7 @@ impl BitRead<LittleEndian> for StringTable {
name,
entries,
max_entries: entry_count,
fixed_userdata_size: None,
fixed_user_data_size: None,
client_entries,
compressed: false,
})
@ -125,7 +125,7 @@ impl Parse for StringTablePacket {
let tables = packet_data.read_sized(count)?;
if packet_data.bits_left() > 7 {
Err(ParseError::DataRemaining(packet_data.bits_left()))
Err(MalformedDemoError::DataRemaining(packet_data.bits_left()).into())
} else {
Ok(StringTablePacket { tick, tables })
}

View file

@ -1,4 +1,4 @@
use bitstream_reader::{BitRead, BitSkip, LittleEndian, ReadError};
use bitstream_reader::{BitRead, BitSkip, FromUtf8Error, LittleEndian, ReadError};
pub use self::messagetypeanalyser::MessageTypeAnalyser;
use crate::demo::gamevent::{GameEventValue, GameEventValueType};
@ -9,6 +9,7 @@ pub use crate::demo::parser::analyser::MatchState;
pub use crate::demo::parser::handler::{DemoHandler, MessageHandler};
pub use crate::demo::parser::state::ParserState;
use crate::Stream;
use err_derive::Error;
mod analyser;
mod handler;
@ -16,57 +17,101 @@ mod messagetypeanalyser;
mod state;
/// Errors that can occur during parsing
#[derive(Debug)]
#[derive(Debug, Error)]
pub enum ParseError {
/// Error while reading bits from stream
ReadError(ReadError),
/// Packet identifier is invalid
InvalidPacketType(u8),
/// Message identifier is invalid
InvalidMessageType(u8),
/// SendProp type is invalid
InvalidSendPropType(u8),
/// Invalid SendProp
InvalidSendProp(&'static str),
/// Expected amount of data left after parsing an object
DataRemaining(usize),
/// String table that was send for update doesn't exist
StringTableNotFound(u8),
/// A unknown game event type was read
UnknownGameEvent(&'static str),
/// A malformed game event was read
MalformedGameEvent(GameEventError),
/// A read game event doesn't contain the expected values
InvalidGameEvent {
expected_type: GameEventValueType,
name: &'static str,
value: GameEventValue,
},
/// Unexpected type of compressed data
#[error(display = "Error while reading bits from stream: {}", _0)]
ReadError(#[error(cause)] ReadError),
#[error(display = "Malformed utf8 while reading string")]
MalformedUTF8(#[error(cause)] FromUtf8Error),
#[error(display = "Malformed demo file: {}", _0)]
MalformedDemo(#[error(cause)] MalformedDemoError),
#[error(display = "Unexpected type of compressed data: {}", _0)]
UnexpectedCompressionType(String),
/// Error while decompressing SNAP compressed string table
SnapError(snap::Error),
/// Unexpected size after decompressing SNAP data
#[error(
display = "Error while decompressing SNAP compressed string table: {}",
_0
)]
SnapError(#[error(cause)] snap::Error),
#[error(
display = "Unexpected size after decompressing SNAP data, got {} bytes, expected {} bytes",
size,
expected
)]
UnexpectedDecompressedSize {
/// Expected decompressed size
expected: u32,
/// Actual decompressed size
size: u32,
},
/// Misc malformed demo error
#[error(display = "Malformed demo file: {}", _0)]
InvalidDemo(&'static str),
}
#[derive(Debug)]
/// Malformed demo file
#[derive(Debug, Error)]
pub enum MalformedDemoError {
#[error(display = "Packet identifier is invalid: {}", _0)]
InvalidPacketType(u8),
#[error(display = "Message identifier is invalid: {}", _0)]
InvalidMessageType(u8),
#[error(display = "Invalid SendProp type: {}", _0)]
InvalidSendPropType(u8),
#[error(display = "Invalid SendProp: {}", _0)]
InvalidSendProp(MalformedSendPropDefinitionError),
#[error(
display = "Unexpected amount of data left after parsing an object, {} bits remaining",
_0
)]
DataRemaining(usize),
#[error(display = "String table with index {} not found", _0)]
StringTableNotFound(u8),
#[error(display = "A malformed game event was read")]
MalformedGameEvent(#[error(cause)] GameEventError),
#[error(
display = "A read game event doesn't contain the expected values, expected type {} for {} event, got type {}",
expected_type,
name,
found_type
)]
InvalidGameEvent {
expected_type: GameEventValueType,
name: &'static str,
found_type: GameEventValueType,
},
}
#[derive(Debug, Error)]
pub enum MalformedSendPropDefinitionError {
#[error(display = "Float property without defined size")]
UnsizedFloat,
#[error(display = "Array property without defined size")]
UnsizedArray,
#[error(display = "Array property without defined inner type")]
UntypedArray,
#[error(display = "Property used that can't be read")]
InvalidPropType,
#[error(display = "Array contents can't have the 'ChangesOften' flag")]
ArrayChangesOften,
#[error(display = "SendProp value out of range")]
OutOfRange,
}
#[derive(Debug, Error)]
pub enum GameEventError {
#[error(display = "Incorrect number of values")]
IncorrectValueCount,
#[error(display = "Event with 'none' value")]
NoneValue,
#[error(display = "Unknown type")]
UnknownType,
}
impl From<ReadError> for ParseError {
fn from(err: ReadError) -> ParseError {
ParseError::ReadError(err)
match err {
ReadError::Utf8Error(utf8_error) => ParseError::MalformedUTF8(utf8_error),
_ => ParseError::ReadError(err),
}
}
}
@ -76,6 +121,24 @@ impl From<snap::Error> for ParseError {
}
}
impl From<MalformedDemoError> for ParseError {
fn from(err: MalformedDemoError) -> ParseError {
ParseError::MalformedDemo(err)
}
}
impl From<MalformedSendPropDefinitionError> for ParseError {
fn from(err: MalformedSendPropDefinitionError) -> ParseError {
ParseError::MalformedDemo(MalformedDemoError::InvalidSendProp(err))
}
}
impl From<GameEventError> for ParseError {
fn from(err: GameEventError) -> ParseError {
ParseError::MalformedDemo(MalformedDemoError::MalformedGameEvent(err))
}
}
pub type Result<T> = std::result::Result<T, ParseError>;
pub trait Parse: Sized {

View file

@ -2,12 +2,13 @@ use bitstream_reader::{BitRead, LittleEndian};
use enumflags2::BitFlags;
use enumflags2_derive::EnumFlags;
use crate::{Parse, ParseError, ReadResult, Result, Stream};
use crate::{MalformedDemoError, Parse, ParseError, ReadResult, Result, Stream};
use super::packet::datatable::ParseSendTable;
use super::vector::{Vector, VectorXY};
use crate::demo::message::stringtable::log_base2;
use crate::demo::packet::datatable::SendTableName;
use crate::demo::parser::MalformedSendPropDefinitionError;
use std::convert::TryInto;
use std::fmt;
use std::rc::Rc;
@ -236,9 +237,7 @@ impl SendPropValue {
Self::read_vector_xy(stream, definition).map(SendPropValue::from)
}
SendPropType::Array => Self::read_array(stream, definition).map(SendPropValue::from),
_ => Err(ParseError::InvalidSendProp(
"Prop type not allowed in entity",
)),
_ => Err(MalformedSendPropDefinitionError::InvalidPropType.into()),
}
}
@ -251,7 +250,7 @@ impl SendPropValue {
let unsigned: u32 = stream.read()?;
unsigned
.try_into()
.map_err(|_| ParseError::InvalidSendProp("SendProp value out of range"))
.map_err(|_| MalformedSendPropDefinitionError::OutOfRange.into())
} else {
stream.read().map_err(ParseError::from)
}
@ -265,7 +264,7 @@ impl SendPropValue {
let num_bits = log_base2(
definition
.element_count
.ok_or(ParseError::InvalidSendProp("Unsized array"))?,
.ok_or(MalformedSendPropDefinitionError::UnsizedArray)?,
);
let count = stream.read_int(num_bits as usize)?;
@ -277,7 +276,7 @@ impl SendPropValue {
definition
.array_property
.as_ref()
.ok_or(ParseError::InvalidSendProp("Untyped array"))?,
.ok_or(MalformedSendPropDefinitionError::UntypedArray)?,
)?;
values.push(value);
}
@ -321,13 +320,13 @@ impl SendPropValue {
} else {
let bit_count = definition
.bit_count
.ok_or(ParseError::InvalidSendProp("Unsized float"))?;
.ok_or(MalformedSendPropDefinitionError::UnsizedFloat)?;
let high = definition
.high_value
.ok_or(ParseError::InvalidSendProp("Unsized float"))?;
.ok_or(MalformedSendPropDefinitionError::UnsizedFloat)?;
let low = definition
.low_value
.ok_or(ParseError::InvalidSendProp("Unsized float"))?;
.ok_or(MalformedSendPropDefinitionError::UnsizedFloat)?;
let raw: u32 = stream.read_int(bit_count as usize)?;
let percentage = (raw as f32) * get_frac_factor(bit_count as usize);
Ok(low + ((high - low) * percentage))

View file

@ -7,8 +7,8 @@ pub use bitstream_reader::Result as ReadResult;
pub use crate::demo::{
message::MessageType,
parser::{
DemoParser, GameEventError, MatchState, MessageTypeAnalyser, Parse, ParseError,
ParserState, Result,
DemoParser, GameEventError, MalformedDemoError, MatchState, MessageTypeAnalyser, Parse,
ParseError, ParserState, Result,
},
Demo, Stream,
};