ds_decomp/config/
config.rs1use 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 pub name: String,
106 pub object: PathBuf,
108 pub hash: String,
110 pub delinks: PathBuf,
112 pub symbols: PathBuf,
114 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}