mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-08-10 22:41:51 +02:00
fixup for byte and datetime values
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
Converts binary and XML PLIST files.
|
Converts binary and XML PLIST files.
|
||||||
|
|
||||||
|
Binary values are converted into an ASCII hex representation.
|
||||||
|
|
||||||
|
Datetime objects are converted into Unix epoch timestamps and ISO strings.
|
||||||
|
|
||||||
Usage (cli):
|
Usage (cli):
|
||||||
|
|
||||||
$ cat file.plist | jc --plist
|
$ cat file.plist | jc --plist
|
||||||
@@ -31,6 +35,8 @@ Examples:
|
|||||||
"""
|
"""
|
||||||
from typing import List, Dict, Union
|
from typing import List, Dict, Union
|
||||||
import plistlib
|
import plistlib
|
||||||
|
import binascii
|
||||||
|
from datetime import datetime
|
||||||
import jc.utils
|
import jc.utils
|
||||||
|
|
||||||
|
|
||||||
@@ -61,6 +67,57 @@ def _process(proc_data: Dict) -> Dict:
|
|||||||
return proc_data
|
return proc_data
|
||||||
|
|
||||||
|
|
||||||
|
def _b2a(byte_string: bytes) -> str:
|
||||||
|
"""Convert a byte string to a colon-delimited hex ascii string"""
|
||||||
|
# need try/except since seperator was only introduced in python 3.8.
|
||||||
|
# provides compatibility for python 3.6 and 3.7.
|
||||||
|
try:
|
||||||
|
return binascii.hexlify(byte_string, ':').decode('utf-8')
|
||||||
|
except TypeError:
|
||||||
|
hex_string = binascii.hexlify(byte_string).decode('utf-8')
|
||||||
|
colon_seperated = ':'.join(hex_string[i:i+2] for i in range(0, len(hex_string), 2))
|
||||||
|
return colon_seperated
|
||||||
|
|
||||||
|
|
||||||
|
def _fix_objects(obj):
|
||||||
|
"""
|
||||||
|
Recursively traverse the nested dictionary or list and convert objects
|
||||||
|
into JSON serializable types.
|
||||||
|
"""
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
for k, v in obj.copy().items():
|
||||||
|
|
||||||
|
if isinstance(v, datetime):
|
||||||
|
iso = v.isoformat()
|
||||||
|
v = int(round(v.timestamp()))
|
||||||
|
obj.update({k: v, f'{k}_iso': iso})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(v, bytes):
|
||||||
|
v = _b2a(v)
|
||||||
|
obj.update({k: v})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(v, dict):
|
||||||
|
obj.update({k: _fix_objects(v)})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(v, list):
|
||||||
|
newlist =[]
|
||||||
|
for i in v:
|
||||||
|
newlist.append(_fix_objects(i))
|
||||||
|
obj.update({k: newlist})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(obj, list):
|
||||||
|
new_list = []
|
||||||
|
for i in obj:
|
||||||
|
new_list.append(_fix_objects(i))
|
||||||
|
obj = new_list
|
||||||
|
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def parse(
|
def parse(
|
||||||
data: Union[str, bytes],
|
data: Union[str, bytes],
|
||||||
raw: bool = False,
|
raw: bool = False,
|
||||||
@@ -89,5 +146,6 @@ def parse(
|
|||||||
if jc.utils.has_data(data):
|
if jc.utils.has_data(data):
|
||||||
|
|
||||||
raw_output = plistlib.loads(data)
|
raw_output = plistlib.loads(data)
|
||||||
|
raw_output = _fix_objects(raw_output)
|
||||||
|
|
||||||
return raw_output if raw else _process(raw_output)
|
return raw_output if raw else _process(raw_output)
|
||||||
|
49
tests/fixtures/generic/plist-alltypes.plist
vendored
Normal file
49
tests/fixtures/generic/plist-alltypes.plist
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?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>aDate</key>
|
||||||
|
<date>2022-07-31T16:34:30Z</date>
|
||||||
|
<key>aDict</key>
|
||||||
|
<dict>
|
||||||
|
<key>aFalseValue</key>
|
||||||
|
<false/>
|
||||||
|
<key>aThirdString</key>
|
||||||
|
<string>Mässig, Maß</string>
|
||||||
|
<key>aTrueValue</key>
|
||||||
|
<true/>
|
||||||
|
<key>anotherString</key>
|
||||||
|
<string><hello & hi there!></string>
|
||||||
|
</dict>
|
||||||
|
<key>aFloat</key>
|
||||||
|
<real>0.1</real>
|
||||||
|
<key>aList</key>
|
||||||
|
<array>
|
||||||
|
<string>A</string>
|
||||||
|
<string>B</string>
|
||||||
|
<integer>12</integer>
|
||||||
|
<real>32.1</real>
|
||||||
|
<array>
|
||||||
|
<integer>1</integer>
|
||||||
|
<integer>2</integer>
|
||||||
|
<integer>3</integer>
|
||||||
|
</array>
|
||||||
|
</array>
|
||||||
|
<key>aString</key>
|
||||||
|
<string>Doodah</string>
|
||||||
|
<key>anInt</key>
|
||||||
|
<integer>728</integer>
|
||||||
|
<key>someData</key>
|
||||||
|
<data>
|
||||||
|
PGJpbmFyeSBndW5rPg==
|
||||||
|
</data>
|
||||||
|
<key>someMoreData</key>
|
||||||
|
<data>
|
||||||
|
PGxvdHMgb2YgYmluYXJ5IGd1bms+PGxvdHMgb2YgYmluYXJ5IGd1bms+PGxvdHMgb2Yg
|
||||||
|
YmluYXJ5IGd1bms+PGxvdHMgb2YgYmluYXJ5IGd1bms+PGxvdHMgb2YgYmluYXJ5IGd1
|
||||||
|
bms+PGxvdHMgb2YgYmluYXJ5IGd1bms+PGxvdHMgb2YgYmluYXJ5IGd1bms+PGxvdHMg
|
||||||
|
b2YgYmluYXJ5IGd1bms+PGxvdHMgb2YgYmluYXJ5IGd1bms+PGxvdHMgb2YgYmluYXJ5
|
||||||
|
IGd1bms+
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Reference in New Issue
Block a user