Skip to main content

android_abx/
lib.rs

1//! # abx — Android Binary XML parser
2//!
3//! Parses the ABX (Android Binary XML) format produced by `BinaryXmlSerializer`
4//! and read back by `BinaryXmlPullParser` in AOSP.
5//!
6//! Not to be confused with **AXML**, the unrelated chunk-based binary format
7//! used for compiled resources inside APKs (`AndroidManifest.xml`,
8//! `res/**/*.xml`) — this crate does not read that format. See the crate
9//! README's "Not AXML" section for the comparison.
10//!
11//! ## Two parsers, one format
12//!
13//! | Parser | Input | When to use |
14//! |---|---|---|
15//! | [`AbxParser`] | `&[u8]` | Data already in memory |
16//! | [`AbxStreamParser`] | `impl Read` | Files, sockets, pipes — any reader |
17//!
18//! ## Format overview
19//!
20//! Every file starts with the 4-byte magic `ABX\0` (`0x41 0x42 0x58 0x00`).
21//! After the magic each token is a single byte split into two nibbles:
22//!
23//! ```text
24//! high nibble (0xF0) → data-type  (TYPE_STRING, TYPE_INT, …)
25//! low  nibble (0x0F) → event kind (START_TAG, ATTRIBUTE, …)
26//! ```
27//!
28//! Interned strings are prefixed with a `u16` index; the sentinel value
29//! `0xFFFF` means "new string follows as a length-prefixed UTF-8 blob".
30//!
31//! ## Quick start
32//!
33//! ```rust,ignore
34//! // Slice-based
35//! use android_abx::AbxParser;
36//! let data = std::fs::read("foo.abx")?;
37//! let mut p = AbxParser::new(&data)?;
38//! while let Some(ev) = p.next_event()? { println!("{ev:?}"); }
39//!
40//! // Stream-based (no intermediate Vec)
41//! use android_abx::AbxStreamParser;
42//! let file = std::fs::File::open("foo.abx")?;
43//! let mut p = AbxStreamParser::new(std::io::BufReader::new(file))?;
44//! while let Some(ev) = p.next_event()? { println!("{ev:?}"); }
45//!
46//! // Convenience helper
47//! let mut p = android_abx::open_file("foo.abx")?;
48//! let xml = p.to_xml()?;
49//! ```
50//!
51//! ## Crate layout
52//!
53//! `error`, `wire`, `event`, `decode` (in-memory + streaming parsers, see
54//! [`stream`]), and `de` (serde support, behind the `serialize` feature)
55//! are internal modules — everything is re-exported at the crate root, so
56//! `android_abx::Event` etc. work regardless of which file it's defined in.
57
58#![warn(missing_docs)]
59
60mod error;
61pub use error::{AbxError, Result};
62
63mod wire;
64pub use wire::MAGIC;
65pub(crate) use wire::{
66    CMD_ATTRIBUTE, CMD_CDSECT, CMD_COMMENT, CMD_DOCDECL, CMD_END_DOCUMENT, CMD_END_TAG,
67    CMD_ENTITY_REF, CMD_IGNORABLE_WHITESPACE, CMD_PROCESSING_INSTRUCTION, CMD_START_DOCUMENT,
68    CMD_START_TAG, CMD_TEXT, INTERNED_NEW, TYPE_BOOLEAN_FALSE, TYPE_BOOLEAN_TRUE,
69    TYPE_BYTES_BASE64, TYPE_BYTES_HEX, TYPE_DOUBLE, TYPE_FLOAT, TYPE_INT, TYPE_INT_HEX, TYPE_LONG,
70    TYPE_LONG_HEX, TYPE_NULL, TYPE_STRING, TYPE_STRING_INTERNED,
71};
72
73mod event;
74pub(crate) use event::render_event;
75pub use event::{Attribute, AttributeValue, Event, InternedStr};
76
77mod decode;
78pub use decode::stream;
79pub use decode::stream::AbxStreamParser;
80pub use decode::{AbxParser, AbxParserOwned};
81
82mod encode;
83#[cfg(feature = "xml")]
84pub use encode::xml_to_abx;
85pub use encode::{AbxWriter, events_to_abx};
86
87#[cfg(feature = "serialize")]
88mod de;
89#[cfg(feature = "serialize")]
90pub use de::{from_element, from_file, from_reader, from_slice};
91
92/// Convert ABX bytes to an XML string.
93pub fn abx_to_xml(data: &[u8]) -> Result<String> {
94    AbxParser::new(data)?.to_xml()
95}
96
97/// Parse ABX bytes and return all events.
98pub fn abx_events(data: &[u8]) -> Result<Vec<Event>> {
99    AbxParser::new(data)?.collect_events()
100}
101
102/// Open a file and return a buffered [`AbxStreamParser`] over it.
103pub fn open_file(
104    path: impl AsRef<std::path::Path>,
105) -> Result<AbxStreamParser<std::io::BufReader<std::fs::File>>> {
106    let f = std::fs::File::open(path)?;
107    AbxStreamParser::new(std::io::BufReader::new(f))
108}