Files
Hippolyzer/hippolyzer/lib/base/llsd.py
2021-04-30 17:30:24 +00:00

114 lines
3.1 KiB
Python

import typing
import zlib
from llbase.llsd import *
# So we can directly reference the original wrapper funcs where necessary
import llbase.llsd
from hippolyzer.lib.base.datatypes import *
class HippoLLSDBaseFormatter(llbase.llsd.LLSDBaseFormatter):
UUID: callable
ARRAY: callable
def __init__(self):
super().__init__()
self.type_map[UUID] = self.UUID
self.type_map[Vector2] = self.TUPLECOORD
self.type_map[Vector3] = self.TUPLECOORD
self.type_map[Vector4] = self.TUPLECOORD
self.type_map[Quaternion] = self.TUPLECOORD
def TUPLECOORD(self, v: TupleCoord):
return self.ARRAY(v.data())
class HippoLLSDXMLFormatter(llbase.llsd.LLSDXMLFormatter, HippoLLSDBaseFormatter):
def __init__(self):
super().__init__()
class HippoLLSDXMLPrettyFormatter(llbase.llsd.LLSDXMLPrettyFormatter, HippoLLSDBaseFormatter):
def __init__(self):
super().__init__()
def format_pretty_xml(val: typing.Any):
return HippoLLSDXMLPrettyFormatter().format(val)
def format_xml(val: typing.Any):
return HippoLLSDXMLFormatter().format(val)
class HippoLLSDNotationFormatter(llbase.llsd.LLSDNotationFormatter, HippoLLSDBaseFormatter):
def __init__(self):
super().__init__()
def format_notation(val: typing.Any):
return HippoLLSDNotationFormatter().format(val)
def format_binary(val: typing.Any, with_header=True):
val = llbase.llsd.format_binary(val)
if not with_header:
return val.split(b"\n", 1)[1]
return val
class HippoLLSDBinaryParser(llbase.llsd.LLSDBinaryParser):
def __init__(self):
super().__init__()
self._dispatch[ord('u')] = lambda: UUID(bytes=self._getc(16))
def _parse_string(self):
# LLSD's C++ API lets you stuff binary in a string field even though it's only
# meant to be allowed in binary fields. Happens in SLM files. Handle that case.
bytes_val = self._parse_string_raw()
try:
return bytes_val.decode('utf-8')
except UnicodeDecodeError:
pass
return bytes_val
def parse_binary(data: bytes):
if data.startswith(b'<?llsd/binary?>'):
data = data.split(b'\n', 1)[1]
return HippoLLSDBinaryParser().parse(data)
def parse_xml(data: bytes):
return llbase.llsd.parse_xml(data)
def parse_notation(data: bytes):
return llbase.llsd.parse_notation(data)
def zip_llsd(val: typing.Any):
return zlib.compress(format_binary(val, with_header=False))
def unzip_llsd(data: bytes):
return parse_binary(zlib.decompress(data))
def parse(data: bytes):
# You always have to content-type sniff because the provided
# content-type is usually nonsense.
try:
data = data.lstrip()
if data.startswith(b'<?llsd/binary?>'):
return parse_binary(data)
elif data.startswith(b'<'):
return parse_xml(data)
else:
return parse_notation(data)
except KeyError as e:
raise llbase.llsd.LLSDParseError('LLSD could not be parsed: %s' % (e,))
except TypeError as e:
raise llbase.llsd.LLSDParseError('Input stream not of type bytes. %s' % (e,))