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 mut 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            let merge_data = data
36                .as_object_mut()
37                .and_then(|obj| obj.remove("data"))
38                .unwrap_or(Value::Null);
39            merge_schema_owned(
40                &mut self.shared.schema["__indir"][indir]["data"],
41                merge_data,
42            );
43
44            self.out = UNPRINTABLE.to_string();
45
46            return Ok(());
47        }
48
49        self.file_path = self.code.clone();
50
51        // For security requires {:allow;
52        if self.file_path.contains(BIF_OPEN) {
53            if !self.contains_allow(&self.file_path) {
54                return Err(self.bif_error("insecure file name"));
55            }
56            self.file_path = new_child_parse!(self, &self.code, false);
57        }
58
59        if let Some(stripped) = self.file_path.strip_prefix('#') {
60            self.file_path = format!("{}{}", self.inherit.current_dir, stripped);
61        }
62
63        let path = Path::new(&self.file_path);
64        if !Path::new(path).exists() {
65            if self.flags.contains("|require|") {
66                return Err(self.bif_error("file not found"));
67            } else {
68                self.out = EMPTY_STRING;
69
70                return Ok(());
71            }
72        }
73
74        let canonical_path = fs::canonicalize(path)
75            .unwrap()
76            .to_string_lossy()
77            .into_owned();
78
79        if self.mod_negate && self.inherit.data_files.contains(&canonical_path) {
80            self.out = UNPRINTABLE.to_string();
81
82            return Ok(());
83        }
84
85        self.inherit.data_files.push(canonical_path);
86        let file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
87
88        let mut data: Value = match serde_json::from_str(&file_raw) {
89            Ok(value) => value,
90            Err(_) => {
91                return Err(self.bif_error(BIF_ERROR_NOT_VALID_JSON));
92            }
93        };
94
95        let indir = &self.inherit.create_block_schema(self.shared);
96
97        // Merge new locale data in curren local data.
98        let merge_data = data
99            .as_object_mut()
100            .and_then(|obj| obj.remove("data"))
101            .unwrap_or(Value::Null);
102        merge_schema_owned(
103            &mut self.shared.schema["__indir"][indir]["data"],
104            merge_data,
105        );
106
107        self.out = UNPRINTABLE.to_string();
108
109        Ok(())
110    }
111}
112
113#[cfg(test)]
114#[path = "parse_bif_data_tests.rs"]
115mod tests;