1mod binary_reader;
4pub use self::binary_reader::BinaryReader;
5
6mod binary_writer;
7pub use self::binary_writer::BinaryWriter;
8
9mod xml_reader;
10pub use self::xml_reader::XmlReader;
11
12mod xml_writer;
13pub use self::xml_writer::XmlWriter;
14#[cfg(feature = "serde")]
15pub(crate) use xml_writer::encode_data_base64 as xml_encode_data_base64;
16
17mod ascii_reader;
18pub use self::ascii_reader::AsciiReader;
19
20use std::{
21 borrow::Cow,
22 io::{self, BufReader, Read, Seek},
23 vec,
24};
25
26use crate::{
27 Date, Integer, Uid, Value, dictionary,
28 error::{Error, ErrorKind},
29};
30
31#[derive(Clone, Debug, PartialEq)]
55#[non_exhaustive]
56pub enum Event<'a> {
57 StartArray(Option<u64>),
60 StartDictionary(Option<u64>),
61 EndCollection,
62
63 Boolean(bool),
64 Data(Cow<'a, [u8]>),
65 Date(Date),
66 Integer(Integer),
67 Real(f64),
68 String(Cow<'a, str>),
69 Uid(Uid),
70}
71
72pub type OwnedEvent = Event<'static>;
77
78pub struct Events<'a> {
80 stack: Vec<StackItem<'a>>,
81}
82
83enum StackItem<'a> {
84 Root(&'a Value),
85 Array(std::slice::Iter<'a, Value>),
86 Dict(dictionary::Iter<'a>),
87 DictValue(&'a Value),
88}
89
90#[derive(Clone, Debug)]
92pub struct XmlWriteOptions {
93 root_element: bool,
94 indent_char: u8,
95 indent_count: usize,
96}
97
98impl XmlWriteOptions {
99 #[deprecated(since = "1.4.0", note = "please use `indent` instead")]
109 pub fn indent_string(self, indent_str: impl Into<Cow<'static, str>>) -> Self {
110 let indent_str = indent_str.into();
111 let indent_str = indent_str.as_ref();
112
113 if indent_str.is_empty() {
114 return self.indent(0, 0);
115 }
116
117 assert!(indent_str.is_ascii(), "indent str must be ascii");
118 let indent_str = indent_str.as_bytes();
119 assert!(
120 indent_str.iter().all(|chr| chr == &indent_str[0]),
121 "indent str must consist of a single repeating character"
122 );
123
124 self.indent(indent_str[0], indent_str.len())
125 }
126
127 pub fn indent(mut self, indent_char: u8, indent_count: usize) -> Self {
133 self.indent_char = indent_char;
134 self.indent_count = indent_count;
135 self
136 }
137
138 pub fn root_element(mut self, write_root: bool) -> Self {
151 self.root_element = write_root;
152 self
153 }
154}
155
156impl Default for XmlWriteOptions {
157 fn default() -> Self {
158 XmlWriteOptions {
159 indent_char: b'\t',
160 indent_count: 1,
161 root_element: true,
162 }
163 }
164}
165
166impl<'a> Events<'a> {
167 pub(crate) fn new(value: &'a Value) -> Events<'a> {
168 Events {
169 stack: vec![StackItem::Root(value)],
170 }
171 }
172}
173
174impl<'a> Iterator for Events<'a> {
175 type Item = Event<'a>;
176
177 fn next(&mut self) -> Option<Event<'a>> {
178 fn handle_value<'c, 'b: 'c>(
179 value: &'b Value,
180 stack: &'c mut Vec<StackItem<'b>>,
181 ) -> Event<'b> {
182 match value {
183 Value::Array(array) => {
184 let len = array.len();
185 let iter = array.iter();
186 stack.push(StackItem::Array(iter));
187 Event::StartArray(Some(len as u64))
188 }
189 Value::Dictionary(dict) => {
190 let len = dict.len();
191 let iter = dict.into_iter();
192 stack.push(StackItem::Dict(iter));
193 Event::StartDictionary(Some(len as u64))
194 }
195 Value::Boolean(value) => Event::Boolean(*value),
196 Value::Data(value) => Event::Data(Cow::Borrowed(value)),
197 Value::Date(value) => Event::Date(*value),
198 Value::Real(value) => Event::Real(*value),
199 Value::Integer(value) => Event::Integer(*value),
200 Value::String(value) => Event::String(Cow::Borrowed(value.as_str())),
201 Value::Uid(value) => Event::Uid(*value),
202 }
203 }
204
205 Some(match self.stack.pop()? {
206 StackItem::Root(value) | StackItem::DictValue(value) => {
207 handle_value(value, &mut self.stack)
208 }
209 StackItem::Array(mut array) => {
210 if let Some(value) = array.next() {
211 self.stack.push(StackItem::Array(array));
213 handle_value(value, &mut self.stack)
214 } else {
215 Event::EndCollection
216 }
217 }
218 StackItem::Dict(mut dict) => {
219 if let Some((key, value)) = dict.next() {
220 self.stack.push(StackItem::Dict(dict));
222 self.stack.push(StackItem::DictValue(value));
224 Event::String(Cow::Borrowed(key))
226 } else {
227 Event::EndCollection
228 }
229 }
230 })
231 }
232}
233
234pub struct Reader<R: Read + Seek>(ReaderInner<R>);
235
236enum ReaderInner<R: Read + Seek> {
237 Uninitialized(Option<R>),
238 Binary(BinaryReader<R>),
239 Xml(XmlReader<BufReader<R>>),
240 Ascii(AsciiReader<BufReader<R>>),
241}
242
243impl<R: Read + Seek> Reader<R> {
244 pub fn new(reader: R) -> Reader<R> {
245 Reader(ReaderInner::Uninitialized(Some(reader)))
246 }
247
248 fn init(&mut self, mut reader: R) -> Result<Option<OwnedEvent>, Error> {
249 if let Err(err) = reader.rewind().map_err(from_io_offset_0) {
251 self.0 = ReaderInner::Uninitialized(Some(reader));
252 return Err(err);
253 }
254
255 match Reader::is_binary(&mut reader) {
257 Ok(true) => {
258 self.0 = ReaderInner::Binary(BinaryReader::new(reader));
259 return self.next().transpose();
260 }
261 Ok(false) => (),
262 Err(err) => {
263 self.0 = ReaderInner::Uninitialized(Some(reader));
264 return Err(err);
265 }
266 }
267
268 let mut xml_reader = XmlReader::new(BufReader::new(reader));
272 let mut reader = match xml_reader.next() {
273 res @ (Some(Ok(_)) | None) => {
274 self.0 = ReaderInner::Xml(xml_reader);
275 return res.transpose();
276 }
277 Some(Err(err)) if xml_reader.xml_doc_started() => {
278 self.0 = ReaderInner::Uninitialized(Some(xml_reader.into_inner().into_inner()));
279 return Err(err);
280 }
281 Some(Err(_)) => xml_reader.into_inner(),
282 };
283
284 if let Err(err) = reader.rewind().map_err(from_io_offset_0) {
286 self.0 = ReaderInner::Uninitialized(Some(reader.into_inner()));
287 return Err(err);
288 }
289
290 let mut ascii_reader = AsciiReader::new(reader);
292 match ascii_reader.next() {
293 res @ (Some(Ok(_)) | None) => {
294 self.0 = ReaderInner::Ascii(ascii_reader);
295 res.transpose()
296 }
297 Some(Err(err)) => {
298 self.0 = ReaderInner::Uninitialized(Some(ascii_reader.into_inner().into_inner()));
299 Err(err)
300 }
301 }
302 }
303
304 fn is_binary(reader: &mut R) -> Result<bool, Error> {
305 let mut magic = [0; 8];
306 reader.read_exact(&mut magic).map_err(from_io_offset_0)?;
307 reader.rewind().map_err(from_io_offset_0)?;
308
309 Ok(&magic == b"bplist00")
310 }
311}
312
313impl<R: Read + Seek> Iterator for Reader<R> {
314 type Item = Result<OwnedEvent, Error>;
315
316 fn next(&mut self) -> Option<Result<OwnedEvent, Error>> {
317 match self.0 {
318 ReaderInner::Xml(ref mut parser) => parser.next(),
319 ReaderInner::Binary(ref mut parser) => parser.next(),
320 ReaderInner::Ascii(ref mut parser) => parser.next(),
321 ReaderInner::Uninitialized(ref mut reader) => {
322 let reader = reader.take().unwrap();
323 self.init(reader).transpose()
324 }
325 }
326 }
327}
328
329fn from_io_offset_0(err: io::Error) -> Error {
330 ErrorKind::Io(err).with_byte_offset(0)
331}
332
333pub trait Writer: private::Sealed {
335 fn write(&mut self, event: Event) -> Result<(), Error> {
336 match event {
337 Event::StartArray(len) => self.write_start_array(len),
338 Event::StartDictionary(len) => self.write_start_dictionary(len),
339 Event::EndCollection => self.write_end_collection(),
340 Event::Boolean(value) => self.write_boolean(value),
341 Event::Data(value) => self.write_data(value),
342 Event::Date(value) => self.write_date(value),
343 Event::Integer(value) => self.write_integer(value),
344 Event::Real(value) => self.write_real(value),
345 Event::String(value) => self.write_string(value),
346 Event::Uid(value) => self.write_uid(value),
347 }
348 }
349
350 fn write_start_array(&mut self, len: Option<u64>) -> Result<(), Error>;
351 fn write_start_dictionary(&mut self, len: Option<u64>) -> Result<(), Error>;
352 fn write_end_collection(&mut self) -> Result<(), Error>;
353
354 fn write_boolean(&mut self, value: bool) -> Result<(), Error>;
355 fn write_data(&mut self, value: Cow<[u8]>) -> Result<(), Error>;
356 fn write_date(&mut self, value: Date) -> Result<(), Error>;
357 fn write_integer(&mut self, value: Integer) -> Result<(), Error>;
358 fn write_real(&mut self, value: f64) -> Result<(), Error>;
359 fn write_string(&mut self, value: Cow<str>) -> Result<(), Error>;
360 fn write_uid(&mut self, value: Uid) -> Result<(), Error>;
361}
362
363pub(crate) mod private {
364 use std::io::Write;
365
366 pub trait Sealed {}
367
368 impl<W: Write> Sealed for super::BinaryWriter<W> {}
369 impl<W: Write> Sealed for super::XmlWriter<W> {}
370}
371
372#[cfg(test)]
373mod tests {
374 use std::fs::File;
375
376 use super::{Event::*, *};
377
378 const ANIMALS_PLIST_EVENTS: &[Event] = &[
379 StartDictionary(None),
380 String(Cow::Borrowed("AnimalColors")),
381 StartDictionary(None),
382 String(Cow::Borrowed("lamb")), String(Cow::Borrowed("black")),
384 String(Cow::Borrowed("pig")), String(Cow::Borrowed("pink")),
386 String(Cow::Borrowed("worm")), String(Cow::Borrowed("pink")),
388 EndCollection,
389 String(Cow::Borrowed("AnimalSmells")),
390 StartDictionary(None),
391 String(Cow::Borrowed("lamb")), String(Cow::Borrowed("lambish")),
393 String(Cow::Borrowed("pig")), String(Cow::Borrowed("piggish")),
395 String(Cow::Borrowed("worm")), String(Cow::Borrowed("wormy")),
397 EndCollection,
398 String(Cow::Borrowed("AnimalSounds")),
399 StartDictionary(None),
400 String(Cow::Borrowed("Lisa")), String(Cow::Borrowed("Why is the worm talking like a lamb?")),
402 String(Cow::Borrowed("lamb")), String(Cow::Borrowed("baa")),
404 String(Cow::Borrowed("pig")), String(Cow::Borrowed("oink")),
406 String(Cow::Borrowed("worm")), String(Cow::Borrowed("baa")),
408 EndCollection,
409 EndCollection,
410 ];
411
412 #[test]
413 fn autodetect_binary() {
414 let reader = File::open("./tests/data/binary.plist").unwrap();
415 let mut streaming_parser = Reader::new(reader);
416 let events: Result<Vec<_>, _> = streaming_parser.by_ref().collect();
417
418 assert!(matches!(streaming_parser.0, ReaderInner::Binary(_)));
419 assert!(events.is_ok());
421 }
422
423 #[test]
424 fn autodetect_xml() {
425 let reader = File::open("./tests/data/xml-animals.plist").unwrap();
426 let mut streaming_parser = Reader::new(reader);
427 let events: Result<Vec<_>, _> = streaming_parser.by_ref().collect();
428
429 assert!(matches!(streaming_parser.0, ReaderInner::Xml(_)));
430 assert_eq!(events.unwrap(), ANIMALS_PLIST_EVENTS);
431 }
432
433 #[test]
434 fn autodetect_ascii() {
435 let reader = File::open("./tests/data/ascii-animals.plist").unwrap();
436 let mut streaming_parser = Reader::new(reader);
437 let events: Result<Vec<_>, _> = streaming_parser.by_ref().collect();
438
439 assert!(matches!(streaming_parser.0, ReaderInner::Ascii(_)));
440 assert_eq!(events.unwrap(), ANIMALS_PLIST_EVENTS);
441 }
442}