neutralts/bif/
parse_bif_data.rs

1#![doc = include_str!("../../doc/bif-data.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        {:data; file-path :} {:* local data *}
10    */
11    pub(crate) fn parse_bif_data(&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|") && !self.flags.contains("|inline|") {
20                return Err(self.bif_error(BIF_ERROR_FLAGS_NOT_ALLOWED));
21            }
22        }
23
24        if self.flags.contains("|inline|") {
25            let data: Value = match serde_json::from_str(&self.code) {
26                Ok(value) => value,
27                Err(_) => {
28                    return Err(self.bif_error(BIF_ERROR_NOT_VALID_JSON));
29                }
30            };
31
32            let indir = &self.inherit.create_block_schema(self.shared);
33
34            // Merge new locale data in curren local data.
35            merge_schema(
36                &mut self.shared.schema["__indir"][indir]["data"],
37                &data["data"],
38            );
39
40            self.out = UNPRINTABLE.to_string();
41
42            return Ok(());
43        }
44
45        self.file_path = self.code.clone();
46
47        // For security requires {:allow;
48        if self.file_path.contains(BIF_OPEN) {
49            if !self.contains_allow(&self.file_path) {
50                return Err(self.bif_error("insecure file name"));
51            }
52            self.file_path = new_child_parse!(self, &self.code, false);
53        }
54
55        if let Some(stripped) = self.file_path.strip_prefix('#') {
56            self.file_path = format!("{}{}", self.inherit.current_dir, stripped);
57        }
58
59        let path = Path::new(&self.file_path);
60        if !Path::new(path).exists() {
61            if self.flags.contains("|require|") {
62                return Err(self.bif_error("file not found"));
63            } else {
64                self.out = EMPTY_STRING;
65
66                return Ok(());
67            }
68        }
69
70        let canonical_path = fs::canonicalize(path)
71            .unwrap()
72            .to_string_lossy()
73            .into_owned();
74
75        if self.mod_negate && self.inherit.data_files.contains(&canonical_path) {
76            self.out = UNPRINTABLE.to_string();
77
78            return Ok(());
79        }
80
81        self.inherit.data_files.push(canonical_path);
82        let file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
83
84        let data: Value = match serde_json::from_str(&file_raw) {
85            Ok(value) => value,
86            Err(_) => {
87                return Err(self.bif_error(BIF_ERROR_NOT_VALID_JSON));
88            }
89        };
90
91        let indir = &self.inherit.create_block_schema(self.shared);
92
93        // Merge new locale data in curren local data.
94        merge_schema(
95            &mut self.shared.schema["__indir"][indir]["data"],
96            &data["data"],
97        );
98
99        self.out = UNPRINTABLE.to_string();
100
101        Ok(())
102    }
103}
104
105#[cfg(test)]
106#[path = "parse_bif_data_tests.rs"]
107mod tests;