1#[cfg(feature = "python")]
2use pyo3::prelude::*;
3#[cfg(feature = "python")]
4use pyo3::types::PyBytes;
5
6pub mod arsc;
7pub mod axml;
8mod error;
9pub mod json_serde;
10#[allow(clippy::all, dead_code)]
11mod proto;
12mod proto_compute;
13mod proto_conv;
14mod public;
15mod resource_map;
16mod string_pool;
17mod typed_value;
18mod xml_element;
19
20pub use error::AxmlError;
22
23#[cfg(feature = "python")]
24use arsc::Arsc;
25#[cfg(feature = "python")]
26use axml::Axml;
27
28#[cfg(feature = "python")]
30#[pyclass(name = "AXML")]
31pub struct PyAxml {
32 inner: Axml,
33}
34
35#[cfg(feature = "python")]
36#[pymethods]
37impl PyAxml {
38 #[new]
39 pub fn new() -> Self {
40 PyAxml { inner: Axml::new() }
41 }
42
43 #[staticmethod]
45 pub fn from_axml(data: &[u8]) -> PyResult<Self> {
46 let inner = Axml::from_axml(data)
47 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
48 Ok(PyAxml { inner })
49 }
50
51 pub fn pack<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
53 let data = self.inner.pack();
54 Ok(PyBytes::new(py, &data))
55 }
56
57 pub fn to_xml(&self) -> PyResult<String> {
59 self.inner
60 .to_xml()
61 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
62 }
63
64 pub fn to_proto_text(&self) -> String {
66 self.inner.to_proto_text()
67 }
68
69 pub fn to_proto_text_pretty(&self) -> String {
71 self.inner.to_proto_text_pretty()
72 }
73
74 pub fn compute(&mut self) {
76 self.inner.compute();
77 }
78
79 pub fn apply_stringblocks_no_compute(&mut self, new_strings: Vec<Vec<u8>>) {
87 self.inner.apply_stringblocks_no_compute(new_strings);
88 }
89
90 pub fn from_xml(&mut self, xml: &str) -> PyResult<()> {
92 self.inner
93 .from_xml(xml)
94 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
95 }
96
97 pub fn get_total_size(&self) -> u32 {
100 self.inner.total_size
101 }
102
103 pub fn set_total_size(&mut self, size: u32) {
106 self.inner.total_size = size;
107 }
108
109 pub fn string_count(&self) -> usize {
111 self.inner.stringblocks.inner.strings.len()
112 }
113
114 pub fn get_string(&self, idx: u32) -> PyResult<String> {
116 self.inner
117 .stringblocks
118 .inner
119 .decode(idx)
120 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
121 }
122
123 pub fn to_proto_bytes<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
125 Ok(PyBytes::new(py, &self.inner.to_proto_bytes()))
126 }
127
128 #[staticmethod]
130 pub fn from_proto_bytes(data: &[u8]) -> PyResult<Self> {
131 let inner = Axml::from_proto_bytes(data)
132 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
133 Ok(PyAxml { inner })
134 }
135
136 pub fn export_proto_file(&self, path: &str) -> PyResult<()> {
138 self.inner
139 .export_proto_file(path)
140 .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))
141 }
142
143 #[staticmethod]
145 pub fn from_proto_file(path: &str) -> PyResult<Self> {
146 let inner = Axml::from_proto_file(path)
147 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
148 Ok(PyAxml { inner })
149 }
150
151 pub fn export_stringblocks_proto_file(&self, path: &str) -> PyResult<()> {
153 self.inner
154 .export_stringblocks_proto_file(path)
155 .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))
156 }
157
158 pub fn import_stringblocks_proto_file(&mut self, path: &str) -> PyResult<()> {
160 self.inner
161 .import_stringblocks_proto_file(path)
162 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
163 }
164
165 pub fn __repr__(&self) -> String {
166 format!(
167 "AXML(strings={}, elements={})",
168 self.inner.stringblocks.inner.strings.len(),
169 self.inner.elements.len()
170 )
171 }
172}
173
174#[cfg(feature = "python")]
175impl Default for PyAxml {
176 fn default() -> Self {
177 Self::new()
178 }
179}
180
181#[cfg(feature = "python")]
183#[pyclass(name = "ARSC")]
184pub struct PyArsc {
185 inner: Arsc,
186}
187
188#[cfg(feature = "python")]
189#[pymethods]
190impl PyArsc {
191 #[staticmethod]
193 pub fn from_axml(data: &[u8]) -> PyResult<Self> {
194 let inner = Arsc::from_axml(data)
195 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
196 Ok(PyArsc { inner })
197 }
198
199 #[pyo3(signature = (language=None))]
203 pub fn list_packages(&self, language: Option<&str>) -> String {
204 self.inner.list_packages(language)
205 }
206
207 pub fn get_total_size(&self) -> u32 {
210 self.inner.total_size
211 }
212
213 pub fn set_total_size(&mut self, size: u32) {
215 self.inner.total_size = size;
216 }
217
218 pub fn get_header_package_count(&self) -> u32 {
221 self.inner.package_count
222 }
223
224 pub fn set_header_package_count(&mut self, count: u32) {
226 self.inner.package_count = count;
227 }
228
229 pub fn get_pkg_chunk_size(&self, idx: usize) -> u32 {
232 self.inner
233 .packages
234 .get(idx)
235 .map(|p| p.chunk_size)
236 .unwrap_or(0)
237 }
238
239 pub fn set_pkg_chunk_size(&mut self, idx: usize, size: u32) {
242 if let Some(pkg) = self.inner.packages.get_mut(idx) {
243 pkg.chunk_size = size;
244 }
245 }
246
247 pub fn package_count(&self) -> usize {
249 self.inner.packages.len()
250 }
251
252 #[pyo3(signature = (recursive = true))]
257 pub fn compute(&mut self, recursive: bool) {
258 self.inner.compute(recursive);
259 }
260
261 pub fn pack<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
263 Ok(PyBytes::new(py, &self.inner.pack()))
264 }
265
266 pub fn add_resource(&mut self, type_name: &str, name: &str, file_path: &str) -> u32 {
273 self.inner.add_resource(type_name, name, file_path)
274 }
275
276 pub fn to_proto_text(&self) -> String {
278 self.inner.to_proto_text()
279 }
280
281 pub fn to_proto_text_pretty(&self) -> String {
283 self.inner.to_proto_text_pretty()
284 }
285
286 pub fn to_proto_bytes<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
288 Ok(PyBytes::new(py, &self.inner.to_proto_bytes()))
289 }
290
291 #[staticmethod]
293 pub fn from_proto_bytes(data: &[u8]) -> PyResult<Self> {
294 let inner = Arsc::from_proto_bytes(data)
295 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
296 Ok(PyArsc { inner })
297 }
298
299 pub fn export_proto_file(&self, path: &str) -> PyResult<()> {
301 self.inner
302 .export_proto_file(path)
303 .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))
304 }
305
306 #[staticmethod]
308 pub fn from_proto_file(path: &str) -> PyResult<Self> {
309 let inner = Arsc::from_proto_file(path)
310 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
311 Ok(PyArsc { inner })
312 }
313
314 pub fn export_pkg_proto_file(&self, idx: usize, path: &str) -> PyResult<()> {
316 self.inner
317 .export_pkg_proto_file(idx, path)
318 .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))
319 }
320
321 pub fn import_pkg_proto_file(&mut self, idx: usize, path: &str) -> PyResult<()> {
323 self.inner
324 .import_pkg_proto_file(idx, path)
325 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
326 }
327
328 pub fn __repr__(&self) -> String {
329 format!("ARSC(packages={})", self.inner.packages.len())
330 }
331}
332
333#[cfg(feature = "python")]
336#[pyfunction]
337fn compute_string_block_proto<'py>(
338 py: Python<'py>,
339 data: &[u8],
340 is_utf8: bool,
341) -> PyResult<Bound<'py, PyBytes>> {
342 proto_compute::compute_string_block_bytes(data, is_utf8)
343 .map(|b| PyBytes::new(py, &b))
344 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
345}
346
347#[cfg(feature = "python")]
348#[pyfunction]
349fn compute_string_blocks_proto<'py>(
350 py: Python<'py>,
351 data: &[u8],
352 recursive: bool,
353) -> PyResult<Bound<'py, PyBytes>> {
354 proto_compute::compute_string_blocks_bytes(data, recursive)
355 .map(|b| PyBytes::new(py, &b))
356 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
357}
358
359#[cfg(feature = "python")]
360#[pyfunction]
361fn compute_resource_map_proto<'py>(py: Python<'py>, data: &[u8]) -> PyResult<Bound<'py, PyBytes>> {
362 proto_compute::compute_resource_map_bytes(data)
363 .map(|b| PyBytes::new(py, &b))
364 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
365}
366
367#[cfg(feature = "python")]
368#[pyfunction]
369fn compute_xml_element_proto<'py>(py: Python<'py>, data: &[u8]) -> PyResult<Bound<'py, PyBytes>> {
370 proto_compute::compute_xml_element_bytes(data)
371 .map(|b| PyBytes::new(py, &b))
372 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
373}
374
375#[cfg(feature = "python")]
376#[pyfunction]
377fn compute_arsc_res_table_config_proto<'py>(
378 py: Python<'py>,
379 data: &[u8],
380) -> PyResult<Bound<'py, PyBytes>> {
381 proto_compute::compute_arsc_res_table_config_bytes(data)
382 .map(|b| PyBytes::new(py, &b))
383 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
384}
385
386#[cfg(feature = "python")]
387#[pyfunction]
388fn compute_arsc_res_type_proto<'py>(
389 py: Python<'py>,
390 data: &[u8],
391 recursive: bool,
392) -> PyResult<Bound<'py, PyBytes>> {
393 proto_compute::compute_arsc_res_type_bytes(data, recursive)
394 .map(|b| PyBytes::new(py, &b))
395 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
396}
397
398#[cfg(feature = "python")]
399#[pyfunction]
400fn compute_arsc_res_table_package_proto<'py>(
401 py: Python<'py>,
402 data: &[u8],
403 recursive: bool,
404) -> PyResult<Bound<'py, PyBytes>> {
405 proto_compute::compute_arsc_res_table_package_bytes(data, recursive)
406 .map(|b| PyBytes::new(py, &b))
407 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
408}
409
410#[cfg(feature = "python")]
411#[pyfunction]
412fn compute_axml_proto_bytes<'py>(
413 py: Python<'py>,
414 data: &[u8],
415 recursive: bool,
416) -> PyResult<Bound<'py, PyBytes>> {
417 proto_compute::compute_axml_bytes(data, recursive)
418 .map(|b| PyBytes::new(py, &b))
419 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
420}
421
422#[cfg(feature = "python")]
423#[pyfunction]
424fn compute_arsc_proto_bytes<'py>(
425 py: Python<'py>,
426 data: &[u8],
427 recursive: bool,
428) -> PyResult<Bound<'py, PyBytes>> {
429 proto_compute::compute_arsc_bytes(data, recursive)
430 .map(|b| PyBytes::new(py, &b))
431 .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
432}
433
434#[cfg(feature = "python")]
436#[pymodule]
437fn _pyaxml(m: &Bound<'_, PyModule>) -> PyResult<()> {
438 m.add_class::<PyAxml>()?;
439 m.add_class::<PyArsc>()?;
440 m.add_function(wrap_pyfunction!(compute_string_block_proto, m)?)?;
441 m.add_function(wrap_pyfunction!(compute_string_blocks_proto, m)?)?;
442 m.add_function(wrap_pyfunction!(compute_resource_map_proto, m)?)?;
443 m.add_function(wrap_pyfunction!(compute_xml_element_proto, m)?)?;
444 m.add_function(wrap_pyfunction!(compute_arsc_res_table_config_proto, m)?)?;
445 m.add_function(wrap_pyfunction!(compute_arsc_res_type_proto, m)?)?;
446 m.add_function(wrap_pyfunction!(compute_arsc_res_table_package_proto, m)?)?;
447 m.add_function(wrap_pyfunction!(compute_axml_proto_bytes, m)?)?;
448 m.add_function(wrap_pyfunction!(compute_arsc_proto_bytes, m)?)?;
449 Ok(())
450}