source_demo_tool/demo_file/
header.rs

1use std::io::Read;
2use crate::parse_tools:: {
3    parse_f32,
4    parse_i32,
5    parse_fixed_width_string
6};
7
8#[derive(Debug, Clone)]
9pub struct DemoHeader {
10	pub demo_protocol: i32,
11	pub network_protocol: i32,
12	pub server_name: String,
13	pub client_name: String,
14	pub map_name: String,
15	pub game_directory: String,
16	pub playback_time: f32,
17	pub ticks: i32,
18	pub frames: i32,
19	pub sign_on_length: i32,
20}
21
22impl DemoHeader {
23    pub fn from_readable(mut reader: impl Read) -> Result<DemoHeader, String> {
24        // parse and check header string
25        let mut buffer: [u8; 8] = [0; 8];
26        match reader.read_exact(&mut buffer) {
27            Ok(()) => match String::from_utf8(buffer.to_vec()) {
28                Ok(str) => {
29                    if str != "HL2DEMO\0" {
30                        return Err(String::from("file magic header != HL2DEMO"))
31                    }
32                },
33                Err(_) => return Err(String::from("couldn't parse header string"))
34            },
35            Err(_) => return Err(String::from("couldn't read header string"))
36        }        
37        
38        // parse demo protocol
39        let demo_protocol = match parse_i32(&mut reader) {
40            Ok(n) => {
41                if n < 0 {
42                    return Err(String::from("unexpected negative demo protocol"))
43                }
44                n
45            }
46            Err(e) => return Err(format!("error parsing demo protocol: {e}"))
47        };
48
49        // parse network protocol
50        let network_protocol = match parse_i32(&mut reader) {
51            Ok(n) => {
52                if n < 0 {
53                    return Err(String::from("unexpected negative network protocol"))
54                }
55                n
56            }
57            Err(e) => return Err(format!("error parsing network protocol: {e}"))
58        };
59
60        // parse server name
61        let server_name = match parse_fixed_width_string(&mut reader, 260) {
62            Ok(s) => s,
63            Err(e) => return Err(format!("error parsing server name: {e}"))
64        };
65
66        // parse client name
67        let client_name = match parse_fixed_width_string(&mut reader, 260) {
68            Ok(s) => s,
69            Err(e) => return Err(format!("error parsing client name: {e}"))
70        };
71
72        // parse map name
73        let map_name = match parse_fixed_width_string(&mut reader, 260) {
74            Ok(s) => s,
75            Err(e) => return Err(format!("error parsing map name: {e}"))
76        };
77
78        // parse game directory
79        let game_directory = match parse_fixed_width_string(&mut reader, 260) {
80            Ok(s) => s,
81            Err(e) => return Err(format!("error parsing game directory: {e}"))
82        };
83
84        // parse playback time
85        let playback_time = match parse_f32(&mut reader) {
86            Ok(n) => {
87                if n < 0.0 {
88                    return Err(String::from("unexpected negative playback time"))
89                }
90                n
91            },
92            Err(e) => return Err(format!("error parsing playback time: {e}"))
93        };
94
95        // parse ticks
96        let ticks = match parse_i32(&mut reader) {
97            Ok(n) => {
98                if n < 0 {
99                    return Err(String::from("unexpected negative ticks"))
100                }
101                n
102            },
103            Err(e) => return Err(format!("error parsing ticks: {e}"))
104        };
105
106        // parse frames
107        let frames = match parse_i32(&mut reader) {
108            Ok(n) => {
109                if n < 0 {
110                    return Err(String::from("unexpected negative frames"))
111                }
112                n
113            },
114            Err(e) => return Err(format!("error parsing frames: {e}"))
115        };
116
117        // parse sign on length
118        let sign_on_length = match parse_i32(&mut reader) {
119            Ok(n) => {
120                if n < 0 {
121                    return Err(String::from("unexpected negative sign on length"))
122                }
123                n
124            }
125            Err(e) => return Err(format!("error parsing sign on length: {e}"))
126        };
127
128        Ok(DemoHeader {
129            demo_protocol,
130            network_protocol,
131            server_name,
132            client_name,
133            map_name,
134            game_directory,
135            playback_time,
136            ticks,
137            frames,
138            sign_on_length
139        })
140    } 
141}