1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! Xml Attributes module
//!
//! Provides an iterator over attributes key/value pairs
use error::{Error, Result};

/// Iterator over attributes key/value pairs
pub struct Attributes<'a> {
    bytes: &'a [u8],
    position: usize,
    was_error: bool,
}

impl<'a> Attributes<'a> {
    /// creates a new attribute from a buffer
    /// 
    /// pos represents current position of the iterator 
    /// (starts after start element name)
    pub fn new(buf: &'a [u8], pos: usize) -> Attributes<'a> {
        Attributes {
            bytes: buf,
            position: pos,
            was_error: false,
        }
    }
}

impl<'a> Iterator for Attributes<'a> {
    type Item = Result<(&'a [u8], &'a [u8])>;
    fn next(&mut self) -> Option<Self::Item> {
        
        if self.was_error { return None; }

        let len = self.bytes.len();
        let p = self.position;
        if len == p { return None; }

        let mut iter = self.bytes[p..].iter().cloned().enumerate();

        let start_key = {
            let mut found_space = false;
            let start: usize;
            loop {
                match iter.next() {
                    Some((_, b' '))
                        | Some((_, b'\r')) 
                        | Some((_, b'\n'))
                        | Some((_, b'\t')) => if !found_space { found_space = true; },
                    Some((i, _)) => if found_space { 
                        start = i;
                        break;
                    },
                    None => {
                        self.position = len;
                        return None;
                    }
                }
            }
            start
        };

        let mut has_equal = false;
        let mut end_key = None;
        let mut start_val = None;
        let mut end_val = None;
        loop {
            match iter.next() {
                Some((i, b' '))
                    | Some((i, b'\r')) 
                    | Some((i, b'\n'))
                    | Some((i, b'\t')) => {
                    if end_key.is_none() { end_key = Some(i); }
                },
                Some((i, b'=')) => {
                    if has_equal {
                        self.was_error = true;
                        return Some(Err(Error::Malformed("Got 2 '=' tokens".to_owned())));
                    }
                    has_equal = true;
                    if end_key.is_none() {
                        end_key = Some(i);
                    }
                },
                Some((i, b'"')) => {
                    if !has_equal {
                        self.was_error = true;
                        return Some(Err(Error::Malformed("Unexpected quote before '='".to_owned())));
                    }
                    if start_val.is_none() {
                        start_val = Some(i + 1);
                    } else if end_val.is_none() {
                        end_val = Some(i);
                        break;
                    }
                },
                None => {
                    self.position = len;
                    return None;
                }
                Some((_, _)) => (),
            }
        }
        self.position += end_val.unwrap() + 1;

        Some(Ok((&self.bytes[(p + start_key)..(p + end_key.unwrap())],
           &self.bytes[(p + start_val.unwrap())..(p + end_val.unwrap())])))
    }
}