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, its three legacy Japanese multi-byte encodings (Shift_JIS, EUC-JP, ISO-2022-JP),
16//!   and its legacy CJK multi-byte encodings (GBK, gb18030, Big5, EUC-KR) — see
17//!   [`Encoding::ALL`] for the complete, up-to-date list — plus [`Encoding::for_label`] to
18//!   resolve an IANA/WHATWG charset label (as found in an `encoding="..."` declaration or a
19//!   `Content-Type` header) to one of them.
20//! * [`Decoder`] — an incremental, chunk-safe decoder: bytes can be fed in arbitrarily small
21//!   pieces (even one byte at a time) and a partial multi-byte sequence at a chunk boundary is
22//!   carried over correctly. Both a strict mode (which reports a [`DecodeError`] with a byte
23//!   offset) and a lossy mode (which substitutes `U+FFFD REPLACEMENT CHARACTER`) are provided.
24//! * [`encode_from_utf8`] — the inverse direction, used when *writing* XML in a legacy
25//!   encoding; reports the first unmappable character and its position.
26//! * [`detect_bom`] — recognizes the three byte-order marks relevant to XML.
27//! * [`sniff_xml_encoding`] — implements the heuristic described in
28//!   [XML 1.0 Appendix F](https://www.w3.org/TR/xml/#sec-guessing): inspect the first few bytes
29//!   of an entity, then (if the bytes look ASCII-compatible or UTF-16) scan the prologue for an
30//!   `encoding="..."` pseudo-attribute.
31//!
32//! # Example
33//!
34//! ```
35//! use oxixml_encoding::{sniff_xml_encoding, Encoding};
36//!
37//! // A UTF-8 document that self-declares its own encoding.
38//! let xml = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
39//! let sniffed = sniff_xml_encoding(xml);
40//! assert_eq!(sniffed.declared_encoding, Some(Encoding::Utf8));
41//!
42//! // Decode a chunk of UTF-8 incrementally, one byte at a time, and get back the original text.
43//! let mut decoder = Encoding::Utf8.new_decoder();
44//! let mut out = String::new();
45//! for (i, byte) in "héllo".as_bytes().iter().enumerate() {
46//!     let last = i + 1 == "héllo".len();
47//!     decoder
48//!         .decode_to_string(std::slice::from_ref(byte), &mut out, last)
49//!         .expect("valid UTF-8 fed one byte at a time");
50//! }
51//! assert_eq!(out, "héllo");
52//! ```
53
54#![deny(missing_docs)]
55#![forbid(unsafe_code)]
56
57mod bom;
58mod cjk;
59mod decoder;
60mod encoder;
61mod jis;
62mod label;
63mod sniff;
64mod tables;
65
66pub use bom::detect_bom;
67pub use decoder::{DecodeError, DecodeErrorKind, Decoder};
68pub use encoder::{EncodeError, encode_from_utf8};
69pub use label::Encoding;
70pub use sniff::{ByteOrderGuess, SniffResult, sniff_xml_encoding};