Skip to main content

egdata_manifests_parser/types/
meta.rs

1use byteorder::{LittleEndian, ReadBytesExt};
2use log::debug;
3use serde::{Deserialize, Serialize};
4use std::io::{Read, Seek};
5
6use crate::error::Error;
7use crate::parser::reader::ReadExt;
8
9#[derive(Debug, Clone, Serialize, Deserialize, Default)]
10pub struct ManifestMeta {
11    pub data_size: u32,
12    pub data_version: u8,
13    pub feature_level: i32,
14    pub is_file_data: bool,
15    pub app_id: i32,
16    #[serde(serialize_with = "trim_null_chars")]
17    pub app_name: String,
18    #[serde(serialize_with = "trim_null_chars")]
19    pub build_version: String,
20    #[serde(serialize_with = "trim_null_chars")]
21    pub launch_exe: String,
22    #[serde(serialize_with = "trim_null_chars")]
23    pub launch_command: String,
24    pub prereq_ids: Vec<String>,
25    #[serde(serialize_with = "trim_null_chars")]
26    pub prereq_name: String,
27    #[serde(serialize_with = "trim_null_chars")]
28    pub prereq_path: String,
29    #[serde(serialize_with = "trim_null_chars")]
30    pub prereq_args: String,
31    pub build_id: Option<String>,
32}
33
34fn trim_null_chars<S>(value: &String, serializer: S) -> Result<S::Ok, S::Error>
35where
36    S: serde::Serializer,
37{
38    let trimmed = value.trim_end_matches('\0');
39    serializer.serialize_str(trimmed)
40}
41
42impl ManifestMeta {
43    pub fn read_meta<R: Read + Seek>(rdr: &mut R) -> Result<(Self, u64), Error> {
44        let start_pos = rdr.stream_position()?;
45
46        debug!("Reading metadata:");
47        let data_size = rdr.read_u32::<LittleEndian>()?;
48        debug!("  Data size: {} (0x{:x})", data_size, data_size);
49
50        // Validate data size
51        if data_size == 0 || data_size > 1024 * 1024 * 1024 {
52            // 1GB max
53            return Err(Error::Invalid(format!(
54                "Invalid data size: {} (0x{:x}). Must be between 1 and 1GB",
55                data_size, data_size
56            )));
57        }
58
59        let data_version = rdr.read_u8()?;
60        debug!("  Data version: {} (0x{:x})", data_version, data_version);
61
62        let feature_level = rdr.read_i32::<LittleEndian>()?;
63        debug!("  Feature level: {} (0x{:x})", feature_level, feature_level);
64
65        let is_file_data = rdr.read_u8()? != 0;
66        debug!("  Is file data: {}", is_file_data);
67
68        let app_id = rdr.read_i32::<LittleEndian>()?;
69        debug!("  App ID: {} (0x{:x})", app_id, app_id);
70
71        let app_name = rdr.fstring()?;
72        debug!("  App name: {}", app_name);
73
74        let build_version = rdr.fstring()?;
75        debug!("  Build version: {}", build_version);
76
77        let launch_exe = rdr.fstring()?;
78        debug!("  Launch exe: {}", launch_exe);
79
80        let launch_command = rdr.fstring()?;
81        debug!("  Launch command: {}", launch_command);
82
83        let prereq_ids = rdr.fstring_array()?;
84        debug!("  Prerequisite IDs: {:?}", prereq_ids);
85
86        let prereq_name = rdr.fstring()?;
87        debug!("  Prerequisite name: {}", prereq_name);
88
89        let prereq_path = rdr.fstring()?;
90        debug!("  Prerequisite path: {}", prereq_path);
91
92        let prereq_args = rdr.fstring()?;
93        debug!("  Prerequisite args: {}", prereq_args);
94
95        let build_id = if data_version >= 1 {
96            let build_id = rdr.fstring()?;
97            debug!("  Build ID: {}", build_id);
98            Some(build_id)
99        } else {
100            None
101        };
102
103        let end_pos = rdr.stream_position()?;
104        let bytes_read = end_pos - start_pos;
105
106        Ok((
107            Self {
108                data_size,
109                data_version,
110                feature_level,
111                is_file_data,
112                app_id,
113                app_name,
114                build_version,
115                launch_exe,
116                launch_command,
117                prereq_ids,
118                prereq_name,
119                prereq_path,
120                prereq_args,
121                build_id,
122            },
123            bytes_read,
124        ))
125    }
126}