1use crate::XmlVersion;
8use crate::encoding::Decoder;
9use crate::errors::Result as XmlResult;
10use crate::escape::{escape, resolve_predefined_entity};
11use crate::name::{LocalName, Namespace, NamespaceResolver, QName};
12use crate::utils::{Bytes, is_whitespace};
13
14use std::collections::HashSet;
15use std::fmt::{self, Debug, Display, Formatter};
16use std::hash::{BuildHasherDefault, DefaultHasher, Hasher};
17use std::iter::FusedIterator;
18use std::{borrow::Cow, ops::Range};
19
20#[derive(Clone, Eq, PartialEq)]
26pub struct Attribute<'a> {
27 pub key: QName<'a>,
31 pub value: Cow<'a, [u8]>,
33}
34
35impl<'a> Attribute<'a> {
36 pub fn normalized_value(&self, version: XmlVersion) -> XmlResult<Cow<'a, str>> {
44 self.normalized_value_with(version, 1, resolve_predefined_entity)
47 }
48
49 pub fn normalized_value_with<'entity>(
62 &self,
63 version: XmlVersion,
64 depth: usize,
65 resolve_entity: impl FnMut(&str) -> Option<&'entity str>,
66 ) -> XmlResult<Cow<'a, str>> {
67 use crate::encoding::EncodingError;
68 use std::str::from_utf8;
69
70 let decoded = match &self.value {
71 Cow::Borrowed(bytes) => Cow::Borrowed(from_utf8(bytes).map_err(EncodingError::Utf8)?),
72 Cow::Owned(bytes) => {
73 Cow::Owned(from_utf8(bytes).map_err(EncodingError::Utf8)?.to_owned())
74 }
75 };
76
77 match version.normalize_attribute_value(&decoded, depth, resolve_entity)? {
78 Cow::Borrowed(_) => Ok(decoded),
79 Cow::Owned(s) => Ok(s.into()),
80 }
81 }
82
83 pub fn decoded_and_normalized_value(
88 &self,
89 version: XmlVersion,
90 decoder: Decoder,
91 ) -> XmlResult<Cow<'a, str>> {
92 self.decoded_and_normalized_value_with(version, decoder, 1, resolve_predefined_entity)
93 }
94
95 pub fn decoded_and_normalized_value_with<'entity>(
100 &self,
101 version: XmlVersion,
102 decoder: Decoder,
103 depth: usize,
104 resolve_entity: impl FnMut(&str) -> Option<&'entity str>,
105 ) -> XmlResult<Cow<'a, str>> {
106 let decoded = match &self.value {
107 Cow::Borrowed(bytes) => decoder.decode(bytes)?,
108 Cow::Owned(bytes) => decoder.decode(bytes)?.into_owned().into(),
109 };
110
111 match version.normalize_attribute_value(&decoded, depth, resolve_entity)? {
112 Cow::Borrowed(_) => Ok(decoded),
113 Cow::Owned(s) => Ok(s.into()),
114 }
115 }
116
117 #[cfg(any(doc, not(feature = "encoding")))]
122 #[deprecated = "use `Self::normalized_value()`"]
123 pub fn unescape_value(&self) -> XmlResult<Cow<'a, str>> {
124 self.normalized_value_with(XmlVersion::Implicit1_0, 1, resolve_predefined_entity)
125 }
126
127 #[cfg(any(doc, not(feature = "encoding")))]
129 #[deprecated = "use `Self::normalized_value_with()`"]
130 #[inline]
131 pub fn unescape_value_with<'entity>(
132 &self,
133 resolve_entity: impl FnMut(&str) -> Option<&'entity str>,
134 ) -> XmlResult<Cow<'a, str>> {
135 self.normalized_value_with(XmlVersion::Implicit1_0, 128, resolve_entity)
136 }
137
138 #[deprecated = "use `Self::decoded_and_normalized_value()`"]
140 pub fn decode_and_unescape_value(&self, decoder: Decoder) -> XmlResult<Cow<'a, str>> {
141 self.decoded_and_normalized_value_with(
142 XmlVersion::Implicit1_0,
143 decoder,
144 1,
145 resolve_predefined_entity,
146 )
147 }
148
149 #[deprecated = "use `Self::decoded_and_normalized_value_with()`"]
151 pub fn decode_and_unescape_value_with<'entity>(
152 &self,
153 decoder: Decoder,
154 resolve_entity: impl FnMut(&str) -> Option<&'entity str>,
155 ) -> XmlResult<Cow<'a, str>> {
156 self.decoded_and_normalized_value_with(
157 XmlVersion::Implicit1_0,
158 decoder,
159 128,
160 resolve_entity,
161 )
162 }
163
164 #[inline]
177 pub fn as_bool(&self) -> Option<bool> {
178 match self.value.as_ref() {
179 b"1" | b"true" => Some(true),
180 b"0" | b"false" => Some(false),
181 _ => None,
182 }
183 }
184}
185
186impl<'a> Debug for Attribute<'a> {
187 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
188 f.debug_struct("Attribute")
189 .field("key", &Bytes(self.key.as_ref()))
190 .field("value", &Bytes(&self.value))
191 .finish()
192 }
193}
194
195impl<'a> From<(&'a [u8], &'a [u8])> for Attribute<'a> {
196 fn from(val: (&'a [u8], &'a [u8])) -> Attribute<'a> {
198 Attribute {
199 key: QName(val.0),
200 value: Cow::from(val.1),
201 }
202 }
203}
204
205impl<'a> From<(&'a str, &'a str)> for Attribute<'a> {
206 fn from(val: (&'a str, &'a str)) -> Attribute<'a> {
209 Attribute {
210 key: QName(val.0.as_bytes()),
211 value: match escape(val.1) {
212 Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
213 Cow::Owned(s) => Cow::Owned(s.into_bytes()),
214 },
215 }
216 }
217}
218
219impl<'a> From<(&'a str, Cow<'a, str>)> for Attribute<'a> {
220 fn from(val: (&'a str, Cow<'a, str>)) -> Attribute<'a> {
223 Attribute {
224 key: QName(val.0.as_bytes()),
225 value: match escape(val.1) {
226 Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
227 Cow::Owned(s) => Cow::Owned(s.into_bytes()),
228 },
229 }
230 }
231}
232
233impl<'a> From<Attr<&'a [u8]>> for Attribute<'a> {
234 #[inline]
235 fn from(attr: Attr<&'a [u8]>) -> Self {
236 Self {
237 key: attr.key(),
238 value: Cow::Borrowed(attr.value()),
239 }
240 }
241}
242
243#[derive(Clone)]
251pub struct Attributes<'a> {
252 bytes: &'a [u8],
254 state: IterState,
256 decoder: Decoder,
258}
259
260impl<'a> Attributes<'a> {
261 #[inline]
263 pub(crate) const fn wrap(buf: &'a [u8], pos: usize, html: bool, decoder: Decoder) -> Self {
264 Self {
265 bytes: buf,
266 state: IterState::new(pos, html),
267 decoder,
268 }
269 }
270
271 pub const fn new(buf: &'a str, pos: usize) -> Self {
286 Self::wrap(buf.as_bytes(), pos, false, Decoder::utf8())
287 }
288
289 pub const fn html(buf: &'a str, pos: usize) -> Self {
300 Self::wrap(buf.as_bytes(), pos, true, Decoder::utf8())
301 }
302
303 pub fn with_checks(&mut self, val: bool) -> &mut Attributes<'a> {
305 self.state.check_duplicates = val;
306 self
307 }
308
309 pub fn has_nil(&mut self, resolver: &NamespaceResolver) -> bool {
330 use crate::name::ResolveResult::*;
331
332 self.any(|attr| {
333 if let Ok(attr) = attr {
334 match resolver.resolve_attribute(attr.key) {
335 (
336 Bound(Namespace(b"http://www.w3.org/2001/XMLSchema-instance")),
337 LocalName(b"nil"),
338 ) => attr.as_bool().unwrap_or_default(),
339 _ => false,
340 }
341 } else {
342 false
343 }
344 })
345 }
346
347 #[inline]
350 pub const fn decoder(&self) -> Decoder {
351 self.decoder
352 }
353}
354
355impl<'a> Debug for Attributes<'a> {
356 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
357 f.debug_struct("Attributes")
358 .field("bytes", &Bytes(self.bytes))
359 .field("state", &self.state)
360 .field("decoder", &self.decoder)
361 .finish()
362 }
363}
364
365impl<'a> Iterator for Attributes<'a> {
366 type Item = Result<Attribute<'a>, AttrError>;
367
368 #[inline]
369 fn next(&mut self) -> Option<Self::Item> {
370 match self.state.next(self.bytes) {
371 None => None,
372 Some(Ok(a)) => Some(Ok(a.map(|range| &self.bytes[range]).into())),
373 Some(Err(e)) => Some(Err(e)),
374 }
375 }
376}
377
378impl<'a> FusedIterator for Attributes<'a> {}
379
380#[derive(Clone, Debug, PartialEq, Eq)]
387pub enum AttrError {
388 ExpectedEq(usize),
391 ExpectedValue(usize),
394 UnquotedValue(usize),
397 ExpectedQuote(usize, u8),
400 Duplicated(usize, usize),
403}
404
405impl Display for AttrError {
406 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
407 match self {
408 Self::ExpectedEq(pos) => write!(
409 f,
410 r#"position {}: attribute key must be directly followed by `=` or space"#,
411 pos
412 ),
413 Self::ExpectedValue(pos) => write!(
414 f,
415 r#"position {}: `=` must be followed by an attribute value"#,
416 pos
417 ),
418 Self::UnquotedValue(pos) => write!(
419 f,
420 r#"position {}: attribute value must be enclosed in `"` or `'`"#,
421 pos
422 ),
423 Self::ExpectedQuote(pos, quote) => write!(
424 f,
425 r#"position {}: missing closing quote `{}` in attribute value"#,
426 pos, *quote as char
427 ),
428 Self::Duplicated(pos1, pos2) => write!(
429 f,
430 r#"position {}: duplicated attribute, previous declaration at position {}"#,
431 pos1, pos2
432 ),
433 }
434 }
435}
436
437impl std::error::Error for AttrError {}
438
439#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
445pub enum Attr<T> {
446 DoubleQ(T, T),
448 SingleQ(T, T),
450 Unquoted(T, T),
453 Empty(T),
455}
456
457impl<T> Attr<T> {
458 #[inline]
460 pub fn map<U, F>(self, mut f: F) -> Attr<U>
461 where
462 F: FnMut(T) -> U,
463 {
464 match self {
465 Attr::DoubleQ(key, value) => Attr::DoubleQ(f(key), f(value)),
466 Attr::SingleQ(key, value) => Attr::SingleQ(f(key), f(value)),
467 Attr::Empty(key) => Attr::Empty(f(key)),
468 Attr::Unquoted(key, value) => Attr::Unquoted(f(key), f(value)),
469 }
470 }
471}
472
473impl<'a> Attr<&'a [u8]> {
474 #[inline]
476 pub const fn key(&self) -> QName<'a> {
477 QName(match self {
478 Attr::DoubleQ(key, _) => key,
479 Attr::SingleQ(key, _) => key,
480 Attr::Empty(key) => key,
481 Attr::Unquoted(key, _) => key,
482 })
483 }
484 #[inline]
486 pub const fn value(&self) -> &'a [u8] {
487 match self {
488 Attr::DoubleQ(_, value) => value,
489 Attr::SingleQ(_, value) => value,
490 Attr::Empty(_) => &[],
491 Attr::Unquoted(_, value) => value,
492 }
493 }
494}
495
496impl<T: AsRef<[u8]>> Debug for Attr<T> {
497 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
498 match self {
499 Attr::DoubleQ(key, value) => f
500 .debug_tuple("Attr::DoubleQ")
501 .field(&Bytes(key.as_ref()))
502 .field(&Bytes(value.as_ref()))
503 .finish(),
504 Attr::SingleQ(key, value) => f
505 .debug_tuple("Attr::SingleQ")
506 .field(&Bytes(key.as_ref()))
507 .field(&Bytes(value.as_ref()))
508 .finish(),
509 Attr::Empty(key) => f
510 .debug_tuple("Attr::Empty")
511 .field(&Bytes(key.as_ref()))
512 .finish(),
513 Attr::Unquoted(key, value) => f
514 .debug_tuple("Attr::Unquoted")
515 .field(&Bytes(key.as_ref()))
516 .field(&Bytes(value.as_ref()))
517 .finish(),
518 }
519 }
520}
521
522impl<T> From<Attr<T>> for (T, Option<T>) {
525 #[inline]
526 fn from(attr: Attr<T>) -> Self {
527 match attr {
528 Attr::DoubleQ(key, value) => (key, Some(value)),
529 Attr::SingleQ(key, value) => (key, Some(value)),
530 Attr::Empty(key) => (key, None),
531 Attr::Unquoted(key, value) => (key, Some(value)),
532 }
533 }
534}
535
536type AttrResult = Result<Attr<Range<usize>>, AttrError>;
539
540#[derive(Clone, Copy, Debug)]
541enum State {
542 Done,
544 Next(usize),
547 SkipValue(usize),
550 SkipEqValue(usize),
553}
554
555const SMALL_ATTRIBUTE_COUNT: usize = 32;
558
559#[derive(Default)]
562struct IdentityHasher(u64);
563
564impl Hasher for IdentityHasher {
565 #[inline]
566 fn finish(&self) -> u64 {
567 self.0
568 }
569
570 #[inline]
571 fn write(&mut self, _: &[u8]) {
572 unreachable!("IdentityHasher only supports u64 keys")
574 }
575
576 #[inline]
577 fn write_u64(&mut self, n: u64) {
578 self.0 = n;
579 }
580}
581
582#[inline]
584fn hash_name(name: &[u8]) -> u64 {
585 let mut hasher = DefaultHasher::new();
586 hasher.write(name);
587 hasher.finish()
588}
589
590#[derive(Clone, Debug)]
592pub(crate) struct IterState {
593 state: State,
595 html: bool,
597 check_duplicates: bool,
599 keys: Vec<Range<usize>>,
601 key_hashes: Option<HashSet<u64, BuildHasherDefault<IdentityHasher>>>,
604}
605
606impl IterState {
607 pub const fn new(offset: usize, html: bool) -> Self {
608 Self {
609 state: State::Next(offset),
610 html,
611 check_duplicates: true,
612 keys: Vec::new(),
613 key_hashes: None,
614 }
615 }
616
617 fn recover(&self, slice: &[u8]) -> Option<usize> {
620 match self.state {
621 State::Done => None,
622 State::Next(offset) => Some(offset),
623 State::SkipValue(offset) => self.skip_value(slice, offset),
624 State::SkipEqValue(offset) => self.skip_eq_value(slice, offset),
625 }
626 }
627
628 #[inline]
630 fn skip_value(&self, slice: &[u8], offset: usize) -> Option<usize> {
631 let mut iter = (offset..).zip(slice[offset..].iter());
632 iter.find(|&(_, &b)| is_whitespace(b)).map(|(e, _)| e)
633 }
634
635 #[inline]
637 fn skip_eq_value(&self, slice: &[u8], offset: usize) -> Option<usize> {
638 let mut iter = (offset..).zip(slice[offset..].iter());
639
640 let quote = match iter.find(|&(_, &b)| !is_whitespace(b)) {
642 Some((_, b'"')) => b'"',
643 Some((_, b'\'')) => b'\'',
644 Some((offset, _)) => return self.skip_value(slice, offset),
645 None => return None,
646 };
647
648 match iter.find(|&(_, &b)| b == quote) {
649 Some((e, b'"')) => Some(e),
650 Some((e, _)) => Some(e),
651 None => None,
652 }
653 }
654
655 #[inline]
659 fn check_for_duplicates(
660 &mut self,
661 slice: &[u8],
662 key: Range<usize>,
663 ) -> Result<Range<usize>, AttrError> {
664 if self.check_duplicates {
665 if self.keys.len() >= SMALL_ATTRIBUTE_COUNT {
666 return self.check_for_duplicates_hashed(slice, key);
667 }
668 if let Some(prev) = self
669 .keys
670 .iter()
671 .find(|r| slice[(*r).clone()] == slice[key.clone()])
672 {
673 return Err(AttrError::Duplicated(key.start, prev.start));
674 }
675 self.keys.push(key.clone());
676 }
677 Ok(key)
678 }
679
680 #[cold]
683 fn check_for_duplicates_hashed(
684 &mut self,
685 slice: &[u8],
686 key: Range<usize>,
687 ) -> Result<Range<usize>, AttrError> {
688 let keys = &self.keys;
689 let key_hashes = self.key_hashes.get_or_insert_with(|| {
690 let mut set = HashSet::with_capacity_and_hasher(
691 keys.len() * 2,
692 BuildHasherDefault::<IdentityHasher>::default(),
693 );
694 for r in keys {
695 set.insert(hash_name(&slice[r.clone()]));
696 }
697 set
698 });
699 if !key_hashes.insert(hash_name(&slice[key.clone()])) {
700 if let Some(prev) = self
701 .keys
702 .iter()
703 .find(|r| slice[(*r).clone()] == slice[key.clone()])
704 {
705 return Err(AttrError::Duplicated(key.start, prev.start));
706 }
707 }
708 self.keys.push(key.clone());
709 Ok(key)
710 }
711
712 #[inline]
713 fn key_only(&mut self, slice: &[u8], key: Range<usize>, offset: usize) -> Option<AttrResult> {
714 Some(if self.html {
715 self.check_for_duplicates(slice, key).map(Attr::Empty)
716 } else {
717 Err(AttrError::ExpectedEq(offset))
718 })
719 }
720
721 #[inline]
722 fn double_q(&mut self, key: Range<usize>, value: Range<usize>) -> Option<AttrResult> {
723 self.state = State::Next(value.end + 1); Some(Ok(Attr::DoubleQ(key, value)))
725 }
726
727 #[inline]
728 fn single_q(&mut self, key: Range<usize>, value: Range<usize>) -> Option<AttrResult> {
729 self.state = State::Next(value.end + 1); Some(Ok(Attr::SingleQ(key, value)))
731 }
732
733 pub fn next(&mut self, slice: &[u8]) -> Option<AttrResult> {
734 let mut iter = match self.recover(slice) {
735 Some(offset) => (offset..).zip(slice[offset..].iter()),
736 None => return None,
737 };
738
739 let start_key = match iter.find(|&(_, &b)| !is_whitespace(b)) {
741 Some((s, _)) => s,
742 None => {
743 self.state = State::Done;
744 return None;
745 }
746 };
747 let (key, offset) = match iter.find(|&(_, &b)| b == b'=' || is_whitespace(b)) {
749 Some((e, b'=')) => (start_key..e, e),
750
751 Some((e, _)) => match iter.find(|&(_, &b)| !is_whitespace(b)) {
752 Some((offset, b'=')) => (start_key..e, offset),
753 Some((offset, _)) => {
754 self.state = State::Next(offset);
755 return self.key_only(slice, start_key..e, offset);
756 }
757 None => {
758 self.state = State::Done;
759 return self.key_only(slice, start_key..e, slice.len());
760 }
761 },
762
763 None => {
764 self.state = State::Done;
765 let e = slice.len();
766 return self.key_only(slice, start_key..e, e);
767 }
768 };
769
770 let key = match self.check_for_duplicates(slice, key) {
771 Err(e) => {
772 self.state = State::SkipEqValue(offset);
773 return Some(Err(e));
774 }
775 Ok(key) => key,
776 };
777
778 let (start_value, quote) = match iter.find(|&(_, &b)| !is_whitespace(b)) {
780 Some((s, b'"')) => (s + 1, b'"'),
781 Some((s, b'\'')) => (s + 1, b'\''),
782
783 Some((s, _)) if self.html => {
784 let end = match iter.find(|&(_, &b)| is_whitespace(b)) {
785 Some((e, _)) => e,
786 None => slice.len(),
787 };
788 self.state = State::Next(end);
789 return Some(Ok(Attr::Unquoted(key, s..end)));
790 }
791 Some((s, _)) => {
792 self.state = State::SkipValue(s);
793 return Some(Err(AttrError::UnquotedValue(s)));
794 }
795
796 None => {
797 self.state = State::Done;
798 return Some(Err(AttrError::ExpectedValue(slice.len())));
799 }
800 };
801
802 match iter.find(|&(_, &b)| b == quote) {
803 Some((e, b'"')) => self.double_q(key, start_value..e),
804 Some((e, _)) => self.single_q(key, start_value..e),
805 None => {
806 self.state = State::Done;
807 Some(Err(AttrError::ExpectedQuote(slice.len(), quote)))
808 }
809 }
810 }
811}
812
813#[cfg(test)]
814mod tests;