Skip to main content

quick_xml/reader/
buffered_reader.rs

1//! This is an implementation of [`Reader`] for reading from a [`BufRead`] as
2//! underlying byte stream.
3
4use std::fs::File;
5use std::io::{self, BufRead, BufReader};
6use std::path::Path;
7
8use crate::encoding;
9use crate::errors::{Error, Result};
10use crate::events::{BytesText, Event};
11use crate::name::QName;
12use crate::parser::Parser;
13use crate::reader::{BangType, ReadRefResult, ReadTextResult, Reader, Span, XmlSource};
14use crate::utils::is_whitespace;
15
16macro_rules! impl_buffered_source {
17    ($($lf:lifetime, $reader:tt, $async:ident, $await:ident)?) => {
18        #[cfg(not(feature = "encoding"))]
19        #[inline]
20        $($async)? fn remove_utf8_bom(&mut self) -> io::Result<()> {
21            loop {
22                break match self $(.$reader)? .fill_buf() $(.$await)? {
23                    Ok(n) => {
24                        if n.starts_with(encoding::UTF8_BOM) {
25                            self $(.$reader)? .consume(encoding::UTF8_BOM.len());
26                        }
27                        Ok(())
28                    },
29                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
30                    Err(e) => Err(e),
31                };
32            }
33        }
34
35        #[cfg(feature = "encoding")]
36        #[inline]
37        $($async)? fn detect_encoding(&mut self) -> io::Result<Option<encoding::DetectedEncoding>> {
38            loop {
39                break match self $(.$reader)? .fill_buf() $(.$await)? {
40                    Ok(n) => if let Some(detected) = encoding::detect_encoding(n) {
41                        self $(.$reader)? .consume(detected.bom_len());
42                        Ok(Some(detected))
43                    } else {
44                        Ok(None)
45                    },
46                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
47                    Err(e) => Err(e),
48                };
49            }
50        }
51
52        #[inline]
53        $($async)? fn read_text $(<$lf>)? (
54            &mut self,
55            buf: &'b mut Vec<u8>,
56            position: &mut u64,
57        ) -> ReadTextResult<'b, &'b mut Vec<u8>> {
58            let mut read = 0;
59            let start = buf.len();
60            loop {
61                let available = match self $(.$reader)? .fill_buf() $(.$await)? {
62                    Ok(n) if n.is_empty() => break,
63                    Ok(n) => n,
64                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
65                    Err(e) => {
66                        *position += read;
67                        return ReadTextResult::Err(e.into());
68                    }
69                };
70
71                // Search for start of markup or an entity or character reference
72                match memchr::memchr2(b'<', b'&', available) {
73                    // Special handling is needed only on the first iteration.
74                    // On next iterations we already read something and should emit Text event
75                    Some(0) if read == 0 && available[0] == b'<' => return ReadTextResult::Markup(buf),
76                    // Do not consume `&` because it may be lone and we would be need to
77                    // return it as part of Text event
78                    Some(0) if read == 0 => return ReadTextResult::Ref(buf),
79                    Some(i) if available[i] == b'<' => {
80                        buf.extend_from_slice(&available[..i]);
81
82                        self $(.$reader)? .consume(i);
83                        read += i as u64;
84
85                        *position += read;
86                        return match std::str::from_utf8(&buf[start..]) {
87                            Ok(s) => ReadTextResult::UpToMarkup(s),
88                            Err(e) => ReadTextResult::Err(e.into()),
89                        };
90                    }
91                    Some(i) => {
92                        buf.extend_from_slice(&available[..i]);
93
94                        self $(.$reader)? .consume(i);
95                        read += i as u64;
96
97                        *position += read;
98                        return match std::str::from_utf8(&buf[start..]) {
99                            Ok(s) => ReadTextResult::UpToRef(s),
100                            Err(e) => ReadTextResult::Err(e.into()),
101                        };
102                    }
103                    None => {
104                        buf.extend_from_slice(available);
105
106                        let used = available.len();
107                        self $(.$reader)? .consume(used);
108                        read += used as u64;
109                    }
110                }
111            }
112
113            *position += read;
114            match std::str::from_utf8(&buf[start..]) {
115                Ok(s) => ReadTextResult::UpToEof(s),
116                Err(e) => ReadTextResult::Err(e.into()),
117            }
118        }
119
120        #[inline]
121        $($async)? fn read_ref $(<$lf>)? (
122            &mut self,
123            buf: &'b mut Vec<u8>,
124            position: &mut u64,
125        ) -> ReadRefResult<'b> {
126            let mut read = 0;
127            let start = buf.len();
128            loop {
129                let available = match self $(.$reader)? .fill_buf() $(.$await)? {
130                    Ok(n) if n.is_empty() => break,
131                    Ok(n) => n,
132                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
133                    Err(e) => {
134                        *position += read;
135                        return ReadRefResult::Err(e.into());
136                    }
137                };
138                // `read_ref` called when the first character is `&`, so we
139                // should explicitly skip it at first iteration lest we confuse
140                // it with the end
141                if read == 0 {
142                    debug_assert!(
143                        available.starts_with(b"&"),
144                        "`read_ref` must be called at `&`:\n{:?}",
145                        crate::utils::Bytes(available)
146                    );
147                    // If that ampersand is lone, then it will be part of text
148                    // and we should keep it
149                    buf.push(b'&');
150                    self $(.$reader)? .consume(1);
151                    read += 1;
152                    continue;
153                }
154
155                match memchr::memchr3(b';', b'&', b'<', available) {
156                    Some(i) if available[i] == b';' => {
157                        // +1 -- skip the end `;`
158                        let used = i + 1;
159
160                        buf.extend_from_slice(&available[..used]);
161                        self $(.$reader)? .consume(used);
162                        read += used as u64;
163
164                        *position += read;
165
166                        return match std::str::from_utf8(&buf[start..]) {
167                            Ok(s) => ReadRefResult::Ref(s),
168                            Err(e) => ReadRefResult::Err(e.into()),
169                        };
170                    }
171                    // Do not consume `&` because it may be lone and we would be need to
172                    // return it as part of Text event
173                    Some(i) => {
174                        let is_amp = available[i] == b'&';
175                        buf.extend_from_slice(&available[..i]);
176
177                        self $(.$reader)? .consume(i);
178                        read += i as u64;
179
180                        *position += read;
181
182                        return match std::str::from_utf8(&buf[start..]) {
183                            Ok(s) => {
184                                if is_amp {
185                                    ReadRefResult::UpToRef(s)
186                                } else {
187                                    ReadRefResult::UpToMarkup(s)
188                                }
189                            }
190                            Err(e) => ReadRefResult::Err(e.into()),
191                        };
192                    }
193                    None => {
194                        buf.extend_from_slice(available);
195
196                        let used = available.len();
197                        self $(.$reader)? .consume(used);
198                        read += used as u64;
199                    }
200                }
201            }
202
203            *position += read;
204            match std::str::from_utf8(&buf[start..]) {
205                Ok(s) => ReadRefResult::UpToEof(s),
206                Err(e) => ReadRefResult::Err(e.into()),
207            }
208        }
209
210        #[inline]
211        $($async)? fn read_with<$($lf,)? P: Parser>(
212            &mut self,
213            mut parser: P,
214            buf: &'b mut Vec<u8>,
215            position: &mut u64,
216        ) -> Result<&'b str> {
217            let mut read = 1;
218            let start = buf.len();
219            // '<' was consumed in peek_one(), but not placed in buf
220            buf.push(b'<');
221            loop {
222                let available = match self $(.$reader)? .fill_buf() $(.$await)? {
223                    Ok(n) if n.is_empty() => break,
224                    Ok(n) => n,
225                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
226                    Err(e) => {
227                        *position += read;
228                        return Err(Error::from(e));
229                    }
230                };
231
232                if let Some(i) = parser.feed(available) {
233                    let used = i + 1; // +1 for `>`
234                    buf.extend_from_slice(&available[..used]);
235
236                    self $(.$reader)? .consume(used);
237                    read += used as u64;
238
239                    *position += read;
240                    return Ok(std::str::from_utf8(&buf[start..])?);
241                }
242
243                // The `>` symbol not yet found, continue reading
244                buf.extend_from_slice(available);
245
246                let used = available.len();
247                self $(.$reader)? .consume(used);
248                read += used as u64;
249            }
250
251            *position += read;
252            Err(Error::Syntax(parser.eof_error(&buf[start..])))
253        }
254
255        #[inline]
256        $($async)? fn read_bang_element $(<$lf>)? (
257            &mut self,
258            buf: &'b mut Vec<u8>,
259            position: &mut u64,
260        ) -> Result<(BangType, &'b str)> {
261            // Peeked '<!' before being called, so it's guaranteed to start with it.
262            let start = buf.len();
263            let mut read = 2;
264            // '<' was consumed in peek_one(), but not placed in buf
265            buf.push(b'<');
266            buf.push(b'!');
267            self $(.$reader)? .consume(1);
268
269            let mut bang_type = loop {
270                break match self $(.$reader)? .fill_buf() $(.$await)? {
271                    Ok(n) => BangType::new(n.first().cloned())?,
272                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
273                    Err(e) => return Err(Error::from(e)),
274                };
275            };
276
277            loop {
278                let available = match self $(.$reader)? .fill_buf() $(.$await)? {
279                    Ok(n) if n.is_empty() => break,
280                    Ok(n) => n,
281                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
282                    Err(e) => {
283                        *position += read;
284                        return Err(Error::from(e));
285                    }
286                };
287                // We only parse from start because we don't want to consider
288                // whatever is in the buffer before the bang element
289                if let Some(i) = bang_type.feed(&buf[start..], available) {
290                    let consumed = i + 1; // +1 for `>`
291                    buf.extend_from_slice(&available[..consumed]);
292
293                    self $(.$reader)? .consume(consumed);
294                    read += consumed as u64;
295
296                    *position += read;
297                    return Ok((bang_type, std::str::from_utf8(&buf[start..])?));
298                }
299
300                // The `>` symbol not yet found, continue reading
301                buf.extend_from_slice(available);
302
303                let used = available.len();
304                self $(.$reader)? .consume(used);
305                read += used as u64;
306            }
307
308            *position += read;
309            Err(Error::Syntax(bang_type.to_err()))
310        }
311
312        #[inline]
313        $($async)? fn skip_whitespace(&mut self, position: &mut u64) -> io::Result<()> {
314            loop {
315                break match self $(.$reader)? .fill_buf() $(.$await)? {
316                    Ok(n) => {
317                        let count = n.iter().position(|b| !is_whitespace(*b)).unwrap_or(n.len());
318                        if count > 0 {
319                            self $(.$reader)? .consume(count);
320                            *position += count as u64;
321                            continue;
322                        } else {
323                            Ok(())
324                        }
325                    }
326                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
327                    Err(e) => Err(e),
328                };
329            }
330        }
331
332        #[inline]
333        $($async)? fn peek_one(&mut self) -> io::Result<Option<u8>> {
334            // That method is called only when available buffer starts from '<'
335            // We need to consume it
336            self $(.$reader)? .consume(1);
337            let available = loop {
338                break match self $(.$reader)? .fill_buf() $(.$await)? {
339                    Ok(n) => n,
340                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
341                    Err(e) => return Err(e),
342                };
343            };
344            Ok(available.first().cloned())
345        }
346    };
347}
348
349// Make it public for use in async implementations.
350// New rustc reports
351// > warning: the item `impl_buffered_source` is imported redundantly
352// so make it public only when async feature is enabled
353#[cfg(feature = "async-tokio")]
354pub(super) use impl_buffered_source;
355
356/// Implementation of `XmlSource` for any `BufRead` reader using a user-given
357/// `Vec<u8>` as buffer that will be borrowed by events.
358impl<'b, R: BufRead> XmlSource<'b, &'b mut Vec<u8>> for R {
359    impl_buffered_source!();
360}
361
362////////////////////////////////////////////////////////////////////////////////////////////////////
363
364/// This is an implementation for reading from a [`BufRead`] as underlying byte stream.
365impl<R: BufRead> Reader<R> {
366    /// Reads the next `Event`.
367    ///
368    /// This is the main entry point for reading XML `Event`s.
369    ///
370    /// `Event`s borrow `buf` and can be converted to own their data if needed (uses `Cow`
371    /// internally).
372    ///
373    /// Having the possibility to control the internal buffers gives you some additional benefits
374    /// such as:
375    ///
376    /// - Reduce the number of allocations by reusing the same buffer. For constrained systems,
377    ///   you can call `buf.clear()` once you are done with processing the event (typically at the
378    ///   end of your loop).
379    /// - Reserve the buffer length if you know the file size (using `Vec::with_capacity`).
380    ///
381    /// # Examples
382    ///
383    /// ```
384    /// # use pretty_assertions::assert_eq;
385    /// use quick_xml::events::Event;
386    /// use quick_xml::reader::Reader;
387    ///
388    /// let xml = r#"<tag1 att1 = "test">
389    ///                 <tag2><!--Test comment-->Test</tag2>
390    ///                 <tag2>Test 2</tag2>
391    ///              </tag1>"#;
392    /// let mut reader = Reader::from_str(xml);
393    /// reader.config_mut().trim_text(true);
394    /// let mut count = 0;
395    /// let mut buf = Vec::new();
396    /// let mut txt = Vec::new();
397    /// loop {
398    ///     match reader.read_event_into(&mut buf) {
399    ///         Ok(Event::Start(_)) => count += 1,
400    ///         Ok(Event::Text(e)) => txt.push(e.into_inner().into_owned()),
401    ///         Err(e) => panic!("Error at position {}: {:?}", reader.error_position(), e),
402    ///         Ok(Event::Eof) => break,
403    ///         _ => (),
404    ///     }
405    ///     buf.clear();
406    /// }
407    /// assert_eq!(count, 3);
408    /// assert_eq!(txt, vec!["Test".to_string(), "Test 2".to_string()]);
409    /// ```
410    #[inline]
411    pub fn read_event_into<'b>(&mut self, buf: &'b mut Vec<u8>) -> Result<Event<'b>> {
412        self.read_event_impl(buf)
413    }
414
415    /// Reads until end element is found using provided buffer as intermediate
416    /// storage for events content. This function is supposed to be called after
417    /// you already read a [`Start`] event.
418    ///
419    /// Returns a span that cover content between `>` of an opening tag and `<` of
420    /// a closing tag or an empty slice, if [`expand_empty_elements`] is set and
421    /// this method was called after reading expanded [`Start`] event.
422    ///
423    /// Manages nested cases where parent and child elements have the _literally_
424    /// same name.
425    ///
426    /// If a corresponding [`End`] event is not found, an error of type [`Error::IllFormed`]
427    /// will be returned. In particularly, that error will be returned if you call
428    /// this method without consuming the corresponding [`Start`] event first.
429    ///
430    /// If your reader created from a string slice or byte array slice, it is
431    /// better to use [`read_to_end()`] method, because it will not copy bytes
432    /// into intermediate buffer.
433    ///
434    /// The provided `buf` buffer will be filled only by one event content at time.
435    /// Before reading of each event the buffer will be cleared. If you know an
436    /// appropriate size of each event, you can preallocate the buffer to reduce
437    /// number of reallocations.
438    ///
439    /// The `end` parameter should contain name of the end element _in the reader
440    /// encoding_. It is good practice to always get that parameter using
441    /// [`BytesStart::to_end()`] method.
442    ///
443    /// The correctness of the skipped events does not checked, if you disabled
444    /// the [`check_end_names`] option.
445    ///
446    /// # Namespaces
447    ///
448    /// While the `Reader` does not support namespace resolution, namespaces
449    /// does not change the algorithm for comparing names. Although the names
450    /// `a:name` and `b:name` where both prefixes `a` and `b` resolves to the
451    /// same namespace, are semantically equivalent, `</b:name>` cannot close
452    /// `<a:name>`, because according to [the specification]
453    ///
454    /// > The end of every element that begins with a **start-tag** MUST be marked
455    /// > by an **end-tag** containing a name that echoes the element's type as
456    /// > given in the **start-tag**
457    ///
458    /// # Examples
459    ///
460    /// This example shows, how you can skip XML content after you read the
461    /// start event.
462    ///
463    /// ```
464    /// # use pretty_assertions::assert_eq;
465    /// use quick_xml::events::{BytesStart, Event};
466    /// use quick_xml::reader::Reader;
467    ///
468    /// let mut reader = Reader::from_str(r#"
469    ///     <outer>
470    ///         <inner>
471    ///             <inner></inner>
472    ///             <inner/>
473    ///             <outer></outer>
474    ///             <outer/>
475    ///         </inner>
476    ///     </outer>
477    /// "#);
478    /// reader.config_mut().trim_text(true);
479    /// let mut buf = Vec::new();
480    ///
481    /// let start = BytesStart::new("outer");
482    /// let end   = start.to_end().into_owned();
483    ///
484    /// // First, we read a start event...
485    /// assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Start(start));
486    ///
487    /// // ...then, we could skip all events to the corresponding end event.
488    /// // This call will correctly handle nested <outer> elements.
489    /// // Note, however, that this method does not handle namespaces.
490    /// reader.read_to_end_into(end.name(), &mut buf).unwrap();
491    ///
492    /// // At the end we should get an Eof event, because we ate the whole XML
493    /// assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Eof);
494    /// ```
495    ///
496    /// [`Start`]: Event::Start
497    /// [`End`]: Event::End
498    /// [`BytesStart::to_end()`]: crate::events::BytesStart::to_end
499    /// [`read_to_end()`]: Self::read_to_end
500    /// [`expand_empty_elements`]: crate::reader::Config::expand_empty_elements
501    /// [`check_end_names`]: crate::reader::Config::check_end_names
502    /// [the specification]: https://www.w3.org/TR/xml11/#dt-etag
503    pub fn read_to_end_into(&mut self, end: QName, buf: &mut Vec<u8>) -> Result<Span> {
504        Ok(read_to_end!(self, end, buf, read_event_impl, {
505            buf.clear();
506        }))
507    }
508
509    /// Reads content between start and end tags, including any markup using
510    /// provided buffer as intermediate storage for events content. This function
511    /// is supposed to be called after you already read a [`Start`] event.
512    ///
513    /// Manages nested cases where parent and child elements have the _literally_
514    /// same name.
515    ///
516    /// This method does not unescape read data, instead it returns content
517    /// "as is" of the XML document. This is because it has no idea what text
518    /// it reads, and if, for example, it contains CDATA section, attempt to
519    /// unescape it content will spoil data.
520    ///
521    /// If your reader created from a string slice or byte array slice, it is
522    /// better to use [`read_text()`] method, because it will not copy bytes
523    /// into intermediate buffer.
524    ///
525    /// # Examples
526    ///
527    /// This example shows, how you can read a HTML content from your XML document.
528    ///
529    /// ```
530    /// # use pretty_assertions::assert_eq;
531    /// # use std::borrow::Cow;
532    /// use quick_xml::events::{BytesStart, Event};
533    /// use quick_xml::reader::Reader;
534    ///
535    /// let mut reader = Reader::from_reader("
536    ///     <html>
537    ///         <title>This is a HTML text</title>
538    ///         <p>Usual XML rules does not apply inside it
539    ///         <p>For example, elements not needed to be &quot;closed&quot;
540    ///     </html>
541    /// ".as_bytes());
542    /// reader.config_mut().trim_text(true);
543    ///
544    /// let start = BytesStart::new("html");
545    /// let end   = start.to_end().into_owned();
546    ///
547    /// let mut buf = Vec::new();
548    ///
549    /// // First, we read a start event...
550    /// assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Start(start));
551    /// // ...and disable checking of end names because we expect HTML further...
552    /// reader.config_mut().check_end_names = false;
553    ///
554    /// // ...then, we could read text content until close tag.
555    /// // This call will correctly handle nested <html> elements.
556    /// let text = reader.read_text_into(end.name(), &mut buf).unwrap();
557    /// let text = text.into_inner();
558    /// assert_eq!(text, r#"
559    ///         <title>This is a HTML text</title>
560    ///         <p>Usual XML rules does not apply inside it
561    ///         <p>For example, elements not needed to be &quot;closed&quot;
562    ///     "#);
563    /// assert!(matches!(text, Cow::Borrowed(_)));
564    ///
565    /// // Now we can enable checks again
566    /// reader.config_mut().check_end_names = true;
567    ///
568    /// // At the end we should get an Eof event, because we ate the whole XML
569    /// assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Eof);
570    /// ```
571    ///
572    /// [`Start`]: Event::Start
573    /// [`read_text()`]: Self::read_text()
574    pub fn read_text_into<'b>(
575        &mut self,
576        end: QName,
577        buf: &'b mut Vec<u8>,
578    ) -> Result<BytesText<'b>> {
579        let start = buf.len();
580        let span = read_to_end!(self, end, buf, read_event_impl, {});
581
582        let len = span.end - span.start;
583        // SAFETY: `buf` may contain not more than isize::MAX bytes and because it is
584        // not cleared when reading event, length of the returned span should fit into
585        // usize (because otherwise we panic at appending to the buffer before that point)
586        let end = start + len as usize;
587
588        let text = std::str::from_utf8(&buf[start..end])?;
589        Ok(BytesText::wrap(text))
590    }
591}
592
593impl Reader<BufReader<File>> {
594    /// Creates an XML reader from a file path.
595    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
596        let file = File::open(path)?;
597        let reader = BufReader::new(file);
598        Ok(Self::from_reader(reader))
599    }
600}
601
602#[cfg(test)]
603mod test {
604    use crate::reader::XmlSource;
605    use crate::reader::test::check;
606
607    /// Default buffer constructor just pass the byte array from the test
608    fn identity<T>(input: T) -> T {
609        input
610    }
611
612    check!(
613        #[test]
614        read_event_impl,
615        identity,
616        1,
617        &mut Vec::new()
618    );
619}