Remove support for PropList data nodes.

This type of PropList entry appears to be completely unused, so let's be rid of
it. This can be reversed in the future if we do want more complete support for
property lists, but for now it's code that we don't need.
This commit is contained in:
2025-10-16 22:00:18 -04:00
parent 8747ac65e7
commit 578eb62d47
4 changed files with 5 additions and 199 deletions

View File

@@ -732,10 +732,6 @@ WMPropList* WMCreatePLArray(WMPropList *elem, ...);
WMPropList* WMCreatePLString(const char *str);
WMPropList* WMCreatePLData(WMData *data);
WMPropList* WMCreatePLDataWithBytes(const unsigned char *bytes, unsigned int length);
WMPropList* WMCreatePLArrayFromSlice(WMPropList *elems, unsigned int length);
WMPropList* WMCreateEmptyPLArray();
@@ -780,8 +776,6 @@ int WMGetPropListItemCount(WMPropList *plist);
Bool WMIsPLString(WMPropList *plist);
Bool WMIsPLData(WMPropList *plist);
Bool WMIsPLArray(WMPropList *plist);
Bool WMIsPLDictionary(WMPropList *plist);

View File

@@ -49,8 +49,6 @@ pub enum Node {
/// It would be better for this to be a `String`, but the C interface
/// requires borrows of C-style strings.
String(CString),
/// Binary data.
Data(Vec<u8>),
/// Array of child `PropList`s.
Array(Vec<PropList>),
/// `PropList`-keyed table of child `PropList`s. Keys should only have
@@ -63,7 +61,6 @@ impl hash::Hash for Node {
fn hash<H: hash::Hasher>(&self, h: &mut H) {
match self {
Node::String(s) => s.hash(h),
Node::Data(d) => d.hash(h),
Node::Array(a) => {
for p in a {
p.hash(h);
@@ -313,7 +310,6 @@ impl PropList {
pub fn deep_clone(&self) -> Self {
match &*self.0.borrow() {
Node::String(s) => PropList::new(Node::String(s.clone())),
Node::Data(d) => PropList::new(Node::Data(d.clone())),
Node::Array(items) => {
PropList::new(Node::Array(items.iter().map(|x| x.deep_clone()).collect()))
}
@@ -357,14 +353,14 @@ impl PropList {
}
pub mod ffi {
use crate::{data::Data, find_file::path_from_cstr, memory};
use crate::{find_file::path_from_cstr, memory};
use super::{
merge_deep, merge_shallow, parser, subtract_deep, subtract_shallow, Node, PropList,
};
use std::{
collections::HashMap, ffi::{c_char, c_int, c_uchar, c_uint, CStr, CString, OsString}, ptr, str::FromStr
collections::HashMap, ffi::{c_char, c_int, c_uint, CStr, CString, OsString}, ptr, str::FromStr
};
#[unsafe(no_mangle)]
@@ -376,27 +372,6 @@ pub mod ffi {
Box::leak(Box::new(PropList::new(Node::String(s.into()))))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreatePLData(data: *mut Data) -> *mut PropList {
if data.is_null() {
return ptr::null_mut();
}
let data = unsafe { &*data };
data.with_bytes(|b| Box::leak(Box::new(PropList::new(Node::Data(Vec::from(b))))))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreatePLDataWithBytes(
bytes: *const c_uchar,
length: c_uint,
) -> *mut PropList {
if bytes.is_null() {
return ptr::null_mut();
}
let bytes = unsafe { &*ptr::slice_from_raw_parts(bytes.cast::<u8>(), length as usize) };
Box::leak(Box::new(PropList::new(Node::Data(Vec::from(bytes)))))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreatePLArrayFromSlice(
elems: *mut PropList,
@@ -630,18 +605,6 @@ pub mod ffi {
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMIsPLData(plist: *mut PropList) -> c_int {
if plist.is_null() {
return 0;
}
let plist = unsafe { &*plist };
match &*plist.0.borrow() {
Node::Data(_) => 1,
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMIsPLArray(plist: *mut PropList) -> c_int {
if plist.is_null() {

View File

@@ -20,7 +20,7 @@ use nom::{
character::complete::{char, multispace0, none_of, satisfy},
combinator::{cut, eof, fail, map, map_res, opt},
error::context,
multi::{fold_many0, many0, many1, many_m_n, separated_list0},
multi::{fold_many0, many1, many_m_n, separated_list0},
sequence::{delimited, preceded, terminated},
AsChar, Finish, IResult, Input, Parser,
};
@@ -32,7 +32,7 @@ fn read_dictionary_key<I: Input<Item: AsChar>>(input: I) -> IResult<I, PropList,
preceded(
multispace0,
terminated(
alt((read_data, read_string)),
read_string,
cut(context(
"looking for '=' after dictionary key",
(multispace0, char('='), multispace0),
@@ -113,48 +113,6 @@ fn read_array<I: Input<Item: AsChar>>(input: I) -> IResult<I, PropList, VerboseE
.parse(input)
}
fn read_data_byte<I: Input<Item: AsChar>>(input: I) -> IResult<I, u8, VerboseError<I>> {
map(
delimited(
multispace0,
(
context(
"looking for first hex value",
satisfy(|c: char| c.is_ascii_hexdigit()),
),
cut(context(
"looking for second hex value",
satisfy(|c: char| c.is_ascii_hexdigit()),
)),
),
multispace0,
),
|(upper, lower)| {
let s = &[upper as u8, lower as u8];
// Safety: upper and lower are ASCII hexdigits, so they
// should fit into a str without validation and provide
// exactly 8 bits of value.
u8::from_str_radix(unsafe { str::from_utf8_unchecked(s) }, 16).unwrap()
},
)
.parse(input)
}
fn read_data<I: Input<Item: AsChar>>(input: I) -> IResult<I, PropList, VerboseError<I>> {
map(
delimited(
(multispace0, char('<')),
many0(read_data_byte),
cut(context(
"looking for data to end with '>'",
(multispace0, char('>')),
)),
),
|bytes: Vec<u8>| PropList::new(Node::Data(bytes)),
)
.parse(input)
}
fn unescape_character(c: char) -> char {
match c {
'\\' => '\\',
@@ -300,7 +258,7 @@ fn read_string<I: Input<Item: AsChar>>(input: I) -> IResult<I, PropList, Verbose
fn read_prop_list<I: Input<Item: AsChar>>(input: I) -> IResult<I, PropList, VerboseError<I>> {
delimited(
multispace0,
alt((read_array, read_data, read_dictionary, read_string)),
alt((read_array, read_dictionary, read_string)),
multispace0,
)
.parse(input)
@@ -363,60 +321,6 @@ mod test {
PropList::new(Node::String(CString::new(s.as_bytes()).unwrap()))
}
#[test]
fn parse_data() {
let plist = from_str("<deadbeef>").unwrap();
assert_eq!(
plist,
PropList::new(Node::Data(vec![0xde, 0xad, 0xbe, 0xef]))
);
}
#[test]
fn error_unclosed_data() {
let e = from_str("<deadbeef").unwrap_err();
assert_eq!(
e,
r#"0: at line 1, in looking for data to end with '>':
<deadbeef
^
"#
);
let e = from_str(
r#"(
<deadbeef
,
{
hello = world;
},
)"#,
)
.unwrap_err();
assert_eq!(
e,
r#"0: at line 3, in looking for data to end with '>':
,
^
"#
);
}
#[test]
fn error_incomplete_data_byte() {
let e = from_str("<deadb").unwrap_err();
assert_eq!(
e,
r#"0: at line 1, in looking for second hex value:
<deadb
^
"#
);
}
#[test]
fn parse_string() {
let plist = from_str("foobar").unwrap();

View File

@@ -49,30 +49,6 @@ pub(crate) struct Display<N: Deref<Target = Node>> {
pub(crate) node: N,
}
/// Quick and dirty single-branch lookup mapping `b` to a hex character. Only
/// valid for `b` in `[0, 15]`.
fn byte_char(b: u8) -> char {
match b {
0 => '0',
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
6 => '6',
7 => '7',
8 => '8',
9 => '9',
10 => 'a',
11 => 'b',
12 => 'c',
13 => 'd',
14 => 'e',
15 => 'f',
_ => unreachable!(),
}
}
impl<N: Deref<Target = Node>> Display<N> {
/// Writes whitespace to `f` for the current level of indentation.
fn write_indent(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -83,32 +59,6 @@ impl<N: Deref<Target = Node>> Display<N> {
}
}
/// Writes a hexadecimal representation of `bytes` to `f`, splitting `bytes` up
/// into space-delimited 32-bit quartets for readability.
fn write_data_bytes(bytes: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
fn write(b: u8, f: &mut fmt::Formatter) -> fmt::Result {
let upper = (b >> 3) as u8;
let lower = (b & 0x0F) as u8;
write!(f, "{}", byte_char(upper))?;
write!(f, "{}", byte_char(lower))
}
let mut chunks = bytes.chunks(4);
if let Some(first) = chunks.next() {
for b in first {
write(*b, f)?;
}
}
for seg in chunks {
f.write_char(' ')?;
for b in seg {
write(*b, f)?;
}
}
Ok(())
}
/// Writes `s` to `f`, backslash-escaping special characters as appropriate for
/// a quoted property list string.
fn write_escaped_string(s: &str, f: &mut fmt::Formatter) -> fmt::Result {
@@ -218,11 +168,6 @@ impl<N: Deref<Target = Node>> fmt::Display for Display<N> {
self.write_indent(f)?;
f.write_char(')')?;
}
Node::Data(bytes) => {
write!(f, "<")?;
write_data_bytes(bytes, f)?;
write!(f, ">")?;
}
Node::Dictionary(items) if items.is_empty() => write!(f, "{{}}")?,
Node::Dictionary(items) if self.inline != Inline::No => {
// Try to fit everything in one line.