1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//! This module defines the ScanObject, which represents a `BinaryObject` that has been //! preprocessed. The `ScanObject` struct defined in this module is accessible in the root //! namespace as `armorlib::ScanObject`. use std::collections::HashMap; use std::ops::Index; use errors::ArmorlibError; use binary_object::BinaryObject; /// A struct that represents a `BinaryObject` (with associated `filetype`) that has been /// preprocessed and therefore contains `metadata`. This is the object that is passed to /// `ScanModule`s. /// /// This object is typically only created by the `coordinator`, and there are few cases /// in which it would be necessary to create this object in your own library. Still, it is /// public so that future versions of the library might be more extendable. pub struct ScanObject { /// A `HashMap` that represents data created by the preprocessors. Each root key string /// corresponds to the ID of the preprocessor. The value of each root pair is a `HashMap` /// created by the preprocessor. Refer to each preprocessor's documentation for information /// about its respective keys and values. pub metadata: HashMap<String, HashMap<String, String>>, /// The filetype of the data. This is passed in by the user, and is not determined by any /// preprocessor. Instead, it is extracted by the CLI or provided by the bound /// program. It should not be trusted; a file may advertise itself with its extension as a /// `.pdf` file but may in fact be a `.tiff` file, for example. /// /// Because there is no guarantee that any filetype will be given by the user (for example, /// when all that is passed to form the root `BinaryObject` is a `Vec<u8>`), there is a /// possibility of absence. pub filetype: Option<String>, /// The BinaryObject that the ScanObject contains. pub binary_object: BinaryObject, } impl ScanObject { /// Get the given key created by the given preprocessor, where the key and preprocessor are /// denoted in the format `<preprocessor/key>`. Will return the HashMap if the /// preprocessor is present, ortherwise a `ProcessingError::MissingPreprocessor` error /// will be returned. /// /// # Examples /// /// ```rust /// # extern crate armorlib; /// # use std::collections::HashMap; /// use armorlib::{ScanObject, ArmorlibError, BinaryObject}; /// #[macro_use] /// extern crate maplit; /// # fn main() { /// # let metadata: HashMap<String, HashMap<String, String>> = hashmap!{ /// # String::from("preprocessor") => hashmap!{ /// # String::from("key_name") => String::from("value"), /// # } /// # }; /// # let scan_object = ScanObject { /// # metadata: metadata, /// # filetype: None, /// # binary_object: BinaryObject::from(vec![]), /// # }; /// // given the scan object with the name `scan_object`, we can easily access its metadata: /// assert_eq!( /// // use a `match` statement in your own code for safety /// scan_object.get_metadata("preprocessor/key_name").unwrap(), /// &String::from("value") /// ); /// /// // if we try to access metadata from a preprocessor that doesn't exist, /// // we'll get a `MissingPreprocessor` error. /// assert_eq!( /// scan_object.get_metadata("fake_preprocessor/key_name"), /// Err(ArmorlibError::MissingPreprocessor(String::from( /// "fake_preprocessor" /// ))) /// ); /// /// // if we try to access metadata that doesn't exist from a preprocessor that does, we'll /// // get a `MissingMetadata` error. /// assert_eq!( /// scan_object.get_metadata("preprocessor/fake_key"), /// Err(ArmorlibError::MissingMetadata(String::from("preprocessor/fake_key"))) /// ); /// # } /// ``` pub fn get_metadata(&self, path: &str) -> Result<&String, ArmorlibError> { let path = String::from(path); let key_pair: Vec<&str> = path.split('/').collect(); let (preprocessor, key) = ( String::from(*key_pair.index(0_usize)), String::from(*key_pair.index(1_usize)), ); match self.metadata.get(&preprocessor) { Some(map) => match map.get(&key) { Some(value) => Ok(value), None => Err(ArmorlibError::MissingMetadata(path.clone())), }, None => Err(ArmorlibError::MissingPreprocessor(preprocessor)), } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_get_metadata() { // in this test, 'modules' refer truly to preprocessors. let metadata: HashMap<String, HashMap<String, String>> = hashmap!{ String::from("module1") => hashmap!{ String::from("key") => String::from("m1::value"), String::from("key2") => String::from("m1::value2") }, String::from("module2") => hashmap!{ String::from("key3") => String::from("m2::value3"), String::from("key2") => String::from("m2::value2") } }; let scan_object = ScanObject { metadata: metadata, filetype: None, binary_object: BinaryObject::from(vec![]), }; assert_eq!( scan_object.get_metadata("module1/key").unwrap(), &String::from("m1::value") ); assert_eq!( scan_object.get_metadata("module1/key2").unwrap(), &String::from("m1::value2") ); assert_eq!( scan_object.get_metadata("module2/key3").unwrap(), &String::from("m2::value3") ); assert_eq!( scan_object.get_metadata("module2/key2").unwrap(), &String::from("m2::value2") ); assert_eq!( scan_object.get_metadata("fakemodule/key2"), Err(ArmorlibError::MissingPreprocessor(String::from( "fakemodule" ))) ); assert_eq!( scan_object.get_metadata("module2/key4"), Err(ArmorlibError::MissingMetadata(String::from("module2/key4"))) ); } }