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