feat: add JSON coercion support for non-JSON plist types#309
feat: add JSON coercion support for non-JSON plist types#309calilkhalil wants to merge 1 commit into
Conversation
- Add PLIST_OPT_COERCE option to coerce PLIST_DATE, PLIST_DATA, and PLIST_UID to JSON-compatible types (ISO 8601 strings, Base64 strings, and integers) - Add plist_to_json_ex() function with coercion parameter - Update plist_write_to_string() and plist_write_to_stream() to support coercion option - Add --coerce flag to plistutil for JSON output - Create plist2json symlink that automatically enables coercion when invoked
325e2c8 to
2d75089
Compare
|
Ok so I am almost done with the changes, and I definitely like the idea about PLIST_OPT_COERCE option. But I feel like rather having a plist_err_t plist_to_json_with_options(plist_t plist, char **plist_json, uint32_t* length, plist_write_options_t options);That essentially only has one parameter for options. But, we already have plist_err_t plist_write_to_string(plist_t plist, char **output, uint32_t* length, plist_format_t format, plist_write_options_t options);Which is essentially the same except for the additional Would this satisfy your needs? |
|
Yes, that works perfectly for my use case. I should have noticed that
|
|
Forget what I said, I need to add a |
|
lol, fair enough the abstraction layers have a way of pulling you back in. Let me know if there's anything I can help with on my end! |
|
See 3edac28 |

Add
--coerceoption andplist2jsonsymlinkProblem
Converting plist files that contain
date,data, orUIDnodes to JSONcurrently fails with
PLIST_ERR_FORMATbecause these types have no nativeJSON representation. This is by design, the JSON writer enforces strict type
compatibility, but in practice it makes JSON output unusable for the majority
of real-world Apple plist files, which almost always contain at least one
dateordatavalue.A common example is Safari's
Downloads.plist:Users currently work around this with Python one-liners:
This defeats the purpose of having a dedicated plist conversion tool.
Solution
This patch adds opt-in coercion of non-JSON plist types to JSON-compatible
representations, following the same conventions used by Apple's own
plutil -convert jsonand by Python'splistlib:PLIST_DATE"2025-03-08T14:03:43Z")xplist.cPLIST_DATAbase64encode()frombase64.cPLIST_UIDxplist.cThe coercion is strictly opt-in and does not change existing behavior in
any way. Without the flag, the JSON writer continues to reject these types
exactly as before.
Changes
Library (
src/jplist.c,include/plist/plist.h)PLIST_OPT_COERCE = 1 << 4toplist_write_options_tplist_to_json_ex()with an additionalint coerceparameterplist_to_json()remains unchanged (delegates toplist_to_json_exwithcoerce=0)node_to_jsonand_node_estimate_sizeare updated to handle thethree new types when coerce is enabled
plist_write_to_stringandplist_write_to_streaminplist.croutePLIST_OPT_COERCEtoplist_to_json_exThe date formatting reuses the exact same
gmtime64_r+strftime+Time64_Tcode path fromxplist.c, ensuring consistent ISO 8601 outputacross formats. The base64 encoding uses the existing
base64encode()frombase64.c. No new dependencies are introduced.Tool (
tools/plistutil.c,tools/Makefile.am)-C/--coercecommand-line optionargv[0]detection: when invoked asplist2json, the toolautomatically implies
-f json --coerceMakefile.aminstalls aplist2json → plistutilsymlink viainstall-exec-hook(same pattern used by gzip/gunzip, vim/vi, busybox)Usage
Testing
Tested with a real-world Safari
Downloads.plistcontainingdateanddatanodes:Verified:
plistutil -f jsonwithout--coercestill returnsPLIST_ERR_FORMATon plist files with date/data nodes (backward compatibility preserved)
plistutil -f json -Cproduces valid JSON (validated withjq empty)-c(compact) and-C(coerce) compose correctlyargv[0]detection works via symlinkwithout
--coercedict) are unaffected by the change