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 "closed"
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 "closed"
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}