use base64; use line_wrap; use std::{borrow::Cow, io::Write}; use xml_rs::{
name::Name,
namespace::Namespace,
writer::{EmitterConfig, Error as XmlWriterError, EventWriter, XmlEvent},
};
// If there are no more open tags then write the </plist> element ifself.stack.is_empty() { // We didn't tell the xml_writer about the <plist> tag so we'll skip telling it // about the </plist> tag as well. self.xml_writer
.inner_mut()
.write_all(b"\n</plist>")
.map_err(error::from_io_without_position)?; self.xml_writer
.inner_mut()
.flush()
.map_err(error::from_io_without_position)?;
}
fn base64_encode_plist(data: &[u8], indent: usize) -> String { // XML plist data elements are always formatted by apple tools as // <data> // AAAA..AA (68 characters per line) // </data> // Allocate space for base 64 string and line endings up front const LINE_LEN: usize = 68; letmut line_ending = Vec::with_capacity(1 + indent);
line_ending.push(b'\n');
(0..indent).for_each(|_| line_ending.push(b'\t'));
// Find the max length of `data` encoded as a base 64 string with padding let base64_max_string_len = data.len() * 4 / 3 + 4;
// Find the max length of the formatted base 64 string as: max length of the base 64 string // + line endings and indents at the start of the string and after every line let base64_max_string_len_with_formatting =
base64_max_string_len + (2 + base64_max_string_len / LINE_LEN) * line_ending.len();
// Start output with a line ending and indent
output[..line_ending.len()].copy_from_slice(&line_ending);
// Encode `data` as a base 64 string let base64_string_len =
base64::encode_config_slice(data, base64::STANDARD, &mut output[line_ending.len()..]);
// Line wrap the base 64 encoded string let line_wrap_len = line_wrap::line_wrap(
&mut output[line_ending.len()..],
base64_string_len,
LINE_LEN,
&line_wrap::SliceLineEnding::new(&line_ending),
);
// Add the final line ending and indent
output[line_ending.len() + base64_string_len + line_wrap_len..][..line_ending.len()]
.copy_from_slice(&line_ending);
// Ensure output is the correct length
output.truncate(base64_string_len + line_wrap_len + 2 * line_ending.len());
String::from_utf8(output).expect("base 64 string must be valid utf8")
}
#[cfg(test)] mod tests { use std::io::Cursor;
usesuper::*; usecrate::stream::Event;
#[test] fn streaming_parser() { let plist = &[
Event::StartDictionary(None),
Event::String("Author".into()),
Event::String("William Shakespeare".into()),
Event::String("Lines".into()),
Event::StartArray(None),
Event::String("It is a tale told by an idiot,".into()),
Event::String("Full of sound and fury, signifying nothing.".into()),
Event::Data((0..128).collect::<Vec<_>>().into()),
Event::EndCollection,
Event::String("Death".into()),
Event::Integer(1564.into()),
Event::String("Height".into()),
Event::Real(1.60),
Event::String("Data".into()),
Event::Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0].into()),
Event::String("Birthdate".into()),
Event::Date(super::Date::from_rfc3339("1981-05-16T11:32:06Z").unwrap()),
Event::String("Comment".into()),
Event::String("2 < 3".into()), // make sure characters are escaped
Event::String("BiggestNumber".into()),
Event::Integer(18446744073709551615u64.into()),
Event::String("SmallestNumber".into()),
Event::Integer((-9223372036854775808i64).into()),
Event::String("IsTrue".into()),
Event::Boolean(true),
Event::String("IsNotFalse".into()),
Event::Boolean(false),
Event::EndCollection,
];
letmut cursor = Cursor::new(Vec::new());
{ letmut plist_w = XmlWriter::new(&mut cursor);
for item in plist {
plist_w.write(item).unwrap();
}
}
let comparison = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
\t<key>Author</key>
\t<string>William Shakespeare</string>
\t<key>Lines</key>
\t<array>
\t\t<string>It is a tale told by an idiot,</string>
\t\t<string>Full of sound and fury, signifying nothing.</string>
\t\t<data>
\t\tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEy
\t\tMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2Rl
\t\tZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=
\t\t</data>
\t</array>
\t<key>Death</key>
\t<integer>1564</integer>
\t<key>Height</key>
\t<real>1.6</real>
\t<key>Data</key>
\t<data>
\tAAAAvgAAAAMAAAAeAAAA
\t</data>
\t<key>Birthdate</key>
\t<date>1981-05-16T11:32:06Z</date>
\t<key>Comment</key>
\t<string>2 < 3</string>
\t<key>BiggestNumber</key>
\t<integer>18446744073709551615</integer>
\t<key>SmallestNumber</key>
\t<integer>-9223372036854775808</integer>
\t<key>IsTrue</key>
\t<true/>
\t<key>IsNotFalse</key>
\t<false/>
</dict>
</plist>";
let s = String::from_utf8(cursor.into_inner()).unwrap();
assert_eq!(s, comparison);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.