Skip to main content

quick_xml/reader/
slice_reader.rs

1//! This is an implementation of [`Reader`] for reading from a `&[u8]` as
2//! underlying byte stream. This implementation supports not using an
3//! intermediate buffer as the byte slice itself can be used to borrow from.
4
5use std::io;
6
7#[cfg(feature = "encoding")]
8use crate::encoding::DetectedEncoding;
9#[cfg(feature = "encoding")]
10use crate::reader::EncodingRef;
11#[cfg(feature = "encoding")]
12use encoding_rs;
13
14use crate::errors::{Error, Result};
15use crate::events::{BytesText, Event};
16use crate::name::QName;
17use crate::parser::Parser;
18use crate::reader::{BangType, ReadRefResult, ReadTextResult, Reader, Span, XmlSource};
19use crate::utils::is_whitespace;
20
21/// This is an implementation for reading from a `&[u8]` as underlying byte stream.
22/// This implementation supports not using an intermediate buffer as the byte slice
23/// itself can be used to borrow from.
24impl<'a> Reader<&'a [u8]> {
25    /// Creates an XML reader from a string slice.
26    #[allow(clippy::should_implement_trait)]
27    pub fn from_str(s: &'a str) -> Self {
28        // Rust strings are guaranteed to be UTF-8, so lock the encoding
29        #[cfg(feature = "encoding")]
30        {
31            let mut reader = Self::from_reader(s.as_bytes());
32            reader.state.encoding = EncodingRef::Explicit(encoding_rs::UTF_8);
33            reader
34        }
35
36        #[cfg(not(feature = "encoding"))]
37        Self::from_reader(s.as_bytes())
38    }
39
40    /// Read an event that borrows from the input rather than a buffer.
41    ///
42    /// There is no asynchronous `read_event_async()` version of this function,
43    /// because it is not necessary -- the contents are already in memory and no IO
44    /// is needed, therefore there is no potential for blocking.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// # use pretty_assertions::assert_eq;
50    /// use quick_xml::events::Event;
51    /// use quick_xml::reader::Reader;
52    ///
53    /// let mut reader = Reader::from_str(r#"
54    ///     <tag1 att1 = "test">
55    ///        <tag2><!--Test comment-->Test</tag2>
56    ///        <tag2>Test 2</tag2>
57    ///     </tag1>
58    /// "#);
59    /// reader.config_mut().trim_text(true);
60    ///
61    /// let mut count = 0;
62    /// let mut txt = Vec::new();
63    /// loop {
64    ///     match reader.read_event().unwrap() {
65    ///         Event::Start(e) => count += 1,
66    ///         Event::Text(e) => txt.push(e.into_inner().into_owned()),
67    ///         Event::Eof => break,
68    ///         _ => (),
69    ///     }
70    /// }
71    /// assert_eq!(count, 3);
72    /// assert_eq!(txt, vec!["Test".to_string(), "Test 2".to_string()]);
73    /// ```
74    #[inline]
75    pub fn read_event(&mut self) -> Result<Event<'a>> {
76        self.read_event_impl(())
77    }
78
79    /// Reads until end element is found. This function is supposed to be called
80    /// after you already read a [`Start`] event.
81    ///
82    /// Returns a span that cover content between `>` of an opening tag and `<` of
83    /// a closing tag or an empty slice, if [`expand_empty_elements`] is set and
84    /// this method was called after reading expanded [`Start`] event.
85    ///
86    /// Manages nested cases where parent and child elements have the _literally_
87    /// same name.
88    ///
89    /// If a corresponding [`End`] event is not found, an error of type [`Error::IllFormed`]
90    /// will be returned. In particularly, that error will be returned if you call
91    /// this method without consuming the corresponding [`Start`] event first.
92    ///
93    /// The `end` parameter should contain name of the end element _in the reader
94    /// encoding_. It is good practice to always get that parameter using
95    /// [`BytesStart::to_end()`] method.
96    ///
97    /// The correctness of the skipped events does not checked, if you disabled
98    /// the [`check_end_names`] option.
99    ///
100    /// There is no asynchronous `read_to_end_async()` version of this function,
101    /// because it is not necessary -- the contents are already in memory and no IO
102    /// is needed, therefore there is no potential for blocking.
103    ///
104    /// # Namespaces
105    ///
106    /// While the `Reader` does not support namespace resolution, namespaces
107    /// does not change the algorithm for comparing names. Although the names
108    /// `a:name` and `b:name` where both prefixes `a` and `b` resolves to the
109    /// same namespace, are semantically equivalent, `</b:name>` cannot close
110    /// `<a:name>`, because according to [the specification]
111    ///
112    /// > The end of every element that begins with a **start-tag** MUST be marked
113    /// > by an **end-tag** containing a name that echoes the element's type as
114    /// > given in the **start-tag**
115    ///
116    /// # Examples
117    ///
118    /// This example shows, how you can skip XML content after you read the
119    /// start event.
120    ///
121    /// ```
122    /// # use pretty_assertions::assert_eq;
123    /// use quick_xml::events::{BytesStart, Event};
124    /// use quick_xml::reader::Reader;
125    ///
126    /// let mut reader = Reader::from_str(r#"
127    ///     <outer>
128    ///         <inner>
129    ///             <inner></inner>
130    ///             <inner/>
131    ///             <outer></outer>
132    ///             <outer/>
133    ///         </inner>
134    ///     </outer>
135    /// "#);
136    /// reader.config_mut().trim_text(true);
137    ///
138    /// let start = BytesStart::new("outer");
139    /// let end   = start.to_end().into_owned();
140    ///
141    /// // First, we read a start event...
142    /// assert_eq!(reader.read_event().unwrap(), Event::Start(start));
143    ///
144    /// // ...then, we could skip all events to the corresponding end event.
145    /// // This call will correctly handle nested <outer> elements.
146    /// // Note, however, that this method does not handle namespaces.
147    /// reader.read_to_end(end.name()).unwrap();
148    ///
149    /// // At the end we should get an Eof event, because we ate the whole XML
150    /// assert_eq!(reader.read_event().unwrap(), Event::Eof);
151    /// ```
152    ///
153    /// [`Start`]: Event::Start
154    /// [`End`]: Event::End
155    /// [`BytesStart::to_end()`]: crate::events::BytesStart::to_end
156    /// [`expand_empty_elements`]: crate::reader::Config::expand_empty_elements
157    /// [`check_end_names`]: crate::reader::Config::check_end_names
158    /// [the specification]: https://www.w3.org/TR/xml11/#dt-etag
159    pub fn read_to_end(&mut self, end: QName) -> Result<Span> {
160        Ok(read_to_end!(self, end, (), read_event_impl, {}))
161    }
162
163    /// Reads content between start and end tags, including any markup. This
164    /// function is supposed to be called after you already read a [`Start`] event.
165    ///
166    /// Manages nested cases where parent and child elements have the _literally_
167    /// same name.
168    ///
169    /// This method does not unescape read data, instead it returns content
170    /// "as is" of the XML document. This is because it has no idea what text
171    /// it reads, and if, for example, it contains CDATA section, attempt to
172    /// unescape it content will spoil data.
173    ///
174    /// Actually, this method perform the following code:
175    ///
176    /// ```ignore
177    /// let span = reader.read_to_end(end)?;
178    /// let text = &reader.inner_slice[span];
179    /// ```
180    ///
181    /// # Examples
182    ///
183    /// This example shows, how you can read a HTML content from your XML document.
184    ///
185    /// ```
186    /// # use pretty_assertions::assert_eq;
187    /// # use std::borrow::Cow;
188    /// use quick_xml::events::{BytesStart, Event};
189    /// use quick_xml::reader::Reader;
190    ///
191    /// let mut reader = Reader::from_str("
192    ///     <html>
193    ///         <title>This is a HTML text</title>
194    ///         <p>Usual XML rules does not apply inside it
195    ///         <p>For example, elements not needed to be &quot;closed&quot;
196    ///     </html>
197    /// ");
198    /// reader.config_mut().trim_text(true);
199    ///
200    /// let start = BytesStart::new("html");
201    /// let end   = start.to_end().into_owned();
202    ///
203    /// // First, we read a start event...
204    /// assert_eq!(reader.read_event().unwrap(), Event::Start(start));
205    /// // ...and disable checking of end names because we expect HTML further...
206    /// reader.config_mut().check_end_names = false;
207    ///
208    /// // ...then, we could read text content until close tag.
209    /// // This call will correctly handle nested <html> elements.
210    /// let text = reader.read_text(end.name()).unwrap();
211    /// let text = text.into_inner();
212    /// assert_eq!(text, r#"
213    ///         <title>This is a HTML text</title>
214    ///         <p>Usual XML rules does not apply inside it
215    ///         <p>For example, elements not needed to be &quot;closed&quot;
216    ///     "#);
217    /// assert!(matches!(text, Cow::Borrowed(_)));
218    ///
219    /// // Now we can enable checks again
220    /// reader.config_mut().check_end_names = true;
221    ///
222    /// // At the end we should get an Eof event, because we ate the whole XML
223    /// assert_eq!(reader.read_event().unwrap(), Event::Eof);
224    /// ```
225    ///
226    /// [`Start`]: Event::Start
227    pub fn read_text(&mut self, end: QName) -> Result<BytesText<'a>> {
228        // self.reader will be changed, so store original reference
229        let buffer = self.reader;
230        let span = self.read_to_end(end)?;
231
232        let len = span.end - span.start;
233        // SAFETY: `span` can only contain indexes up to usize::MAX because it
234        // was created from offsets from a single &[u8] slice
235        // Could use from_utf8_unchecked: buffer was validated during event parsing
236        let text = std::str::from_utf8(&buffer[0..len as usize])?;
237        Ok(BytesText::wrap(text))
238    }
239}
240
241////////////////////////////////////////////////////////////////////////////////////////////////////
242
243/// Implementation of `XmlSource` for `&[u8]` reader using a `Self` as buffer
244/// that will be borrowed by events. This implementation provides a zero-copy deserialization.
245///
246/// Note: When the reader is created via [`Reader::from_str`], the input is
247/// guaranteed to be valid UTF-8. In that case, the `from_utf8` calls below
248/// could safely use `from_utf8_unchecked`. However, `Reader::from_reader`
249/// also instantiates this impl with arbitrary bytes, so we must validate.
250impl<'a> XmlSource<'a, ()> for &'a [u8] {
251    #[cfg(not(feature = "encoding"))]
252    #[inline]
253    fn remove_utf8_bom(&mut self) -> io::Result<()> {
254        if self.starts_with(crate::encoding::UTF8_BOM) {
255            *self = &self[crate::encoding::UTF8_BOM.len()..];
256        }
257        Ok(())
258    }
259
260    #[cfg(feature = "encoding")]
261    #[inline]
262    fn detect_encoding(&mut self) -> io::Result<Option<DetectedEncoding>> {
263        if let Some(detected) = crate::encoding::detect_encoding(self) {
264            *self = &self[detected.bom_len() as usize..];
265            return Ok(Some(detected));
266        }
267        Ok(None)
268    }
269
270    #[inline]
271    fn read_text(&mut self, _buf: (), position: &mut u64) -> ReadTextResult<'a, ()> {
272        // Search for start of markup or an entity or character reference
273        match memchr::memchr2(b'<', b'&', self) {
274            Some(0) if self[0] == b'<' => ReadTextResult::Markup(()),
275            // Do not consume `&` because it may be lone and we would be need to
276            // return it as part of Text event
277            Some(0) => ReadTextResult::Ref(()),
278
279            Some(i) if self[i] == b'<' => {
280                let (bytes, rest) = self.split_at(i);
281                *self = rest;
282                *position += i as u64;
283                match std::str::from_utf8(bytes) {
284                    Ok(s) => ReadTextResult::UpToMarkup(s),
285                    Err(e) => ReadTextResult::Err(e.into()),
286                }
287            }
288            Some(i) => {
289                let (bytes, rest) = self.split_at(i);
290                *self = rest;
291                *position += i as u64;
292                match std::str::from_utf8(bytes) {
293                    Ok(s) => ReadTextResult::UpToRef(s),
294                    Err(e) => ReadTextResult::Err(e.into()),
295                }
296            }
297            None => {
298                let bytes = &self[..];
299                *self = &[];
300                *position += bytes.len() as u64;
301                match std::str::from_utf8(bytes) {
302                    Ok(s) => ReadTextResult::UpToEof(s),
303                    Err(e) => ReadTextResult::Err(e.into()),
304                }
305            }
306        }
307    }
308
309    #[inline]
310    fn read_ref(&mut self, _buf: (), position: &mut u64) -> ReadRefResult<'a> {
311        debug_assert!(
312            self.starts_with(b"&"),
313            "`read_ref` must be called at `&`:\n{:?}",
314            crate::utils::Bytes(self)
315        );
316        // Search for the end of reference or a start of another reference or a markup
317        match memchr::memchr3(b';', b'&', b'<', &self[1..]) {
318            Some(i) if self[i + 1] == b';' => {
319                // +1 for the start `&`
320                // +1 for the end `;`
321                let end = i + 2;
322                let (bytes, rest) = self.split_at(end);
323                *self = rest;
324                *position += end as u64;
325
326                match std::str::from_utf8(bytes) {
327                    Ok(s) => ReadRefResult::Ref(s),
328                    Err(e) => ReadRefResult::Err(e.into()),
329                }
330            }
331            // Do not consume `&` because it may be lone and we would be need to
332            // return it as part of Text event
333            Some(i) => {
334                let is_amp = self[i + 1] == b'&';
335                let (bytes, rest) = self.split_at(i + 1);
336                *self = rest;
337                *position += i as u64 + 1;
338
339                match std::str::from_utf8(bytes) {
340                    Ok(s) => {
341                        if is_amp {
342                            ReadRefResult::UpToRef(s)
343                        } else {
344                            ReadRefResult::UpToMarkup(s)
345                        }
346                    }
347                    Err(e) => ReadRefResult::Err(e.into()),
348                }
349            }
350            None => {
351                let bytes = &self[..];
352                *self = &[];
353                *position += bytes.len() as u64;
354
355                match std::str::from_utf8(bytes) {
356                    Ok(s) => ReadRefResult::UpToEof(s),
357                    Err(e) => ReadRefResult::Err(e.into()),
358                }
359            }
360        }
361    }
362
363    #[inline]
364    fn read_with<P>(&mut self, mut parser: P, _buf: (), position: &mut u64) -> Result<&'a str>
365    where
366        P: Parser,
367    {
368        if let Some(i) = parser.feed(self) {
369            let used = i + 1; // +1 for `>`
370            *position += used as u64;
371            let (bytes, rest) = self.split_at(used);
372            *self = rest;
373            return Ok(std::str::from_utf8(bytes)?);
374        }
375
376        *position += self.len() as u64;
377        Err(Error::Syntax(parser.eof_error(self)))
378    }
379
380    #[inline]
381    fn read_bang_element(&mut self, _buf: (), position: &mut u64) -> Result<(BangType, &'a str)> {
382        // Peeked one bang ('!') before being called, so it's guaranteed to
383        // start with it.
384        debug_assert!(
385            self.starts_with(b"<!"),
386            "`read_bang_element` must be called at `<!`:\n{:?}",
387            crate::utils::Bytes(self)
388        );
389
390        let mut bang_type = BangType::new(self.get(2).copied())?;
391
392        if let Some(i) = bang_type.feed(&[], self) {
393            let consumed = i + 1; // +1 for `>`
394            *position += consumed as u64;
395            let (bytes, rest) = self.split_at(consumed);
396            *self = rest;
397            return Ok((bang_type, std::str::from_utf8(bytes)?));
398        }
399
400        *position += self.len() as u64;
401        Err(Error::Syntax(bang_type.to_err()))
402    }
403
404    #[inline]
405    fn skip_whitespace(&mut self, position: &mut u64) -> io::Result<()> {
406        let whitespaces = self
407            .iter()
408            .position(|b| !is_whitespace(*b))
409            .unwrap_or(self.len());
410        *position += whitespaces as u64;
411        *self = &self[whitespaces..];
412        Ok(())
413    }
414
415    #[inline]
416    fn peek_one(&mut self) -> io::Result<Option<u8>> {
417        debug_assert!(
418            self.starts_with(b"<"),
419            "markup must start from '<':\n{:?}",
420            crate::utils::Bytes(self)
421        );
422        Ok(self.get(1).copied())
423    }
424}
425
426#[cfg(test)]
427mod test {
428    use crate::reader::XmlSource;
429    use crate::reader::test::check;
430
431    /// Default buffer constructor just pass the byte array from the test
432    fn identity<T>(input: T) -> T {
433        input
434    }
435
436    check!(
437        #[test]
438        read_event_impl,
439        identity,
440        0,
441        ()
442    );
443}