Repository: tafia/quick-xml (rust)

Issue:
Strange buffer_position behaviour inside a comment
Took this example from the unit tests:
```rust
r = Reader::from_str("<a><!--b>");
r.trim_text(true).check_end_names(true);

let mut buf = Vec::new();
r.read_event(&mut buf);

let mut buf = Vec::new();
r.read_event(&mut buf);
assert_eq!(r.buffer_position(), 5);
```

But if we will use a single buffer:
```rust
r = Reader::from_str("<a><!--b>");
r.trim_text(true).check_end_names(true);

let mut buf = Vec::new();
r.read_event(&mut buf);

r.read_event(&mut buf);
assert_eq!(r.buffer_position(), 4);
```

Also interesting that the `buffer_position` isn't changed for the next inputs: `"<a>\n<!--b>"`, `"<a>\n\n<!--b>"` and so on.

Pull request:
Buf position
Close #201

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index eac399e..b407255 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "quick-xml"
-version = "0.17.2"
+version = "0.18.1"
 authors = ["Johann Tuffe <tafia973@gmail.com>"]
 description = "High performance xml reader and writer"
 
@@ -16,9 +16,9 @@ license = "MIT"
 travis-ci = { repository = "tafia/quick-xml" }
 
 [dependencies]
-encoding_rs = { version = "0.8.17", optional = true }
+encoding_rs = { version = "0.8.22", optional = true }
 serde = { version = "1.0", optional = true }
-memchr = "2.2.1"
+memchr = "2.3.3"
 
 [dev-dependencies]
 serde = { version = "1.0", features = ["derive"] }
diff --git a/examples/nested_readers.rs b/examples/nested_readers.rs
deleted file mode 100644
index 892fdc9..0000000
--- a/examples/nested_readers.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-extern crate quick_xml;
-use quick_xml::events::Event;
-use quick_xml::Reader;
-// a structure to capture the rows we've extracted
-// from a ECMA-376 table in document.xml
-#[derive(Debug, Clone)]
-struct TableStat {
-    index: u8,
-    rows: Vec<Vec<String>>,
-}
-// demonstrate how to nest readers
-// This is useful for when you need to traverse
-// a few levels of a document to extract things.
-fn main() -> Result<(), quick_xml::Error> {
-    let mut buf = Vec::new();
-    // buffer for nested reader
-    let mut skip_buf = Vec::new();
-    let mut count = 0;
-    let mut reader = Reader::from_file("tests/documents/document.xml")?;
-    let mut found_tables = Vec::new();
-    loop {
-        match reader.read_event(&mut buf)? {
-            Event::Start(element) => match element.name() {
-                b"w:tbl" => {
-                    count += 1;
-                    let mut stats = TableStat {
-                        index: count,
-                        rows: vec![],
-                    };
-                    // must define stateful variables
-                    // outside the nested loop else they are overwritten
-                    let mut row_index = 0;
-                    loop {
-                        skip_buf.clear();
-                        match reader.read_event(&mut skip_buf)? {
-                            Event::Start(element) => match element.name() {
-                                b"w:tr" => {
-                                    stats.rows.push(vec![]);
-                                    row_index = stats.rows.len() - 1;
-                                }
-                                b"w:tc" => {
-                                    stats.rows[row_index]
-                                        .push(String::from_utf8(element.name().to_vec()).unwrap());
-                                }
-                                _ => {}
-                            },
-                            Event::End(element) => {
-                                if element.name() == b"w:tbl" {
-                                    found_tables.push(stats);
-                                    break;
-                                }
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-                _ => {}
-            },
-            Event::Eof => break,
-            _ => {}
-        }
-        buf.clear();
-    }
-    assert_eq!(found_tables.len(), 2);
-    // pretty print the table
-    println!("{:#?}", found_tables);
-    assert_eq!(found_tables[0].rows.len(), 2);
-    assert_eq!(found_tables[0].rows[0].len(), 4);
-    assert_eq!(found_tables[0].rows[1].len(), 4);
-
-    assert_eq!(found_tables[1].rows.len(), 2);
-    assert_eq!(found_tables[1].rows[0].len(), 4);
-    assert_eq!(found_tables[1].rows[1].len(), 4);
-    Ok(())
-}
diff --git a/src/reader.rs b/src/reader.rs
index 0f42031..092d45a 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -199,12 +199,11 @@ impl<B: BufRead> Reader<B> {
     pub fn buffer_position(&self) -> usize {
         // when internal state is Opened, we have actually read until '<',
         // which we don't want to show
-        let offset = if let TagState::Opened = self.tag_state {
-            1
+        if let TagState::Opened = self.tag_state {
+            self.buf_position - 1
         } else {
-            0
-        };
-        self.buf_position - offset
+            self.buf_position
+        }
     }
 
     /// private function to read until '<' is found
@@ -212,10 +211,9 @@ impl<B: BufRead> Reader<B> {
     fn read_until_open<'a, 'b>(&'a mut self, buf: &'b mut Vec<u8>) -> Result<Event<'b>> {
         self.tag_state = TagState::Opened;
         let buf_start = buf.len();
-        match read_until(&mut self.reader, b'<', buf) {
+        match read_until(&mut self.reader, b'<', buf, &mut self.buf_position) {
             Ok(0) => Ok(Event::Eof),
-            Ok(n) => {
-                self.buf_position += n;
+            Ok(_) => {
                 let (start, len) = if self.trim_text {
                     match buf.iter().skip(buf_start).position(|&b| !is_whitespace(b)) {
                         Some(start) => (
@@ -255,31 +253,27 @@ impl<B: BufRead> Reader<B> {
         };
 
         if start != b'/' && start != b'!' && start != b'?' {
-            match read_elem_until(&mut self.reader, b'>', buf) {
+            match read_elem_until(&mut self.reader, b'>', buf, &mut self.buf_position) {
                 Ok(0) => Ok(Event::Eof),
-                Ok(n) => {
-                    self.buf_position += n;
+                Ok(_) => {
                     // we already *know* that we are in this case
                     self.read_start(&buf[buf_start..])
                 }
                 Err(e) => Err(e),
             }
         } else {
-            match read_until(&mut self.reader, b'>', buf) {
+            match read_until(&mut self.reader, b'>', buf, &mut self.buf_position) {
                 Ok(0) => Ok(Event::Eof),
-                Ok(n) => {
-                    self.buf_position += n;
-                    match start {
-                        b'/' => self.read_end(&buf[buf_start..]),
-                        b'!' => self.read_bang(buf_start, buf),
-                        b'?' => self.read_question_mark(&buf[buf_start..]),
-                        _ => unreachable!(
-                            "We checked that `start` must be one of [/!?], was {:?} \
+                Ok(_) => match start {
+                    b'/' => self.read_end(&buf[buf_start..]),
+                    b'!' => self.read_bang(buf_start, buf),
+                    b'?' => self.read_question_mark(&buf[buf_start..]),
+                    _ => unreachable!(
+                        "We checked that `start` must be one of [/!?], was {:?} \
                              instead.",
-                            start
-                        ),
-                    }
-                }
+                        start
+                    ),
+                },
                 Err(e) => Err(e),
             }
         }
@@ -289,7 +283,6 @@ impl<B: BufRead> Reader<B> {
     /// if `self.check_end_names`, checks that element matches last opened element
     /// return `End` event
     fn read_end<'a, 'b>(&'a mut self, buf: &'b [u8]) -> Result<Event<'b>> {
-        let len = buf.len();
         // XML standard permits whitespaces after the markup name in closing tags.
         // Let's strip them from the buffer before comparing tag names.
         let name = if self.trim_markup_names_in_closing_tags {
@@ -304,7 +297,7 @@ impl<B: BufRead> Reader<B> {
         };
         if self.check_end_names {
             let mismatch_err = |expected: &[u8], found: &[u8], buf_position: &mut usize| {
-                *buf_position -= len;
+                *buf_position -= buf.len();
                 Err(Error::EndEventMismatch {
                     expected: from_utf8(expected).unwrap_or("").to_owned(),
                     found: from_utf8(found).unwrap_or("").to_owned(),
@@ -337,65 +330,59 @@ impl<B: BufRead> Reader<B> {
         buf_start: usize,
         buf: &'b mut Vec<u8>,
     ) -> Result<Event<'b>> {
-        let len = buf.len();
-        if len >= buf_start + 3 && &buf[buf_start + 1..buf_start + 3] == b"--" {
-            let mut len = buf.len();
-            while (len - buf_start) < 5 || &buf[len - 2..] != b"--" {
+        if buf[buf_start..].starts_with(b"!--") {
+            while buf.len() < buf_start + 5 || !buf.ends_with(b"--") {
                 buf.push(b'>');
-                match read_until(&mut self.reader, b'>', buf) {
+                match read_until(&mut self.reader, b'>', buf, &mut self.buf_position) {
                     Ok(0) => {
-                        self.buf_position -= len;
+                        self.buf_position -= buf.len() - buf_start;
                         return Err(Error::UnexpectedEof("Comment".to_string()));
                     }
-                    Ok(n) => self.buf_position += n,
+                    Ok(_) => (),
                     Err(e) => return Err(e.into()),
                 }
-                len = buf.len();
             }
+            let len = buf.len();
             if self.check_comments {
-                let mut offset = len - 3;
-                for w in buf[buf_start + 3..len - 1].windows(2) {
-                    if &*w == b"--" {
-                        self.buf_position -= offset;
-                        return Err(Error::UnexpectedToken("--".to_string()));
-                    }
-                    offset -= 1;
+                // search if '--' not in comments
+                if let Some(p) = memchr::memchr_iter(b'-', &buf[buf_start + 3..len - 2])
+                    .position(|p| buf[buf_start + 3 + p + 1] == b'-')
+                {
+                    self.buf_position -= buf.len() - buf_start + p;
+                    return Err(Error::UnexpectedToken("--".to_string()));
                 }
             }
             Ok(Event::Comment(BytesText::from_escaped(
                 &buf[buf_start + 3..len - 2],
             )))
-        } else if len >= buf_start + 8 {
+        } else if buf.len() >= buf_start + 8 {
             match &buf[buf_start + 1..buf_start + 8] {
                 b"[CDATA[" => {
-                    let mut len = buf.len();
-                    while len < 10 || &buf[len - 2..] != b"]]" {
+                    while buf.len() < 10 || !buf.ends_with(b"]]") {
                         buf.push(b'>');
-                        match read_until(&mut self.reader, b'>', buf) {
+                        match read_until(&mut self.reader, b'>', buf, &mut self.buf_position) {
                             Ok(0) => {
-                                self.buf_position -= len;
+                                self.buf_position -= buf.len() - buf_start;
                                 return Err(Error::UnexpectedEof("CData".to_string()));
                             }
-                            Ok(n) => self.buf_position += n,
+                            Ok(_) => (),
                             Err(e) => return Err(e),
                         }
-                        len = buf.len();
                     }
                     Ok(Event::CData(BytesText::from_escaped(
-                        &buf[buf_start + 8..len - 2],
+                        &buf[buf_start + 8..buf.len() - 2],
                     )))
                 }
                 b"DOCTYPE" => {
                     let mut count = buf.iter().skip(buf_start).filter(|&&b| b == b'<').count();
                     while count > 0 {
                         buf.push(b'>');
-                        match read_until(&mut self.reader, b'>', buf) {
+                        match read_until(&mut self.reader, b'>', buf, &mut self.buf_position) {
                             Ok(0) => {
-                                self.buf_position -= buf.len();
+                                self.buf_position -= buf.len() - buf_start;
                                 return Err(Error::UnexpectedEof("DOCTYPE".to_string()));
                             }
                             Ok(n) => {
-                                self.buf_position += n;
                                 let start = buf.len() - n;
                                 count += buf.iter().skip(start).filter(|&&b| b == b'<').count();
                                 count -= 1;
@@ -403,15 +390,14 @@ impl<B: BufRead> Reader<B> {
                             Err(e) => return Err(e),
                         }
                     }
-                    let len = buf.len();
                     Ok(Event::DocType(BytesText::from_escaped(
-                        &buf[buf_start + 8..len],
+                        &buf[buf_start + 8..buf.len()],
                     )))
                 }
                 _ => return Err(Error::UnexpectedBang),
             }
         } else {
-            self.buf_position -= buf.len();
+            self.buf_position -= buf.len() - buf_start;
             return Err(Error::UnexpectedBang);
         }
     }
@@ -915,16 +901,24 @@ impl<'a> Reader<&'a [u8]> {
 /// read until `byte` is found or end of file
 /// return the position of byte
 #[inline]
-fn read_until<R: BufRead>(r: &mut R, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
+fn read_until<R: BufRead>(
+    r: &mut R,
+    byte: u8,
+    buf: &mut Vec<u8>,
+    position: &mut usize,
+) -> Result<usize> {
     let mut read = 0;
     let mut done = false;
     while !done {
         let used = {
             let available = match r.fill_buf() {
-                Ok(n) if n.is_empty() => return Ok(read),
+                Ok(n) if n.is_empty() => break,
                 Ok(n) => n,
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
-                Err(e) => return Err(Error::Io(e)),
+                Err(e) => {
+                    *position += read;
+                    return Err(Error::Io(e));
+                }
             };
 
             match memchr::memchr(byte, available) {
@@ -942,6 +936,7 @@ fn read_until<R: BufRead>(r: &mut R, byte: u8, buf: &mut Vec<u8>) -> Result<usiz
         r.consume(used);
         read += used;
     }
+    *position += read;
     Ok(read)
 }
 
@@ -956,7 +951,12 @@ fn read_until<R: BufRead>(r: &mut R, byte: u8, buf: &mut Vec<u8>) -> Result<usiz
 /// (`Reference` is something like `&quot;`, but we don't care about escaped characters at this
 /// level)
 #[inline]
-fn read_elem_until<R: BufRead>(r: &mut R, end_byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
+fn read_elem_until<R: BufRead>(
+    r: &mut R,
+    end_byte: u8,
+    buf: &mut Vec<u8>,
+    position: &mut usize,
+) -> Result<usize> {
     #[derive(Clone, Copy)]
     enum State {
         /// The initial state (inside element, but outside of attribute value)
@@ -975,7 +975,10 @@ fn read_elem_until<R: BufRead>(r: &mut R, end_byte: u8, buf: &mut Vec<u8>) -> Re
                 Ok(n) if n.is_empty() => return Ok(read),
                 Ok(n) => n,
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
-                Err(e) => return Err(Error::Io(e)),
+                Err(e) => {
+                    *position += read;
+                    return Err(Error::Io(e));
+                }
             };
 
             let mut memiter = memchr::memchr3_iter(end_byte, b'\'', b'"', available);
@@ -1013,6 +1016,7 @@ fn read_elem_until<R: BufRead>(r: &mut R, end_byte: u8, buf: &mut Vec<u8>) -> Re
         r.consume(used);
         read += used;
     }
+    *position += read;
     Ok(read)
 }
 


Test patch:
diff --git a/tests/documents/document.xml b/tests/documents/document.xml
deleted file mode 100644
index ce7bf85..0000000
--- a/tests/documents/document.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14 wp14"><w:body><w:tbl><w:tblPr><w:tblW w:w="9972" w:type="dxa"/><w:jc w:val="left"/><w:tblInd w:w="0" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tblBorders><w:tblCellMar><w:top w:w="55" w:type="dxa"/><w:left w:w="53" w:type="dxa"/><w:bottom w:w="55" w:type="dxa"/><w:right w:w="55" w:type="dxa"/></w:tblCellMar></w:tblPr><w:tblGrid><w:gridCol w:w="2493"/><w:gridCol w:w="2493"/><w:gridCol w:w="2493"/><w:gridCol w:w="2492"/></w:tblGrid><w:tr><w:trPr></w:trPr><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>A</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>B</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>C</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2492" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:right w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideV w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>D</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:trPr></w:trPr><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>E</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>F</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>G</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2492" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:right w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideV w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>H</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:p><w:pPr><w:sectPr><w:type w:val="nextPage"/><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:left="1134" w:right="1134" w:header="0" w:top="1134" w:footer="0" w:bottom="1134" w:gutter="0"/><w:pgNumType w:fmt="decimal"/><w:formProt w:val="false"/><w:textDirection w:val="lrTb"/><w:docGrid w:type="default" w:linePitch="100" w:charSpace="0"/></w:sectPr><w:pStyle w:val="Normal"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><w:tbl><w:tblPr><w:tblW w:w="9972" w:type="dxa"/><w:jc w:val="left"/><w:tblInd w:w="0" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tblBorders><w:tblCellMar><w:top w:w="55" w:type="dxa"/><w:left w:w="53" w:type="dxa"/><w:bottom w:w="55" w:type="dxa"/><w:right w:w="55" w:type="dxa"/></w:tblCellMar></w:tblPr><w:tblGrid><w:gridCol w:w="2493"/><w:gridCol w:w="2493"/><w:gridCol w:w="2493"/><w:gridCol w:w="2492"/></w:tblGrid><w:tr><w:trPr></w:trPr><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>A</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>B</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>C</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2492" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:right w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideV w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>D</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:trPr></w:trPr><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>E</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>F</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2493" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>G</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:w="2492" w:type="dxa"/><w:tcBorders><w:top w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:right w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="2" w:space="0" w:color="000000"/><w:insideV w:val="single" w:sz="2" w:space="0" w:color="000000"/></w:tcBorders><w:shd w:fill="auto" w:val="clear"/></w:tcPr><w:p><w:pPr><w:pStyle w:val="TableContents"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><w:t>H</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:p><w:pPr><w:pStyle w:val="Normal"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><w:sectPr><w:type w:val="nextPage"/><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:left="1134" w:right="1134" w:header="0" w:top="1134" w:footer="0" w:bottom="1134" w:gutter="0"/><w:pgNumType w:fmt="decimal"/><w:formProt w:val="false"/><w:textDirection w:val="lrTb"/><w:docGrid w:type="default" w:linePitch="100" w:charSpace="0"/></w:sectPr></w:body></w:document>
\ No newline at end of file
diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs
index 5644661..e8cdb00 100644
--- a/tests/unit_tests.rs
+++ b/tests/unit_tests.rs
@@ -387,13 +387,13 @@ fn test_new_xml_decl_empty() {
 }
 
 #[test]
-fn test_buf_position() {
+fn test_buf_position_err_end_element() {
     let mut r = Reader::from_str("</a>");
     r.trim_text(true).check_end_names(true);
 
     let mut buf = Vec::new();
     match r.read_event(&mut buf) {
-        Err(_) if r.buffer_position() == 2 => assert!(true), // error at char 2: no opening tag
+        Err(_) if r.buffer_position() == 2 => (), // error at char 2: no opening tag
         Err(e) => panic!(
             "expecting buf_pos = 2, found {}, err: {:?}",
             r.buffer_position(),
@@ -401,15 +401,66 @@ fn test_buf_position() {
         ),
         e => panic!("expecting error, found {:?}", e),
     }
+}
+
+#[test]
+fn test_buf_position_err_comment() {
+    let mut r = Reader::from_str("<a><!--b>");
+    r.trim_text(true).check_end_names(true);
+
+    next_eq!(r, Start, b"a");
+    assert_eq!(r.buffer_position(), 3);
+
+    let mut buf = Vec::new();
+    match r.read_event(&mut buf) {
+        Err(_) if r.buffer_position() == 4 => {
+            // error at char 5: no closing --> tag found
+            assert!(true);
+        }
+        Err(e) => panic!(
+            "expecting buf_pos = 5, found {}, err: {:?}",
+            r.buffer_position(),
+            e
+        ),
+        e => assert!(false, "expecting error, found {:?}", e),
+    }
+}
 
-    r = Reader::from_str("<a><!--b>");
+#[test]
+fn test_buf_position_err_comment_2_buf() {
+    let mut r = Reader::from_str("<a><!--b>");
+    r.trim_text(true).check_end_names(true);
+
+    let mut buf = Vec::new();
+    let _ = r.read_event(&mut buf).unwrap();
+    assert_eq!(r.buffer_position(), 3);
+
+    let mut buf = Vec::new();
+    match r.read_event(&mut buf) {
+        Err(_) if r.buffer_position() == 4 => {
+            // error at char 5: no closing --> tag found
+            assert!(true);
+        }
+        Err(e) => panic!(
+            "expecting buf_pos = 5, found {}, err: {:?}",
+            r.buffer_position(),
+            e
+        ),
+        e => assert!(false, "expecting error, found {:?}", e),
+    }
+}
+
+#[test]
+fn test_buf_position_err_comment_trim_text() {
+    let mut r = Reader::from_str("<a>\r\n <!--b>");
     r.trim_text(true).check_end_names(true);
 
     next_eq!(r, Start, b"a");
+    assert_eq!(r.buffer_position(), 3);
 
     let mut buf = Vec::new();
     match r.read_event(&mut buf) {
-        Err(_) if r.buffer_position() == 5 => {
+        Err(_) if r.buffer_position() == 7 => {
             // error at char 5: no closing --> tag found
             assert!(true);
         }