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
#![deny(missing_debug_implementations)]
pub mod aggregate_report;

use std::fs::{File, read_dir};
use std::io::BufReader;
use std::path::Path;
use serde_xml_rs::from_reader;
use libflate::gzip;
use zip;
use std::io::Read;

pub fn parse(path: &Path) -> Result<aggregate_report::feedback, Box<std::error::Error>> {
    if path.is_dir() {
        panic!("{} is a directory")
    }

    let extension = path.extension();

    match extension {
        Some(extension) => {
            match extension.to_str().unwrap() {
                "xml" => {
                    let mut reader = get_file_reader(&path)?;
                    return parse_reader(&mut reader);
                },
                "gz" | "gzip" => {
                    let reader = get_file_reader(&path)?;
                    let mut decoder = gzip::Decoder::new(reader)?;
                    return parse_reader(&mut decoder);
                },
                "zip" => {
                    let file = File::open(&path)?;
                    let mut archive = zip::ZipArchive::new(file)?;
                    let mut file = archive.by_index(0)?;
                    return parse_reader(&mut file);
                },
                _       => {
                    let error_message = format!("Do not know how to handle {} files :-(", extension.to_str().unwrap());
                    return Err(error_message.into());
                }
            }
        },
        None            => ()
    }

    let file = File::open(&path)?;
    let mut file = BufReader::new(file);

    parse_reader(&mut file)
}

fn get_file_reader(path: &Path) -> Result<BufReader<File>, Box<std::error::Error>> {
    let file = File::open(&path)?;
    Ok(BufReader::new(file))
}

fn parse_reader(reader: &mut Read) -> Result<aggregate_report::feedback, Box<std::error::Error>> {
    match from_reader(reader) {
        Ok(result) => Ok(result),
        Err(error) => Err(error.into())
    }
}

pub fn parse_dir(path: &Path) -> Vec<aggregate_report::feedback> {
    let mut results = Vec::new();

    if path.is_dir() {
        for entry in read_dir(path).unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            let result = parse(&path);
            match result {
                Ok(result) => results.push(result),
                Err(error) => println!("could not parse: {:?} because {:?}", path, error)
            }
        }
    }
    
    results
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_parse_single() {
        parse("dmarc.xml");
    }

    #[test]
    fn test_parse_dir() {
        parse_dir(Path::new("./"));
    }
}