Skip to main content

s2protocol/
protocol_version_decoder.rs

1//! Nom Parsing The S2 Protocol Version
2//! This is stored in the MPQ UserData Section
3//! and can be decoded with any Protocol Version
4//! Decoder.
5//! In the original code, in s2protocol from Blizzard, each protocol version
6//! has its own version decoder. and whatever protocol is latest would decoded
7//! the target file. In this verison we are not yet doing that but we should.
8
9use super::*;
10// TODO: Find a way to parse the version with the latest available protocol.
11use crate::versions::protocol87702::byte_aligned::{ReplaySHeader, SVersion};
12use nom::bytes::complete::*;
13use nom::error::dbg_dmp;
14use nom_mpq::MPQ;
15use nom_mpq::parser::peek_hex;
16
17/// The S2 Protocol Header
18#[derive(Debug, PartialEq, Clone)]
19pub struct ProtocolHeader {
20    pub m_signature: Vec<u8>,
21    pub m_version: SVersion,
22}
23
24impl ProtocolHeader {
25    #[tracing::instrument(level = "debug", skip(input), fields(input = peek_hex(input)))]
26    pub fn parse(input: &[u8]) -> S2ProtoResult<&[u8], Self> {
27        let (tail, _) = validate_struct_tag(input)?;
28        let (tail, _) = dbg_dmp(tag(&b"\x12"[..]), "Protocol Header struct size")(tail)?;
29        // This 0x12 translates to a 9 decimal, which is the number of fields
30        // expected in the Protocol Version
31        let (tail, m_signature) = Self::parse_m_signature(tail)?;
32        let (tail, _) = dbg_dmp(tag(&b"\x02"[..]), "Protocol Header.Version struct Tag")(tail)?;
33        let (tail, m_version) = SVersion::parse(tail)?;
34        Ok((
35            tail,
36            Self {
37                m_signature,
38                m_version,
39            },
40        ))
41    }
42
43    #[tracing::instrument(level = "debug", skip(input), fields(input = peek_hex(input)))]
44    pub fn parse_m_signature(input: &[u8]) -> S2ProtoResult<&[u8], Vec<u8>> {
45        let (tail, _) = dbg_dmp(tag(&b"\x00"[..]), "m_signature field tag")(input)?;
46        let (tail, m_signature) = tagged_blob(tail)?;
47        Ok((tail, m_signature))
48    }
49}
50
51/// Read the protocol header, this can be read with any protocol
52pub fn read_protocol_header(mpq: &MPQ) -> S2ProtoResult<&[u8], ReplaySHeader> {
53    let user_data = mpq
54        .user_data
55        .as_ref()
56        .expect("Unable to locate protocol version, missing user data in MPQ");
57    ReplaySHeader::parse(&user_data.content)
58}