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
use super::aapt2_tool;
use crate::error::*;
use std::path::{Path, PathBuf};

/// # Dump
/// Dump is used for printing information about the APK you generated using the link
/// command. For example, the following command prints content from the resource table of
/// the specified APK:
///
/// ```sh
/// `aapt2 dump resources output.apk`
/// ```
///
/// ## Dump syntax
/// The general syntax for using dump is as follows:
///
/// ```sh
/// `aapt2 dump sub-command filename.apk [options]`
/// ```
#[derive(Default)]
pub struct Aapt2Dump {
    subcommand: SubCommand,
    filename_apk: PathBuf,
    no_values: bool,
    dumped_file: Option<PathBuf>,
    verbose: bool,
    help: bool,
}

impl Aapt2Dump {
    /// Initialize aapt2 dump then specifies subcommand and apk file
    pub fn new(subcommand: SubCommand, filename_apk: &Path) -> Self {
        Self {
            subcommand,
            filename_apk: filename_apk.to_owned(),
            ..Default::default()
        }
    }

    /// Suppresses the output of values when displaying resource
    pub fn no_values(&mut self, no_values: bool) -> &mut Self {
        self.no_values = no_values;
        self
    }

    /// Specifies a file as an argument to be dumped from the APK
    pub fn dumped_file(&mut self, dumped_file: &Path) -> &mut Self {
        self.dumped_file = Some(dumped_file.to_owned());
        self
    }

    /// Increases verbosity of the output
    pub fn verbose(&mut self, verbose: bool) -> &mut Self {
        self.verbose = verbose;
        self
    }

    /// Displays help menu
    pub fn help(&mut self, help: bool) -> &mut Self {
        self.help = help;
        self
    }

    /// Executes aapt2 dump with arguments
    pub fn run(&self) -> Result<()> {
        let mut aapt2 = aapt2_tool()?;
        aapt2.arg("dump");
        aapt2.arg(self.subcommand.to_string());
        aapt2.arg(&self.filename_apk);
        if self.no_values {
            aapt2.arg("--no-values");
        }
        if let Some(dumped_file) = &self.dumped_file {
            aapt2.arg("--file").arg(dumped_file);
        }
        if self.verbose {
            aapt2.arg("-v");
        }
        if self.help {
            aapt2.arg("-h");
        }
        aapt2.output_err(true)?;
        Ok(())
    }
}

pub enum SubCommand {
    /// Print the contents of the AAPT2 Container (APC) generated during compilation.
    Apc,
    /// Print information extracted from the APK's manifest.
    Badging,
    /// Print every configuration used by a resource in the APK.
    Configurations,
    /// Print the APK's package name.
    Packagename,
    /// Print the permissions extracted from the APK's manifest.
    Permissions,
    /// Print the contents of the APK's resource table string pool.
    Strings,
    /// Print the parents of styles used in the APK.
    Styleparents,
    /// Print the contents of the APK's resource table.
    Resources,
    /// Print strings from the APK's compiled xml.
    Xmlstrings,
    /// Print a tree of the APK's compiled xml.
    Xmltree,
}

impl std::fmt::Display for SubCommand {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match *self {
            Self::Apc => write!(f, "apc"),
            Self::Badging => write!(f, "badging"),
            Self::Configurations => write!(f, "configurations"),
            Self::Packagename => write!(f, "packagename"),
            Self::Permissions => write!(f, "permissions"),
            Self::Strings => write!(f, "strings"),
            Self::Styleparents => write!(f, "styleparents"),
            Self::Resources => write!(f, "resources"),
            Self::Xmlstrings => write!(f, "xmlstrings"),
            Self::Xmltree => write!(f, "xmltree"),
        }
    }
}

impl Default for SubCommand {
    fn default() -> Self {
        Self::Apc
    }
}