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

fix packet parsers

This commit is contained in:
Robin Appelman 2019-02-26 18:15:42 +01:00
commit 5f4af8333b
13 changed files with 132 additions and 48 deletions

View file

@ -1,4 +1,5 @@
use bitstream_reader::{BitBuffer, BitStream, LittleEndian, NonPadded}; use bitstream_reader::{BitBuffer, BitStream, LittleEndian, NonPadded};
use crate::{ParserState, Parse, ParseError, Result};
use rentals::OwnedBuffer; use rentals::OwnedBuffer;
pub mod gamevent; pub mod gamevent;

View file

@ -1,5 +1,6 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
#[derive(Debug)]
pub struct ConsoleCmdPacket { pub struct ConsoleCmdPacket {
tick: u32, tick: u32,
command: String, command: String,
@ -8,16 +9,18 @@ pub struct ConsoleCmdPacket {
impl<'a> Parse<'a> for ConsoleCmdPacket { impl<'a> Parse<'a> for ConsoleCmdPacket {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> { fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
let tick = stream.read(32)?; let tick = stream.read(32)?;
let len = stream.read(32)?; let len = stream.read::<usize>(32)?;
let mut packet_data = stream.read_bits(len * 8)?;
let command = packet_data.read_string(None)?;
Ok(ConsoleCmdPacket { Ok(ConsoleCmdPacket {
tick, tick,
command: stream.read_string(Some(len))?, command,
}) })
} }
fn skip(stream: &mut Stream) -> Result<()> { fn skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip(32)?; let _ = stream.skip(32)?;
let len = stream.read(32)?; let len = stream.read::<usize>(32)?;
stream.skip(len).map_err(ParseError::from) stream.skip(len * 8).map_err(ParseError::from)
} }
} }

View file

@ -1,12 +1,14 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropType}; use crate::demo::sendprop::{SendPropDefinition, SendPropFlag, SendPropType};
#[derive(Debug)]
pub struct ServerClass { pub struct ServerClass {
id: u32, id: u32,
name: String, name: String,
data_table: String, data_table: String,
} }
#[derive(Debug)]
pub struct SendTable { pub struct SendTable {
name: String, name: String,
props: Vec<SendPropDefinition>, props: Vec<SendPropDefinition>,
@ -14,6 +16,7 @@ pub struct SendTable {
flattened_props: Option<Vec<SendPropDefinition>>, flattened_props: Option<Vec<SendPropDefinition>>,
} }
#[derive(Debug)]
pub struct DataTablePacket { pub struct DataTablePacket {
tick: u32, tick: u32,
tables: Vec<SendTable>, tables: Vec<SendTable>,
@ -23,27 +26,29 @@ pub struct DataTablePacket {
impl<'a> Parse<'a> for DataTablePacket { impl<'a> Parse<'a> for DataTablePacket {
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> { fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self> {
let tick = stream.read(32)?; let tick = stream.read(32)?;
let _len = stream.read::<u32>(32)?; let start = stream.pos();
let len = stream.read::<usize>(32)?;
let mut packet_data = stream.read_bits(len * 8)?;
let mut tables = vec![]; let mut tables = vec![];
while stream.read_bool()? { while packet_data.read_bool()? {
let needs_decoder = stream.read_bool()?; let needs_decoder = packet_data.read_bool()?;
let name = stream.read_string(None)?; let name = packet_data.read_string(None)?;
let prop_count = stream.read(10)?; let prop_count = packet_data.read(10)?;
let mut array_element_prop = None; let mut array_element_prop = None;
let mut props = Vec::with_capacity(prop_count); let mut props = Vec::with_capacity(prop_count);
for i in 0..prop_count { for i in 0..prop_count {
let prop: SendPropDefinition = SendPropDefinition::parse(stream, state, name.clone())?; let prop: SendPropDefinition = SendPropDefinition::parse(&mut packet_data, state, name.clone())?;
if prop.flags.contains(SendPropFlag::InsideArray) { if prop.flags.contains(SendPropFlag::InsideArray) {
if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) { if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) {
return Err(ParseError::InvalidSendPropArray); return Err(ParseError::InvalidSendPropArray("Array contents can't have the 'ChangesOften' flag".to_owned()));
} }
array_element_prop = Some(prop); array_element_prop = Some(prop);
} else if let Some(array_element) = array_element_prop { } else if let Some(array_element) = array_element_prop {
if prop.prop_type == SendPropType::Array { if prop.prop_type != SendPropType::Array {
return Err(ParseError::InvalidSendPropArray); return Err(ParseError::InvalidSendPropArray("Array contents can without array".to_owned()));
} }
array_element_prop = None; array_element_prop = None;
props.push(prop.with_array_property(array_element)); props.push(prop.with_array_property(array_element));
@ -63,12 +68,12 @@ impl<'a> Parse<'a> for DataTablePacket {
// TODO linked tables? // TODO linked tables?
let server_class_count = stream.read(16)?; let server_class_count = packet_data.read(16)?;
let mut server_classes = Vec::with_capacity(server_class_count); let mut server_classes = Vec::with_capacity(server_class_count);
for i in 0..server_class_count { for i in 0..server_class_count {
let id = stream.read(16)?; let id = packet_data.read(16)?;
let name = stream.read_string(None)?; let name = packet_data.read_string(None)?;
let data_table = stream.read_string(None)?; let data_table = packet_data.read_string(None)?;
server_classes.push(ServerClass { server_classes.push(ServerClass {
id, id,
name, name,
@ -76,16 +81,20 @@ impl<'a> Parse<'a> for DataTablePacket {
}); });
} }
Ok(DataTablePacket { if packet_data.bits_left() > 7 {
tick, Err(ParseError::DataRemaining(packet_data.bits_left()))
tables, } else {
server_classes, Ok(DataTablePacket {
}) tick,
tables,
server_classes,
})
}
} }
fn skip(stream: &mut Stream) -> Result<()> { fn skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip(32)?; let _ = stream.skip(32)?;
let len = stream.read(32)?; let len = stream.read::<usize>(32)?;
stream.skip(len).map_err(ParseError::from) stream.skip(len * 8).map_err(ParseError::from)
} }
} }

View file

@ -1,8 +1,10 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
#[derive(Debug)]
pub struct Message; pub struct Message;
#[derive(Debug)]
pub struct MessagePacket { pub struct MessagePacket {
tick: u32, tick: u32,
messages: Vec<Message>, messages: Vec<Message>,
@ -29,11 +31,11 @@ impl<'a> Parse<'a> for MessagePacket {
let sequence_in = stream.read(32)?; let sequence_in = stream.read(32)?;
let sequence_out = stream.read(32)?; let sequence_out = stream.read(32)?;
let length: usize = stream.read(32)?; let length: usize = stream.read(32)?;
let _ = stream.skip(length).map_err(ParseError::from); let mut packet_data = stream.read_bits(length * 8)?;
let mut messages = vec![]; let messages = vec![];
Ok(MessagePacket { let packet = MessagePacket {
tick, tick,
messages, messages,
view_origin, view_origin,
@ -42,7 +44,8 @@ impl<'a> Parse<'a> for MessagePacket {
sequence_in, sequence_in,
sequence_out, sequence_out,
flags, flags,
}) };
Ok(packet)
} }
fn skip(stream: &mut Stream) -> Result<()> { fn skip(stream: &mut Stream) -> Result<()> {
@ -53,7 +56,7 @@ impl<'a> Parse<'a> for MessagePacket {
} }
let _ = stream.skip(32 * 2)?; let _ = stream.skip(32 * 2)?;
let length: usize = stream.read(32)?; let length: usize = stream.read::<usize>(32)?;
stream.skip(length).map_err(ParseError::from) stream.skip(length * 8).map_err(ParseError::from)
} }
} }

View file

@ -19,6 +19,7 @@ pub mod usercmd;
pub mod datatable; pub mod datatable;
pub mod message; pub mod message;
#[derive(Debug)]
pub enum Packet<'a> { pub enum Packet<'a> {
Sigon(MessagePacket), Sigon(MessagePacket),
Message(MessagePacket), Message(MessagePacket),
@ -30,7 +31,7 @@ pub enum Packet<'a> {
StringTables(StringTablePacket<'a>), StringTables(StringTablePacket<'a>),
} }
#[derive(Primitive)] #[derive(Primitive, Debug)]
pub enum PacketType { pub enum PacketType {
Sigon = 1, Sigon = 1,
Message = 2, Message = 2,
@ -71,6 +72,7 @@ impl<'a> Parse<'a> for Packet<'a> {
fn skip(stream: &mut Stream) -> Result<()> { fn skip(stream: &mut Stream) -> Result<()> {
let packet_type = PacketType::parse(stream, &ParserState::new(&stream))?; let packet_type = PacketType::parse(stream, &ParserState::new(&stream))?;
dbg!(&packet_type);
match packet_type { match packet_type {
PacketType::Sigon => MessagePacket::skip(stream), PacketType::Sigon => MessagePacket::skip(stream),
PacketType::Message => MessagePacket::skip(stream), PacketType::Message => MessagePacket::skip(stream),

View file

@ -1,5 +1,6 @@
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
#[derive(Debug)]
pub struct StopPacket; pub struct StopPacket;
impl<'a> Parse<'a> for StopPacket { impl<'a> Parse<'a> for StopPacket {

View file

@ -1,5 +1,7 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
use std::fmt;
#[derive(Debug)]
pub struct StringTable<'a> { pub struct StringTable<'a> {
name: String, name: String,
entries: Vec<StringTableEntry<'a>>, entries: Vec<StringTableEntry<'a>>,
@ -60,6 +62,16 @@ impl<'a> StringTableEntry<'a> {
} }
} }
impl<'a> fmt::Debug for StringTableEntry<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.extra_data {
None => write!(f, "Table Entry: '{}'", self.text),
Some(extra_data) => write!(f, "Table Entry: '{}' with {} bits of extra data", self.text, extra_data.bit_len())
}
}
}
#[derive(Debug)]
pub struct StringTablePacket<'a> { pub struct StringTablePacket<'a> {
tick: u32, tick: u32,
tables: Vec<StringTable<'a>>, tables: Vec<StringTable<'a>>,
@ -68,18 +80,24 @@ pub struct StringTablePacket<'a> {
impl<'a> Parse<'a> for StringTablePacket<'a> { impl<'a> Parse<'a> for StringTablePacket<'a> {
fn parse(stream: &mut Stream<'a>, _state: &ParserState<'a>) -> Result<Self> { fn parse(stream: &mut Stream<'a>, _state: &ParserState<'a>) -> Result<Self> {
let tick = stream.read(32)?; let tick = stream.read(32)?;
let start = stream.pos();
let length: usize = stream.read(32)?; let length: usize = stream.read(32)?;
let count: u32 = stream.read(8)?; let mut packet_data = stream.read_bits(length * 8)?;
let count: u32 = packet_data.read(8)?;
let mut tables = Vec::with_capacity(count as usize); let mut tables = Vec::with_capacity(count as usize);
for _ in 0..count { for _ in 0..count {
tables.push(StringTable::parse(stream)?); tables.push(StringTable::parse(&mut packet_data)?);
}
if packet_data.bits_left() > 7 {
Err(ParseError::DataRemaining(packet_data.bits_left()))
} else {
Ok(StringTablePacket { tick, tables })
} }
Ok(StringTablePacket { tick, tables })
} }
fn skip(stream: &mut Stream) -> Result<()> { fn skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip(32)?; let _ = stream.skip(32)?;
let length = stream.read(32)?; let length = stream.read::<usize>(32)?;
stream.skip(length).map_err(ParseError::from) stream.skip(length).map_err(ParseError::from)
} }
} }

View file

@ -1,5 +1,6 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
#[derive(Debug)]
pub struct SyncTickPacket { pub struct SyncTickPacket {
tick: u32, tick: u32,
} }

View file

@ -1,8 +1,8 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
#[derive(Debug)]
pub struct UserCmdPacket { pub struct UserCmdPacket {
tick: u32, tick: u32,
command: String,
sequence_out: u32, sequence_out: u32,
} }
@ -10,17 +10,18 @@ impl<'a> Parse<'a> for UserCmdPacket {
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> { fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
let tick = stream.read(32)?; let tick = stream.read(32)?;
let sequence_out = stream.read(32)?; let sequence_out = stream.read(32)?;
let len = stream.read(32)?; let len = stream.read::<usize>(32)?;
let mut _packet_data = stream.read_bits(len * 8)?;
// TODO parse the packet data
Ok(UserCmdPacket { Ok(UserCmdPacket {
tick, tick,
sequence_out, sequence_out
command: stream.read_string(Some(len))?,
}) })
} }
fn skip(stream: &mut Stream) -> Result<()> { fn skip(stream: &mut Stream) -> Result<()> {
let _ = stream.skip(64)?; let _ = stream.skip(64)?;
let len = stream.read(32)?; let len = stream.read::<usize>(32)?;
stream.skip(len).map_err(ParseError::from) stream.skip(len * 8).map_err(ParseError::from)
} }
} }

View file

@ -1,6 +1,11 @@
use std::error::Error;
use bitstream_reader::ReadError;
use crate::demo::header::Header;
use crate::demo::packet::Packet;
pub use crate::demo::parser::state::ParserState; pub use crate::demo::parser::state::ParserState;
use crate::Stream; use crate::Stream;
use bitstream_reader::ReadError;
mod state; mod state;
@ -14,7 +19,9 @@ pub enum ParseError {
/// SendProp type is invalid /// SendProp type is invalid
InvalidSendPropType(u8), InvalidSendPropType(u8),
/// Invalid structure found while creating array SendProp /// Invalid structure found while creating array SendProp
InvalidSendPropArray, InvalidSendPropArray(String),
/// Expected amount of data left after parsing an object
DataRemaining(usize),
} }
impl From<ReadError> for ParseError { impl From<ReadError> for ParseError {
@ -59,4 +66,30 @@ impl<'a> DemoParser<'a> {
self.stream.set_pos(pos)?; self.stream.set_pos(pos)?;
Ok(()) Ok(())
} }
pub fn split_packets(mut self) -> Result<Vec<Stream<'a>>> {
let _ = self.skip::<Header>()?;
let mut streams = vec![];
while self.stream.bits_left() > 7 {
let start = self.stream.pos();
let _ = self.skip::<Packet>()?;
let end = self.stream.pos();
let _ = self.stream.set_pos(start);
streams.push(self.stream.read_bits(end - start)?);
}
Ok(streams)
}
pub fn parse_demo(mut self) -> Result<(Header, Vec<Packet<'a>>)> {
let header = self.read::<Header>()?;
let mut packets = vec![];
loop {
let packet = self.read::<Packet>()?;
match packet {
Packet::Stop(_) => break,
packet => packets.push(packet)
}
}
Ok((header, packets))
}
} }

View file

@ -8,6 +8,7 @@ use crate::{Parse, ParseError, ParserState, Result, Stream};
use super::packet::datatable::SendTable; use super::packet::datatable::SendTable;
use super::vector::{Vector, VectorXY}; use super::vector::{Vector, VectorXY};
#[derive(Debug)]
pub struct SendPropDefinition { pub struct SendPropDefinition {
pub prop_type: SendPropType, pub prop_type: SendPropType,
pub name: String, pub name: String,

View file

@ -1,5 +1,6 @@
use crate::{Parse, ParseError, ParserState, Result, Stream}; use crate::{Parse, ParseError, ParserState, Result, Stream};
#[derive(Debug)]
pub struct Vector { pub struct Vector {
pub x: f32, pub x: f32,
pub y: f32, pub y: f32,
@ -20,6 +21,7 @@ impl Parse<'_> for Vector {
} }
} }
#[derive(Debug)]
pub struct VectorXY { pub struct VectorXY {
pub x: f32, pub x: f32,
pub y: f32, pub y: f32,

View file

@ -1,15 +1,24 @@
#[macro_use] #[macro_use]
extern crate rental; extern crate rental;
use std::error::Error;
use std::fs;
pub use demo::{ pub use demo::{
parser::{DemoParser, Parse, ParseError, ParserState, Result}, Demo,
Demo, Stream, parser::{DemoParser, Parse, ParseError, ParserState, Result}, Stream,
}; };
mod demo; mod demo;
mod state; mod state;
mod test; mod test;
fn main() { fn main() -> std::result::Result<(), Box<ParseError>> {
println!("Hello, world!"); let file = fs::read("data/small.dem").expect("Unable to read file");
let demo = Demo::new(file);
let stream: Stream = demo.get_stream();
let mut parser = DemoParser::new(stream);
let (header, packets) = parser.parse_demo()?;
dbg!(header);
Ok(())
} }