1use std::borrow::Cow;
2
3use deser_core::de::{
4 self, ContentKey, Deserialize, DeserializeDriver, DuplicateKeys, LexicalRules,
5};
6use deser_core::{Atom, ContainerShape, Error, ErrorKind, Event, Order, Source, Text};
7use quick_xml::XmlVersion;
8use quick_xml::events::{BytesRef, BytesStart, Event as XmlEvent};
9use quick_xml::name::{QName, ResolveResult};
10use quick_xml::reader::NsReader;
11
12use crate::Names;
13use crate::mixed::WhitespaceDepths;
14use crate::root::{Declarations, RootData};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct DeserializerConfig {
22 pub(crate) names: Names,
23 resolve_namespaces: bool,
24 duplicate_keys: DuplicateKeys,
25 track_locations: bool,
26}
27
28impl Default for DeserializerConfig {
29 fn default() -> DeserializerConfig {
30 DeserializerConfig::new()
31 }
32}
33
34impl DeserializerConfig {
35 pub const fn new() -> DeserializerConfig {
37 DeserializerConfig {
38 names: Names::new(),
39 resolve_namespaces: false,
40 duplicate_keys: DuplicateKeys::Error,
41 track_locations: true,
42 }
43 }
44
45 pub const fn attribute_prefix(mut self, prefix: &'static str) -> DeserializerConfig {
49 self.names.attribute_prefix = prefix;
50 self
51 }
52
53 pub const fn text_key(mut self, key: &'static str) -> DeserializerConfig {
58 self.names.text_key = key;
59 self
60 }
61
62 pub const fn namespaces(
97 mut self,
98 namespaces: &'static [(&'static str, &'static str)],
99 ) -> DeserializerConfig {
100 self.names.namespaces = namespaces;
101 self
102 }
103
104 pub const fn resolve_namespaces(mut self, yes: bool) -> DeserializerConfig {
150 self.resolve_namespaces = yes;
151 self
152 }
153
154 pub const fn duplicate_keys(mut self, policy: DuplicateKeys) -> DeserializerConfig {
162 self.duplicate_keys = policy;
163 self
164 }
165
166 pub const fn track_locations(mut self, yes: bool) -> DeserializerConfig {
173 self.track_locations = yes;
174 self
175 }
176
177 pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
179 Deserializer::from_str_with_config(s, self).deserialize()
180 }
181
182 pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
186 Deserializer::from_slice_with_config(bytes, self).deserialize()
187 }
188}
189
190pub fn from_str<'de, T: Deserialize<'de>>(s: &'de str) -> Result<T, Error> {
203 Deserializer::from_str(s).deserialize()
204}
205
206pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
208 Deserializer::from_slice(bytes).deserialize()
209}
210
211pub struct Deserializer<'a> {
213 input: &'a str,
214 error: Option<Error>,
215 config: DeserializerConfig,
216}
217
218impl<'a> Deserializer<'a> {
219 #[allow(clippy::should_implement_trait)]
221 pub fn from_str(input: &'a str) -> Deserializer<'a> {
222 Deserializer::from_str_with_config(input, &DeserializerConfig::new())
223 }
224
225 pub fn from_str_with_config(input: &'a str, config: &DeserializerConfig) -> Deserializer<'a> {
227 Deserializer {
228 input,
229 error: None,
230 config: config.clone(),
231 }
232 }
233
234 pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
236 Deserializer::from_slice_with_config(input, &DeserializerConfig::new())
237 }
238
239 pub fn from_slice_with_config(
242 input: &'a [u8],
243 config: &DeserializerConfig,
244 ) -> Deserializer<'a> {
245 let input = input.strip_prefix(b"\xef\xbb\xbf").unwrap_or(input);
247 match std::str::from_utf8(input) {
248 Ok(input) => Deserializer::from_str_with_config(input, config),
249 Err(err) => Deserializer {
250 input: "",
251 error: Some(
252 Error::new(ErrorKind::Unexpected, "input is not valid UTF-8")
253 .with_offset(err.valid_up_to()),
254 ),
255 config: config.clone(),
256 },
257 }
258 }
259
260 pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
262 de::Deserializer::deserialize(self)
263 }
264
265 pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
270 where
271 T: Deserialize<'a>,
272 F: FnOnce(&mut DeserializeDriver<'_, 'a>),
273 {
274 de::Deserializer::deserialize_with(self, setup)
275 }
276
277 pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
283 if let Some(err) = self.error.take() {
284 return Err(err);
285 }
286 let state = driver.state_mut();
287 if self.config.track_locations {
288 Source::set(state, self.input);
289 }
290 self.config.duplicate_keys.set(state);
291 TEXT_RULES.set(state);
292 ContentKey(self.config.names.text_key).set(state);
295 *state.get_mut::<Names>() = self.config.names.clone();
296 Parser {
297 input: self.input,
298 config: &self.config,
299 reader: NsReader::from_str(self.input),
300 stack: Vec::new(),
301 root_done: false,
302 root: None,
303 declarations: None,
304 }
305 .run(driver)
306 .map_err(|err| err.resolve_position(self.input.as_bytes()))
307 }
308}
309
310impl<'a> de::Deserializer<'a> for Deserializer<'a> {
311 fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
312 Deserializer::drive(self, driver)
313 }
314}
315
316const TEXT_RULES: LexicalRules = LexicalRules::STRICT.with_empty_is_null(true);
322
323type Range = (usize, usize);
325
326enum PendingText<'a> {
328 None,
329 Borrowed(&'a str, Range),
330 Owned(String, Range),
331}
332
333impl<'a> PendingText<'a> {
334 fn push(&mut self, text: Cow<'a, str>, range: Range) {
335 *self = match (std::mem::replace(self, PendingText::None), text) {
336 (PendingText::None, Cow::Borrowed(text)) => PendingText::Borrowed(text, range),
337 (PendingText::None, Cow::Owned(text)) => PendingText::Owned(text, range),
338 (PendingText::Borrowed(prev, (start, _)), text) => {
339 PendingText::Owned(prev.to_string() + &text, (start, range.1))
340 }
341 (PendingText::Owned(mut prev, (start, _)), text) => {
342 prev.push_str(&text);
343 PendingText::Owned(prev, (start, range.1))
344 }
345 };
346 }
347
348 fn is_blank(&self) -> bool {
349 match self {
350 PendingText::None => true,
351 PendingText::Borrowed(text, _) => is_blank(text),
352 PendingText::Owned(text, _) => is_blank(text),
353 }
354 }
355
356 fn emit(self, driver: &mut DeserializeDriver<'_, 'a>, fallback: Range) -> Result<(), Error> {
358 match self {
359 PendingText::None => emit_at(driver, Atom::Lexical(Text::borrowed("")), fallback),
360 PendingText::Borrowed(text, range) => {
361 driver.state_mut().set_input_range(range.0, range.1);
362 driver.emit_borrowed(Atom::Lexical(Text::borrowed(text)))
363 }
364 PendingText::Owned(text, range) => {
365 emit_at(driver, Atom::Lexical(Text::owned(text)), range)
366 }
367 }
368 }
369}
370
371fn is_blank(text: &str) -> bool {
372 text.bytes()
373 .all(|b| matches!(b, b' ' | b'\t' | b'\n' | b'\r'))
374}
375
376struct Element<'a> {
378 is_map: bool,
380 text: PendingText<'a>,
381 start: Range,
383}
384
385struct Parser<'a, 'c> {
386 input: &'a str,
387 config: &'c DeserializerConfig,
388 reader: NsReader<&'a [u8]>,
389 stack: Vec<Element<'a>>,
390 root_done: bool,
391 root: Option<RootData>,
394 declarations: Option<Vec<(String, String)>>,
397}
398
399impl<'a> Parser<'a, '_> {
400 fn run(mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
401 loop {
402 let start = self.position();
403 let event = self
404 .reader
405 .read_event()
406 .map_err(|err| xml_error(err, self.reader.error_position() as usize))?;
407 let range = (start, self.position());
408 match event {
409 XmlEvent::Start(ref tag) => self.start(driver, tag, range)?,
410 XmlEvent::Empty(ref tag) => {
411 self.start(driver, tag, range)?;
412 self.end(driver, range)?;
413 }
414 XmlEvent::End(_) => self.end(driver, range)?,
415 XmlEvent::Text(text) => {
416 self.text(text.xml_content(XmlVersion::Implicit1_0), range)?
417 }
418 XmlEvent::CData(text) => {
419 self.text(text.xml_content(XmlVersion::Implicit1_0), range)?
420 }
421 XmlEvent::GeneralRef(reference) => {
422 let text = resolve_reference(&reference, start)?;
423 self.text(Cow::Owned(text.to_string()), range)?
424 }
425 XmlEvent::Decl(_)
426 | XmlEvent::PI(_)
427 | XmlEvent::Comment(_)
428 | XmlEvent::DocType(_) => {}
429 XmlEvent::Eof => {
430 if !self.stack.is_empty() {
431 return Err(Error::new(
432 ErrorKind::EndOfFile,
433 "unexpected end of input, an element is not closed",
434 )
435 .with_offset(start));
436 }
437 if !self.root_done {
438 return Err(
439 Error::new(ErrorKind::EndOfFile, "no root element").with_offset(start)
440 );
441 }
442 return Ok(());
443 }
444 }
445 }
446 }
447
448 fn position(&self) -> usize {
449 self.reader.buffer_position() as usize
450 }
451
452 fn make_map(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
454 if !self.stack.last().unwrap().is_map {
455 self.attach_element(driver);
456 let element = self.stack.last_mut().unwrap();
457 element.is_map = true;
458 emit_at(
459 driver,
460 Event::MapStart(
461 ContainerShape::new()
462 .with_order(Order::Significant)
463 .with_multimap(true),
464 ),
465 element.start,
466 )?;
467 }
468 self.flush_text(driver)
469 }
470
471 fn flush_text(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
473 let element = self.stack.last_mut().unwrap();
474 if matches!(element.text, PendingText::None)
477 || (element.text.is_blank() && !WhitespaceDepths::applies(driver.state()))
478 {
479 element.text = PendingText::None;
480 return Ok(());
481 }
482 let text = std::mem::replace(&mut element.text, PendingText::None);
483 let range = match text {
484 PendingText::Borrowed(_, range) | PendingText::Owned(_, range) => range,
485 PendingText::None => unreachable!(),
486 };
487 emit_at(
488 driver,
489 Atom::Lexical(Text::borrowed(self.config.names.text_key)),
490 range,
491 )?;
492 text.emit(driver, range)
493 }
494
495 fn start(
496 &mut self,
497 driver: &mut DeserializeDriver<'_, 'a>,
498 tag: &BytesStart<'a>,
499 range: Range,
500 ) -> Result<(), Error> {
501 if self.stack.is_empty() {
502 if self.root_done {
503 return Err(
504 Error::new(ErrorKind::Unexpected, "more than one root element")
505 .with_offset(range.0),
506 );
507 }
508 self.root = Some(self.root_data(tag, range.0)?);
509 } else {
510 self.make_map(driver)?;
511 let name = self.name(tag.name(), false, range.0)?;
512 emit_key(driver, name, range)?;
513 if tag.attributes_raw().contains("xmlns") {
516 let declarations = self.declarations(tag, false, range.0)?;
517 if !declarations.is_empty() {
518 self.declarations = Some(declarations);
519 }
520 }
521 }
522 self.stack.push(Element {
523 is_map: false,
524 text: PendingText::None,
525 start: range,
526 });
527
528 for attr in tag.attributes() {
529 let attr = attr.map_err(|err| {
530 Error::new(ErrorKind::Unexpected, format!("invalid attribute: {err}"))
531 .with_offset(range.0)
532 })?;
533 let raw = attr.key.as_ref();
534 if raw == "xmlns" || raw.starts_with("xmlns:") {
536 continue;
537 }
538 self.make_map(driver)?;
539 let name = self.name(attr.key, true, range.0)?;
540 emit_key(driver, name, range)?;
541 let value = attr
542 .normalized_value(XmlVersion::Implicit1_0)
543 .map_err(|err| xml_error(err, range.0))?;
544 match reborrow(self.input, &value) {
545 Some(value) => {
546 driver.state_mut().set_input_range(range.0, range.1);
547 driver.emit_borrowed(Atom::Lexical(Text::borrowed(value)))?;
548 }
549 None => emit_at(driver, Atom::Lexical(Text::borrowed(&value)), range)?,
550 }
551 }
552 Ok(())
553 }
554
555 fn root_data(&self, tag: &BytesStart<'a>, offset: usize) -> Result<RootData, Error> {
561 Ok(RootData {
562 name: Some(self.name(tag.name(), false, offset)?.into_owned()),
563 namespaces: self.declarations(tag, true, offset)?,
564 })
565 }
566
567 fn declarations(
574 &self,
575 tag: &BytesStart<'a>,
576 is_root: bool,
577 offset: usize,
578 ) -> Result<Vec<(String, String)>, Error> {
579 let mut namespaces: Vec<(String, String)> = Vec::new();
580 for attr in tag.attributes().flatten() {
582 let raw: &str = attr.key.as_ref();
583 let prefix = match raw.strip_prefix("xmlns") {
584 Some("") => "",
585 Some(rest) => match rest.strip_prefix(':') {
586 Some(prefix) => prefix,
587 None => continue,
588 },
589 None => continue,
590 };
591 let uri = attr
592 .normalized_value(XmlVersion::Implicit1_0)
593 .map_err(|err| xml_error(err, offset))?;
594 if uri.is_empty() && (is_root || !prefix.is_empty()) {
595 continue;
596 }
597 let prefix = match self.config.names.namespaces.iter().find(|(_, x)| *x == uri) {
598 Some((alias, _)) => alias,
599 None => prefix,
600 };
601 if !namespaces.iter().any(|(x, _)| x == prefix) {
602 namespaces.push((prefix.to_string(), uri.into_owned()));
603 }
604 }
605 Ok(namespaces)
606 }
607
608 fn attach_element(&mut self, driver: &mut DeserializeDriver<'_, 'a>) {
615 if let Some(root) = self.root.take() {
616 *driver.state_mut().event_mut::<RootData>() = root;
617 }
618 if let Some(declarations) = self.declarations.take() {
619 driver.state_mut().event_mut::<Declarations>().0 = declarations;
620 }
621 }
622
623 fn end(&mut self, driver: &mut DeserializeDriver<'_, 'a>, range: Range) -> Result<(), Error> {
624 if self.stack.last().unwrap().is_map {
625 self.flush_text(driver)?;
626 self.stack.pop();
627 emit_at(driver, Event::MapEnd, range)?;
628 WhitespaceDepths::prune(driver.state_mut());
629 } else {
630 self.attach_element(driver);
631 let element = self.stack.pop().unwrap();
632 element.text.emit(driver, element.start)?;
633 }
634 if self.stack.is_empty() {
635 self.root_done = true;
636 }
637 Ok(())
638 }
639
640 fn text(&mut self, text: Cow<'a, str>, range: Range) -> Result<(), Error> {
641 match self.stack.last_mut() {
642 Some(element) => {
643 element.text.push(text, range);
644 Ok(())
645 }
646 None if is_blank(&text) => Ok(()),
647 None => Err(
648 Error::new(ErrorKind::Unexpected, "text outside of the root element")
649 .with_offset(range.0),
650 ),
651 }
652 }
653
654 fn name(
656 &self,
657 name: QName<'_>,
658 is_attribute: bool,
659 offset: usize,
660 ) -> Result<Cow<'a, str>, Error> {
661 let names = &self.config.names;
662 let written: &str = name.as_ref();
663 let local_name = name.local_name();
664 let local: &str = local_name.as_ref();
665 let mut key = match self.namespace(name, is_attribute) {
666 Namespace::Alias("") => Cow::Owned(local.to_string()),
667 Namespace::Alias(alias) => Cow::Owned(format!("{alias}:{local}")),
668 Namespace::Uri(uri) => Cow::Owned(format!("{{{uri}}}{local}")),
669 Namespace::Unknown if self.config.resolve_namespaces => {
670 return Err(Error::new(
671 ErrorKind::Unexpected,
672 format!("the prefix of `{written}` is not declared"),
673 )
674 .with_offset(offset));
675 }
676 Namespace::Written | Namespace::Unknown => match reborrow(self.input, written) {
677 Some(written) => Cow::Borrowed(written),
678 None => Cow::Owned(written.to_string()),
679 },
680 };
681 if is_attribute && !names.attribute_prefix.is_empty() {
682 key = Cow::Owned(format!("{}{}", names.attribute_prefix, key));
683 }
684 Ok(key)
685 }
686
687 fn namespace(&self, name: QName<'_>, is_attribute: bool) -> Namespace {
689 let namespaces = self.config.names.namespaces;
690 let resolve = self.config.resolve_namespaces;
691 if namespaces.is_empty() && !resolve {
692 return Namespace::Written;
693 }
694 let resolver = self.reader.resolver();
695 let (ns, _) = if is_attribute {
696 resolver.resolve_attribute(name)
697 } else {
698 resolver.resolve_element(name)
699 };
700 match ns {
701 ResolveResult::Bound(ns) => {
702 let uri: &str = ns.as_ref();
703 if let Some((alias, _)) = namespaces.iter().find(|(_, x)| *x == uri) {
704 Namespace::Alias(alias)
705 } else if !resolve {
706 Namespace::Written
707 } else if uri == XML_NAMESPACE {
708 Namespace::Alias("xml")
709 } else {
710 Namespace::Uri(uri.to_string())
711 }
712 }
713 ResolveResult::Unbound => Namespace::Written,
714 ResolveResult::Unknown(_) => Namespace::Unknown,
715 }
716 }
717}
718
719pub(crate) const XML_NAMESPACE: &str = "http://www.w3.org/XML/1998/namespace";
721
722enum Namespace {
724 Written,
726 Alias(&'static str),
728 Uri(String),
730 Unknown,
732}
733
734fn reborrow<'a>(input: &'a str, text: &str) -> Option<&'a str> {
736 let start = (text.as_ptr() as usize).checked_sub(input.as_ptr() as usize)?;
737 let end = start.checked_add(text.len())?;
738 input
739 .get(start..end)
740 .filter(|x| x.as_ptr() == text.as_ptr())
741}
742
743fn resolve_reference(reference: &BytesRef<'_>, offset: usize) -> Result<char, Error> {
748 if let Some(c) = reference
749 .resolve_char_ref()
750 .map_err(|err| xml_error(err, offset))?
751 {
752 return Ok(c);
753 }
754 match &*reference.xml_content(XmlVersion::Implicit1_0) {
755 "lt" => Ok('<'),
756 "gt" => Ok('>'),
757 "amp" => Ok('&'),
758 "apos" => Ok('\''),
759 "quot" => Ok('"'),
760 name => Err(
761 Error::new(ErrorKind::Unexpected, format!("unknown entity `&{name};`"))
762 .with_offset(offset),
763 ),
764 }
765}
766
767fn xml_error(err: quick_xml::Error, offset: usize) -> Error {
768 Error::new(ErrorKind::Unexpected, format!("invalid XML: {err}")).with_offset(offset)
769}
770
771fn emit_key<'a>(
772 driver: &mut DeserializeDriver<'_, 'a>,
773 key: Cow<'a, str>,
774 range: Range,
775) -> Result<(), Error> {
776 driver.state_mut().set_input_range(range.0, range.1);
777 match key {
778 Cow::Borrowed(key) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(key))),
779 Cow::Owned(key) => driver.emit(Atom::Lexical(Text::owned(key))),
780 }
781}
782
783fn emit_at<'e, E: Into<Event<'e>>>(
784 driver: &mut DeserializeDriver<'_, '_>,
785 event: E,
786 range: Range,
787) -> Result<(), Error> {
788 driver.state_mut().set_input_range(range.0, range.1);
789 driver.emit(event)
790}