infinite_rs/tag/
loader.rs

1//! Main abstraction file for tags.
2
3use std::io::SeekFrom;
4
5use super::{
6    data_reference::TagDataReference, datablock::TagDataBlock, dependency::TagDependency,
7    header::TagHeader, reference::TagReference, structure::TagStruct,
8};
9use crate::Result;
10use crate::common::extensions::BufReaderExt;
11use crate::module::header::ModuleVersion;
12
13#[derive(Default, Debug)]
14/// Tag structure containing structure of entire tag file.
15pub struct TagFile {
16    /// Header containing info on how to read other parts of the file.
17    pub header: TagHeader,
18    /// Tags that are referenced by this tag and that need to be lazy loaded.
19    pub dependencies: Vec<TagDependency>,
20    /// Blocks making up the entire tag (Internal and External)
21    pub datablock_definitions: Vec<TagDataBlock>,
22    /// Internal structure units of the tag.
23    pub struct_definitions: Vec<TagStruct>,
24    /// References to external data from the tag.
25    pub data_references: Vec<TagDataReference>,
26    /// Tags that are referenced by this tag inside the module.
27    pub tag_references: Vec<TagReference>,
28}
29
30impl TagFile {
31    /// Reads the tag file from the given readers implementing [`BufReaderExt`].
32    /// # Arguments
33    ///
34    /// * `reader` - A mutable reference to a reader that implements [`BufReaderExt`] from which to read the data.
35    /// * `module_version` - Version of the module being read
36    ///
37    /// # Errors
38    /// - If the reader fails to read the exact number of bytes [`ReadError`](`crate::Error::ReadError`)
39    pub fn read<R: BufReaderExt>(&mut self, reader: &mut R, version: &ModuleVersion) -> Result<()> {
40        self.header.read(reader)?;
41        self.dependencies =
42            reader.read_enumerable::<TagDependency>(u64::from(self.header.dependency_count))?;
43
44        self.datablock_definitions =
45            reader.read_enumerable::<TagDataBlock>(u64::from(self.header.datablock_count))?;
46
47        self.struct_definitions =
48            reader.read_enumerable::<TagStruct>(u64::from(self.header.tagstruct_count))?;
49
50        self.data_references = reader
51            .read_enumerable::<TagDataReference>(u64::from(self.header.data_reference_count))?;
52
53        self.tag_references =
54            reader.read_enumerable::<TagReference>(u64::from(self.header.tag_reference_count))?;
55
56        let string_table_position = reader.stream_position()?;
57
58        // This is only valid before Season 3.
59        if version < &ModuleVersion::Season3 {
60            for dep in &mut self.dependencies {
61                reader.seek(SeekFrom::Start(
62                    string_table_position + u64::from(dep.name_offset),
63                ))?;
64                dep.name = Some(reader.read_null_terminated_string()?);
65            }
66            for reference in &mut self.tag_references {
67                reader.seek(SeekFrom::Start(
68                    string_table_position + u64::from(reference.name_offset),
69                ))?;
70                reference.name = Some(reader.read_null_terminated_string()?);
71            }
72        }
73        // Ensure that tag data starts where it is supposed to.
74        reader.seek(SeekFrom::Start(u64::from(self.header.header_size)))?;
75        Ok(())
76    }
77}