plutil(1)
does: (which, honestly, isn't much)./usr/libexec/PlistBuddy
: because it's only friendly to MacOS users, and even that, barely.plutil(1)
's -p
switch, but more readily machine readable and grep(1)
-friendly.plutil(1)
and the code in CFBinaryPlist.c
require JCOLOR=1
as with the rest of my tools. And export/setenv
to apply as default. Note when piping, you'll need less -R
, rather than more
. Colors will identify the datatypes.morpheus@Zephyr (~/Documents/Work/SimPLISTic) %JCOLOR=1 ./jlutil /System/Library/LaunchDaemons/com.apple.syslogd.plist 14:46 HopefullyExitsLast: true JetsamProperties: JetsamPriority: -49 JetsamMemoryLimit: 300 EnvironmentVariables: ASL_DISABLE: 1 POSIXSpawnType: Adaptive MachServices: com.apple.system.logger: ResetAtClose: true EnableTransactions: true ProgramArguments[0]: /usr/sbin/syslogd Sockets: BSDSystemLogger: SockPathMode: 438 SockPathName: /var/run/syslog SockType: dgram OnDemand: false Label: com.apple.syslogd
jlutil
so it gets all UTF-8,UTF-16 and UTF-32 correctly, so as to support any language (important, since plists often i18n-alize) and not (perish the thought...) leave any emoji behind...morpheus@Zephyr (~/Documents/Work/SimPLISTic) %./jlutil -x tests/com.apple.time-zh-CN.plist 14:45 <?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> <key>VSRecognitionClasses</key> <array> <dict> <key>VSRecognitionClassIdentifier</key> <string>command</string> <key>VSRecognitionClassElements</key> <array> <string>几点了</string> <string>什么时间</string> <string>现在是几点钟</string> <string>现在的时间是</string> </array> <key>VSRecognitionClassType</key> <string>VSRecognitionClassTypeCommand</string> </dict> </array> <key>VSRecognitionSequences</key> <array> <dict> <key>VSRecognitionSequenceElements</key> <array> <string>command</string> </array> </dict> </array> </dict> </plist>
root@Zephyr (~/Documents/Work/SimPLISTic) #hexdump -C /tmp/out2.bplist16 00000000 62 70 6c 69 73 74 31 36 a0 d6 00 00 00 00 00 00 |bplist16........| 00000010 00 7f 11 6d 64 6f 4d 61 72 6b 55 73 65 72 41 63 |...mdoMarkUserAc| 00000020 74 69 76 69 74 79 41 73 44 69 72 74 79 3a 66 6f |tivityAsDirty:fo| 00000030 72 63 65 49 6d 6d 65 64 69 61 74 65 3a 77 65 62 |rceImmediate:web| 00000040 70 61 67 65 55 52 4c 3a 65 78 70 69 72 61 74 69 |pageURL:expirati| 00000050 6f 6e 3a 68 61 73 69 43 6c 6f 75 64 44 6f 63 75 |on:hasiCloudDocu| 00000060 6d 65 6e 74 3a 68 61 73 55 6e 73 79 6e 63 68 72 |ment:hasUnsynchr| 00000070 6f 6e 69 7a 65 64 69 43 6c 6f 75 64 44 6f 63 3a |onizediCloudDoc:| 00000080 00 7a 76 40 3a 40 63 40 40 63 63 00 a0 d6 00 00 |.zv@:@c@@cc.....| 00000090 00 00 00 00 00 d0 ce 00 00 00 00 00 00 00 77 24 |..............w$| 000000a0 63 6c 61 73 73 00 77 4e 53 55 55 49 44 00 7d 4e |class.wNSUUID.}N| 000000b0 53 2e 75 75 69 64 62 79 74 65 73 00 4f 11 10 b8 |S.uuidbytes.O...| 000000c0 fc 22 8b e6 86 4e 6d 99 9f 3a c1 31 61 58 0a 11 |."...Nm..:.1aX..| 000000d0 01 e0 e0 11 00 11 00 |.......| 000000d7 root@Zephyr (~/Documents/Work/SimPLISTic) #jlutil !$ jlutil /tmp/out2.bplist16 0: doMarkUserActivityAsDirty:forceImmediate:webpageURL:expiration:hasiCloudDocument:hasUnsynchronizediCloudDoc: 1: v@:@c@@cc 2: 0: $class: NSUUID NS.uuidbytes: data 1: 1 2: NULL 3: NULL 4: 0 5: 0
This makes it easy to piece together remote invocations of ObjC over NSXPC: In the example above, the selector is doMarkUserActivityAsDirty:forceImmediate:webpageURL:expiration:hasiCloudDocument:hasUnsynchronizediCloudDoc:
with an Objective-C protocol of v@:@c@@cc
(return void, get id, char, id, id char char) with the object (an NSUUID, the activity), a '1' for the 2nd argument
(counting from 0) two NULLs for webPageURL
and expiration
, a false for hasiCloudDocument
and another false for hasUnsynchronizediCloudDoc
.
You can get bplist16 output from breakpointing XPC in lldb
and mem read -o ..
or using XPoCe 2.5.
plutil(1)
? - Because they're displayed in order of appearance (from the top object downwards), and not their order in memory. When loaded into a CFDict and then enumerated (the way plutil(1)
does it) the elements get sorted.