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
use std::{
fs,
io::{Read, Write},
path::Path,
};
use failure::{format_err, Error, ResultExt};
use zip::read::ZipArchive;
use crate::decoder::BufferedDecoder;
#[derive(Debug)]
pub struct Apk {
handler: ZipArchive<fs::File>,
decoder: BufferedDecoder,
}
impl Apk {
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
let mut buffer = Vec::new();
let file = fs::File::open(&path)?;
let mut zip_handler = ZipArchive::new(file)?;
zip_handler
.by_name("resources.arsc")?
.read_to_end(&mut buffer)?;
Ok(Self {
handler: zip_handler,
decoder: buffer.into(),
})
}
pub fn export<P: AsRef<Path>>(&mut self, output_path: P, force: bool) -> Result<(), Error> {
use crate::visitor::XmlVisitor;
let decoder = self
.decoder
.get_decoder()
.context("could not get the decoder")?;
if fs::create_dir_all(&output_path).is_err() && force {
fs::remove_dir_all(&output_path).context(format_err!(
"could not clean target directory: {}",
output_path.as_ref().display()
))?;
fs::create_dir_all(&output_path).context(format_err!(
"error creating the output folder: {}",
output_path.as_ref().display()
))?;
}
for i in 0..self.handler.len() {
let (file_name, contents) = {
let mut current_file = self
.handler
.by_index(i)
.context("could not read ZIP entry")?;
let mut contents = Vec::new();
current_file
.read_to_end(&mut contents)
.context(format!("could not read: {}", current_file.name()))?;
let is_xml = current_file.name().to_string();
(is_xml, contents)
};
let contents = if (file_name.starts_with("res/") && file_name.ends_with(".xml"))
|| file_name == "AndroidManifest.xml"
{
decoder
.xml_visitor(&contents)
.and_then(XmlVisitor::into_string)
.and_then(|string| Ok(string.into_bytes()))
.unwrap_or(contents)
} else {
contents
};
Self::write_file(&output_path, &file_name, &contents)
.context("could not write output file")?;
}
Ok(())
}
fn write_file<B: AsRef<Path>, R: AsRef<Path>>(
base_path: B,
relative: R,
content: &[u8],
) -> Result<(), Error> {
let full_path = base_path.as_ref().join(&relative);
fs::create_dir_all(full_path.parent().unwrap())
.context("could not create the output dir")?;
let mut descriptor = fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(full_path)
.context("could not open file to write")?;
descriptor
.write_all(content)
.context("could not write to target file")?;
Ok(())
}
}