ds_decomp/config/
config.rs

1use std::{
2    backtrace::Backtrace,
3    path::{Path, PathBuf},
4};
5
6use ds_rom::rom::raw::AutoloadKind;
7use serde::{Deserialize, Serialize};
8use snafu::Snafu;
9
10use crate::{
11    config::{
12        delinks::{Delinks, DelinksParseError},
13        module::{Module, ModuleError, ModuleKind, ModuleOptions},
14        relocations::{Relocations, RelocationsParseError},
15        symbol::SymbolMaps,
16    },
17    util::io::{self, FileError, open_file},
18};
19
20#[derive(Serialize, Deserialize)]
21pub struct Config {
22    pub rom_config: PathBuf,
23    pub build_path: PathBuf,
24    pub delinks_path: PathBuf,
25    pub main_module: ConfigModule,
26    pub autoloads: Vec<ConfigAutoload>,
27    pub overlays: Vec<ConfigOverlay>,
28}
29
30#[derive(Debug, Snafu)]
31pub enum ConfigParseError {
32    #[snafu(transparent)]
33    File { source: FileError },
34    #[snafu(display("Failed to parse dsd config file '{}': {error}\n{backtrace}", path.display()))]
35    SerdeYml { path: PathBuf, error: serde_yml::Error, backtrace: Backtrace },
36}
37
38#[derive(Debug, Snafu)]
39pub enum LoadModuleError {
40    #[snafu(display("Failed to load module config for kind {module_kind}: \n{backtrace}"))]
41    ModuleConfigNotFound { module_kind: ModuleKind, backtrace: Backtrace },
42    #[snafu(transparent)]
43    RelocationsParse { source: RelocationsParseError },
44    #[snafu(transparent)]
45    DelinksParse { source: DelinksParseError },
46    #[snafu(transparent)]
47    File { source: FileError },
48    #[snafu(transparent)]
49    Module { source: ModuleError },
50}
51
52impl Config {
53    pub fn from_file(path: &Path) -> Result<Config, ConfigParseError> {
54        let file = open_file(path)?;
55        serde_yml::from_reader(file).map_err(|error| SerdeYmlSnafu { path, error }.build())
56    }
57
58    pub fn get_module_config_by_kind(&self, module_kind: ModuleKind) -> Option<&ConfigModule> {
59        match module_kind {
60            ModuleKind::Arm9 => Some(&self.main_module),
61            ModuleKind::Autoload(autoload_kind) => {
62                self.autoloads.iter().find(|autoload| autoload.kind == autoload_kind).map(|autoload| &autoload.module)
63            }
64            ModuleKind::Overlay(id) => self.overlays.iter().find(|overlay| overlay.id == id).map(|overlay| &overlay.module),
65        }
66    }
67
68    pub fn load_module<P: AsRef<Path>>(
69        &self,
70        config_path: P,
71        symbol_maps: &mut SymbolMaps,
72        module_kind: ModuleKind,
73    ) -> Result<Module, LoadModuleError> {
74        let config_path = config_path.as_ref();
75        let symbol_map = symbol_maps.get_mut(module_kind);
76        let module_config =
77            self.get_module_config_by_kind(module_kind).ok_or_else(|| ModuleConfigNotFoundSnafu { module_kind }.build())?;
78        let relocations = Relocations::from_file(config_path.join(&module_config.relocations))?;
79        let delinks = Delinks::from_file(config_path.join(&module_config.delinks), module_kind)?;
80        let code = if delinks.sections.text_size() == 0 {
81            vec![]
82        } else {
83            io::read_file(config_path.join(&module_config.object))?
84        };
85
86        let module = Module::new(
87            symbol_map,
88            ModuleOptions {
89                kind: module_kind,
90                name: module_config.name.clone(),
91                relocations,
92                sections: delinks.sections,
93                code: &code,
94                signed: false,
95            },
96        )?;
97
98        Ok(module)
99    }
100}
101
102#[derive(Serialize, Deserialize)]
103pub struct ConfigModule {
104    /// Name of module
105    pub name: String,
106    /// Binary file to build
107    pub object: PathBuf,
108    /// 64-bit fxhash of the binary file
109    pub hash: String,
110    /// Path to delinks file
111    pub delinks: PathBuf,
112    /// Path to symbols file
113    pub symbols: PathBuf,
114    /// Path to relocs file
115    pub relocations: PathBuf,
116}
117
118#[derive(Serialize, Deserialize)]
119pub struct ConfigOverlay {
120    pub id: u16,
121    #[serde(default = "default_overlay_signed", skip_serializing_if = "skip_overlay_signed")]
122    pub signed: bool,
123    #[serde(flatten)]
124    pub module: ConfigModule,
125}
126
127fn default_overlay_signed() -> bool {
128    false
129}
130
131fn skip_overlay_signed(signed: &bool) -> bool {
132    *signed == default_overlay_signed()
133}
134
135#[derive(Serialize, Deserialize)]
136pub struct ConfigAutoload {
137    pub kind: AutoloadKind,
138    #[serde(flatten)]
139    pub module: ConfigModule,
140}