neutralts/bif/
parse_bif_locale.rs

1#![doc = include_str!("../../doc/bif-locale.md")]
2
3use crate::{bif::constants::*, bif::Bif, bif::BifError, constants::*, utils::*, Value};
4use std::fs;
5use std::path::Path;
6
7impl<'a> Bif<'a> {
8    /*
9        {:locale; file-path :}
10    */
11    pub(crate) fn parse_bif_locale(&mut self) -> Result<(), BifError> {
12        if self.mod_filter || self.mod_scope {
13            return Err(self.bif_error(BIF_ERROR_MODIFIER_NOT_ALLOWED));
14        }
15
16        self.extract_params_code(true);
17
18        if !self.flags.is_empty() {
19            if !self.flags.contains("|require|")
20                && !self.flags.contains("|inline|")
21                && !self.flags.contains("|noparse|")
22            {
23                return Err(self.bif_error(BIF_ERROR_FLAGS_NOT_ALLOWED));
24            }
25        }
26
27        if self.flags.contains("|inline|") {
28            // Parse possible bifs included in json
29            if self.code.contains(BIF_OPEN) {
30                self.code = new_child_parse!(self, &self.code, false);
31            }
32
33            let locale: Value = match serde_json::from_str(&self.code) {
34                Ok(value) => value,
35                Err(_) => {
36                    return Err(self.bif_error(BIF_ERROR_NOT_VALID_JSON));
37                }
38            };
39
40            let indir = &self.inherit.create_block_schema(self.shared);
41
42            // Merge new locale data in curren locale.
43            merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
44
45            self.out = EMPTY_STRING;
46
47            return Ok(());
48        }
49
50        self.file_path = self.code.clone();
51
52        // For security requires {:allow;
53        if self.file_path.contains(BIF_OPEN) {
54            if !self.contains_allow(&self.file_path) {
55                return Err(self.bif_error(BIF_ERROR_INSECURE_FILE_NAME));
56            }
57            self.file_path = new_child_parse!(self, &self.code, false);
58        }
59
60        if let Some(stripped) = self.file_path.strip_prefix('#') {
61            self.file_path = format!("{}{}", self.inherit.current_dir, stripped);
62        }
63
64        let path = Path::new(&self.file_path);
65        if !Path::new(path).exists() {
66            if self.flags.contains("|require|") {
67                return Err(self.bif_error(BIF_ERROR_FILE_NOT_FOUND));
68            } else {
69                return Ok(());
70            }
71        }
72
73        let canonical_path = fs::canonicalize(path)
74            .unwrap()
75            .to_string_lossy()
76            .into_owned();
77        if self.mod_negate && self.inherit.locale_files.contains(&canonical_path) {
78            self.out = UNPRINTABLE.to_string();
79
80            return Ok(());
81        }
82
83        self.inherit.locale_files.push(canonical_path);
84        let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
85
86        if !self.flags.contains("|noparse|") {
87            // Parse possible bifs included in json
88            if file_raw.contains(BIF_OPEN) {
89                file_raw = new_child_parse!(self, &file_raw, false);
90            }
91        }
92
93        let locale: Value = match serde_json::from_str(&file_raw) {
94            Ok(value) => value,
95            Err(_) => {
96                return Err(self.bif_error(BIF_ERROR_NOT_VALID_JSON));
97            }
98        };
99
100        let indir = &self.inherit.create_block_schema(self.shared);
101
102        // Merge new locale data in curren locale.
103        merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
104
105        self.out = UNPRINTABLE.to_string();
106
107        Ok(())
108    }
109}
110
111#[cfg(test)]
112#[path = "parse_bif_locale_tests.rs"]
113mod tests;