dbus-fast 2.45.1__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dbus-fast might be problematic. Click here for more details.
- dbus_fast/__init__.py +82 -0
- dbus_fast/__version__.py +10 -0
- dbus_fast/_private/__init__.py +1 -0
- dbus_fast/_private/_cython_compat.py +14 -0
- dbus_fast/_private/address.cpython-311-darwin.so +0 -0
- dbus_fast/_private/address.pxd +15 -0
- dbus_fast/_private/address.py +117 -0
- dbus_fast/_private/constants.py +20 -0
- dbus_fast/_private/marshaller.cpython-311-darwin.so +0 -0
- dbus_fast/_private/marshaller.pxd +110 -0
- dbus_fast/_private/marshaller.py +228 -0
- dbus_fast/_private/unmarshaller.cpython-311-darwin.so +0 -0
- dbus_fast/_private/unmarshaller.pxd +261 -0
- dbus_fast/_private/unmarshaller.py +902 -0
- dbus_fast/_private/util.py +176 -0
- dbus_fast/aio/__init__.py +5 -0
- dbus_fast/aio/message_bus.py +578 -0
- dbus_fast/aio/message_reader.cpython-311-darwin.so +0 -0
- dbus_fast/aio/message_reader.pxd +13 -0
- dbus_fast/aio/message_reader.py +49 -0
- dbus_fast/aio/proxy_object.py +207 -0
- dbus_fast/auth.py +126 -0
- dbus_fast/constants.py +152 -0
- dbus_fast/errors.py +84 -0
- dbus_fast/glib/__init__.py +3 -0
- dbus_fast/glib/message_bus.py +515 -0
- dbus_fast/glib/proxy_object.py +319 -0
- dbus_fast/introspection.py +683 -0
- dbus_fast/message.cpython-311-darwin.so +0 -0
- dbus_fast/message.pxd +76 -0
- dbus_fast/message.py +387 -0
- dbus_fast/message_bus.cpython-311-darwin.so +0 -0
- dbus_fast/message_bus.pxd +75 -0
- dbus_fast/message_bus.py +1310 -0
- dbus_fast/proxy_object.py +358 -0
- dbus_fast/py.typed +0 -0
- dbus_fast/send_reply.py +61 -0
- dbus_fast/service.cpython-311-darwin.so +0 -0
- dbus_fast/service.pxd +50 -0
- dbus_fast/service.py +686 -0
- dbus_fast/signature.cpython-311-darwin.so +0 -0
- dbus_fast/signature.pxd +31 -0
- dbus_fast/signature.py +481 -0
- dbus_fast/unpack.cpython-311-darwin.so +0 -0
- dbus_fast/unpack.pxd +13 -0
- dbus_fast/unpack.py +24 -0
- dbus_fast/validators.py +199 -0
- dbus_fast-2.45.1.dist-info/METADATA +263 -0
- dbus_fast-2.45.1.dist-info/RECORD +51 -0
- dbus_fast-2.45.1.dist-info/WHEEL +6 -0
- dbus_fast-2.45.1.dist-info/licenses/LICENSE +22 -0
dbus_fast/__init__.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from . import introspection, message_bus, proxy_object, service
|
|
2
|
+
from .constants import (
|
|
3
|
+
ArgDirection,
|
|
4
|
+
BusType,
|
|
5
|
+
ErrorType,
|
|
6
|
+
MessageFlag,
|
|
7
|
+
MessageType,
|
|
8
|
+
NameFlag,
|
|
9
|
+
PropertyAccess,
|
|
10
|
+
ReleaseNameReply,
|
|
11
|
+
RequestNameReply,
|
|
12
|
+
)
|
|
13
|
+
from .errors import (
|
|
14
|
+
AuthError,
|
|
15
|
+
DBusError,
|
|
16
|
+
InterfaceNotFoundError,
|
|
17
|
+
InvalidAddressError,
|
|
18
|
+
InvalidBusNameError,
|
|
19
|
+
InvalidInterfaceNameError,
|
|
20
|
+
InvalidIntrospectionError,
|
|
21
|
+
InvalidMemberNameError,
|
|
22
|
+
InvalidMessageError,
|
|
23
|
+
InvalidObjectPathError,
|
|
24
|
+
InvalidSignatureError,
|
|
25
|
+
SignalDisabledError,
|
|
26
|
+
SignatureBodyMismatchError,
|
|
27
|
+
)
|
|
28
|
+
from .message import Message
|
|
29
|
+
from .signature import SignatureTree, SignatureType, Variant
|
|
30
|
+
from .unpack import unpack_variants
|
|
31
|
+
from .validators import (
|
|
32
|
+
assert_bus_name_valid,
|
|
33
|
+
assert_interface_name_valid,
|
|
34
|
+
assert_member_name_valid,
|
|
35
|
+
assert_object_path_valid,
|
|
36
|
+
is_bus_name_valid,
|
|
37
|
+
is_interface_name_valid,
|
|
38
|
+
is_member_name_valid,
|
|
39
|
+
is_object_path_valid,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"ArgDirection",
|
|
44
|
+
"AuthError",
|
|
45
|
+
"BusType",
|
|
46
|
+
"DBusError",
|
|
47
|
+
"ErrorType",
|
|
48
|
+
"InterfaceNotFoundError",
|
|
49
|
+
"InvalidAddressError",
|
|
50
|
+
"InvalidBusNameError",
|
|
51
|
+
"InvalidInterfaceNameError",
|
|
52
|
+
"InvalidIntrospectionError",
|
|
53
|
+
"InvalidMemberNameError",
|
|
54
|
+
"InvalidMessageError",
|
|
55
|
+
"InvalidObjectPathError",
|
|
56
|
+
"InvalidSignatureError",
|
|
57
|
+
"Message",
|
|
58
|
+
"MessageFlag",
|
|
59
|
+
"MessageType",
|
|
60
|
+
"NameFlag",
|
|
61
|
+
"PropertyAccess",
|
|
62
|
+
"ReleaseNameReply",
|
|
63
|
+
"RequestNameReply",
|
|
64
|
+
"SignalDisabledError",
|
|
65
|
+
"SignatureBodyMismatchError",
|
|
66
|
+
"SignatureTree",
|
|
67
|
+
"SignatureType",
|
|
68
|
+
"Variant",
|
|
69
|
+
"assert_bus_name_valid",
|
|
70
|
+
"assert_interface_name_valid",
|
|
71
|
+
"assert_member_name_valid",
|
|
72
|
+
"assert_object_path_valid",
|
|
73
|
+
"introspection",
|
|
74
|
+
"is_bus_name_valid",
|
|
75
|
+
"is_interface_name_valid",
|
|
76
|
+
"is_member_name_valid",
|
|
77
|
+
"is_object_path_valid",
|
|
78
|
+
"message_bus",
|
|
79
|
+
"proxy_object",
|
|
80
|
+
"service",
|
|
81
|
+
"unpack_variants",
|
|
82
|
+
]
|
dbus_fast/__version__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
__title__ = "dbus_fast"
|
|
2
|
+
__description__ = (
|
|
3
|
+
"A performant zero-dependency DBus library for Python with asyncio support"
|
|
4
|
+
)
|
|
5
|
+
__url__ = "https://github.com/bluetooth-devices/dbus-fast"
|
|
6
|
+
__version__ = "2.45.1"
|
|
7
|
+
__author__ = "Bluetooth Devices authors, Tony Crisci"
|
|
8
|
+
__author_email__ = "bluetooth@koston.org"
|
|
9
|
+
__license__ = "MIT"
|
|
10
|
+
__copyright__ = "Copyright 2022 Bluetooth Devices authors, 2019 Tony Crisci"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
Binary file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""cdefs for address.py"""
|
|
2
|
+
|
|
3
|
+
import cython
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
cdef object unquote
|
|
7
|
+
|
|
8
|
+
@cython.locals(kv=cython.str, opt_string=cython.str, address=cython.str)
|
|
9
|
+
cpdef parse_address(cython.str address_str)
|
|
10
|
+
|
|
11
|
+
cpdef get_bus_address(object bus_type)
|
|
12
|
+
|
|
13
|
+
cpdef get_session_bus_address()
|
|
14
|
+
|
|
15
|
+
cpdef get_system_bus_address()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from urllib.parse import unquote
|
|
6
|
+
|
|
7
|
+
from ..constants import BusType
|
|
8
|
+
from ..errors import InvalidAddressError
|
|
9
|
+
|
|
10
|
+
invalid_address_chars_re = re.compile(r"[^-0-9A-Za-z_/.%]")
|
|
11
|
+
|
|
12
|
+
str_ = str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_address(address_str: str_) -> list[tuple[str, dict[str, str]]]:
|
|
16
|
+
"""Parse a dbus address string into a list of addresses."""
|
|
17
|
+
addresses: list[tuple[str, dict[str, str]]] = []
|
|
18
|
+
|
|
19
|
+
for address in address_str.split(";"):
|
|
20
|
+
if not address:
|
|
21
|
+
continue
|
|
22
|
+
if address.find(":") == -1:
|
|
23
|
+
raise InvalidAddressError("address did not contain a transport")
|
|
24
|
+
|
|
25
|
+
transport, opt_string = address.split(":", 1)
|
|
26
|
+
options: dict[str, str] = {}
|
|
27
|
+
|
|
28
|
+
for kv in opt_string.split(","):
|
|
29
|
+
if not kv:
|
|
30
|
+
continue
|
|
31
|
+
if kv.find("=") == -1:
|
|
32
|
+
raise InvalidAddressError("address option did not contain a value")
|
|
33
|
+
k, v = kv.split("=", 1)
|
|
34
|
+
if invalid_address_chars_re.search(v):
|
|
35
|
+
raise InvalidAddressError("address contains invalid characters")
|
|
36
|
+
# XXX the actual unquote rules are simpler than this
|
|
37
|
+
options[k] = unquote(v)
|
|
38
|
+
|
|
39
|
+
addresses.append((transport, options))
|
|
40
|
+
|
|
41
|
+
if not addresses:
|
|
42
|
+
raise InvalidAddressError(
|
|
43
|
+
f'address string contained no addresses: "{address_str}"'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return addresses
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_system_bus_address() -> str:
|
|
50
|
+
"""Get the system bus address from the environment or return the default."""
|
|
51
|
+
return (
|
|
52
|
+
os.environ.get("DBUS_SYSTEM_BUS_ADDRESS")
|
|
53
|
+
or "unix:path=/var/run/dbus/system_bus_socket"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
display_re = re.compile(r".*:([0-9]+)\.?.*")
|
|
58
|
+
remove_quotes_re = re.compile(r"""^['"]?(.*?)['"]?$""")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_session_bus_address() -> str:
|
|
62
|
+
"""Get the session bus address from the environment or return the default."""
|
|
63
|
+
dbus_session_bus_address = os.environ.get("DBUS_SESSION_BUS_ADDRESS")
|
|
64
|
+
if dbus_session_bus_address:
|
|
65
|
+
return dbus_session_bus_address
|
|
66
|
+
|
|
67
|
+
home = os.environ["HOME"]
|
|
68
|
+
if "DISPLAY" not in os.environ:
|
|
69
|
+
raise InvalidAddressError(
|
|
70
|
+
"DBUS_SESSION_BUS_ADDRESS not set and could not get DISPLAY environment variable to get bus address"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
display = os.environ["DISPLAY"]
|
|
74
|
+
try:
|
|
75
|
+
display = display_re.search(display).group(1)
|
|
76
|
+
except Exception as ex:
|
|
77
|
+
raise InvalidAddressError(
|
|
78
|
+
f"DBUS_SESSION_BUS_ADDRESS not set and could not parse DISPLAY environment variable to get bus address: {display}"
|
|
79
|
+
) from ex
|
|
80
|
+
|
|
81
|
+
# XXX: this will block but they're very small files and fs operations
|
|
82
|
+
# should be fairly reliable. fix this by passing in an async func to read
|
|
83
|
+
# the file for each io backend.
|
|
84
|
+
machine_id = None
|
|
85
|
+
with open("/var/lib/dbus/machine-id") as f:
|
|
86
|
+
machine_id = f.read().rstrip()
|
|
87
|
+
|
|
88
|
+
dbus_info_file_name = f"{home}/.dbus/session-bus/{machine_id}-{display}"
|
|
89
|
+
dbus_info: str | None = None
|
|
90
|
+
try:
|
|
91
|
+
with open(dbus_info_file_name) as f:
|
|
92
|
+
dbus_info = f.read().rstrip()
|
|
93
|
+
except Exception as ex:
|
|
94
|
+
raise InvalidAddressError(
|
|
95
|
+
f"could not open dbus info file: {dbus_info_file_name}"
|
|
96
|
+
) from ex
|
|
97
|
+
|
|
98
|
+
for line in dbus_info.split("\n"):
|
|
99
|
+
if line.strip().startswith("DBUS_SESSION_BUS_ADDRESS="):
|
|
100
|
+
_, addr = line.split("=", 1)
|
|
101
|
+
if not addr:
|
|
102
|
+
raise InvalidAddressError(
|
|
103
|
+
f"DBUS_SESSION_BUS_ADDRESS variable not set correctly in dbus info file: {dbus_info_file_name}"
|
|
104
|
+
)
|
|
105
|
+
addr = remove_quotes_re.search(addr).group(1)
|
|
106
|
+
return addr
|
|
107
|
+
|
|
108
|
+
raise InvalidAddressError("could not find dbus session bus address")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_bus_address(bus_type: BusType) -> str:
|
|
112
|
+
"""Get the address of the bus specified by the bus type."""
|
|
113
|
+
if bus_type == BusType.SESSION:
|
|
114
|
+
return get_session_bus_address()
|
|
115
|
+
if bus_type == BusType.SYSTEM:
|
|
116
|
+
return get_system_bus_address()
|
|
117
|
+
raise Exception(f"got unknown bus type: {bus_type}")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
PROTOCOL_VERSION = 1
|
|
6
|
+
|
|
7
|
+
LITTLE_ENDIAN = ord("l")
|
|
8
|
+
BIG_ENDIAN = ord("B")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HeaderField(Enum):
|
|
12
|
+
PATH = 1
|
|
13
|
+
INTERFACE = 2
|
|
14
|
+
MEMBER = 3
|
|
15
|
+
ERROR_NAME = 4
|
|
16
|
+
REPLY_SERIAL = 5
|
|
17
|
+
DESTINATION = 6
|
|
18
|
+
SENDER = 7
|
|
19
|
+
SIGNATURE = 8
|
|
20
|
+
UNIX_FDS = 9
|
|
Binary file
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""cdefs for marshaller.py"""
|
|
2
|
+
|
|
3
|
+
import cython
|
|
4
|
+
|
|
5
|
+
from ..signature cimport SignatureTree, SignatureType, Variant
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
cdef object PACK_UINT32
|
|
9
|
+
|
|
10
|
+
cdef bytes PACKED_UINT32_ZERO
|
|
11
|
+
cdef bytes PACKED_BOOL_TRUE
|
|
12
|
+
cdef bytes PACKED_BOOL_FALSE
|
|
13
|
+
|
|
14
|
+
cdef get_signature_tree
|
|
15
|
+
|
|
16
|
+
cdef class Marshaller:
|
|
17
|
+
|
|
18
|
+
cdef SignatureTree signature_tree
|
|
19
|
+
cdef bytearray _buf
|
|
20
|
+
cdef cython.list body
|
|
21
|
+
|
|
22
|
+
cdef _buffer(self)
|
|
23
|
+
|
|
24
|
+
cpdef align(self, unsigned int n)
|
|
25
|
+
|
|
26
|
+
@cython.locals(
|
|
27
|
+
offset=cython.ulong,
|
|
28
|
+
)
|
|
29
|
+
cdef unsigned int _align(self, unsigned int n)
|
|
30
|
+
|
|
31
|
+
cpdef write_boolean(self, bint boolean, SignatureType type_)
|
|
32
|
+
|
|
33
|
+
@cython.locals(
|
|
34
|
+
written=cython.uint,
|
|
35
|
+
)
|
|
36
|
+
cdef unsigned int _write_boolean(self, bint boolean)
|
|
37
|
+
|
|
38
|
+
cpdef write_string(self, object value, SignatureType type_)
|
|
39
|
+
|
|
40
|
+
@cython.locals(
|
|
41
|
+
buf=cython.bytearray,
|
|
42
|
+
value_len=cython.uint,
|
|
43
|
+
signature_len=cython.uint,
|
|
44
|
+
written=cython.uint,
|
|
45
|
+
)
|
|
46
|
+
cdef unsigned int _write_string(self, object value)
|
|
47
|
+
|
|
48
|
+
@cython.locals(
|
|
49
|
+
signature_len=cython.uint,
|
|
50
|
+
)
|
|
51
|
+
cdef unsigned int _write_signature(self, bytes signature_bytes)
|
|
52
|
+
|
|
53
|
+
cpdef write_array(self, object array, SignatureType type_)
|
|
54
|
+
|
|
55
|
+
@cython.locals(
|
|
56
|
+
array_len=cython.uint,
|
|
57
|
+
buf=cython.bytearray,
|
|
58
|
+
written=cython.uint,
|
|
59
|
+
token=cython.str,
|
|
60
|
+
child_type=SignatureType,
|
|
61
|
+
array_len_packed=cython.bytes,
|
|
62
|
+
size=cython.uint,
|
|
63
|
+
writer=cython.object,
|
|
64
|
+
packer=cython.object,
|
|
65
|
+
i=cython.uint,
|
|
66
|
+
)
|
|
67
|
+
cdef unsigned int _write_array(self, object array, SignatureType type_)
|
|
68
|
+
|
|
69
|
+
cpdef write_struct(self, object array, SignatureType type_)
|
|
70
|
+
|
|
71
|
+
@cython.locals(
|
|
72
|
+
written=cython.uint,
|
|
73
|
+
i=cython.uint,
|
|
74
|
+
)
|
|
75
|
+
cdef unsigned int _write_struct(self, object array, SignatureType type_)
|
|
76
|
+
|
|
77
|
+
cpdef write_variant(self, Variant variant, SignatureType type_)
|
|
78
|
+
|
|
79
|
+
@cython.locals(
|
|
80
|
+
written=cython.uint,
|
|
81
|
+
signature=cython.str,
|
|
82
|
+
signature_bytes=cython.bytes,
|
|
83
|
+
)
|
|
84
|
+
cdef unsigned int _write_variant(self, Variant variant, SignatureType type_)
|
|
85
|
+
|
|
86
|
+
@cython.locals(
|
|
87
|
+
written=cython.uint,
|
|
88
|
+
size=cython.uint,
|
|
89
|
+
)
|
|
90
|
+
cdef unsigned int _write_single(self, SignatureType type_, object body)
|
|
91
|
+
|
|
92
|
+
@cython.locals(
|
|
93
|
+
written=cython.uint,
|
|
94
|
+
t=cython.str,
|
|
95
|
+
)
|
|
96
|
+
cpdef write_dict_entry(self, cython.list dict_entry, SignatureType type_)
|
|
97
|
+
|
|
98
|
+
cpdef marshall(self)
|
|
99
|
+
|
|
100
|
+
cdef _marshall(self)
|
|
101
|
+
|
|
102
|
+
@cython.locals(
|
|
103
|
+
offset=cython.ulong,
|
|
104
|
+
t=cython.str,
|
|
105
|
+
size=cython.uint,
|
|
106
|
+
writer=cython.object,
|
|
107
|
+
packer=cython.object,
|
|
108
|
+
type_=SignatureType,
|
|
109
|
+
)
|
|
110
|
+
cdef _construct_buffer(self)
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from struct import Struct, error
|
|
4
|
+
from typing import Any, Callable
|
|
5
|
+
|
|
6
|
+
from ..signature import SignatureType, Variant, get_signature_tree
|
|
7
|
+
|
|
8
|
+
PACK_LITTLE_ENDIAN = "<"
|
|
9
|
+
|
|
10
|
+
PACK_UINT32 = Struct(f"{PACK_LITTLE_ENDIAN}I").pack
|
|
11
|
+
PACKED_UINT32_ZERO = PACK_UINT32(0)
|
|
12
|
+
PACKED_BOOL_FALSE = PACK_UINT32(0)
|
|
13
|
+
PACKED_BOOL_TRUE = PACK_UINT32(1)
|
|
14
|
+
|
|
15
|
+
_int = int
|
|
16
|
+
_bytes = bytes
|
|
17
|
+
_str = str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Marshaller:
|
|
21
|
+
"""Marshall data for Dbus."""
|
|
22
|
+
|
|
23
|
+
__slots__ = ("_buf", "body", "signature_tree")
|
|
24
|
+
|
|
25
|
+
def __init__(self, signature: str, body: list[Any]) -> None:
|
|
26
|
+
"""Marshaller constructor."""
|
|
27
|
+
self.signature_tree = get_signature_tree(signature)
|
|
28
|
+
self._buf = bytearray()
|
|
29
|
+
self.body = body
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def buffer(self) -> bytearray:
|
|
33
|
+
return self._buf
|
|
34
|
+
|
|
35
|
+
def _buffer(self) -> bytearray:
|
|
36
|
+
return self._buf
|
|
37
|
+
|
|
38
|
+
def align(self, n: _int) -> int:
|
|
39
|
+
return self._align(n)
|
|
40
|
+
|
|
41
|
+
def _align(self, n: _int) -> _int:
|
|
42
|
+
offset = n - len(self._buf) % n
|
|
43
|
+
if offset == 0 or offset == n:
|
|
44
|
+
return 0
|
|
45
|
+
for _ in range(offset):
|
|
46
|
+
self._buf.append(0)
|
|
47
|
+
return offset
|
|
48
|
+
|
|
49
|
+
def write_boolean(self, boolean: bool, type_: SignatureType) -> int:
|
|
50
|
+
return self._write_boolean(boolean)
|
|
51
|
+
|
|
52
|
+
def _write_boolean(self, boolean: bool) -> int:
|
|
53
|
+
written = self._align(4)
|
|
54
|
+
self._buf += PACKED_BOOL_TRUE if boolean else PACKED_BOOL_FALSE
|
|
55
|
+
return written + 4
|
|
56
|
+
|
|
57
|
+
def write_signature(self, signature: str, type_: SignatureType) -> int:
|
|
58
|
+
return self._write_signature(signature.encode())
|
|
59
|
+
|
|
60
|
+
def _write_signature(self, signature_bytes: _bytes) -> int:
|
|
61
|
+
signature_len = len(signature_bytes)
|
|
62
|
+
buf = self._buf
|
|
63
|
+
buf.append(signature_len)
|
|
64
|
+
buf += signature_bytes
|
|
65
|
+
buf.append(0)
|
|
66
|
+
return signature_len + 2
|
|
67
|
+
|
|
68
|
+
def write_string(self, value: _str, type_: SignatureType) -> int:
|
|
69
|
+
return self._write_string(value)
|
|
70
|
+
|
|
71
|
+
def _write_string(self, value: _str) -> int:
|
|
72
|
+
value_bytes = value.encode()
|
|
73
|
+
value_len = len(value_bytes)
|
|
74
|
+
written = self._align(4) + 4
|
|
75
|
+
buf = self._buf
|
|
76
|
+
buf += PACK_UINT32(value_len)
|
|
77
|
+
buf += value_bytes
|
|
78
|
+
written += value_len
|
|
79
|
+
buf.append(0)
|
|
80
|
+
written += 1
|
|
81
|
+
return written
|
|
82
|
+
|
|
83
|
+
def write_variant(self, variant: Variant, type_: SignatureType) -> int:
|
|
84
|
+
return self._write_variant(variant, type_)
|
|
85
|
+
|
|
86
|
+
def _write_variant(self, variant: Variant, type_: SignatureType) -> int:
|
|
87
|
+
signature = variant.signature
|
|
88
|
+
signature_bytes = signature.encode()
|
|
89
|
+
written = self._write_signature(signature_bytes)
|
|
90
|
+
written += self._write_single(variant.type, variant.value)
|
|
91
|
+
return written
|
|
92
|
+
|
|
93
|
+
def write_array(
|
|
94
|
+
self, array: bytes | list[Any] | dict[Any, Any], type_: SignatureType
|
|
95
|
+
) -> int:
|
|
96
|
+
return self._write_array(array, type_)
|
|
97
|
+
|
|
98
|
+
def _write_array(
|
|
99
|
+
self, array: bytes | list[Any] | dict[Any, Any], type_: SignatureType
|
|
100
|
+
) -> int:
|
|
101
|
+
# TODO max array size is 64MiB (67108864 bytes)
|
|
102
|
+
written = self._align(4)
|
|
103
|
+
# length placeholder
|
|
104
|
+
buf: bytearray = self._buf
|
|
105
|
+
offset = len(buf)
|
|
106
|
+
written += self._align(4) + 4
|
|
107
|
+
buf += PACKED_UINT32_ZERO
|
|
108
|
+
child_type = type_.children[0]
|
|
109
|
+
token = child_type.token
|
|
110
|
+
|
|
111
|
+
if token in "xtd{(":
|
|
112
|
+
# the first alignment is not included in array size
|
|
113
|
+
written += self._align(8)
|
|
114
|
+
|
|
115
|
+
array_len = 0
|
|
116
|
+
if token == "{":
|
|
117
|
+
for key, value in array.items(): # type: ignore[union-attr]
|
|
118
|
+
array_len += self.write_dict_entry([key, value], child_type)
|
|
119
|
+
elif token == "y":
|
|
120
|
+
array_len = len(array)
|
|
121
|
+
buf += array # type: ignore[arg-type]
|
|
122
|
+
elif token == "(":
|
|
123
|
+
for value in array:
|
|
124
|
+
array_len += self._write_struct(value, child_type)
|
|
125
|
+
else:
|
|
126
|
+
writer, packer, size = self._writers[token]
|
|
127
|
+
if not writer:
|
|
128
|
+
for value in array:
|
|
129
|
+
array_len += self._align(size) + size
|
|
130
|
+
buf += packer(value) # type: ignore[misc]
|
|
131
|
+
else:
|
|
132
|
+
for value in array:
|
|
133
|
+
array_len += writer(self, value, child_type)
|
|
134
|
+
|
|
135
|
+
array_len_packed = PACK_UINT32(array_len)
|
|
136
|
+
for i in range(offset, offset + 4):
|
|
137
|
+
buf[i] = array_len_packed[i - offset]
|
|
138
|
+
|
|
139
|
+
return written + array_len
|
|
140
|
+
|
|
141
|
+
def write_struct(self, array: tuple[Any] | list[Any], type_: SignatureType) -> int:
|
|
142
|
+
return self._write_struct(array, type_)
|
|
143
|
+
|
|
144
|
+
def _write_struct(self, array: tuple[Any] | list[Any], type_: SignatureType) -> int:
|
|
145
|
+
written = self._align(8)
|
|
146
|
+
for i, value in enumerate(array):
|
|
147
|
+
written += self._write_single(type_.children[i], value)
|
|
148
|
+
return written
|
|
149
|
+
|
|
150
|
+
def write_dict_entry(self, dict_entry: list[Any], type_: SignatureType) -> int:
|
|
151
|
+
written = self._align(8)
|
|
152
|
+
written += self._write_single(type_.children[0], dict_entry[0])
|
|
153
|
+
written += self._write_single(type_.children[1], dict_entry[1])
|
|
154
|
+
return written
|
|
155
|
+
|
|
156
|
+
def _write_single(self, type_: SignatureType, body: Any) -> int:
|
|
157
|
+
t = type_.token
|
|
158
|
+
if t == "y":
|
|
159
|
+
self._buf.append(body)
|
|
160
|
+
return 1
|
|
161
|
+
if t == "u":
|
|
162
|
+
written = self._align(4)
|
|
163
|
+
self._buf += PACK_UINT32(body)
|
|
164
|
+
return written + 4
|
|
165
|
+
if t == "a":
|
|
166
|
+
return self._write_array(body, type_)
|
|
167
|
+
if t == "s" or t == "o":
|
|
168
|
+
return self._write_string(body)
|
|
169
|
+
if t == "v":
|
|
170
|
+
return self._write_variant(body, type_)
|
|
171
|
+
if t == "b":
|
|
172
|
+
return self._write_boolean(body)
|
|
173
|
+
writer, packer, size = self._writers[t]
|
|
174
|
+
if not writer:
|
|
175
|
+
written = self._align(size)
|
|
176
|
+
self._buf += packer(body) # type: ignore[misc]
|
|
177
|
+
return written + size
|
|
178
|
+
return writer(self, body, type_)
|
|
179
|
+
|
|
180
|
+
def marshall(self) -> bytearray:
|
|
181
|
+
"""Marshalls the body into a byte array"""
|
|
182
|
+
return self._marshall()
|
|
183
|
+
|
|
184
|
+
def _marshall(self) -> bytearray:
|
|
185
|
+
"""Marshalls the body into a byte array"""
|
|
186
|
+
try:
|
|
187
|
+
return self._construct_buffer()
|
|
188
|
+
except KeyError as ex:
|
|
189
|
+
raise NotImplementedError(
|
|
190
|
+
f'type is not implemented yet: "{ex.args}"'
|
|
191
|
+
) from ex
|
|
192
|
+
except error:
|
|
193
|
+
self.signature_tree.verify(self.body)
|
|
194
|
+
raise RuntimeError("should not reach here")
|
|
195
|
+
|
|
196
|
+
def _construct_buffer(self) -> bytearray:
|
|
197
|
+
self._buf.clear()
|
|
198
|
+
body = self.body
|
|
199
|
+
for i, type_ in enumerate(self.signature_tree.types):
|
|
200
|
+
self._write_single(type_, body[i])
|
|
201
|
+
return self._buf
|
|
202
|
+
|
|
203
|
+
_writers: dict[
|
|
204
|
+
str,
|
|
205
|
+
tuple[
|
|
206
|
+
Callable[[Any, Any, SignatureType], int] | None,
|
|
207
|
+
Callable[[Any], bytes] | None,
|
|
208
|
+
int,
|
|
209
|
+
],
|
|
210
|
+
] = {
|
|
211
|
+
"y": (None, Struct(f"{PACK_LITTLE_ENDIAN}B").pack, 1),
|
|
212
|
+
"b": (write_boolean, None, 0),
|
|
213
|
+
"n": (None, Struct(f"{PACK_LITTLE_ENDIAN}h").pack, 2),
|
|
214
|
+
"q": (None, Struct(f"{PACK_LITTLE_ENDIAN}H").pack, 2),
|
|
215
|
+
"i": (None, Struct(f"{PACK_LITTLE_ENDIAN}i").pack, 4),
|
|
216
|
+
"u": (None, PACK_UINT32, 4),
|
|
217
|
+
"x": (None, Struct(f"{PACK_LITTLE_ENDIAN}q").pack, 8),
|
|
218
|
+
"t": (None, Struct(f"{PACK_LITTLE_ENDIAN}Q").pack, 8),
|
|
219
|
+
"d": (None, Struct(f"{PACK_LITTLE_ENDIAN}d").pack, 8),
|
|
220
|
+
"h": (None, Struct(f"{PACK_LITTLE_ENDIAN}I").pack, 4),
|
|
221
|
+
"o": (write_string, None, 0),
|
|
222
|
+
"s": (write_string, None, 0),
|
|
223
|
+
"g": (write_signature, None, 0),
|
|
224
|
+
"a": (write_array, None, 0),
|
|
225
|
+
"(": (write_struct, None, 0),
|
|
226
|
+
"{": (write_dict_entry, None, 0),
|
|
227
|
+
"v": (write_variant, None, 0),
|
|
228
|
+
}
|
|
Binary file
|