product_os_utilities/
lib.rs

1#![no_std]
2extern crate no_std_compat as std;
3
4use std::prelude::v1::*;
5
6pub mod data;
7
8use std::fmt::Formatter;
9
10use crate::data::DataFormat;
11
12#[cfg(any(feature = "networking", feature = "networking_std"))]
13use product_os_net::{ IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs };
14
15#[cfg(feature = "networking_std")]
16use dns_lookup::lookup_host;
17
18#[cfg(feature = "files")]
19use product_os_security::RandomGeneratorTemplate;
20
21#[cfg(feature = "content")]
22use content_inspector::{ContentType, inspect};
23#[cfg(feature = "content")]
24use mime_sniffer::MimeTypeSniffer;
25
26
27#[cfg(feature = "files")]
28use std::sync::Arc;
29
30#[cfg(feature = "files")]
31use parking_lot::Mutex;
32
33
34#[cfg(feature = "json")]
35use regex::Regex;
36#[cfg(feature = "json")]
37use chrono::NaiveDateTime;
38
39#[cfg(any(feature = "json", feature = "yaml", feature = "networking", feature = "networking_std"))]
40use std::str::FromStr;
41
42use serde::{ Serialize, Deserialize };
43
44
45#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
46pub enum ProductOSError {
47    GenericError(String)
48}
49
50impl ProductOSError {
51    pub fn to_string(&self) -> String {
52        match self {
53            ProductOSError::GenericError(e) => e.to_owned(),
54            // _ => "Dunno".to_string()
55        }
56    }
57}
58
59impl std::fmt::Display for ProductOSError {
60    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61        match self {
62            ProductOSError::GenericError(s) => write!(f, "{}", s)
63        }
64    }
65}
66
67
68pub struct ProductOSUtilities {}
69
70impl ProductOSUtilities {
71    #[cfg(feature = "files")]
72    pub fn get_current_working_dir() -> String {
73        let res = std::env::current_dir();
74        match res {
75            Ok(path) => path.into_os_string().into_string().unwrap(),
76            Err(_) => panic!("Problem getting current working directory")
77        }
78    }
79
80    #[cfg(feature = "files")]
81    pub fn get_base_path(files_path: &str) -> String {
82        let mut files_base_path = String::new();
83
84        if !files_path.starts_with("/") {
85            files_base_path.push_str(ProductOSUtilities::get_current_working_dir().as_str());
86        }
87
88        if !files_path.ends_with("/") {
89            files_base_path.push_str("/");
90        }
91
92        files_base_path.push_str(files_path);
93
94        tracing::info!("File list path used for file list get is: {:?}", files_base_path);
95
96        files_base_path
97    }
98
99    #[cfg(feature = "files")]
100    pub fn get_file_list(files_path: &str) -> Result<Vec<String>, ProductOSError> {
101        let files_base_path = ProductOSUtilities::get_base_path(files_path);
102
103        tracing::info!("File list path used for file list get is: {:?}", files_base_path);
104
105        let entries = walkdir::WalkDir::new(files_base_path.as_str())
106            .min_depth(1)
107            .max_depth(5)
108            .follow_links(true)
109            .into_iter()
110            .filter_entry(|e| ProductOSUtilities::is_not_hidden(e));
111        //.filter_map(|v| v.ok());
112        //.for_each(|entry| );
113
114        let mut files_list = Vec::new();
115
116        for entry in entries {
117            match entry {
118                Ok(entry) => {
119                    let path = entry.path();
120                    match path.to_str() {
121                        None => {}
122                        Some(s) => {
123                            if entry.metadata().unwrap().is_file() {
124                                // let filename = s.split('/').collect::<Vec<&str>>().last().unwrap().to_owned();
125
126                                let mut files_path = files_path.to_owned();
127                                files_path.push_str(s.to_string().replace(files_base_path.as_str(), "").as_str());
128
129                                let mut files_data_path = String::from(files_base_path.as_str());
130                                files_data_path.push_str(s.to_string().replace(files_base_path.as_str(), "").as_str());
131
132                                files_list.push(files_data_path);
133                            }
134                        }
135                    }
136                }
137                Err(e) => return Err(ProductOSError::GenericError(format!("Failed to read files folder entry: {:?}", e)))
138            }
139        }
140
141        Ok(files_list)
142    }
143
144    #[cfg(feature = "files")]
145    fn is_not_hidden(entry: &walkdir::DirEntry) -> bool {
146        entry
147            .file_name()
148            .to_str()
149            .map(|s| !s.starts_with("."))
150            .unwrap_or(false)
151    }
152
153    #[cfg(feature = "files")]
154    pub fn get_select_file(random_generator: Arc<Mutex<product_os_security::RandomGenerator>>, files_path: &str) -> Result<String, ProductOSError> {
155        let mut generator = random_generator.lock();
156
157        match ProductOSUtilities::get_file_list(files_path) {
158            Ok(files_list) => {
159                let random_value = generator.get_random_usize(0, files_list.len());
160                let value: String = files_list.get(random_value).unwrap().to_string();
161                Ok(value)
162            }
163            Err(e) => Err(e)
164        }
165    }
166
167    #[cfg(feature = "logging_std")]
168    pub fn define_logging(level: tracing::Level) -> tracing_subscriber::FmtSubscriber {
169        // a builder for `FmtSubscriber`.
170        tracing_subscriber::FmtSubscriber::builder()
171            // filter spans/events with level TRACE or higher.
172            .with_max_level(level)
173            // build but do not install the subscriber.
174            .finish()
175    }
176
177    #[cfg(feature = "logging_std")]
178    pub fn set_global_logger(definition: tracing_subscriber::FmtSubscriber) {
179        match tracing::subscriber::set_global_default(definition) {
180            Ok(_) => {}
181            Err(e) => { tracing::warn!("Error setting default subscriber: {}", e) }
182        }
183    }
184
185    #[cfg(feature = "networking_advanced")]
186    pub fn get_all_current_host_ip_addresses() -> Vec<core::net::IpAddr> {
187        let mut ip_list = Vec::new();
188
189        for iface in pnet::datalink::interfaces() {
190            let ips = iface.ips;
191
192            for ip in ips {
193                tracing::info!("Idnentified current host IP address: {:?}", ip);
194                ip_list.push(ip.network())
195            }
196        }
197
198        ip_list
199    }
200
201    #[cfg(feature = "networking_std")]
202    pub fn get_socket_address(host: &str, port: u16, default_all_interfaces: bool) -> SocketAddr {
203        let socket_port = port;
204
205        let default_address = match default_all_interfaces {
206            true => SocketAddr::from((Ipv4Addr::new(0, 0, 0, 0), socket_port)),
207            false => SocketAddr::from((Ipv4Addr::new(127, 0, 0, 1), socket_port))
208        };
209
210        match lookup_host(host) {
211            Ok(addresses) => {
212                for address in addresses {
213                    let address_string = address.to_string();
214                    match SocketAddr::from_str(address_string.as_str()) {
215                        Ok(socket_addr) => return socket_addr,
216                        Err(_) => {}
217                    }
218                }
219
220                tracing::info!("Hostname did not resolve any meaningful address, using default address");
221                default_address
222            },
223            Err(_) => {
224                match Ipv4Addr::from_str(host) {
225                    Ok(address) => {
226                        SocketAddr::from((IpAddr::V4(address), socket_port))
227                    },
228                    Err(_) => {
229                        match Ipv6Addr::from_str(host) {
230                            Ok(address) => {
231                                SocketAddr::from((IpAddr::V6(address), socket_port))
232                            },
233                            Err(_) => {
234                                tracing::error!("Address defined does not meet any allowed formats, using default address");
235                                default_address
236                            }
237                        }
238                    }
239                }
240            }
241        }
242    }
243
244    #[cfg(feature = "networking_std")]
245    pub fn get_all_interfaces_socket_address(host: &str, port: u16) -> SocketAddr {
246        let socket_port = port;
247
248        let default_address = SocketAddr::from((Ipv4Addr::new(0, 0, 0, 0), socket_port));
249
250        match Ipv4Addr::from_str(host) {
251            Ok(address) => {
252                SocketAddr::from((IpAddr::V4(address), socket_port))
253            },
254            Err(_) => {
255                match Ipv6Addr::from_str(host) {
256                    Ok(address) => {
257                        SocketAddr::from((IpAddr::V6(address), socket_port))
258                    },
259                    Err(_) => {
260                        tracing::error!("Address defined does not meet any allowed formats, using default address");
261                        default_address
262                    }
263                }
264            }
265        }
266    }
267
268    #[cfg(feature = "networking_std")]
269    pub fn get_local_socket_address(host: &str, port: u16) -> SocketAddr {
270        let socket_port = port;
271
272        let default_address = SocketAddr::from((Ipv4Addr::new(127, 0, 0, 1), socket_port));
273
274        match Ipv4Addr::from_str(host) {
275            Ok(address) => {
276                SocketAddr::from((IpAddr::V4(address), socket_port))
277            },
278            Err(_) => {
279                match Ipv6Addr::from_str(host) {
280                    Ok(address) => {
281                        SocketAddr::from((IpAddr::V6(address), socket_port))
282                    },
283                    Err(_) => {
284                        tracing::error!("Address defined does not meet any allowed formats, using default address");
285                        default_address
286                    }
287                }
288            }
289        }
290    }
291
292    // JSON
293
294    #[cfg(feature = "json")]
295    pub fn find_json_property(object: &serde_json::Value, property: &str, default_value: &serde_json::Value) -> serde_json::Value {
296        let property_parts = property.split(".").collect::<Vec<&str>>();
297        let property_parts_length = property_parts.len();
298
299        ProductOSUtilities::find_json_property_internal(object, property_parts, default_value, 0, property_parts_length)
300    }
301
302    #[cfg(feature = "json")]
303    fn find_json_property_internal(object: &serde_json::Value, property_parts: Vec<&str>, default_value: &serde_json::Value, depth: usize, property_parts_length: usize) -> serde_json::Value {
304        match object {
305            serde_json::Value::Array(array) => {
306                match usize::from_str(property_parts.get(depth).unwrap()) {
307                    Ok(prop) => {
308                        match array.get(prop) {
309                            None => default_value.to_owned(),
310                            Some(value) => {
311                                if depth == property_parts_length - 1 {
312                                    value.to_owned()
313                                }
314                                else {
315                                    ProductOSUtilities::find_json_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
316                                }
317                            }
318                        }
319                    }
320                    Err(_) => default_value.to_owned()
321                }
322            }
323            serde_json::Value::Object(o) => {
324                #[cfg(feature = "logging")]
325                tracing::info!("Name {:?} in object {:?} for remap", &property_parts.get(depth).unwrap().to_string(), o);
326                match o.get_key_value(&property_parts.get(depth).unwrap().to_string()) {
327                    None => default_value.to_owned(),
328                    Some((_, value)) => {
329                        if depth == property_parts_length - 1 {
330                            value.to_owned()
331                        }
332                        else {
333                            ProductOSUtilities::find_json_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
334                        }
335                    }
336                }
337            }
338            _ => default_value.to_owned()
339        }
340    }
341
342    #[cfg(feature = "json")]
343    pub fn is_number_json(object: &serde_json::Value) -> bool {
344        match object {
345            serde_json::Value::Number(_) => true,
346            serde_json::Value::String(s) => {
347                let regex = Regex::new("^[-+]?[0-9]+([.][0-9]+)?$").unwrap();
348                regex.is_match(s.as_str())
349            }
350            _ => false
351        }
352    }
353
354    #[cfg(feature = "json")]
355    pub fn is_integer_json(object: &serde_json::Value) -> bool {
356        match object {
357            serde_json::Value::Number(n) => {
358                if n.is_i64() || n.is_u64() { true }
359                else { false }
360            },
361            serde_json::Value::String(s) => {
362                let regex = Regex::new("^[-+]?[0-9]+$").unwrap();
363                regex.is_match(s.as_str())
364            }
365            _ => false
366        }
367    }
368
369    #[cfg(feature = "json")]
370    pub fn is_float_json(object: &serde_json::Value) -> bool {
371        match object {
372            serde_json::Value::Number(n) => {
373                if n.is_f64() { true }
374                else { false }
375            },
376            serde_json::Value::String(s) => {
377                let regex = Regex::new("^[-+]?[0-9]+([.][0-9]+)$").unwrap();
378                regex.is_match(s.as_str())
379            }
380            _ => false
381        }
382    }
383
384    #[cfg(feature = "json")]
385    pub fn is_boolean_json(object: &serde_json::Value) -> bool {
386        match object {
387            serde_json::Value::Bool(_) => true,
388            serde_json::Value::Number(n) => {
389                if n.is_i64() {
390                    match n.as_i64().unwrap() {
391                        0 | 1 => true,
392                        _ => false
393                    }
394                }
395                else if n.is_u64() {
396                    match n.as_u64().unwrap() {
397                        0 | 1 => true,
398                        _ => false
399                    }
400                }
401                else { false }
402            }
403            serde_json::Value::String(s) => {
404                let regex = Regex::new("^(?i)(none|some|null|true|false|0|1)$").unwrap();
405                regex.is_match(s.as_str())
406            }
407            _ => false
408        }
409    }
410
411    #[cfg(feature = "json")]
412    pub fn is_date_json(object: &serde_json::Value) -> bool {
413        match object {
414            serde_json::Value::String(s) => {
415                match NaiveDateTime::from_str(s.as_str()) {
416                    Ok(_) => true,
417                    Err(_) => false
418                }
419            }
420            _ => false
421        }
422    }
423
424    #[cfg(feature = "json")]
425    pub fn is_base64_json(object: &serde_json::Value) -> bool {
426        match object {
427            serde_json::Value::String(s) => {
428                let regex = Regex::new("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$").unwrap();
429                regex.is_match(s.as_str())
430            }
431            _ => false
432        }
433    }
434
435    #[cfg(feature = "json")]
436    pub fn is_mime_type_json(object: &serde_json::Value) -> bool {
437        match object {
438            serde_json::Value::String(s) => {
439                let regex = Regex::new("\\w+/[-.\\w]+(?:\\+[-.\\w]+)?").unwrap();
440                regex.is_match(s.as_str())
441            }
442            _ => false
443        }
444    }
445
446    #[cfg(all(feature = "json", feature = "content"))]
447    pub fn is_valid_mime_type_json(object: &serde_json::Value) -> Option<String> {
448        match object {
449            serde_json::Value::String(s) => {
450                match s.as_str().sniff_mime_type() {
451                    None => None,
452                    Some(s) => Some(s.to_string())
453                }
454            }
455            _ => None
456        }
457    }
458
459    #[cfg(all(feature = "json", feature = "content"))]
460    pub fn is_binary_json(object: &serde_json::Value) -> bool {
461        match object {
462            serde_json::Value::String(s) => {
463                match inspect(s.as_bytes()) {
464                    ContentType::BINARY => true,
465                    _ => false
466                }
467            }
468            _ => false
469        }
470    }
471
472    #[cfg(all(feature = "json", feature = "xml"))]
473    pub fn is_xml_json(object: &serde_json::Value) -> bool {
474        match object {
475            serde_json::Value::String(s) => {
476                let parser = xml::reader::EventReader::from_str(s.as_str());
477
478                let mut is_valid = false;
479                for e in parser {
480                    match e {
481                        Ok(_) => { is_valid = true },
482                        Err(_) => {}
483                    }
484                }
485
486                is_valid
487            }
488            _ => false
489        }
490    }
491
492    #[cfg(feature = "json")]
493    pub fn is_array_json(object: &serde_json::Value) -> bool {
494        match object {
495            serde_json::Value::Array(_) => true,
496            _ => false
497        }
498    }
499
500    #[cfg(feature = "json")]
501    pub fn is_string_json(object: &serde_json::Value) -> bool {
502        match object {
503            serde_json::Value::String(_) => true,
504            _ => false
505        }
506    }
507
508    #[cfg(feature = "json")]
509    pub fn is_option_json(object: &serde_json::Value) -> bool {
510        match object {
511            serde_json::Value::String(_) => true,
512            serde_json::Value::Number(_) => true,
513            serde_json::Value::Bool(_) => true,
514            _ => false
515        }
516    }
517
518    #[cfg(feature = "json")]
519    pub fn is_object_json(object: &serde_json::Value) -> bool {
520        match object {
521            serde_json::Value::Object(_) => true,
522            _ => false
523        }
524    }
525
526    #[cfg(feature = "json")]
527    pub fn is_null_json(object: &serde_json::Value) -> bool {
528        match object {
529            serde_json::Value::Null => true,
530            _ => false
531        }
532    }
533
534    #[cfg(feature = "json")]
535    pub fn data_type_json(object: &serde_json::Value) -> DataFormat {
536        if ProductOSUtilities::is_number_json(object) {
537            return DataFormat::Number
538        }
539
540        if ProductOSUtilities::is_boolean_json(object) {
541            return DataFormat::Boolean
542        }
543
544        if ProductOSUtilities::is_date_json(object) {
545            return DataFormat::Date
546        }
547
548        #[cfg(all(feature = "json", feature = "xml"))] {
549            if ProductOSUtilities::is_xml_json(object) {
550                return DataFormat::XML
551            }
552        }
553
554        if ProductOSUtilities::is_object_json(object) {
555            return DataFormat::JSON
556        }
557
558        if ProductOSUtilities::is_array_json(object) {
559            return DataFormat::List
560        }
561
562        if ProductOSUtilities::is_base64_json(object) {
563            return DataFormat::Base64
564        }
565
566        #[cfg(all(feature = "json", feature = "content"))] {
567            if ProductOSUtilities::is_binary_json(object) {
568                return DataFormat::Binary
569            }
570        }
571
572        #[cfg(all(feature = "json", feature = "content"))] {
573            match ProductOSUtilities::is_valid_mime_type_json(object) {
574                None => {
575                    if ProductOSUtilities::is_string_json(object) {
576                        return DataFormat::Text
577                    }
578                    else if ProductOSUtilities::is_option_json(object) {
579                        return DataFormat::Option(object.to_string())
580                    }
581                }
582                Some(s) => {
583                    return DataFormat::Mime(s)
584                }
585            }
586        }
587
588        DataFormat::Unknown
589    }
590
591    #[cfg(feature = "text")]
592    pub fn text_indent(size: usize) -> String {
593        const INDENT: &'static str = "    ";
594        (0..size).map(|_| INDENT)
595            .fold(String::with_capacity(size*INDENT.len()), |r, s| r + s)
596    }
597
598    #[cfg(feature = "yaml")]
599    pub fn yaml_to_string(yaml: &serde_yaml::Value, is_document: bool) -> Result<String, ProductOSError> {
600        let depth = 0;
601
602        let mut yaml_string = String::new();
603
604        if is_document {
605            yaml_string.push_str("---\n");
606        }
607
608        match ProductOSUtilities::yaml_to_string_internal(yaml, depth) {
609            Ok(yaml_str) => yaml_string.push_str(yaml_str.as_str()),
610            Err(e) => return Err(e)
611        }
612
613        Ok(yaml_string)
614    }
615
616    #[cfg(feature = "yaml")]
617    pub fn string_to_yaml(yaml_string: &str) -> Result<serde_yaml::Value, ProductOSError> {
618        match serde_yaml::from_str(yaml_string) {
619            Ok(v) => Ok(v),
620            Err(e) => Err(ProductOSError::GenericError(e.to_string()))
621        }
622    }
623
624    #[cfg(feature = "yaml")]
625    fn yaml_to_string_internal(yaml: &serde_yaml::Value, mut depth: usize) -> Result<String, ProductOSError> {
626        let mut yaml_string = String::new();
627
628        match yaml {
629            serde_yaml::Value::Null => {},
630            serde_yaml::Value::Bool(b) => yaml_string.push_str(format!("{}", b).as_str()),
631            serde_yaml::Value::Number(n) => {
632                match n.as_u64() {
633                    Some(u) => yaml_string.push_str(format!("{}", u).as_str()),
634                    None => {
635                        match n.as_f64() {
636                            Some(f) => yaml_string.push_str(format!("{}", f).as_str()),
637                            None => {
638                                match n.as_i64() {
639                                    Some(i) => yaml_string.push_str(format!("{}", i).as_str()),
640                                    None => return Err(ProductOSError::GenericError(String::from("Could not convert YAML")))
641                                }
642                            }
643                        }
644                    }
645                }
646            }
647            serde_yaml::Value::String(s) => yaml_string.push_str(format!("{}", s).as_str()),
648            serde_yaml::Value::Sequence(a) => {
649                for element in a {
650                    match ProductOSUtilities::yaml_to_string_internal(element, depth) {
651                        Ok(value) => {
652                            yaml_string.push_str(format!("{}- ", ProductOSUtilities::text_indent(depth)).as_str());
653
654                            depth = depth + 1;
655                            yaml_string.push_str(format!("{}", value).as_str());
656                            depth = depth - 1;
657                        }
658                        Err(e) => return Err(e)
659                    };
660
661                    yaml_string.push_str("\n");
662                }
663            }
664            serde_yaml::Value::Mapping(m) => {
665                for (key, value) in m {
666                    match ProductOSUtilities::yaml_to_string_internal(key, depth) {
667                        Ok(key) => {
668                            yaml_string.push_str(format!("{}{}: ", ProductOSUtilities::text_indent(depth), key).as_str());
669                        }
670                        Err(e) => return Err(e)
671                    };
672
673                    depth = depth + 1;
674                    match ProductOSUtilities::yaml_to_string_internal(value, depth) {
675                        Ok(value) => {
676                            yaml_string.push_str(format!("{}", value).as_str());
677                        }
678                        Err(e) => return Err(e)
679                    };
680                    depth = depth - 1;
681
682                    yaml_string.push_str("\n");
683                }
684            }
685            serde_yaml::Value::Tagged(t) => {
686                let value = match ProductOSUtilities::yaml_to_string_internal(&t.value, depth + 1) {
687                    Ok(v) => v,
688                    Err(e) => return Err(e)
689                };
690
691                yaml_string.push_str(format!("{}: {}\n", t.tag.to_string(), value).as_str());
692            }
693        }
694
695        Ok(yaml_string)
696
697        /*
698        match yaml.as_hash() {
699            Some(hash) => {
700                for (key, value) in hash {
701                    match ProductOSUtilities::yaml_to_string_internal(key, depth) {
702                        Ok(key) => {
703                            yaml_string.push_str(format!("{}{}: ", ProductOSUtilities::text_indent(depth), key).as_str());
704                        }
705                        Err(e) => return Err(e)
706                    };
707
708                    depth = depth + 1;
709                    match ProductOSUtilities::yaml_to_string_internal(value, depth) {
710                        Ok(value) => {
711                            yaml_string.push_str(format!("{}", value).as_str());
712                        }
713                        Err(e) => return Err(e)
714                    };
715                    depth = depth - 1;
716
717                    yaml_string.push_str("\n");
718                }
719
720                Ok(yaml_string)
721            }
722            None => {
723                match yaml.as_vec() {
724                    Some(array) => {
725                        for element in array {
726                            match ProductOSUtilities::yaml_to_string_internal(element, depth) {
727                                Ok(value) => {
728                                    yaml_string.push_str(format!("{}- ", ProductOSUtilities::text_indent(depth)).as_str());
729
730                                    depth = depth + 1;
731                                    yaml_string.push_str(format!("{}", value).as_str());
732                                    depth = depth - 1;
733                                }
734                                Err(e) => return Err(e)
735                            };
736
737                            yaml_string.push_str("\n");
738                        }
739                    }
740                    None => {
741                        match yaml.as_str() {
742                            Some(s) => yaml_string.push_str(format!("{}", s).as_str()),
743                            None => {
744                                match yaml.as_bool() {
745                                    Some(b) => yaml_string.push_str(format!("{}", b).as_str()),
746                                    None => {
747                                        match yaml.as_f64() {
748                                            Some(f) => yaml_string.push_str(format!("{}", f).as_str()),
749                                            None => {
750                                                match yaml.as_i64() {
751                                                    Some(i) => yaml_string.push_str(format!("{}", i).as_str()),
752                                                    None => return Err(ProductOSError::GenericError(String::from("Could not convert YAML")))
753                                                }
754                                            }
755                                        }
756                                    }
757                                }
758                            }
759                        }
760
761                        yaml_string.push_str("\n");
762                    }
763                }
764
765                Ok(yaml_string)
766            }
767        }
768        */
769    }
770
771
772    #[cfg(all(feature = "json", feature = "yaml"))]
773    pub fn yaml_to_json(yaml: &serde_yaml::Value) -> Result<serde_json::Value, ProductOSError> {
774        ProductOSUtilities::yaml_value_to_json_value(yaml)
775        /*
776        match yaml.as_hash() {
777            Some(hash) => {
778                let mut map = serde_json::Map::new();
779
780                for (key, value) in hash {
781                    let key = match ProductOSUtilities::yaml_to_json(key) {
782                        Ok(json_key) => {
783                            match json_key {
784                                serde_json::Value::String(s) => s,
785                                _ => return Err(ProductOSError::GenericError(String::from("Invalid type for a JSON key converting from serde_yaml::Value to Json")))
786                            }
787                        }
788                        Err(e) => return Err(e)
789                    };
790
791                    let value = match ProductOSUtilities::yaml_to_json(value) {
792                        Ok(json_value) => json_value,
793                        Err(e) => return Err(e)
794                    };
795
796                    map.insert(key, value);
797                }
798
799                Ok(serde_json::Value::Object(map))
800            }
801            None => {
802                match yaml.as_vec() {
803                    Some(array) => {
804                        let mut vector = vec!();
805
806                        for element in array {
807                            match ProductOSUtilities::yaml_to_json(element) {
808                                Ok(result) => vector.push(result),
809                                Err(e) => return Err(e)
810                            }
811                        }
812
813                        Ok(serde_json::Value::Array(vector))
814                    }
815                    None => {
816                        match yaml.as_str() {
817                            Some(s) => Ok(serde_json::Value::String(s.to_string())),
818                            None => {
819                                match yaml.as_bool() {
820                                    Some(b) => Ok(serde_json::Value::Bool(b)),
821                                    None => {
822                                        match yaml.as_f64() {
823                                            Some(f) => {
824                                                match serde_json::Number::from_f64(f) {
825                                                    Some(n) => Ok(serde_json::Value::Number(n)),
826                                                    None => Err(ProductOSError::GenericError(String::from("Could not convert YAML")))
827                                                }
828                                            }
829                                            None => {
830                                                match yaml.as_i64() {
831                                                    Some(i) => Ok(serde_json::Value::Number(serde_json::Number::from(i))),
832                                                    None => Err(ProductOSError::GenericError(String::from("Could not convert YAML")))
833                                                }
834                                            }
835                                        }
836                                    }
837                                }
838                            }
839                        }
840                    }
841                }
842            }
843        }
844        */
845    }
846
847    #[cfg(all(feature = "json", feature = "yaml"))]
848    pub fn json_to_yaml(value: &serde_json::Value, mut depth: usize) -> Result<serde_yaml::Value, ProductOSError> {
849        let mut yaml_string = String::new();
850
851        match value {
852            serde_json::Value::Object(o) => {
853                for (key, value) in o {
854                    yaml_string.push_str(format!("{}{}: ", ProductOSUtilities::text_indent(depth), key).as_str());
855
856                    match ProductOSUtilities::json_to_yaml(value, depth) {
857                        Ok(yaml_value) => {
858                            depth = depth + 1;
859                            match ProductOSUtilities::yaml_to_string(&yaml_value, false) {
860                                Ok(value_string) => yaml_string.push_str(format!("{}", value_string).as_str()),
861                                Err(e) => return Err(e)
862                            }
863                            depth = depth - 1;
864                        }
865                        Err(e) => return Err(e)
866                    };
867
868                    yaml_string.push_str("\n");
869                }
870            }
871            serde_json::Value::Array(array) => {
872                for _ in array {
873                    match ProductOSUtilities::json_to_yaml(value, depth) {
874                        Ok(value) => {
875                            yaml_string.push_str(format!("{}- ", ProductOSUtilities::text_indent(depth)).as_str());
876
877                            depth = depth + 1;
878                            match ProductOSUtilities::yaml_to_string(&value, false) {
879                                Ok(value_string) => yaml_string.push_str(format!("{}", value_string).as_str()),
880                                Err(e) => return Err(e)
881                            }
882                            depth = depth - 1;
883                        }
884                        Err(e) => return Err(e)
885                    };
886
887                    yaml_string.push_str("\n");
888                }
889            }
890            serde_json::Value::String(s) => {
891                yaml_string.push_str(format!("{}", s).as_str());
892                yaml_string.push_str("\n");
893            }
894            serde_json::Value::Bool(b) => {
895                yaml_string.push_str(format!("{}", b).as_str());
896                yaml_string.push_str("\n");
897            }
898            serde_json::Value::Number(n) => {
899                match n.as_f64() {
900                    Some(f) => yaml_string.push_str(format!("{}", f).as_str()),
901                    None => {
902                        match n.as_i64() {
903                            Some(i) => yaml_string.push_str(format!("{}", i).as_str()),
904                            None => {
905                                match n.as_u64() {
906                                    Some(u) => yaml_string.push_str(format!("{}", u).as_str()),
907                                    None => return Err(ProductOSError::GenericError(String::from("Could not convert number value")))
908                                }
909                            }
910                        }
911                    }
912                }
913                yaml_string.push_str("\n");
914            }
915            serde_json::Value::Null => {
916                yaml_string.push_str("null");
917                yaml_string.push_str("\n");
918            }
919        }
920
921        ProductOSUtilities::string_to_yaml(yaml_string.as_str())
922    }
923
924    #[cfg(all(feature = "yaml", feature = "json"))]
925    pub fn yaml_value_to_json_value(value: &serde_yaml::Value) -> Result<serde_json::Value, ProductOSError> {
926        match value {
927            serde_yaml::Value::Null => Ok(serde_json::Value::Null),
928            serde_yaml::Value::Bool(b) => Ok(serde_json::Value::Bool(b.to_owned())),
929            serde_yaml::Value::Number(n) => {
930                match n.as_u64() {
931                    None => match n.as_i64() {
932                        None => match n.as_f64() {
933                            None => return Err(ProductOSError::GenericError(String::from("Invalid value returned"))),
934                            Some(f) => {
935                                match serde_json::Number::from_f64(f.to_owned()) {
936                                    None => return Err(ProductOSError::GenericError(String::from("Invalid float value returned"))),
937                                    Some(f) => Ok(serde_json::Value::Number(f))
938                                }
939                            }
940                        }
941                        Some(i) => Ok(serde_json::Value::Number(serde_json::Number::from(i.to_owned())))
942                    }
943                    Some(u) => Ok(serde_json::Value::Number(serde_json::Number::from(u.to_owned())))
944                }
945            }
946            serde_yaml::Value::String(s) => Ok(serde_json::Value::String(s.to_owned())),
947            serde_yaml::Value::Sequence(a) => {
948                let mut val_vec: Vec<serde_json::Value> = vec!();
949
950                for e in a.as_slice() {
951                    match ProductOSUtilities::yaml_value_to_json_value(e) {
952                        Ok(v) => val_vec.push(v),
953                        Err(e) => return Err(e)
954                    }
955                }
956
957                Ok(serde_json::Value::Array(val_vec))
958            }
959            serde_yaml::Value::Mapping(m) => {
960                let mut map = serde_json::Map::new();
961
962                for (k, v) in m.iter() {
963                    let key = match ProductOSUtilities::yaml_value_to_json_value(k) {
964                        Ok(v) => match v {
965                            serde_json::Value::String(k) => k,
966                            _ => return Err(ProductOSError::GenericError(String::from("Invalid value returned")))
967                        },
968                        Err(e) => return Err(e)
969                    };
970
971                    let value = match ProductOSUtilities::yaml_value_to_json_value(v) {
972                        Ok(v) => v,
973                        Err(e) => return Err(e)
974                    };
975
976                    map.insert(key, value);
977                }
978
979                Ok(serde_json::Value::Object(map))
980            }
981            serde_yaml::Value::Tagged(t) => {
982                let tag = t.tag.to_string();
983                let value = match ProductOSUtilities::yaml_value_to_json_value(&t.value) {
984                    Ok(v) => v,
985                    Err(e) => return Err(e)
986                };
987
988                let mut map = serde_json::Map::new();
989                map.insert(tag, value);
990
991                Ok(serde_json::Value::Object(map))
992            }
993        }
994    }
995
996    #[cfg(all(feature = "yaml", feature = "json"))]
997    pub fn json_value_to_yaml_value(value: &serde_json::Value) -> Result<serde_yaml::Value, ProductOSError> {
998        match value {
999            serde_json::Value::Null => Ok(serde_yaml::Value::Null),
1000            serde_json::Value::Bool(b) => Ok(serde_yaml::Value::Bool(b.to_owned())),
1001            serde_json::Value::Number(n) => {
1002                match n.as_u64() {
1003                    None => match n.as_i64() {
1004                        None => match n.as_f64() {
1005                            None => return Err(ProductOSError::GenericError(String::from("Invalid value returned"))),
1006                            Some(f) => Ok(serde_yaml::Value::Number(serde_yaml::Number::from(f.to_owned())))
1007                        }
1008                        Some(i) => Ok(serde_yaml::Value::Number(serde_yaml::Number::from(i.to_owned())))
1009                    }
1010                    Some(u) => Ok(serde_yaml::Value::Number(serde_yaml::Number::from(u.to_owned())))
1011                }
1012            }
1013            serde_json::Value::String(s) => Ok(serde_yaml::Value::String(s.to_owned())),
1014            serde_json::Value::Array(a) => {
1015                let mut val_vec: Vec<serde_yaml::Value> = vec!();
1016
1017                for e in a.as_slice() {
1018                    match ProductOSUtilities::json_value_to_yaml_value(e) {
1019                        Ok(v) => val_vec.push(v),
1020                        Err(e) => return Err(e)
1021                    }
1022                }
1023
1024                Ok(serde_yaml::Value::Sequence(val_vec))
1025            }
1026            serde_json::Value::Object(o) => {
1027                let mut map = serde_yaml::Mapping::new();
1028
1029                for (k, v) in o.iter() {
1030                    let key = serde_yaml::Value::String(k.to_owned());
1031
1032                    let value = match ProductOSUtilities::json_value_to_yaml_value(v) {
1033                        Ok(v) => v,
1034                        Err(e) => return Err(e)
1035                    };
1036
1037                    map.insert(key, value);
1038                }
1039
1040                Ok(serde_yaml::Value::Mapping(map))
1041            }
1042        }
1043    }
1044
1045    #[cfg(feature = "yaml")]
1046    pub fn find_yaml_property(yaml: &serde_yaml::Value, property: &str, default_value: &serde_yaml::Value) -> serde_yaml::Value {
1047        let property_parts = property.split(".").collect::<Vec<&str>>();
1048        let property_parts_length = property_parts.len();
1049
1050        ProductOSUtilities::find_yaml_property_internal(yaml, property_parts, default_value, 0, property_parts_length)
1051    }
1052
1053    #[cfg(feature = "yaml")]
1054    fn find_yaml_property_internal(yaml: &serde_yaml::Value, property_parts: Vec<&str>, default_value: &serde_yaml::Value, depth: usize, property_parts_length: usize) -> serde_yaml::Value {
1055        match yaml {
1056            serde_yaml::Value::Sequence(array) => {
1057                match usize::from_str(property_parts.get(depth).unwrap()) {
1058                    Ok(prop) => {
1059                        match array.get(prop) {
1060                            None => default_value.to_owned(),
1061                            Some(value) => {
1062                                if depth == property_parts_length - 1 {
1063                                    value.to_owned()
1064                                }
1065                                else {
1066                                    ProductOSUtilities::find_yaml_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
1067                                }
1068                            }
1069                        }
1070                    }
1071                    Err(_) => default_value.to_owned()
1072                }
1073            }
1074            serde_yaml::Value::Mapping(map) => {
1075                match map.get(&serde_yaml::Value::String(property_parts.get(depth).unwrap().to_string())) {
1076                    None => default_value.to_owned(),
1077                    Some(value) => {
1078                        if depth == property_parts_length - 1 {
1079                            value.to_owned()
1080                        }
1081                        else {
1082                            ProductOSUtilities::find_yaml_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
1083                        }
1084                    }
1085                }
1086            }
1087            _ => default_value.to_owned()
1088        }
1089
1090        /*
1091        match yaml.as_hash() {
1092            Some(hash) => {
1093                match hash.get(&serde_yaml::Value::String(property_parts.get(depth).unwrap().to_string())) {
1094                    None => default_value,
1095                    Some(value) => {
1096                        if depth == property_parts_length - 1 {
1097                            value.to_owned()
1098                        }
1099                        else {
1100                            ProductOSUtilities::find_yaml_property_internal(value, property_parts.to_owned(), default_value.to_owned(), depth + 1, property_parts_length)
1101                        }
1102                    }
1103                }
1104            }
1105            None => {
1106                match yaml.as_vec() {
1107                    Some(array) => {
1108                        match usize::from_str(property_parts.get(depth).unwrap()) {
1109                            Ok(prop) => {
1110                                match array.get(prop) {
1111                                    None => default_value,
1112                                    Some(value) => {
1113                                        if depth == property_parts_length - 1 {
1114                                            value.to_owned()
1115                                        }
1116                                        else {
1117                                            ProductOSUtilities::find_yaml_property_internal(value, property_parts.to_owned(), default_value.to_owned(), depth + 1, property_parts_length)
1118                                        }
1119                                    }
1120                                }
1121                            }
1122                            Err(_) => default_value
1123                        }
1124                    }
1125                    None => default_value
1126                }
1127            }
1128        }
1129        */
1130    }
1131}
1132
1133
1134/*
1135fn is_directory(entry: &walkdir::DirEntry) -> bool {
1136    entry
1137        .metadata()
1138        .unwrap()
1139        .is_dir()
1140}
1141
1142fn is_file(entry: &walkdir::DirEntry) -> bool {
1143    entry
1144        .metadata()
1145        .unwrap()
1146        .is_file()
1147}
1148*/