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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! Parser and encoder for Android Binary XML (ABX).
//!
//! ABX is the binary XML format written by AOSP's `BinaryXmlSerializer` and read
//! by `BinaryXmlPullParser`. Android uses it for platform files such as
//! `/data/system/packages.xml`. It is not AXML, the format of compiled APK
//! resources such as `AndroidManifest.xml`, which this crate cannot read.
//!
//! # Parsing
//!
//! [`AbxParser`] reads a document from a byte slice and [`AbxStreamParser`] from
//! any [`Read`](std::io::Read). Both have the same methods and yield the same
//! [`Event`]s.
//!
//! ```
//! use android_abx::{AbxParser, Event};
//!
//! # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
//! let mut parser = AbxParser::new(data)?;
//! while let Some(event) = parser.next_event()? {
//! if let Event::StartTag { name, attributes } = event {
//! println!("<{name}> has {} attributes", attributes.len());
//! }
//! }
//! # Ok::<(), android_abx::AbxError>(())
//! ```
//!
//! To convert a whole document to XML text, use [`abx_to_xml`]:
//!
//! ```
//! # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
//! let xml = android_abx::abx_to_xml(data)?;
//! assert_eq!(
//! xml,
//! r#"<?xml version="1.0" encoding="UTF-8"?><pkg name="com.example.chat" version="3" flags="1"></pkg>"#,
//! );
//! # Ok::<(), android_abx::AbxError>(())
//! ```
//!
//! # Encoding
//!
//! [`AbxWriter`] and [`events_to_abx`] encode [`Event`]s back to ABX. With the
//! `xml` feature, `xml_to_abx` encodes XML text.
//!
//! ```
//! use android_abx::{AbxParser, events_to_abx};
//!
//! # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
//! let events = AbxParser::new(data)?.collect_events()?;
//! assert_eq!(events_to_abx(&events)?, data);
//! # Ok::<(), android_abx::AbxError>(())
//! ```
//!
//! # Deserializing with serde
//!
//! With the `serde` feature, an element can be deserialized into any type
//! that implements `serde::Deserialize`. Struct fields are filled from:
//!
//! - attributes, by name. Use `#[serde(rename = "...")]` for names that are not
//! Rust identifiers;
//! - child elements, by tag name. A `Vec<T>` field takes every matching child,
//! any other field takes the first one. A child with only text can fill a
//! scalar field such as `String` or `u32`;
//! - the element's text, through a field renamed to `"$text"`. Only text events
//! are collected: entity references such as `&` are dropped.
//!
//! When an attribute and a child element have the same name, the attribute is
//! used. An `Option` field is `None` when the attribute or child is missing, or
//! when the attribute has a null value. Enums with unit variants are matched by
//! name against a string value.
//!
//! Use `from_slice`, `from_reader` or `from_file` when the root element is the
//! record you want. For repeated elements under a root, such as `<pkg>` entries
//! in `packages.xml`, use `AbxParser::deserialize_all` or
//! `AbxStreamParser::deserialize_iter`.
//!
//! # Feature flags
//!
//! - `serde`: serde deserialization.
//! - `xml`: `xml_to_abx`, to encode XML text.
pub use ;
pub use MAGIC;
pub use ;
pub use render_event;
pub use ;
pub use stream;
pub use AbxStreamParser;
pub use ;
pub use xml_to_abx;
pub use ;
pub use ;
/// Converts an ABX document to an XML string.
///
/// Shorthand for [`AbxParser::new`] followed by [`AbxParser::to_xml`].
///
/// # Errors
///
/// Returns an error if the input is truncated or malformed (unknown token,
/// invalid interned-string index, invalid UTF-8).
///
/// # Examples
///
/// ```
/// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
/// let xml = android_abx::abx_to_xml(data)?;
/// assert!(xml.starts_with(r#"<?xml version="1.0" encoding="UTF-8"?><pkg "#));
/// # Ok::<(), android_abx::AbxError>(())
/// ```
/// Parses an ABX document into a list of events.
///
/// Shorthand for [`AbxParser::new`] followed by [`AbxParser::collect_events`].
///
/// # Errors
///
/// Returns an error if the input is truncated or malformed (unknown token,
/// invalid interned-string index, invalid UTF-8).
///
/// # Examples
///
/// ```
/// use android_abx::Event;
///
/// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
/// let events = android_abx::abx_events(data)?;
/// assert_eq!(events.first(), Some(&Event::StartDocument));
/// assert_eq!(events.last(), Some(&Event::EndDocument));
/// # Ok::<(), android_abx::AbxError>(())
/// ```
/// Opens a file and returns an [`AbxStreamParser`] over it.
///
/// # Errors
///
/// Returns [`AbxError::Io`] if the file cannot be opened or read, and
/// [`AbxError::InvalidMagic`] or [`AbxError::UnexpectedEof`] if it does not start
/// with [`MAGIC`].
///
/// # Examples
///
/// ```no_run
/// let xml = android_abx::open_file("/data/system/packages.xml")?.to_xml()?;
/// # Ok::<(), android_abx::AbxError>(())
/// ```