1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
use std::fmt; use bitbuffer::{BitRead, LittleEndian}; use crate::demo::message::stringtable::StringTableMeta; use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream}; use std::cmp::min; #[derive(BitRead, Clone, Copy, Debug)] pub struct FixedUserDataSize { #[size = 12] pub size: u16, #[size = 4] pub bits: u8, } #[derive(Debug)] pub struct StringTable { pub name: String, pub entries: Vec<(u16, StringTableEntry)>, pub max_entries: u16, pub fixed_user_data_size: Option<FixedUserDataSize>, pub client_entries: Option<Vec<StringTableEntry>>, pub compressed: bool, } impl StringTable { pub fn get_table_meta(&self) -> StringTableMeta { StringTableMeta { fixed_userdata_size: self.fixed_user_data_size, max_entries: self.max_entries, } } } impl BitRead<LittleEndian> for StringTable { fn read(stream: &mut Stream) -> ReadResult<Self> { let name = stream.read()?; let entry_count = stream.read_int(16)?; let mut entries = Vec::with_capacity(min(entry_count, 128) as usize); for index in 0..entry_count { entries.push((index, stream.read()?)) } let client_entries = if stream.read_bool()? { let count = stream.read_int(16)?; Some(stream.read_sized(count)?) } else { None }; Ok(StringTable { name, entries, max_entries: entry_count, fixed_user_data_size: None, client_entries, compressed: false, }) } } #[derive(BitRead, Clone, Debug)] #[endianness = "LittleEndian"] pub struct ExtraData { pub byte_len: u16, #[size = "byte_len.saturating_mul(8)"] pub data: Stream, } impl ExtraData { pub fn new(data: Stream) -> Self { let byte_len = (data.bit_len() / 8) as u16; ExtraData { byte_len, data } } } #[derive(Clone, Default)] pub struct StringTableEntry { pub text: Option<String>, pub extra_data: Option<ExtraData>, } impl StringTableEntry { pub fn text(&self) -> &str { self.text.as_ref().map(|s| s.as_str()).unwrap_or("") } } impl BitRead<LittleEndian> for StringTableEntry { fn read(stream: &mut Stream) -> ReadResult<Self> { Ok(StringTableEntry { text: Some(stream.read()?), extra_data: stream.read()?, }) } } impl fmt::Debug for StringTableEntry { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.extra_data { None => write!(f, "StringTableEntry {{ text: \"{}\" }}", self.text()), Some(extra_data) => write!( f, "StringTableEntry{{ text: \"{}\" extra_data: {} bytes }}", self.text(), extra_data.byte_len ), } } } #[derive(Debug)] pub struct StringTablePacket { pub tick: u32, pub tables: Vec<StringTable>, } impl Parse for StringTablePacket { fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> { let tick = stream.read_int(32)?; let length: usize = stream.read_int(32)?; let mut packet_data = stream.read_bits(length.saturating_mul(8))?; let count: usize = packet_data.read_int(8)?; let tables = packet_data.read_sized(count)?; if packet_data.bits_left() > 7 { Err(ParseError::DataRemaining(packet_data.bits_left())) } else { Ok(StringTablePacket { tick, tables }) } } }