From b1ac8db3f8c3d8f393701a2f644a85cb44e7c24d Mon Sep 17 00:00:00 2001 From: Date: Wed, 1 Feb 2017 11:18:05 +0000 Subject: Documentation for ebarnard/rust-plist@bf6b567 --- src/plist/src/binary/mod.rs.html | 114 ++++ src/plist/src/binary/reader.rs.html | 814 +++++++++++++++++++++++ src/plist/src/builder.rs.html | 396 ++++++++++++ src/plist/src/de.rs.html | 660 +++++++++++++++++++ src/plist/src/lib.rs.html | 1216 +++++++++++++++++++++++++++++++++++ src/plist/src/ser.rs.html | 480 ++++++++++++++ src/plist/src/xml/mod.rs.html | 118 ++++ src/plist/src/xml/reader.rs.html | 530 +++++++++++++++ src/plist/src/xml/writer.rs.html | 614 ++++++++++++++++++ 9 files changed, 4942 insertions(+) create mode 100644 src/plist/src/binary/mod.rs.html create mode 100644 src/plist/src/binary/reader.rs.html create mode 100644 src/plist/src/builder.rs.html create mode 100644 src/plist/src/de.rs.html create mode 100644 src/plist/src/lib.rs.html create mode 100644 src/plist/src/ser.rs.html create mode 100644 src/plist/src/xml/mod.rs.html create mode 100644 src/plist/src/xml/reader.rs.html create mode 100644 src/plist/src/xml/writer.rs.html (limited to 'src') diff --git a/src/plist/src/binary/mod.rs.html b/src/plist/src/binary/mod.rs.html new file mode 100644 index 0000000..8fe81c2 --- /dev/null +++ b/src/plist/src/binary/mod.rs.html @@ -0,0 +1,114 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + + + +
1
+2
+3
+
+mod reader;
+
+pub use self::reader::EventReader;
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/binary/reader.rs.html b/src/plist/src/binary/reader.rs.html new file mode 100644 index 0000000..dee0f96 --- /dev/null +++ b/src/plist/src/binary/reader.rs.html @@ -0,0 +1,814 @@ + + + + + + + + + + reader.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+
+use byteorder::{BigEndian, ReadBytesExt};
+use chrono::{TimeZone, UTC};
+use std::io::{Cursor, Read, Seek, SeekFrom};
+use std::string::{FromUtf8Error, FromUtf16Error};
+
+use {Error, Result, PlistEvent, u64_to_usize};
+
+impl From<FromUtf8Error> for Error {
+    fn from(_: FromUtf8Error) -> Error {
+        Error::InvalidData
+    }
+}
+
+impl From<FromUtf16Error> for Error {
+    fn from(_: FromUtf16Error) -> Error {
+        Error::InvalidData
+    }
+}
+
+struct StackItem {
+    object_refs: Vec<u64>,
+    ty: StackType,
+}
+
+enum StackType {
+    Array,
+    Dict,
+    Root,
+}
+
+/// https://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c
+/// https://hg.python.org/cpython/file/3.4/Lib/plistlib.py
+pub struct EventReader<R> {
+    stack: Vec<StackItem>,
+    object_offsets: Vec<u64>,
+    reader: R,
+    ref_size: u8,
+    finished: bool,
+}
+
+impl<R: Read + Seek> EventReader<R> {
+    pub fn new(reader: R) -> EventReader<R> {
+        EventReader {
+            stack: Vec::new(),
+            object_offsets: Vec::new(),
+            reader: reader,
+            ref_size: 0,
+            finished: false,
+        }
+    }
+
+    fn read_trailer(&mut self) -> Result<()> {
+        try!(self.reader.seek(SeekFrom::Start(0)));
+        let mut magic = [0; 8];
+        try!(self.reader.read(&mut magic));
+        if &magic != b"bplist00" {
+            return Err(Error::InvalidData);
+        }
+
+        // Trailer starts with 6 bytes of padding
+        try!(self.reader.seek(SeekFrom::End(-32 + 6)));
+        let offset_size = try!(self.reader.read_u8());
+        self.ref_size = try!(self.reader.read_u8());
+        let num_objects = try!(self.reader.read_u64::<BigEndian>());
+        let top_object = try!(self.reader.read_u64::<BigEndian>());
+        let offset_table_offset = try!(self.reader.read_u64::<BigEndian>());
+
+        // Read offset table
+        try!(self.reader.seek(SeekFrom::Start(offset_table_offset)));
+        self.object_offsets = try!(self.read_ints(num_objects, offset_size));
+
+        // Seek to top object
+        self.stack.push(StackItem {
+            object_refs: vec![top_object],
+            ty: StackType::Root,
+        });
+
+        Ok(())
+    }
+
+    fn read_ints(&mut self, len: u64, size: u8) -> Result<Vec<u64>> {
+        let len = try!(u64_to_usize(len));
+        let mut ints = Vec::with_capacity(len);
+        // TODO: Is the match hoisted out of the loop?
+        for _ in 0..len {
+            match size {
+                1 => ints.push(try!(self.reader.read_u8()) as u64),
+                2 => ints.push(try!(self.reader.read_u16::<BigEndian>()) as u64),
+                4 => ints.push(try!(self.reader.read_u32::<BigEndian>()) as u64),
+                8 => ints.push(try!(self.reader.read_u64::<BigEndian>()) as u64),
+                _ => return Err(Error::InvalidData),
+            }
+        }
+        Ok(ints)
+    }
+
+    fn read_refs(&mut self, len: u64) -> Result<Vec<u64>> {
+        let ref_size = self.ref_size;
+        self.read_ints(len, ref_size)
+    }
+
+    fn read_object_len(&mut self, len: u8) -> Result<u64> {
+        if (len & 0x0f) == 0x0f {
+            let len_power_of_two = try!(self.reader.read_u8()) & 0x03;
+            Ok(match len_power_of_two {
+                0 => try!(self.reader.read_u8()) as u64,
+                1 => try!(self.reader.read_u16::<BigEndian>()) as u64,
+                2 => try!(self.reader.read_u32::<BigEndian>()) as u64,
+                3 => try!(self.reader.read_u64::<BigEndian>()),
+                _ => return Err(Error::InvalidData),
+            })
+        } else {
+            Ok(len as u64)
+        }
+    }
+
+    fn read_data(&mut self, len: u64) -> Result<Vec<u8>> {
+        let len = try!(u64_to_usize(len));
+        let mut data = vec![0; len];
+        let mut total_read = 0;
+
+        while total_read < len {
+            let read = try!(self.reader.read(&mut data[total_read..]));
+            if read == 0 {
+                return Err(Error::UnexpectedEof);
+            }
+            total_read += read;
+        }
+
+        Ok(data)
+    }
+
+    fn seek_to_object(&mut self, object_ref: u64) -> Result<u64> {
+        let object_ref = try!(u64_to_usize(object_ref));
+        let offset = *&self.object_offsets[object_ref];
+        let pos = try!(self.reader.seek(SeekFrom::Start(offset)));
+        Ok(pos)
+    }
+
+    fn read_next(&mut self) -> Result<Option<PlistEvent>> {
+        if self.ref_size == 0 {
+            // Initialise here rather than in new
+            try!(self.read_trailer());
+        }
+
+        let object_ref = match self.stack.last_mut() {
+            Some(stack_item) => stack_item.object_refs.pop(),
+            // Reached the end of the plist
+            None => return Ok(None),
+        };
+
+        match object_ref {
+            Some(object_ref) => {
+                try!(self.seek_to_object(object_ref));
+            }
+            None => {
+                // We're at the end of an array or dict. Pop the top stack item and return
+                let item = self.stack.pop().unwrap();
+                match item.ty {
+                    StackType::Array => return Ok(Some(PlistEvent::EndArray)),
+                    StackType::Dict => return Ok(Some(PlistEvent::EndDictionary)),
+                    // We're at the end of the plist
+                    StackType::Root => return Ok(None),
+                }
+            }
+        }
+
+        let token = try!(self.reader.read_u8());
+        let ty = (token & 0xf0) >> 4;
+        let size = token & 0x0f;
+
+        let result = match (ty, size) {
+            (0x0, 0x00) => return Err(Error::InvalidData), // null
+            (0x0, 0x08) => Some(PlistEvent::BooleanValue(false)),
+            (0x0, 0x09) => Some(PlistEvent::BooleanValue(true)),
+            (0x0, 0x0f) => return Err(Error::InvalidData), // fill
+            (0x1, 0) => Some(PlistEvent::IntegerValue(try!(self.reader.read_u8()) as i64)),
+            (0x1, 1) => {
+                Some(PlistEvent::IntegerValue(try!(self.reader.read_u16::<BigEndian>()) as i64))
+            }
+            (0x1, 2) => {
+                Some(PlistEvent::IntegerValue(try!(self.reader.read_u32::<BigEndian>()) as i64))
+            }
+            (0x1, 3) => Some(PlistEvent::IntegerValue(try!(self.reader.read_i64::<BigEndian>()))),
+            (0x1, 4) => return Err(Error::InvalidData), // 128 bit int
+            (0x1, _) => return Err(Error::InvalidData), // variable length int
+            (0x2, 2) => {
+                Some(PlistEvent::RealValue(try!(self.reader.read_f32::<BigEndian>()) as f64))
+            }
+            (0x2, 3) => Some(PlistEvent::RealValue(try!(self.reader.read_f64::<BigEndian>()))),
+            (0x2, _) => return Err(Error::InvalidData), // odd length float
+            (0x3, 3) => {
+                // Date
+                // Seconds since 1/1/2001 00:00:00
+                let timestamp = try!(self.reader.read_f64::<BigEndian>());
+
+                let secs = timestamp.floor();
+                let subsecs = timestamp - secs;
+
+                let int_secs = (secs as i64) + (31 * 365 + 8) * 86400;
+                let int_nanos = (subsecs * 1_000_000_000f64) as u32;
+
+                Some(PlistEvent::DateValue(UTC.timestamp(int_secs, int_nanos)))
+            }
+            (0x4, n) => {
+                // Data
+                let len = try!(self.read_object_len(n));
+                Some(PlistEvent::DataValue(try!(self.read_data(len))))
+            }
+            (0x5, n) => {
+                // ASCII string
+                let len = try!(self.read_object_len(n));
+                let raw = try!(self.read_data(len));
+                let string = try!(String::from_utf8(raw));
+                Some(PlistEvent::StringValue(string))
+            }
+            (0x6, n) => {
+                // UTF-16 string
+                // n is the length of 16 bit code units
+                // len is the number of bytes
+                let len = try!(self.read_object_len(n)) * 2;
+                let raw = try!(self.read_data(len));
+                let mut cursor = Cursor::new(raw);
+
+                let len_div_2 = try!(u64_to_usize(len / 2));
+                let mut raw_utf16 = Vec::with_capacity(len_div_2);
+                while cursor.position() < len {
+                    raw_utf16.push(try!(cursor.read_u16::<BigEndian>()))
+                }
+
+                let string = try!(String::from_utf16(&raw_utf16));
+                Some(PlistEvent::StringValue(string))
+            }
+            (0xa, n) => {
+                // Array
+                let len = try!(self.read_object_len(n));
+                let mut object_refs = try!(self.read_refs(len));
+                // Reverse so we can pop off the end of the stack in order
+                object_refs.reverse();
+
+                self.stack.push(StackItem {
+                    ty: StackType::Array,
+                    object_refs: object_refs,
+                });
+
+                Some(PlistEvent::StartArray(Some(len)))
+            }
+            (0xd, n) => {
+                // Dict
+                let len = try!(self.read_object_len(n));
+                let key_refs = try!(self.read_refs(len));
+                let value_refs = try!(self.read_refs(len));
+
+                let len_mul_2 = try!(u64_to_usize(len * 2));
+                let len = try!(u64_to_usize(len));
+
+                let mut object_refs = Vec::with_capacity(len_mul_2);
+
+                for i in 1..len + 1 {
+                    // Reverse so we can pop off the end of the stack in order
+                    object_refs.push(value_refs[len - i]);
+                    object_refs.push(key_refs[len - i]);
+                }
+
+                self.stack.push(StackItem {
+                    ty: StackType::Dict,
+                    object_refs: object_refs,
+                });
+
+                Some(PlistEvent::StartDictionary(Some(len as u64)))
+            }
+            (_, _) => return Err(Error::InvalidData),
+        };
+
+        Ok(result)
+    }
+}
+
+impl<R: Read + Seek> Iterator for EventReader<R> {
+    type Item = Result<PlistEvent>;
+
+    fn next(&mut self) -> Option<Result<PlistEvent>> {
+        if self.finished {
+            None
+        } else {
+            match self.read_next() {
+                Ok(Some(event)) => Some(Ok(event)),
+                Err(err) => {
+                    self.finished = true;
+                    Some(Err(err))
+                }
+                Ok(None) => {
+                    self.finished = true;
+                    None
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use chrono::{TimeZone, UTC};
+    use std::fs::File;
+    use std::path::Path;
+
+    use super::*;
+    use PlistEvent;
+
+    #[test]
+    fn streaming_parser() {
+        use PlistEvent::*;
+
+        let reader = File::open(&Path::new("./tests/data/binary.plist")).unwrap();
+        let streaming_parser = EventReader::new(reader);
+        let events: Vec<PlistEvent> = streaming_parser.map(|e| e.unwrap()).collect();
+
+        let comparison = &[StartDictionary(Some(6)),
+                           StringValue("Lines".to_owned()),
+                           StartArray(Some(2)),
+                           StringValue("It is a tale told by an idiot,".to_owned()),
+                           StringValue("Full of sound and fury, signifying nothing.".to_owned()),
+                           EndArray,
+                           StringValue("Death".to_owned()),
+                           IntegerValue(1564),
+                           StringValue("Height".to_owned()),
+                           RealValue(1.60),
+                           StringValue("Birthdate".to_owned()),
+                           DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)),
+                           StringValue("Author".to_owned()),
+                           StringValue("William Shakespeare".to_owned()),
+                           StringValue("Data".to_owned()),
+                           DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
+                           EndDictionary];
+
+        assert_eq!(events, comparison);
+    }
+
+    #[test]
+    fn utf16_plist() {
+        use PlistEvent::*;
+
+        let reader = File::open(&Path::new("./tests/data/utf16_bplist.plist")).unwrap();
+        let streaming_parser = EventReader::new(reader);
+        let mut events: Vec<PlistEvent> = streaming_parser.map(|e| e.unwrap()).collect();
+
+        assert_eq!(events[2], StringValue("\u{2605} or better".to_owned()));
+
+        let poem = if let StringValue(ref mut poem) = events[4] { poem } else { panic!("not a string") };
+        assert_eq!(poem.len(), 643);
+        assert_eq!(poem.pop().unwrap(), '\u{2605}');
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/builder.rs.html b/src/plist/src/builder.rs.html new file mode 100644 index 0000000..78ab47d --- /dev/null +++ b/src/plist/src/builder.rs.html @@ -0,0 +1,396 @@ + + + + + + + + + + builder.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+
+use std::collections::BTreeMap;
+
+use {Error, Result, Plist, PlistEvent, u64_option_to_usize};
+
+pub struct Builder<T> {
+    stream: T,
+    token: Option<PlistEvent>,
+}
+
+impl<T: Iterator<Item = Result<PlistEvent>>> Builder<T> {
+    pub fn new(stream: T) -> Builder<T> {
+        Builder {
+            stream: stream,
+            token: None,
+        }
+    }
+
+    pub fn build(mut self) -> Result<Plist> {
+        try!(self.bump());
+
+        let plist = try!(self.build_value());
+        try!(self.bump());
+        match self.token {
+            None => (),
+            // The stream should have finished
+            _ => return Err(Error::InvalidData),
+        };
+        Ok(plist)
+    }
+
+    fn bump(&mut self) -> Result<()> {
+        self.token = match self.stream.next() {
+            Some(Ok(token)) => Some(token),
+            Some(Err(err)) => return Err(err),
+            None => None,
+        };
+        Ok(())
+    }
+
+    fn build_value(&mut self) -> Result<Plist> {
+        match self.token.take() {
+            Some(PlistEvent::StartArray(len)) => Ok(Plist::Array(try!(self.build_array(len)))),
+            Some(PlistEvent::StartDictionary(len)) => {
+                Ok(Plist::Dictionary(try!(self.build_dict(len))))
+            }
+
+            Some(PlistEvent::BooleanValue(b)) => Ok(Plist::Boolean(b)),
+            Some(PlistEvent::DataValue(d)) => Ok(Plist::Data(d)),
+            Some(PlistEvent::DateValue(d)) => Ok(Plist::Date(d)),
+            Some(PlistEvent::IntegerValue(i)) => Ok(Plist::Integer(i)),
+            Some(PlistEvent::RealValue(f)) => Ok(Plist::Real(f)),
+            Some(PlistEvent::StringValue(s)) => Ok(Plist::String(s)),
+
+            Some(PlistEvent::EndArray) => Err(Error::InvalidData),
+            Some(PlistEvent::EndDictionary) => Err(Error::InvalidData),
+
+            // The stream should not have ended here
+            None => Err(Error::InvalidData),
+        }
+    }
+
+    fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>> {
+        let len = try!(u64_option_to_usize(len));
+        let mut values = match len {
+            Some(len) => Vec::with_capacity(len),
+            None => Vec::new(),
+        };
+
+        loop {
+            try!(self.bump());
+            if let Some(PlistEvent::EndArray) = self.token {
+                self.token.take();
+                return Ok(values);
+            }
+            values.push(try!(self.build_value()));
+        }
+    }
+
+    fn build_dict(&mut self, _len: Option<u64>) -> Result<BTreeMap<String, Plist>> {
+        let mut values = BTreeMap::new();
+
+        loop {
+            try!(self.bump());
+            match self.token.take() {
+                Some(PlistEvent::EndDictionary) => return Ok(values),
+                Some(PlistEvent::StringValue(s)) => {
+                    try!(self.bump());
+                    values.insert(s, try!(self.build_value()));
+                }
+                _ => {
+                    // Only string keys are supported in plists
+                    return Err(Error::InvalidData);
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::collections::BTreeMap;
+
+    use super::*;
+    use Plist;
+
+    #[test]
+    fn builder() {
+        use PlistEvent::*;
+
+        // Input
+
+        let events = vec![StartDictionary(None),
+                          StringValue("Author".to_owned()),
+                          StringValue("William Shakespeare".to_owned()),
+                          StringValue("Lines".to_owned()),
+                          StartArray(None),
+                          StringValue("It is a tale told by an idiot,".to_owned()),
+                          StringValue("Full of sound and fury, signifying nothing.".to_owned()),
+                          EndArray,
+                          StringValue("Birthdate".to_owned()),
+                          IntegerValue(1564),
+                          StringValue("Height".to_owned()),
+                          RealValue(1.60),
+                          EndDictionary];
+
+        let builder = Builder::new(events.into_iter().map(|e| Ok(e)));
+        let plist = builder.build();
+
+        // Expected output
+
+        let mut lines = Vec::new();
+        lines.push(Plist::String("It is a tale told by an idiot,".to_owned()));
+        lines.push(Plist::String("Full of sound and fury, signifying nothing.".to_owned()));
+
+        let mut dict = BTreeMap::new();
+        dict.insert("Author".to_owned(),
+                    Plist::String("William Shakespeare".to_owned()));
+        dict.insert("Lines".to_owned(), Plist::Array(lines));
+        dict.insert("Birthdate".to_owned(), Plist::Integer(1564));
+        dict.insert("Height".to_owned(), Plist::Real(1.60));
+
+        assert_eq!(plist.unwrap(), Plist::Dictionary(dict));
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/de.rs.html b/src/plist/src/de.rs.html new file mode 100644 index 0000000..a720da7 --- /dev/null +++ b/src/plist/src/de.rs.html @@ -0,0 +1,660 @@ + + + + + + + + + + de.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+
+// Tests for the serializer and deserializer are located in tests/serde_/mod.rs.
+// They can be run with `cargo test --features serde_tests`.
+
+use serde::de::{Deserializer as SerdeDeserializer, Error as SerdeError, Visitor, SeqVisitor,
+                MapVisitor, VariantVisitor, Deserialize, EnumVisitor};
+use std::iter::Peekable;
+
+use {Error, PlistEvent, u64_option_to_usize};
+
+macro_rules! expect {
+    ($next:expr, $pat:pat) => {
+        match $next {
+            Some(Ok(v@$pat)) => v,
+            None => return Err(Error::UnexpectedEof),
+            _ => return Err(event_mismatch_error())
+        }
+    };
+    ($next:expr, $pat:pat => $save:expr) => {
+        match $next {
+            Some(Ok($pat)) => $save,
+            None => return Err(Error::UnexpectedEof),
+            _ => return Err(event_mismatch_error())
+        }
+    };
+}
+
+macro_rules! try_next {
+    ($next:expr) => {
+        match $next {
+            Some(Ok(v)) => v,
+            Some(Err(_)) => return Err(event_mismatch_error()),
+            None => return Err(Error::UnexpectedEof)
+        }
+    }
+}
+
+fn event_mismatch_error() -> Error {
+    Error::InvalidData
+}
+
+impl SerdeError for Error {
+    fn custom<T: Into<String>>(msg: T) -> Self {
+        Error::Serde(msg.into())
+    }
+
+    fn end_of_stream() -> Self {
+        Error::UnexpectedEof
+    }
+}
+
+pub struct Deserializer<I>
+    where I: IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    events: Peekable<<I as IntoIterator>::IntoIter>,
+}
+
+impl<I> Deserializer<I> where I: IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    pub fn new(iter: I) -> Deserializer<I> {
+        Deserializer { events: iter.into_iter().peekable() }
+    }
+}
+
+impl<I> SerdeDeserializer for Deserializer<I>
+    where I: IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    type Error = Error;
+
+    fn deserialize<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error>
+        where V: Visitor
+    {
+        match try_next!(self.events.next()) {
+            PlistEvent::StartArray(len) => {
+                let len = try!(u64_option_to_usize(len));
+                visitor.visit_seq(MapSeq::new(self, len))
+            }
+            PlistEvent::EndArray => return Err(event_mismatch_error()),
+
+            PlistEvent::StartDictionary(len) => {
+                let len = try!(u64_option_to_usize(len));
+                visitor.visit_map(MapSeq::new(self, len))
+            }
+            PlistEvent::EndDictionary => return Err(event_mismatch_error()),
+
+            PlistEvent::BooleanValue(v) => visitor.visit_bool(v),
+            PlistEvent::DataValue(v) => visitor.visit_byte_buf(v),
+            PlistEvent::DateValue(v) => visitor.visit_string(v.to_rfc3339()),
+            PlistEvent::IntegerValue(v) if v.is_positive() => visitor.visit_u64(v as u64),
+            PlistEvent::IntegerValue(v) => visitor.visit_i64(v as i64),
+            PlistEvent::RealValue(v) => visitor.visit_f64(v),
+            PlistEvent::StringValue(v) => visitor.visit_string(v),
+        }
+    }
+
+    fn deserialize_unit<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error>
+        where V: Visitor
+    {
+        expect!(self.events.next(), PlistEvent::StringValue(_));
+        visitor.visit_unit()
+    }
+
+    fn deserialize_option<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error>
+        where V: Visitor
+    {
+        expect!(self.events.next(), PlistEvent::StartDictionary(_));
+
+        let ret = match try_next!(self.events.next()) {
+            PlistEvent::StringValue(ref s) if &s[..] == "None" => {
+                let ret = match visitor.visit_none() {
+                    Ok(ret) => ret,
+                    Err(e) => return Err(e),
+                };
+                // For some reason the try! below doesn't work - probably a macro hygene issue
+                // with Error and ::Error
+                // let ret = try!(visitor.visit_none());
+                expect!(self.events.next(), PlistEvent::StringValue(_));
+                ret
+            }
+            PlistEvent::StringValue(ref s) if &s[..] == "Some" => try!(visitor.visit_some(self)),
+            _ => return Err(event_mismatch_error()),
+        };
+
+        expect!(self.events.next(), PlistEvent::EndDictionary);
+
+        Ok(ret)
+    }
+
+    fn deserialize_newtype_struct<V>(&mut self,
+                               _name: &'static str,
+                               mut visitor: V)
+                               -> Result<V::Value, Self::Error>
+        where V: Visitor
+    {
+        visitor.visit_newtype_struct(self)
+    }
+
+    fn deserialize_enum<V>(&mut self,
+                     _enum: &'static str,
+                     _variants: &'static [&'static str],
+                     mut visitor: V)
+                     -> Result<V::Value, Self::Error>
+        where V: EnumVisitor
+    {
+        expect!(self.events.next(), PlistEvent::StartDictionary(_));
+        let ret = try!(visitor.visit(&mut *self));
+        expect!(self.events.next(), PlistEvent::EndDictionary);
+        Ok(ret)
+    }
+}
+
+impl<I> VariantVisitor for Deserializer<I> where I: IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    type Error = Error;
+
+    fn visit_variant<V>(&mut self) -> Result<V, Self::Error>
+        where V: Deserialize
+    {
+        <V as Deserialize>::deserialize(self)
+    }
+
+    fn visit_unit(&mut self) -> Result<(), Self::Error> {
+        <() as Deserialize>::deserialize(self)
+    }
+
+    fn visit_newtype<T>(&mut self) -> Result<T, Self::Error>
+        where T: Deserialize
+    {
+        <T as Deserialize>::deserialize(self)
+    }
+
+    fn visit_tuple<V>(&mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
+        where V: Visitor
+    {
+        <Self as SerdeDeserializer>::deserialize_tuple(self, len, visitor)
+    }
+
+    fn visit_struct<V>(&mut self,
+                       fields: &'static [&'static str],
+                       visitor: V)
+                       -> Result<V::Value, Self::Error>
+        where V: Visitor
+    {
+        let name = "";
+        <Self as SerdeDeserializer>::deserialize_struct(self, name, fields, visitor)
+    }
+}
+
+struct MapSeq<'a, I>
+    where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    de: &'a mut Deserializer<I>,
+    remaining: Option<usize>,
+    finished: bool,
+}
+
+impl<'a, I> MapSeq<'a, I> where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    fn new(de: &'a mut Deserializer<I>, len: Option<usize>) -> MapSeq<'a, I> {
+        MapSeq {
+            de: de,
+            remaining: len,
+            finished: false,
+        }
+    }
+}
+
+impl<'a, I> SeqVisitor for MapSeq<'a, I>
+    where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    type Error = Error;
+
+    fn visit<T>(&mut self) -> Result<Option<T>, Self::Error>
+        where T: Deserialize
+    {
+        match self.de.events.peek() {
+            Some(&Ok(PlistEvent::EndArray)) => {
+                self.de.events.next();
+                self.finished = true;
+                return Ok(None);
+            }
+            _ => <T as Deserialize>::deserialize(self.de).map(|k| Some(k)),
+        }
+    }
+
+    fn end(&mut self) -> Result<(), Self::Error> {
+        if !self.finished {
+            self.finished = true;
+            expect!(self.de.events.next(), PlistEvent::EndArray);
+        }
+        Ok(())
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        <Self as MapVisitor>::size_hint(self)
+    }
+}
+
+impl<'a, I> MapVisitor for MapSeq<'a, I>
+    where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>>
+{
+    type Error = Error;
+
+    fn visit_key<K>(&mut self) -> Result<Option<K>, Self::Error>
+        where K: Deserialize
+    {
+        match self.de.events.peek() {
+            Some(&Ok(PlistEvent::EndDictionary)) => {
+                self.de.events.next();
+                self.finished = true;
+                return Ok(None);
+            }
+            _ => <K as Deserialize>::deserialize(self.de).map(|k| Some(k)),
+        }
+    }
+
+    fn visit_value<V>(&mut self) -> Result<V, Self::Error>
+        where V: Deserialize
+    {
+        <V as Deserialize>::deserialize(self.de)
+    }
+
+    fn end(&mut self) -> Result<(), Self::Error> {
+        if !self.finished {
+            self.finished = true;
+            expect!(self.de.events.next(), PlistEvent::EndDictionary);
+        }
+        Ok(())
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        match self.remaining {
+            Some(len) => (len, Some(len)),
+            None => (0, None),
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/lib.rs.html b/src/plist/src/lib.rs.html new file mode 100644 index 0000000..304566c --- /dev/null +++ b/src/plist/src/lib.rs.html @@ -0,0 +1,1216 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+
+//! # Plist
+//!
+//! A rusty plist parser.
+//!
+//! ## Usage
+//!
+//! Put this in your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! plist = "0.0.12"
+//! ```
+//!
+//! And put this in your crate root:
+//!
+//! ```rust
+//! extern crate plist;
+//! ```
+//!
+//! ## Examples
+//!
+//! ```rust ignore
+//! use plist::Plist;
+//! use std::fs::File;
+//!
+//! let file = File::open("tests/data/xml.plist").unwrap();
+//! let plist = Plist::read(file).unwrap();
+//!
+//! match plist {
+//!     Plist::Array(_array) => (),
+//!     _ => ()
+//! }
+//!
+//! ```
+//!
+//!
+
+extern crate byteorder;
+extern crate chrono;
+extern crate rustc_serialize;
+extern crate serde;
+extern crate xml as xml_rs;
+
+pub mod binary;
+pub mod xml;
+
+mod builder;
+mod de;
+mod ser;
+
+pub use de::Deserializer;
+pub use ser::Serializer;
+
+use chrono::{DateTime, UTC};
+use serde::{Deserialize, Serialize};
+use std::collections::BTreeMap;
+use std::fmt;
+use std::io::{Read, Seek, SeekFrom, Write};
+use std::io::Error as IoError;
+
+pub fn deserialize<R: Read + Seek, T: Deserialize>(reader: R) -> Result<T> {
+    let reader = EventReader::new(reader);
+    let mut de = Deserializer::new(reader);
+    Deserialize::deserialize(&mut de)
+}
+
+pub fn serialize_to_xml<W: Write, T: Serialize>(writer: W, value: &T) -> Result<()> {
+    let writer = xml::EventWriter::new(writer);
+    let mut ser = Serializer::new(writer);
+    value.serialize(&mut ser)
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Plist {
+    Array(Vec<Plist>),
+    Dictionary(BTreeMap<String, Plist>),
+    Boolean(bool),
+    Data(Vec<u8>),
+    Date(DateTime<UTC>),
+    Real(f64),
+    Integer(i64),
+    String(String),
+}
+
+use rustc_serialize::base64::{STANDARD, ToBase64};
+use rustc_serialize::json::Json as RustcJson;
+
+impl Plist {
+    pub fn read<R: Read + Seek>(reader: R) -> Result<Plist> {
+        let reader = EventReader::new(reader);
+        Plist::from_events(reader)
+    }
+
+    pub fn from_events<T>(events: T) -> Result<Plist>
+        where T: IntoIterator<Item = Result<PlistEvent>>
+    {
+        let iter = events.into_iter();
+        let builder = builder::Builder::new(iter);
+        builder.build()
+    }
+
+    pub fn into_events(self) -> Vec<PlistEvent> {
+        let mut events = Vec::new();
+        self.into_events_inner(&mut events);
+        events
+    }
+
+    fn into_events_inner(self, events: &mut Vec<PlistEvent>) {
+        match self {
+            Plist::Array(array) => {
+                events.push(PlistEvent::StartArray(Some(array.len() as u64)));
+                for value in array.into_iter() {
+                    value.into_events_inner(events);
+                }
+                events.push(PlistEvent::EndArray);
+            }
+            Plist::Dictionary(dict) => {
+                events.push(PlistEvent::StartDictionary(Some(dict.len() as u64)));
+                for (key, value) in dict.into_iter() {
+                    events.push(PlistEvent::StringValue(key));
+                    value.into_events_inner(events);
+                }
+                events.push(PlistEvent::EndDictionary);
+            }
+            Plist::Boolean(value) => events.push(PlistEvent::BooleanValue(value)),
+            Plist::Data(value) => events.push(PlistEvent::DataValue(value)),
+            Plist::Date(value) => events.push(PlistEvent::DateValue(value)),
+            Plist::Real(value) => events.push(PlistEvent::RealValue(value)),
+            Plist::Integer(value) => events.push(PlistEvent::IntegerValue(value)),
+            Plist::String(value) => events.push(PlistEvent::StringValue(value)),
+        }
+    }
+
+    pub fn into_rustc_serialize_json(self) -> RustcJson {
+        match self {
+            Plist::Array(value) => {
+                RustcJson::Array(value.into_iter().map(|p| p.into_rustc_serialize_json()).collect())
+            }
+            Plist::Dictionary(value) => {
+                RustcJson::Object(value.into_iter()
+                                       .map(|(k, v)| (k, v.into_rustc_serialize_json()))
+                                       .collect())
+            }
+            Plist::Boolean(value) => RustcJson::Boolean(value),
+            Plist::Data(value) => RustcJson::String(value.to_base64(STANDARD)),
+            Plist::Date(value) => RustcJson::String(value.to_rfc3339()),
+            Plist::Real(value) => RustcJson::F64(value),
+            Plist::Integer(value) => RustcJson::I64(value),
+            Plist::String(value) => RustcJson::String(value),
+        }
+    }
+}
+
+impl Plist {
+    /// If the `Plist` is an Array, returns the associated Vec.
+    /// Returns None otherwise.
+    pub fn as_array(&self) -> Option<&Vec<Plist>> {
+        match self {
+            &Plist::Array(ref array) => Some(array),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is an Array, returns the associated mutable Vec.
+    /// Returns None otherwise.
+    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Plist>> {
+        match self {
+            &mut Plist::Array(ref mut array) => Some(array),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Dictionary, returns the associated BTreeMap.
+    /// Returns None otherwise.
+    pub fn as_dictionary(&self) -> Option<&BTreeMap<String, Plist>> {
+        match self {
+            &Plist::Dictionary(ref map) => Some(map),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Dictionary, returns the associated mutable BTreeMap.
+    /// Returns None otherwise.
+    pub fn as_dictionary_mut(&mut self) -> Option<&mut BTreeMap<String, Plist>> {
+        match self {
+            &mut Plist::Dictionary(ref mut map) => Some(map),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Boolean, returns the associated bool.
+    /// Returns None otherwise.
+    pub fn as_boolean(&self) -> Option<bool> {
+        match self {
+            &Plist::Boolean(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Data, returns the underlying Vec.
+    /// Returns None otherwise.
+    ///
+    /// This method consumes the `Plist`. If this is not desired, please use
+    /// `as_data` method.
+    pub fn into_data(self) -> Option<Vec<u8>> {
+        match self {
+            Plist::Data(data) => Some(data),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Data, returns the associated Vec.
+    /// Returns None otherwise.
+    pub fn as_data(&self) -> Option<&[u8]> {
+        match self {
+            &Plist::Data(ref data) => Some(data),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Date, returns the associated DateTime.
+    /// Returns None otherwise.
+    pub fn as_date(&self) -> Option<DateTime<UTC>> {
+        match self {
+            &Plist::Date(date) => Some(date),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a Real, returns the associated f64.
+    /// Returns None otherwise.
+    pub fn as_real(&self) -> Option<f64> {
+        match self {
+            &Plist::Real(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is an Integer, returns the associated i64.
+    /// Returns None otherwise.
+    pub fn as_integer(&self) -> Option<i64> {
+        match self {
+            &Plist::Integer(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a String, returns the underlying String.
+    /// Returns None otherwise.
+    ///
+    /// This method consumes the `Plist`. If this is not desired, please use
+    /// `as_string` method.
+    pub fn into_string(self) -> Option<String> {
+        match self {
+            Plist::String(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// If the `Plist` is a String, returns the associated str.
+    /// Returns None otherwise.
+    pub fn as_string(&self) -> Option<&str> {
+        match self {
+            &Plist::String(ref v) => Some(v),
+            _ => None,
+        }
+    }
+}
+
+impl From<Vec<Plist>> for Plist {
+    fn from(from: Vec<Plist>) -> Plist { Plist::Array(from) }
+}
+
+impl From<BTreeMap<String, Plist>> for Plist {
+    fn from(from: BTreeMap<String, Plist>) -> Plist { Plist::Dictionary(from) }
+}
+
+impl From<bool> for Plist {
+    fn from(from: bool) -> Plist { Plist::Boolean(from) }
+}
+
+impl<'a> From<&'a bool> for Plist {
+    fn from(from: &'a bool) -> Plist { Plist::Boolean(*from) }
+}
+
+impl From<DateTime<UTC>> for Plist {
+    fn from(from: DateTime<UTC>) -> Plist { Plist::Date(from) }
+}
+
+impl<'a> From<&'a DateTime<UTC>> for Plist {
+    fn from(from: &'a DateTime<UTC>) -> Plist { Plist::Date(from.clone()) }
+}
+
+impl From<f64> for Plist {
+    fn from(from: f64) -> Plist { Plist::Real(from) }
+}
+
+impl From<f32> for Plist {
+    fn from(from: f32) -> Plist { Plist::Real(from as f64) }
+}
+
+impl From<i64> for Plist {
+    fn from(from: i64) -> Plist { Plist::Integer(from) }
+}
+
+impl From<i32> for Plist {
+    fn from(from: i32) -> Plist { Plist::Integer(from as i64) }
+}
+
+impl From<i16> for Plist {
+    fn from(from: i16) -> Plist { Plist::Integer(from as i64) }
+}
+
+impl From<i8> for Plist {
+    fn from(from: i8) -> Plist { Plist::Integer(from as i64) }
+}
+
+impl From<u32> for Plist {
+    fn from(from: u32) -> Plist { Plist::Integer(from as i64) }
+}
+
+impl From<u16> for Plist {
+    fn from(from: u16) -> Plist { Plist::Integer(from as i64) }
+}
+
+impl From<u8> for Plist {
+    fn from(from: u8) -> Plist { Plist::Integer(from as i64) }
+}
+
+impl<'a> From<&'a f64> for Plist {
+    fn from(from: &'a f64) -> Plist { Plist::Real(*from) }
+}
+
+impl<'a> From<&'a f32> for Plist {
+    fn from(from: &'a f32) -> Plist { Plist::Real(*from as f64) }
+}
+
+impl<'a> From<&'a i64> for Plist {
+    fn from(from: &'a i64) -> Plist { Plist::Integer(*from) }
+}
+
+impl<'a> From<&'a i32> for Plist {
+    fn from(from: &'a i32) -> Plist { Plist::Integer(*from as i64) }
+}
+
+impl<'a> From<&'a i16> for Plist {
+    fn from(from: &'a i16) -> Plist { Plist::Integer(*from as i64) }
+}
+
+impl<'a> From<&'a i8> for Plist {
+    fn from(from: &'a i8) -> Plist { Plist::Integer(*from as i64) }
+}
+
+impl<'a> From<&'a u32> for Plist {
+    fn from(from: &'a u32) -> Plist { Plist::Integer(*from as i64) }
+}
+
+impl<'a> From<&'a u16> for Plist {
+    fn from(from: &'a u16) -> Plist { Plist::Integer(*from as i64) }
+}
+
+impl<'a> From<&'a u8> for Plist {
+    fn from(from: &'a u8) -> Plist { Plist::Integer(*from as i64) }
+}
+
+impl From<String> for Plist {
+    fn from(from: String) -> Plist { Plist::String(from) }
+}
+
+impl<'a> From<&'a str> for Plist {
+    fn from(from: &'a str) -> Plist { Plist::String(from.into()) }
+}
+
+/// An encoding of a plist as a flat structure.
+///
+/// Output by the event readers.
+///
+/// Dictionary keys and values are represented as pairs of values e.g.:
+///
+/// ```ignore rust
+/// StartDictionary
+/// StringValue("Height") // Key
+/// RealValue(181.2)      // Value
+/// StringValue("Age")    // Key
+/// IntegerValue(28)      // Value
+/// EndDictionary
+/// ```
+#[derive(Clone, Debug, PartialEq)]
+pub enum PlistEvent {
+    // While the length of an array or dict cannot be feasably greater than max(usize) this better
+    // conveys the concept of an effectively unbounded event stream.
+    StartArray(Option<u64>),
+    EndArray,
+
+    StartDictionary(Option<u64>),
+    EndDictionary,
+
+    BooleanValue(bool),
+    DataValue(Vec<u8>),
+    DateValue(DateTime<UTC>),
+    IntegerValue(i64),
+    RealValue(f64),
+    StringValue(String),
+}
+
+pub type Result<T> = ::std::result::Result<T, Error>;
+
+#[derive(Debug)]
+pub enum Error {
+    InvalidData,
+    UnexpectedEof,
+    Io(IoError),
+    Serde(String)
+}
+
+impl ::std::error::Error for Error {
+    fn description(&self) -> &str {
+        match *self {
+            Error::InvalidData => "invalid data",
+            Error::UnexpectedEof => "unexpected eof",
+            Error::Io(ref err) => err.description(),
+            Error::Serde(ref err) => &err
+        }
+    }
+
+    fn cause(&self) -> Option<&::std::error::Error> {
+        match *self {
+            Error::Io(ref err) => Some(err),
+            _ => None,
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Error::Io(ref err) => err.fmt(fmt),
+            _ => <Self as ::std::error::Error>::description(self).fmt(fmt),
+        }
+    }
+}
+
+impl From<IoError> for Error {
+    fn from(err: IoError) -> Error {
+        Error::Io(err)
+    }
+}
+
+pub struct EventReader<R: Read + Seek>(EventReaderInner<R>);
+
+enum EventReaderInner<R: Read + Seek> {
+    Uninitialized(Option<R>),
+    Xml(xml::EventReader<R>),
+    Binary(binary::EventReader<R>),
+}
+
+impl<R: Read + Seek> EventReader<R> {
+    pub fn new(reader: R) -> EventReader<R> {
+        EventReader(EventReaderInner::Uninitialized(Some(reader)))
+    }
+
+    fn is_binary(reader: &mut R) -> Result<bool> {
+        try!(reader.seek(SeekFrom::Start(0)));
+        let mut magic = [0; 8];
+        try!(reader.read(&mut magic));
+        try!(reader.seek(SeekFrom::Start(0)));
+
+        Ok(if &magic == b"bplist00" {
+            true
+        } else {
+            false
+        })
+    }
+}
+
+impl<R: Read + Seek> Iterator for EventReader<R> {
+    type Item = Result<PlistEvent>;
+
+    fn next(&mut self) -> Option<Result<PlistEvent>> {
+        let mut reader = match self.0 {
+            EventReaderInner::Xml(ref mut parser) => return parser.next(),
+            EventReaderInner::Binary(ref mut parser) => return parser.next(),
+            EventReaderInner::Uninitialized(ref mut reader) => reader.take().unwrap(),
+        };
+
+        let event_reader = match EventReader::is_binary(&mut reader) {
+            Ok(true) => EventReaderInner::Binary(binary::EventReader::new(reader)),
+            Ok(false) => EventReaderInner::Xml(xml::EventReader::new(reader)),
+            Err(err) => {
+                ::std::mem::replace(&mut self.0, EventReaderInner::Uninitialized(Some(reader)));
+                return Some(Err(err));
+            }
+        };
+
+        ::std::mem::replace(&mut self.0, event_reader);
+
+        self.next()
+    }
+}
+
+pub trait EventWriter {
+    fn write(&mut self, event: &PlistEvent) -> Result<()>;
+}
+
+fn u64_to_usize(len_u64: u64) -> Result<usize> {
+    let len = len_u64 as usize;
+    if len as u64 != len_u64 {
+        return Err(Error::InvalidData); // Too long
+    }
+    Ok(len)
+}
+
+fn u64_option_to_usize(len: Option<u64>) -> Result<Option<usize>> {
+    match len {
+        Some(len) => Ok(Some(try!(u64_to_usize(len)))),
+        None => Ok(None),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::Plist;
+
+    #[test]
+    fn test_plist_access() {
+        use std::collections::BTreeMap;
+        use chrono::*;
+
+        let vec = vec![Plist::Real(0.0)];
+        let mut array = Plist::Array(vec.clone());
+        assert_eq!(array.as_array(), Some(&vec.clone()));
+        assert_eq!(array.as_array_mut(), Some(&mut vec.clone()));
+
+        let mut map = BTreeMap::new();
+        map.insert("key1".to_owned(), Plist::String("value1".to_owned()));
+        let mut dict = Plist::Dictionary(map.clone());
+        assert_eq!(dict.as_dictionary(), Some(&map.clone()));
+        assert_eq!(dict.as_dictionary_mut(), Some(&mut map.clone()));
+
+        assert_eq!(Plist::Boolean(true).as_boolean(), Some(true));
+
+        let slice: &[u8] = &[1, 2, 3];
+        assert_eq!(Plist::Data(slice.to_vec()).as_data(), Some(slice));
+        assert_eq!(Plist::Data(slice.to_vec()).into_data(), Some(slice.to_vec()));
+
+        let date: DateTime<UTC> = UTC::now();
+        assert_eq!(Plist::Date(date).as_date(), Some(date));
+
+        assert_eq!(Plist::Real(0.0).as_real(), Some(0.0));
+        assert_eq!(Plist::Integer(1).as_integer(), Some(1));
+        assert_eq!(Plist::String("2".to_owned()).as_string(), Some("2"));
+        assert_eq!(Plist::String("t".to_owned()).into_string(), Some("t".to_owned()));
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/ser.rs.html b/src/plist/src/ser.rs.html new file mode 100644 index 0000000..2bded7a --- /dev/null +++ b/src/plist/src/ser.rs.html @@ -0,0 +1,480 @@ + + + + + + + + + + ser.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+
+// Tests for the serializer and deserializer are located in tests/serde_/mod.rs.
+// They can be run with `cargo test --features serde_tests`.
+
+use serde::ser::{Error as SerdeError, MapVisitor, Serialize, Serializer as SerdeSerializer, SeqVisitor};
+
+use {Error, EventWriter, PlistEvent};
+
+impl SerdeError for Error {
+    fn custom<T: Into<String>>(msg: T) -> Self {
+        Error::Serde(msg.into())
+    }
+
+    fn invalid_value(_: &str) -> Self {
+        Error::InvalidData
+    }
+}
+
+pub struct Serializer<W: EventWriter> {
+    writer: W,
+}
+
+impl<W: EventWriter> Serializer<W> {
+    pub fn new(writer: W) -> Serializer<W> {
+        Serializer { writer: writer }
+    }
+
+    #[inline]
+    fn emit(&mut self, event: PlistEvent) -> Result<(), Error> {
+        self.writer.write(&event)
+    }
+
+    pub fn into_inner(self) -> W {
+        self.writer
+    }
+
+    fn single_key_dict<F>(&mut self,
+                          key: String,
+                          value_fn: F)
+                          -> Result<(), <Self as SerdeSerializer>::Error>
+        where F: FnOnce(&mut Serializer<W>) -> Result<(), <Self as SerdeSerializer>::Error>
+    {
+        // Emit {key: value}
+        try!(self.emit(PlistEvent::StartDictionary(Some(1))));
+        try!(self.emit(PlistEvent::StringValue(key)));
+        try!(value_fn(self));
+        try!(self.emit(PlistEvent::EndDictionary));
+        Ok(())
+    }
+}
+
+impl<W: EventWriter> SerdeSerializer for Serializer<W> {
+    type Error = Error;
+
+    fn serialize_bool(&mut self, v: bool) -> Result<(), Self::Error> {
+        self.emit(PlistEvent::BooleanValue(v))
+    }
+
+    fn serialize_i64(&mut self, v: i64) -> Result<(), Self::Error> {
+        self.emit(PlistEvent::IntegerValue(v))
+    }
+
+    fn serialize_u64(&mut self, v: u64) -> Result<(), Self::Error> {
+        self.emit(PlistEvent::IntegerValue(v as i64))
+    }
+
+    fn serialize_f64(&mut self, v: f64) -> Result<(), Self::Error> {
+        self.emit(PlistEvent::RealValue(v))
+    }
+
+    fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error> {
+        self.emit(PlistEvent::StringValue(value.to_owned()))
+    }
+
+    fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
+        self.emit(PlistEvent::DataValue(value.to_owned()))
+    }
+
+    fn serialize_unit(&mut self) -> Result<(), Self::Error> {
+        // Emit empty string
+        self.emit(PlistEvent::StringValue(String::new()))
+    }
+
+    fn serialize_none(&mut self) -> Result<(), Self::Error> {
+        self.single_key_dict("None".to_owned(), |this| this.serialize_unit())
+    }
+
+    fn serialize_some<V>(&mut self, value: V) -> Result<(), Self::Error>
+        where V: Serialize
+    {
+        self.single_key_dict("Some".to_owned(), |this| value.serialize(this))
+    }
+
+    fn serialize_seq<V>(&mut self, mut visitor: V) -> Result<(), Self::Error>
+        where V: SeqVisitor
+    {
+        let len = visitor.len().map(|len| len as u64);
+        try!(self.emit(PlistEvent::StartArray(len)));
+        loop {
+            match try!(visitor.visit(self)) {
+                Some(()) => (),
+                None => break,
+            }
+        }
+        try!(self.emit(PlistEvent::EndArray));
+        Ok(())
+    }
+
+    fn serialize_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
+        where T: Serialize
+    {
+        value.serialize(self)
+    }
+
+    fn serialize_map<V>(&mut self, mut visitor: V) -> Result<(), Self::Error>
+        where V: MapVisitor
+    {
+        let len = visitor.len().map(|len| len as u64);
+        try!(self.emit(PlistEvent::StartDictionary(len)));
+        loop {
+            match try!(visitor.visit(self)) {
+                Some(()) => (),
+                None => break,
+            }
+        }
+        try!(self.emit(PlistEvent::EndDictionary));
+        Ok(())
+    }
+
+    fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
+        where K: Serialize,
+              V: Serialize
+    {
+        try!(key.serialize(self));
+        try!(value.serialize(self));
+        Ok(())
+    }
+
+    fn serialize_unit_variant(&mut self,
+                          _name: &'static str,
+                          _variant_index: usize,
+                          variant: &'static str)
+                          -> Result<(), Self::Error> {
+        self.single_key_dict(variant.to_owned(), |this| this.serialize_unit())
+    }
+
+    fn serialize_newtype_struct<T>(&mut self, _name: &'static str, value: T) -> Result<(), Self::Error>
+        where T: Serialize
+    {
+        value.serialize(self)
+    }
+
+    fn serialize_newtype_variant<T>(&mut self,
+                                _name: &'static str,
+                                _variant_index: usize,
+                                variant: &'static str,
+                                value: T)
+                                -> Result<(), Self::Error>
+        where T: Serialize
+    {
+        self.single_key_dict(variant.to_owned(), |this| value.serialize(this))
+    }
+
+    fn serialize_tuple_variant<V>(&mut self,
+                              _name: &'static str,
+                              _variant_index: usize,
+                              variant: &'static str,
+                              visitor: V)
+                              -> Result<(), Self::Error>
+        where V: SeqVisitor
+    {
+        self.single_key_dict(variant.to_owned(),
+                             |this| this.serialize_tuple_struct(variant, visitor))
+    }
+
+    fn serialize_struct_variant<V>(&mut self,
+                               _name: &'static str,
+                               _variant_index: usize,
+                               variant: &'static str,
+                               visitor: V)
+                               -> Result<(), Self::Error>
+        where V: MapVisitor
+    {
+        self.single_key_dict(variant.to_owned(),
+                             |this| this.serialize_struct(variant, visitor))
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/xml/mod.rs.html b/src/plist/src/xml/mod.rs.html new file mode 100644 index 0000000..37c8434 --- /dev/null +++ b/src/plist/src/xml/mod.rs.html @@ -0,0 +1,118 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + + + +
1
+2
+3
+4
+5
+
+mod reader;
+mod writer;
+
+pub use self::reader::EventReader;
+pub use self::writer::EventWriter;
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/xml/reader.rs.html b/src/plist/src/xml/reader.rs.html new file mode 100644 index 0000000..612b8ab --- /dev/null +++ b/src/plist/src/xml/reader.rs.html @@ -0,0 +1,530 @@ + + + + + + + + + + reader.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+
+use chrono::{DateTime, UTC};
+use chrono::format::ParseError as ChronoParseError;
+use rustc_serialize::base64::FromBase64;
+use std::io::Read;
+use std::str::FromStr;
+use xml_rs::reader::{EventReader as XmlEventReader, ParserConfig, XmlEvent};
+
+use {Error, Result, PlistEvent};
+
+impl From<ChronoParseError> for Error {
+    fn from(_: ChronoParseError) -> Error {
+        Error::InvalidData
+    }
+}
+
+pub struct EventReader<R: Read> {
+    xml_reader: XmlEventReader<R>,
+    queued_event: Option<XmlEvent>,
+    element_stack: Vec<String>,
+    finished: bool,
+}
+
+impl<R: Read> EventReader<R> {
+    pub fn new(reader: R) -> EventReader<R> {
+        let config = ParserConfig {
+            trim_whitespace: false,
+            whitespace_to_characters: true,
+            cdata_to_characters: true,
+            ignore_comments: true,
+            coalesce_characters: true,
+        };
+
+        EventReader {
+            xml_reader: XmlEventReader::new_with_config(reader, config),
+            queued_event: None,
+            element_stack: Vec::new(),
+            finished: false,
+        }
+    }
+
+    fn read_content<F>(&mut self, f: F) -> Result<PlistEvent>
+        where F: FnOnce(String) -> Result<PlistEvent>
+    {
+        match self.xml_reader.next() {
+            Ok(XmlEvent::Characters(s)) => f(s),
+            Ok(event @ XmlEvent::EndElement{..}) => {
+                self.queued_event = Some(event);
+                f("".to_owned())
+            }
+            _ => Err(Error::InvalidData),
+        }
+    }
+
+    fn next_event(&mut self) -> ::std::result::Result<XmlEvent, ()> {
+        if let Some(event) = self.queued_event.take() {
+            Ok(event)
+        } else {
+            self.xml_reader.next().map_err(|_| ())
+        }
+    }
+
+    fn read_next(&mut self) -> Option<Result<PlistEvent>> {
+        loop {
+            match self.next_event() {
+                Ok(XmlEvent::StartElement { name, .. }) => {
+                    // Add the current element to the element stack
+                    self.element_stack.push(name.local_name.clone());
+
+                    match &name.local_name[..] {
+                        "plist" => (),
+                        "array" => return Some(Ok(PlistEvent::StartArray(None))),
+                        "dict" => return Some(Ok(PlistEvent::StartDictionary(None))),
+                        "key" => return Some(self.read_content(|s| Ok(PlistEvent::StringValue(s)))),
+                        "true" => return Some(Ok(PlistEvent::BooleanValue(true))),
+                        "false" => return Some(Ok(PlistEvent::BooleanValue(false))),
+                        "data" => {
+                            return Some(self.read_content(|s| {
+                                let s: String = s.replace(" ", "").replace("\t", "");
+                                match FromBase64::from_base64(&s[..]) {
+                                    Ok(b) => Ok(PlistEvent::DataValue(b)),
+                                    Err(_) => Err(Error::InvalidData),
+                                }
+                            }))
+                        }
+                        "date" => {
+                            return Some(self.read_content(|s| {
+                                let date = try!(DateTime::parse_from_rfc3339(&s));
+                                Ok(PlistEvent::DateValue(date.with_timezone(&UTC)))
+                            }))
+                        }
+                        "integer" => {
+                            return Some(self.read_content(|s| {
+                                match FromStr::from_str(&s) {
+                                    Ok(i) => Ok(PlistEvent::IntegerValue(i)),
+                                    Err(_) => Err(Error::InvalidData),
+                                }
+                            }))
+                        }
+                        "real" => {
+                            return Some(self.read_content(|s| {
+                                match FromStr::from_str(&s) {
+                                    Ok(f) => Ok(PlistEvent::RealValue(f)),
+                                    Err(_) => Err(Error::InvalidData),
+                                }
+                            }))
+                        }
+                        "string" => {
+                            return Some(self.read_content(|s| Ok(PlistEvent::StringValue(s))))
+                        }
+                        _ => return Some(Err(Error::InvalidData)),
+                    }
+                }
+                Ok(XmlEvent::EndElement { name, .. }) => {
+                    // Check the corrent element is being closed
+                    match self.element_stack.pop() {
+                        Some(ref open_name) if &name.local_name == open_name => (),
+                        Some(ref _open_name) => return Some(Err(Error::InvalidData)),
+                        None => return Some(Err(Error::InvalidData)),
+                    }
+
+                    match &name.local_name[..] {
+                        "array" => return Some(Ok(PlistEvent::EndArray)),
+                        "dict" => return Some(Ok(PlistEvent::EndDictionary)),
+                        "plist" => (),
+                        _ => (),
+                    }
+                }
+                Ok(XmlEvent::EndDocument) => {
+                    match self.element_stack.is_empty() {
+                        true => return None,
+                        false => return Some(Err(Error::UnexpectedEof)),
+                    }
+                }
+                Err(_) => return Some(Err(Error::InvalidData)),
+                _ => (),
+            }
+        }
+    }
+}
+
+impl<R: Read> Iterator for EventReader<R> {
+    type Item = Result<PlistEvent>;
+
+    fn next(&mut self) -> Option<Result<PlistEvent>> {
+        if self.finished {
+            None
+        } else {
+            match self.read_next() {
+                Some(Ok(event)) => Some(Ok(event)),
+                Some(Err(err)) => {
+                    self.finished = true;
+                    Some(Err(err))
+                }
+                None => {
+                    self.finished = true;
+                    None
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use chrono::{TimeZone, UTC};
+    use std::fs::File;
+    use std::path::Path;
+
+    use super::*;
+    use PlistEvent;
+
+    #[test]
+    fn streaming_parser() {
+        use PlistEvent::*;
+
+        let reader = File::open(&Path::new("./tests/data/xml.plist")).unwrap();
+        let streaming_parser = EventReader::new(reader);
+        let events: Vec<PlistEvent> = streaming_parser.map(|e| e.unwrap()).collect();
+
+        let comparison = &[StartDictionary(None),
+                           StringValue("Author".to_owned()),
+                           StringValue("William Shakespeare".to_owned()),
+                           StringValue("Lines".to_owned()),
+                           StartArray(None),
+                           StringValue("It is a tale told by an idiot,".to_owned()),
+                           StringValue("Full of sound and fury, signifying nothing.".to_owned()),
+                           EndArray,
+                           StringValue("Death".to_owned()),
+                           IntegerValue(1564),
+                           StringValue("Height".to_owned()),
+                           RealValue(1.60),
+                           StringValue("Data".to_owned()),
+                           DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
+                           StringValue("Birthdate".to_owned()),
+                           DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)),
+                           StringValue("Blank".to_owned()),
+                           StringValue("".to_owned()),
+                           EndDictionary];
+
+        assert_eq!(events, comparison);
+    }
+
+    #[test]
+    fn bad_data() {
+        let reader = File::open(&Path::new("./tests/data/xml_error.plist")).unwrap();
+        let streaming_parser = EventReader::new(reader);
+        let events: Vec<_> = streaming_parser.collect();
+
+        assert!(events.last().unwrap().is_err());
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/plist/src/xml/writer.rs.html b/src/plist/src/xml/writer.rs.html new file mode 100644 index 0000000..bc7c990 --- /dev/null +++ b/src/plist/src/xml/writer.rs.html @@ -0,0 +1,614 @@ + + + + + + + + + + writer.rs.html -- source + + + + + + + + + + + + + + + + + +
  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
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+
+use rustc_serialize::base64::{MIME, ToBase64};
+use std::borrow::Cow;
+use std::io::Write;
+use xml_rs::attribute::Attribute;
+use xml_rs::name::Name;
+use xml_rs::namespace::Namespace;
+use xml_rs::writer::{Error as XmlWriterError, EventWriter as XmlEventWriter, EmitterConfig};
+use xml_rs::writer::events::XmlEvent as WriteXmlEvent;
+
+use {Error, EventWriter as PlistEventWriter, PlistEvent, Result};
+
+impl From<XmlWriterError> for Error {
+    fn from(err: XmlWriterError) -> Error {
+        match err {
+            XmlWriterError::Io(err) => Error::Io(err),
+            _ => Error::InvalidData,
+        }
+    }
+}
+
+enum Element {
+    Dictionary(DictionaryState),
+    Array,
+    Root,
+}
+
+enum DictionaryState {
+    ExpectKey,
+    ExpectValue,
+}
+
+pub struct EventWriter<W: Write> {
+    xml_writer: XmlEventWriter<W>,
+    stack: Vec<Element>,
+    // Not very nice
+    empty_namespace: Namespace,
+}
+
+impl<W: Write> EventWriter<W> {
+    pub fn new(writer: W) -> EventWriter<W> {
+        let config = EmitterConfig {
+            line_separator: "\n".into(),
+            indent_string: "    ".into(),
+            perform_indent: true,
+            perform_escaping: true,
+            write_document_declaration: true,
+            normalize_empty_elements: true,
+            cdata_to_characters: true,
+            keep_element_names_stack: false,
+            autopad_comments: true,
+        };
+
+        EventWriter {
+            xml_writer: XmlEventWriter::new_with_config(writer, config),
+            stack: Vec::new(),
+            empty_namespace: Namespace::empty(),
+        }
+    }
+
+    fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<()> {
+        try!(self.start_element(name));
+        try!(self.write_value(value));
+        try!(self.end_element(name));
+        Ok(())
+    }
+
+    fn start_element(&mut self, name: &str) -> Result<()> {
+        try!(self.xml_writer.write(WriteXmlEvent::StartElement {
+            name: Name::local(name),
+            attributes: Cow::Borrowed(&[]),
+            namespace: Cow::Borrowed(&self.empty_namespace),
+        }));
+        Ok(())
+    }
+
+    fn end_element(&mut self, name: &str) -> Result<()> {
+        try!(self.xml_writer.write(WriteXmlEvent::EndElement { name: Some(Name::local(name)) }));
+        Ok(())
+    }
+
+    fn write_value(&mut self, value: &str) -> Result<()> {
+        try!(self.xml_writer.write(WriteXmlEvent::Characters(value)));
+        Ok(())
+    }
+
+    fn maybe_end_plist(&mut self) -> Result<()> {
+        // If there are no more open tags then write the </plist> element
+        if self.stack.len() == 1 {
+            try!(self.end_element("plist"));
+            if let Some(Element::Root) = self.stack.pop() {} else {
+                return Err(Error::InvalidData);
+            }
+        }
+        Ok(())
+    }
+
+    pub fn write(&mut self, event: &PlistEvent) -> Result<()> {
+        <Self as PlistEventWriter>::write(self, event)
+    }
+}
+
+impl<W: Write> PlistEventWriter for EventWriter<W> {
+    fn write(&mut self, event: &PlistEvent) -> Result<()> {
+        match self.stack.pop() {
+            Some(Element::Dictionary(DictionaryState::ExpectKey)) => {
+                match *event {
+                    PlistEvent::StringValue(ref value) => {
+                        try!(self.write_element_and_value("key", &*value));
+                        self.stack.push(Element::Dictionary(DictionaryState::ExpectValue));
+                    }
+                    PlistEvent::EndDictionary => {
+                        try!(self.end_element("dict"));
+                        // We might be closing the last tag here as well
+                        try!(self.maybe_end_plist());
+                    }
+                    _ => return Err(Error::InvalidData),
+                };
+                return Ok(());
+            }
+            Some(Element::Dictionary(DictionaryState::ExpectValue)) => {
+                self.stack.push(Element::Dictionary(DictionaryState::ExpectKey))
+            }
+            Some(other) => self.stack.push(other),
+            None => {
+                let version_name = Name::local("version");
+                let version_attr = Attribute::new(version_name, "1.0");
+
+                try!(self.xml_writer.write(WriteXmlEvent::StartElement {
+                    name: Name::local("plist"),
+                    attributes: Cow::Borrowed(&[version_attr]),
+                    namespace: Cow::Borrowed(&self.empty_namespace),
+                }));
+
+                self.stack.push(Element::Root);
+            }
+        }
+
+        match *event {
+            PlistEvent::StartArray(_) => {
+                try!(self.start_element("array"));
+                self.stack.push(Element::Array);
+            }
+            PlistEvent::EndArray => {
+                try!(self.end_element("array"));
+                if let Some(Element::Array) = self.stack.pop() {} else {
+                    return Err(Error::InvalidData);
+                }
+            }
+
+            PlistEvent::StartDictionary(_) => {
+                try!(self.start_element("dict"));
+                self.stack.push(Element::Dictionary(DictionaryState::ExpectKey));
+            }
+            PlistEvent::EndDictionary => return Err(Error::InvalidData),
+
+            PlistEvent::BooleanValue(true) => {
+                try!(self.start_element("true"));
+                try!(self.end_element("true"));
+            }
+            PlistEvent::BooleanValue(false) => {
+                try!(self.start_element("false"));
+                try!(self.end_element("false"));
+            }
+            PlistEvent::DataValue(ref value) => {
+                let base64_data = value.to_base64(MIME);
+                try!(self.write_element_and_value("data", &base64_data));
+            }
+            PlistEvent::DateValue(ref value) => {
+                let date = format!("{:?}", value);
+                try!(self.write_element_and_value("date", &date));
+            }
+            PlistEvent::IntegerValue(ref value) => {
+                try!(self.write_element_and_value("integer", &value.to_string()))
+            }
+            PlistEvent::RealValue(ref value) => {
+                try!(self.write_element_and_value("real", &value.to_string()))
+            }
+            PlistEvent::StringValue(ref value) => {
+                try!(self.write_element_and_value("string", &*value))
+            }
+        };
+
+        try!(self.maybe_end_plist());
+
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use chrono::{TimeZone, UTC};
+    use std::io::Cursor;
+
+    use super::*;
+
+    #[test]
+    fn streaming_parser() {
+        use PlistEvent::*;
+
+        let plist = &[StartDictionary(None),
+                      StringValue("Author".to_owned()),
+                      StringValue("William Shakespeare".to_owned()),
+                      StringValue("Lines".to_owned()),
+                      StartArray(None),
+                      StringValue("It is a tale told by an idiot,".to_owned()),
+                      StringValue("Full of sound and fury, signifying nothing.".to_owned()),
+                      EndArray,
+                      StringValue("Death".to_owned()),
+                      IntegerValue(1564),
+                      StringValue("Height".to_owned()),
+                      RealValue(1.60),
+                      StringValue("Data".to_owned()),
+                      DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
+                      StringValue("Birthdate".to_owned()),
+                      DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)),
+                      EndDictionary];
+
+        let mut cursor = Cursor::new(Vec::new());
+
+        {
+            let mut plist_w = EventWriter::new(&mut cursor);
+
+            for item in plist {
+                plist_w.write(item).unwrap();
+            }
+        }
+
+        let comparison = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<plist version=\"1.0\">
+    <dict>
+        <key>Author</key>
+        <string>William Shakespeare</string>
+        <key>Lines</key>
+        <array>
+            <string>It is a tale told by an idiot,</string>
+            <string>Full of sound and fury, signifying nothing.</string>
+        </array>
+        <key>Death</key>
+        <integer>1564</integer>
+        <key>Height</key>
+        <real>1.6</real>
+        <key>Data</key>
+        <data>AAAAvgAAAAMAAAAeAAAA</data>
+        <key>Birthdate</key>
+        <date>1981-05-16T11:32:06Z</date>
+    </dict>
+</plist>";
+
+        let s = String::from_utf8(cursor.into_inner()).unwrap();
+
+        assert_eq!(s, comparison);
+    }
+}
+
+
+ + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3