1
0
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:
Kelly Brazil
2022-07-31 16:47:48 -07:00
parent 108e1b730e
commit 4744757726
2 changed files with 107 additions and 0 deletions

View File

@@ -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)

View 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>&lt;hello &amp; hi there!&gt;</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>