57 lines
1.6 KiB
Python
57 lines
1.6 KiB
Python
|
|
import json
|
||
|
|
from typing import Dict, Any, Tuple
|
||
|
|
|
||
|
|
|
||
|
|
class PackingError(Exception):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class GXPacker:
|
||
|
|
MAGIC = b'XIC'
|
||
|
|
VERSION = 1
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def pack(manifest: Dict[str, Any], compressed_payload: bytes) -> bytes:
|
||
|
|
try:
|
||
|
|
header = GXPacker.MAGIC
|
||
|
|
header += bytes([GXPacker.VERSION])
|
||
|
|
|
||
|
|
manifest_json = json.dumps(manifest, separators=(',', ':')).encode('utf-8')
|
||
|
|
manifest_len = len(manifest_json)
|
||
|
|
header += manifest_len.to_bytes(4, 'big')
|
||
|
|
|
||
|
|
result = header + manifest_json + compressed_payload
|
||
|
|
|
||
|
|
return result
|
||
|
|
except Exception as e:
|
||
|
|
raise PackingError(f"Packing failed: {e}")
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def unpack(data: bytes) -> Tuple[Dict[str, Any], bytes]:
|
||
|
|
try:
|
||
|
|
if len(data) < 8:
|
||
|
|
raise PackingError("Data too short for GX header")
|
||
|
|
|
||
|
|
if data[:3] != GXPacker.MAGIC:
|
||
|
|
raise PackingError("Invalid magic number")
|
||
|
|
|
||
|
|
version = data[3]
|
||
|
|
if version != GXPacker.VERSION:
|
||
|
|
raise PackingError(f"Unsupported version: {version}")
|
||
|
|
|
||
|
|
manifest_len = int.from_bytes(data[4:8], 'big')
|
||
|
|
|
||
|
|
if len(data) < 8 + manifest_len:
|
||
|
|
raise PackingError("Incomplete manifest")
|
||
|
|
|
||
|
|
manifest_json = data[8:8 + manifest_len]
|
||
|
|
compressed_payload = data[8 + manifest_len:]
|
||
|
|
|
||
|
|
manifest = json.loads(manifest_json.decode('utf-8'))
|
||
|
|
|
||
|
|
return manifest, compressed_payload
|
||
|
|
except PackingError:
|
||
|
|
raise
|
||
|
|
except Exception as e:
|
||
|
|
raise PackingError(f"Unpacking failed: {e}")
|