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
use std::{io::Read, collections::BTreeMap};
use buf_redux::BufReader;
use source_demo_tool_impl_proc_macros::event;

use crate::{parse_tools::{parse_varint, parse_u32, ParseVarIntExit}, event_data::EventData, demo_file::packet::protobuf_value::ProtobufValue};

pub trait ProtobufMessageEnumTraits {
    fn to_map_new(&self) -> BTreeMap<&'static str, ProtobufValue>;
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct ProtobufMessage {
    pub message: WireMessage,
    pub field_number: u8,
}

#[derive(Debug)]
pub enum FromReadableErr {
    BufferErr(EventData),
    InvalidOrCorrupt(EventData),
    UnsupportedWireType(EventData, u8)
}

impl ProtobufMessage {
    pub fn many_from_vec(raw_data: &Vec<u8>) -> Result<Vec<Self>, FromReadableErr> {
        let mut reader = BufReader::with_capacity
            (raw_data.len(), raw_data.as_slice());
        reader.read_into_buf().unwrap();

        let mut msgs = Vec::new();
        while reader.buf_len() > 0 {
            msgs.push(
                match Self::from_readable(&mut reader) {
                    Ok(val) => val,
                    Err(e) => return Err(e)
                }
            );
        }
        Ok(msgs)
    }

    pub fn from_readable(mut reader: impl Read) -> Result<ProtobufMessage, FromReadableErr> {
        let tag = match parse_varint(&mut reader) {
            ParseVarIntExit::Ok(n) => n,
            _ => return Err(FromReadableErr::InvalidOrCorrupt(event!{"bad tag varint read"}))
        };

        let message = match (tag & 0b111) as u8 {
            wire_type::VARINT => WireMessage::VarInt(match parse_varint(&mut reader) {
                ParseVarIntExit::Ok(n) => n,
                _ => return Err(FromReadableErr::InvalidOrCorrupt(event!{"bad varint read, message"}))
            }),
            wire_type::LENGTH => WireMessage::Length({
                let len = match parse_varint(&mut reader) {
                    ParseVarIntExit::Ok(n) => n,
                _ => return Err(FromReadableErr::InvalidOrCorrupt(event!{"bad varint read, len"}))
                };

                let mut v = Vec::new();
                v.resize(len as usize, 0);
                if let Err(_) = reader.read_exact(v.as_mut_slice()) {
                    return Err(FromReadableErr::BufferErr(event!{"length data read"}))
                }
                v
            }),
            wire_type::FIXED32 => WireMessage::Fixed32(match parse_u32(&mut reader) {
                Ok(n) => n,
                Err(e) => {
                    let mut ev = event!{""};
                    ev.details = e.into();
                    return Err(FromReadableErr::InvalidOrCorrupt(ev))
                }
            }),
            n => return Err(FromReadableErr::UnsupportedWireType(event!{"bad wire type"}, n))
        };

        let field_number = ((tag & !0b111) >> 3) as u8;

        Ok(ProtobufMessage { message, field_number })     
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum WireMessage {
    VarInt(u64),
    Length(Vec<u8>),
    Fixed32(u32)
}
pub mod wire_type {
    pub const VARINT: u8 = 0;
    pub const LENGTH: u8 = 2;
    pub const FIXED32: u8 = 5;
}