Skip to main content

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};