oxixml_encoding/lib.rs
1//! `oxixml-encoding` — Character-encoding decoders and encoders for XML processing.
2//!
3//! Part of the [OxiXML](https://github.com/cool-japan/oxixml) workspace — the COOLJAPAN
4//! Pure-Rust foundation for all XML and RDF processing.
5//!
6//! This crate provides the character-encoding subset that an XML processor actually needs:
7//! it plays the role that [`encoding_rs`](https://docs.rs/encoding_rs) plays in other Rust XML
8//! stacks, but is written from scratch against `std` alone, with no external dependencies.
9//!
10//! # What's here
11//!
12//! * [`Encoding`] — the core set of encodings an XML parser must recognize (`UTF-8`,
13//! `UTF-16LE`, `UTF-16BE`, `ISO-8859-1`, `windows-1252`, `US-ASCII`), extended with the rest of
14//! the [WHATWG Encoding Standard](https://encoding.spec.whatwg.org/)'s legacy single-byte
15//! encodings and its three legacy Japanese multi-byte encodings (Shift_JIS, EUC-JP,
16//! ISO-2022-JP) — see [`Encoding::ALL`] for the complete, up-to-date list — plus
17//! [`Encoding::for_label`] to resolve an IANA/WHATWG charset label (as found in an
18//! `encoding="..."` declaration or a `Content-Type` header) to one of them.
19//! * [`Decoder`] — an incremental, chunk-safe decoder: bytes can be fed in arbitrarily small
20//! pieces (even one byte at a time) and a partial multi-byte sequence at a chunk boundary is
21//! carried over correctly. Both a strict mode (which reports a [`DecodeError`] with a byte
22//! offset) and a lossy mode (which substitutes `U+FFFD REPLACEMENT CHARACTER`) are provided.
23//! * [`encode_from_utf8`] — the inverse direction, used when *writing* XML in a legacy
24//! encoding; reports the first unmappable character and its position.
25//! * [`detect_bom`] — recognizes the three byte-order marks relevant to XML.
26//! * [`sniff_xml_encoding`] — implements the heuristic described in
27//! [XML 1.0 Appendix F](https://www.w3.org/TR/xml/#sec-guessing): inspect the first few bytes
28//! of an entity, then (if the bytes look ASCII-compatible or UTF-16) scan the prologue for an
29//! `encoding="..."` pseudo-attribute.
30//!
31//! # Example
32//!
33//! ```
34//! use oxixml_encoding::{sniff_xml_encoding, Encoding};
35//!
36//! // A UTF-8 document that self-declares its own encoding.
37//! let xml = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
38//! let sniffed = sniff_xml_encoding(xml);
39//! assert_eq!(sniffed.declared_encoding, Some(Encoding::Utf8));
40//!
41//! // Decode a chunk of UTF-8 incrementally, one byte at a time, and get back the original text.
42//! let mut decoder = Encoding::Utf8.new_decoder();
43//! let mut out = String::new();
44//! for (i, byte) in "héllo".as_bytes().iter().enumerate() {
45//! let last = i + 1 == "héllo".len();
46//! decoder
47//! .decode_to_string(std::slice::from_ref(byte), &mut out, last)
48//! .expect("valid UTF-8 fed one byte at a time");
49//! }
50//! assert_eq!(out, "héllo");
51//! ```
52
53#![deny(missing_docs)]
54
55mod bom;
56mod decoder;
57mod encoder;
58mod jis;
59mod label;
60mod sniff;
61mod tables;
62
63pub use bom::detect_bom;
64pub use decoder::{DecodeError, DecodeErrorKind, Decoder};
65pub use encoder::{EncodeError, encode_from_utf8};
66pub use label::Encoding;
67pub use sniff::{ByteOrderGuess, SniffResult, sniff_xml_encoding};