Skip to content

Commit

Permalink
Add ASCII plist reader
Browse files Browse the repository at this point in the history
The reader currently parses OpenStep format ASCII plists but it may be
extended to the GnuStep format in the future so is called AsciiReader.

Co-authored-by: Francois Stephany <[email protected]>
Co-authored-by: Ed Barnard <[email protected]>
  • Loading branch information
3 people authored Jun 30, 2024
1 parent cb89f38 commit 45d9a58
Show file tree
Hide file tree
Showing 14 changed files with 5,626 additions and 49 deletions.
4 changes: 4 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ git = "https://github.com/rust-fuzz/libfuzzer-sys.git"
[workspace]
members = ["."]

[[bin]]
name = "ascii_reader"
path = "fuzz_targets/ascii_reader.rs"

[[bin]]
name = "binary_reader"
path = "fuzz_targets/binary_reader.rs"
Expand Down
14 changes: 14 additions & 0 deletions fuzz/fuzz_targets/ascii_reader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate plist;

use plist::stream::AsciiReader;
use plist::Value;
use std::io::Cursor;

fuzz_target!(|data: &[u8]| {
let cursor = Cursor::new(data);
let reader = AsciiReader::new(cursor);
let _ = Value::from_events(reader);
});
7 changes: 7 additions & 0 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,13 @@ pub fn from_reader<R: Read + Seek, T: de::DeserializeOwned>(reader: R) -> Result
de::Deserialize::deserialize(&mut de)
}

/// Deserializes an instance of type `T` from a byte stream containing an ASCII encoded plist.
pub fn from_reader_ascii<R: Read, T: de::DeserializeOwned>(reader: R) -> Result<T, Error> {
let reader = stream::AsciiReader::new(reader);
let mut de = Deserializer::new(reader);
de::Deserialize::deserialize(&mut de)
}

/// Deserializes an instance of type `T` from a byte stream containing an XML encoded plist.
pub fn from_reader_xml<R: Read, T: de::DeserializeOwned>(reader: R) -> Result<T, Error> {
let reader = stream::XmlReader::new(reader);
Expand Down
6 changes: 6 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ pub(crate) enum ErrorKind {
found: EventKind,
},

// Ascii format-specific errors
UnclosedString,
IncompleteComment,
InvalidUtf8AsciiStream,
InvalidOctalString,

// Xml format-specific errors
UnclosedXmlElement,
UnexpectedXmlCharactersExpectedElement,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ mod ser;
pub use self::{de::Deserializer, ser::Serializer};
#[cfg(feature = "serde")]
pub use self::{
de::{from_bytes, from_file, from_reader, from_reader_xml, from_value},
de::{from_bytes, from_file, from_reader, from_reader_ascii, from_reader_xml, from_value},
ser::{
to_file_binary, to_file_xml, to_value, to_writer_binary, to_writer_xml,
to_writer_xml_with_options,
Expand Down
63 changes: 63 additions & 0 deletions src/serde_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,69 @@ fn deserialize_dictionary_binary_nskeyedarchiver() {
assert_eq!(version, 100000);
}

fn try_parse_xml(bom: bool, whitespace: bool, decl: bool, comment: bool, doctype: bool) -> bool {
#[derive(Deserialize)]
struct LayerinfoData {
color: Option<String>,
}

let mut data = Vec::new();
if bom {
// The UTF-8 byte order mark
data.extend(b"\xef\xbb\xbf");
}

if whitespace {
data.extend(b"\r\n\t ");
}

if decl {
data.extend(br#"<?xml version="1.0" encoding="UTF-8"?>"#);
}

if comment {
data.extend(br#"<!-- hello -->"#);
}

if doctype {
data.extend(br#"<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">"#);
}

data.extend(
br#"<plist version="1.0">
<dict>
<key>color</key>
<string>1,0.75,0,0.7</string>
</dict>
</plist>
"#,
);

if let Ok(lib_dict) = crate::from_bytes::<LayerinfoData>(&data) {
lib_dict.color.unwrap() == "1,0.75,0,0.7"
} else {
false
}
}

#[test]
fn xml_detection() {
for bom in [true, false] {
for whitespace in [true, false] {
for decl in [true, false] {
for comment in [true, false] {
for doctype in [true, false] {
assert!(
try_parse_xml(bom, whitespace, decl, comment, doctype),
"bom={bom}, whitespace={whitespace}, decl={decl}, comment={comment}, doctype={doctype}"
);
}
}
}
}
}
}

#[test]
fn dictionary_deserialize_dictionary_in_struct() {
// Example from <https://github.com/ebarnard/rust-plist/issues/54>
Expand Down
Loading

0 comments on commit 45d9a58

Please sign in to comment.