dbus-fast 2.45.0__cp39-cp39-musllinux_1_2_aarch64.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.
Files changed (51) hide show
  1. dbus_fast/__init__.py +82 -0
  2. dbus_fast/__version__.py +10 -0
  3. dbus_fast/_private/__init__.py +1 -0
  4. dbus_fast/_private/_cython_compat.py +14 -0
  5. dbus_fast/_private/address.cpython-39-aarch64-linux-gnu.so +0 -0
  6. dbus_fast/_private/address.pxd +15 -0
  7. dbus_fast/_private/address.py +117 -0
  8. dbus_fast/_private/constants.py +20 -0
  9. dbus_fast/_private/marshaller.cpython-39-aarch64-linux-gnu.so +0 -0
  10. dbus_fast/_private/marshaller.pxd +110 -0
  11. dbus_fast/_private/marshaller.py +228 -0
  12. dbus_fast/_private/unmarshaller.cpython-39-aarch64-linux-gnu.so +0 -0
  13. dbus_fast/_private/unmarshaller.pxd +261 -0
  14. dbus_fast/_private/unmarshaller.py +902 -0
  15. dbus_fast/_private/util.py +176 -0
  16. dbus_fast/aio/__init__.py +5 -0
  17. dbus_fast/aio/message_bus.py +578 -0
  18. dbus_fast/aio/message_reader.cpython-39-aarch64-linux-gnu.so +0 -0
  19. dbus_fast/aio/message_reader.pxd +13 -0
  20. dbus_fast/aio/message_reader.py +49 -0
  21. dbus_fast/aio/proxy_object.py +207 -0
  22. dbus_fast/auth.py +126 -0
  23. dbus_fast/constants.py +152 -0
  24. dbus_fast/errors.py +84 -0
  25. dbus_fast/glib/__init__.py +3 -0
  26. dbus_fast/glib/message_bus.py +515 -0
  27. dbus_fast/glib/proxy_object.py +319 -0
  28. dbus_fast/introspection.py +683 -0
  29. dbus_fast/message.cpython-39-aarch64-linux-gnu.so +0 -0
  30. dbus_fast/message.pxd +76 -0
  31. dbus_fast/message.py +387 -0
  32. dbus_fast/message_bus.cpython-39-aarch64-linux-gnu.so +0 -0
  33. dbus_fast/message_bus.pxd +75 -0
  34. dbus_fast/message_bus.py +1310 -0
  35. dbus_fast/proxy_object.py +358 -0
  36. dbus_fast/py.typed +0 -0
  37. dbus_fast/send_reply.py +61 -0
  38. dbus_fast/service.cpython-39-aarch64-linux-gnu.so +0 -0
  39. dbus_fast/service.pxd +50 -0
  40. dbus_fast/service.py +682 -0
  41. dbus_fast/signature.cpython-39-aarch64-linux-gnu.so +0 -0
  42. dbus_fast/signature.pxd +31 -0
  43. dbus_fast/signature.py +481 -0
  44. dbus_fast/unpack.cpython-39-aarch64-linux-gnu.so +0 -0
  45. dbus_fast/unpack.pxd +13 -0
  46. dbus_fast/unpack.py +24 -0
  47. dbus_fast/validators.py +199 -0
  48. dbus_fast-2.45.0.dist-info/METADATA +263 -0
  49. dbus_fast-2.45.0.dist-info/RECORD +51 -0
  50. dbus_fast-2.45.0.dist-info/WHEEL +4 -0
  51. dbus_fast-2.45.0.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,902 @@
1
+ from __future__ import annotations
2
+
3
+ import array
4
+ import errno
5
+ import io
6
+ import socket
7
+ import sys
8
+ from collections.abc import Iterable
9
+ from struct import Struct
10
+ from typing import TYPE_CHECKING, Any, Callable
11
+
12
+ from ..constants import MESSAGE_FLAG_MAP, MESSAGE_TYPE_MAP, MessageFlag
13
+ from ..errors import InvalidMessageError
14
+ from ..message import Message
15
+ from ..signature import SignatureType, Variant, get_signature_tree
16
+ from .constants import BIG_ENDIAN, LITTLE_ENDIAN, PROTOCOL_VERSION
17
+
18
+ MESSAGE_FLAG_INTENUM = MessageFlag
19
+
20
+ MAX_UNIX_FDS = 16
21
+ MAX_UNIX_FDS_SIZE = array.array("i").itemsize
22
+ UNIX_FDS_CMSG_LENGTH = socket.CMSG_LEN(MAX_UNIX_FDS_SIZE * MAX_UNIX_FDS)
23
+
24
+ UNPACK_SYMBOL = {LITTLE_ENDIAN: "<", BIG_ENDIAN: ">"}
25
+
26
+ UINT32_CAST = "I"
27
+ UINT32_SIZE = 4
28
+ UINT32_DBUS_TYPE = "u"
29
+
30
+ INT16_CAST = "h"
31
+ INT16_SIZE = 2
32
+ INT16_DBUS_TYPE = "n"
33
+
34
+ UINT16_CAST = "H"
35
+ UINT16_SIZE = 2
36
+ UINT16_DBUS_TYPE = "q"
37
+
38
+ SYS_IS_LITTLE_ENDIAN = sys.byteorder == "little"
39
+ SYS_IS_BIG_ENDIAN = sys.byteorder == "big"
40
+
41
+ DBUS_TO_CTYPE = {
42
+ "y": ("B", 1), # byte
43
+ INT16_DBUS_TYPE: (INT16_CAST, INT16_SIZE), # int16
44
+ UINT16_DBUS_TYPE: (UINT16_CAST, UINT16_SIZE), # uint16
45
+ "i": ("i", 4), # int32
46
+ UINT32_DBUS_TYPE: (UINT32_CAST, UINT32_SIZE), # uint32
47
+ "x": ("q", 8), # int64
48
+ "t": ("Q", 8), # uint64
49
+ "d": ("d", 8), # double
50
+ "h": (UINT32_CAST, UINT32_SIZE), # uint32
51
+ }
52
+
53
+ UNPACK_HEADER_LITTLE_ENDIAN = Struct("<III").unpack_from
54
+ UNPACK_HEADER_BIG_ENDIAN = Struct(">III").unpack_from
55
+
56
+ UINT32_UNPACK_LITTLE_ENDIAN = Struct(f"<{UINT32_CAST}").unpack_from
57
+ UINT32_UNPACK_BIG_ENDIAN = Struct(f">{UINT32_CAST}").unpack_from
58
+
59
+ INT16_UNPACK_LITTLE_ENDIAN = Struct(f"<{INT16_CAST}").unpack_from
60
+ INT16_UNPACK_BIG_ENDIAN = Struct(f">{INT16_CAST}").unpack_from
61
+
62
+ UINT16_UNPACK_LITTLE_ENDIAN = Struct(f"<{UINT16_CAST}").unpack_from
63
+ UINT16_UNPACK_BIG_ENDIAN = Struct(f">{UINT16_CAST}").unpack_from
64
+
65
+ HEADER_SIGNATURE_SIZE = 16
66
+ HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION = 12
67
+
68
+
69
+ # Most common signatures
70
+
71
+ SIGNATURE_TREE_EMPTY = get_signature_tree("")
72
+ SIGNATURE_TREE_B = get_signature_tree("b")
73
+ SIGNATURE_TREE_N = get_signature_tree("n")
74
+ SIGNATURE_TREE_S = get_signature_tree("s")
75
+ SIGNATURE_TREE_O = get_signature_tree("o")
76
+ SIGNATURE_TREE_U = get_signature_tree("u")
77
+ SIGNATURE_TREE_Y = get_signature_tree("y")
78
+
79
+ SIGNATURE_TREE_AY = get_signature_tree("ay")
80
+ SIGNATURE_TREE_AS = get_signature_tree("as")
81
+ SIGNATURE_TREE_AS_TYPES_0 = SIGNATURE_TREE_AS.root_type
82
+ SIGNATURE_TREE_A_SV = get_signature_tree("a{sv}")
83
+ SIGNATURE_TREE_A_SV_TYPES_0 = SIGNATURE_TREE_A_SV.root_type
84
+
85
+ SIGNATURE_TREE_AO = get_signature_tree("ao")
86
+ SIGNATURE_TREE_AO_TYPES_0 = SIGNATURE_TREE_AO.root_type
87
+
88
+ SIGNATURE_TREE_OAS = get_signature_tree("oas")
89
+ SIGNATURE_TREE_OAS_TYPES_1 = SIGNATURE_TREE_OAS.types[1]
90
+
91
+ SIGNATURE_TREE_AY_TYPES_0 = SIGNATURE_TREE_AY.root_type
92
+ SIGNATURE_TREE_A_QV = get_signature_tree("a{qv}")
93
+ SIGNATURE_TREE_A_QV_TYPES_0 = SIGNATURE_TREE_A_QV.root_type
94
+
95
+ SIGNATURE_TREE_SA_SV_AS = get_signature_tree("sa{sv}as")
96
+ SIGNATURE_TREE_SA_SV_AS_TYPES_1 = SIGNATURE_TREE_SA_SV_AS.types[1]
97
+ SIGNATURE_TREE_SA_SV_AS_TYPES_2 = SIGNATURE_TREE_SA_SV_AS.types[2]
98
+
99
+ SIGNATURE_TREE_OA_SA_SV = get_signature_tree("oa{sa{sv}}")
100
+ SIGNATURE_TREE_OA_SA_SV_TYPES_1 = SIGNATURE_TREE_OA_SA_SV.types[1]
101
+
102
+ SIGNATURE_TREE_A_OA_SA_SV = get_signature_tree("a{oa{sa{sv}}}")
103
+ SIGNATURE_TREE_A_OA_SA_SV_TYPES_0 = SIGNATURE_TREE_A_OA_SA_SV.root_type
104
+
105
+
106
+ TOKEN_B_AS_INT = ord("b")
107
+ TOKEN_U_AS_INT = ord("u")
108
+ TOKEN_Y_AS_INT = ord("y")
109
+ TOKEN_A_AS_INT = ord("a")
110
+ TOKEN_O_AS_INT = ord("o")
111
+ TOKEN_S_AS_INT = ord("s")
112
+ TOKEN_G_AS_INT = ord("g")
113
+ TOKEN_N_AS_INT = ord("n")
114
+ TOKEN_X_AS_INT = ord("x")
115
+ TOKEN_T_AS_INT = ord("t")
116
+ TOKEN_D_AS_INT = ord("d")
117
+ TOKEN_Q_AS_INT = ord("q")
118
+ TOKEN_V_AS_INT = ord("v")
119
+ TOKEN_LEFT_CURLY_AS_INT = ord("{")
120
+ TOKEN_LEFT_PAREN_AS_INT = ord("(")
121
+
122
+
123
+ VARIANT_BOOL_TRUE = Variant._factory(SIGNATURE_TREE_B, True)
124
+ VARIANT_BOOL_FALSE = Variant._factory(SIGNATURE_TREE_B, False)
125
+
126
+
127
+ ARRAY = array.array
128
+ SOL_SOCKET = socket.SOL_SOCKET
129
+ SCM_RIGHTS = socket.SCM_RIGHTS
130
+
131
+ EAGAIN = errno.EAGAIN
132
+ EWOULDBLOCK = errno.EWOULDBLOCK
133
+
134
+ HEADER_IDX_TO_ARG_NAME = [
135
+ "",
136
+ "path",
137
+ "interface",
138
+ "member",
139
+ "error_name",
140
+ "reply_serial",
141
+ "destination",
142
+ "sender",
143
+ "signature",
144
+ "unix_fds",
145
+ ]
146
+ HEADER_PATH_IDX = HEADER_IDX_TO_ARG_NAME.index("path")
147
+ HEADER_INTERFACE_IDX = HEADER_IDX_TO_ARG_NAME.index("interface")
148
+ HEADER_MEMBER_IDX = HEADER_IDX_TO_ARG_NAME.index("member")
149
+ HEADER_ERROR_NAME_IDX = HEADER_IDX_TO_ARG_NAME.index("error_name")
150
+ HEADER_REPLY_SERIAL_IDX = HEADER_IDX_TO_ARG_NAME.index("reply_serial")
151
+ HEADER_DESTINATION_IDX = HEADER_IDX_TO_ARG_NAME.index("destination")
152
+ HEADER_SENDER_IDX = HEADER_IDX_TO_ARG_NAME.index("sender")
153
+ HEADER_SIGNATURE_IDX = HEADER_IDX_TO_ARG_NAME.index("signature")
154
+ HEADER_UNIX_FDS_IDX = HEADER_IDX_TO_ARG_NAME.index("unix_fds")
155
+
156
+ _EMPTY_HEADERS: list[Any | None] = [None] * len(HEADER_IDX_TO_ARG_NAME)
157
+
158
+ _SignatureType = SignatureType
159
+ _int = int
160
+
161
+ READER_TYPE = Callable[["Unmarshaller", SignatureType], Any]
162
+
163
+ MARSHALL_STREAM_END_ERROR = BlockingIOError
164
+
165
+ DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE
166
+
167
+
168
+ def unpack_parser_factory(unpack_from: Callable, size: int) -> READER_TYPE:
169
+ """Build a parser that unpacks the bytes using the given unpack_from function."""
170
+
171
+ def _unpack_from_parser(self: Unmarshaller, signature: SignatureType) -> Any:
172
+ self._pos += size + (-self._pos & (size - 1)) # align
173
+ return unpack_from(self._buf, self._pos - size)[0]
174
+
175
+ return _unpack_from_parser
176
+
177
+
178
+ def build_simple_parsers(
179
+ endian: int,
180
+ ) -> dict[str, Callable[[Unmarshaller, SignatureType], Any]]:
181
+ """Build a dict of parsers for simple types."""
182
+ parsers: dict[str, READER_TYPE] = {}
183
+ for dbus_type, ctype_size in DBUS_TO_CTYPE.items():
184
+ ctype, size = ctype_size
185
+ size = ctype_size[1]
186
+ parsers[dbus_type] = unpack_parser_factory(
187
+ Struct(f"{UNPACK_SYMBOL[endian]}{ctype}").unpack_from, size
188
+ )
189
+ return parsers
190
+
191
+
192
+ try:
193
+ import cython
194
+ except ImportError:
195
+ from ._cython_compat import FAKE_CYTHON as cython
196
+ int_ = int
197
+ bytearray_ = bytearray
198
+
199
+
200
+ def is_compiled() -> bool:
201
+ return cython.compiled
202
+
203
+
204
+ def _ustr_uint32(buf: bytearray_, pos: int_, endian: int_) -> int_:
205
+ if endian == LITTLE_ENDIAN:
206
+ return (
207
+ buf[pos] | (buf[pos + 1] << 8) | (buf[pos + 2] << 16) | (buf[pos + 3] << 24)
208
+ )
209
+ return buf[pos + 3] | (buf[pos + 2] << 8) | (buf[pos + 1] << 16) | (buf[pos] << 24)
210
+
211
+
212
+ def buffer_to_uint32(buf: bytearray, pos: int, endian: int) -> int:
213
+ return _ustr_uint32(buf, pos, endian)
214
+
215
+
216
+ def _ustr_int16(buf: bytearray_, pos: int_, endian: int_) -> int_:
217
+ # Caution: this function will only work with Cython
218
+ # because it relies on casting the result to a signed int
219
+ # and will return an unsigned int if not compiled.
220
+ if endian == LITTLE_ENDIAN:
221
+ return buf[pos] | (buf[pos + 1] << 8) # pragma: no cover
222
+ return buf[pos + 1] | (buf[pos] << 8) # pragma: no cover
223
+
224
+
225
+ def buffer_to_int16(buf: bytearray | bytes, pos: int, endian: int) -> int:
226
+ # Caution: this function will only work with Cython
227
+ # because it relies on casting the result to a signed int
228
+ # and will return an unsigned int if not compiled.
229
+ return _ustr_int16(buf, pos, endian)
230
+
231
+
232
+ def _ustr_uint16(buf: bytearray_, pos: int_, endian: int_) -> int_:
233
+ if endian == LITTLE_ENDIAN:
234
+ return buf[pos] | (buf[pos + 1] << 8)
235
+ return buf[pos + 1] | (buf[pos] << 8)
236
+
237
+
238
+ def buffer_to_uint16(buf: bytearray, pos: int, endian: int) -> int:
239
+ return _ustr_uint16(buf, pos, endian)
240
+
241
+
242
+ # Alignment padding is handled with the following formula below
243
+ #
244
+ # For any align value, the correct padding formula is:
245
+ #
246
+ # (align - (pos % align)) % align
247
+ #
248
+ # However, if align is a power of 2 (always the case here), the slow MOD
249
+ # operator can be replaced by a bitwise AND:
250
+ #
251
+ # (align - (pos & (align - 1))) & (align - 1)
252
+ #
253
+ # Which can be simplified to:
254
+ #
255
+ # (-pos) & (align - 1)
256
+ #
257
+ #
258
+ class Unmarshaller:
259
+ """Unmarshall messages from a stream.
260
+
261
+ When calling with sock and _negotiate_unix_fd False, the unmashaller must
262
+ be called continuously for each new message as it will buffer the data
263
+ until a complete message is available.
264
+ """
265
+
266
+ __slots__ = (
267
+ "_body_len",
268
+ "_buf",
269
+ "_buf_len",
270
+ "_buf_ustr",
271
+ "_endian",
272
+ "_flag",
273
+ "_header_len",
274
+ "_int16_unpack",
275
+ "_message",
276
+ "_message_type",
277
+ "_msg_len",
278
+ "_negotiate_unix_fd",
279
+ "_pos",
280
+ "_read_complete",
281
+ "_readers",
282
+ "_serial",
283
+ "_sock",
284
+ "_sock_with_fds_reader",
285
+ "_sock_without_fds_reader",
286
+ "_stream",
287
+ "_stream_reader",
288
+ "_uint16_unpack",
289
+ "_uint32_unpack",
290
+ "_unix_fds",
291
+ )
292
+
293
+ _stream_reader: Callable[[int], bytes]
294
+
295
+ def __init__(
296
+ self,
297
+ stream: io.BufferedRWPair | None = None,
298
+ sock: socket.socket | None = None,
299
+ negotiate_unix_fd: bool = True,
300
+ ) -> None:
301
+ self._unix_fds: list[int] = []
302
+ self._buf: bytearray = bytearray.__new__(bytearray) # Actual buffer
303
+ self._buf_ustr = self._buf # Used to avoid type checks
304
+ self._buf_len = 0
305
+ self._stream = stream
306
+ self._sock = sock
307
+ self._message: Message | None = None
308
+ self._readers: dict[str, READER_TYPE] = {}
309
+ self._pos = 0
310
+ self._body_len = 0
311
+ self._serial = 0
312
+ self._header_len = 0
313
+ self._message_type = 0
314
+ self._flag = 0
315
+ self._msg_len = 0
316
+ self._uint32_unpack: Callable[[bytearray, int], tuple[int]] | None = None
317
+ self._int16_unpack: Callable[[bytearray, int], tuple[int]] | None = None
318
+ self._uint16_unpack: Callable[[bytearray, int], tuple[int]] | None = None
319
+ self._negotiate_unix_fd = negotiate_unix_fd
320
+ self._read_complete = False
321
+ if stream:
322
+ if isinstance(stream, io.BufferedRWPair) and hasattr(stream, "reader"):
323
+ self._stream_reader = stream.reader.read
324
+ else:
325
+ self._stream_reader = stream.read
326
+ elif self._negotiate_unix_fd:
327
+ if TYPE_CHECKING:
328
+ assert self._sock is not None
329
+ self._sock_with_fds_reader = self._sock.recvmsg
330
+ else:
331
+ if TYPE_CHECKING:
332
+ assert self._sock is not None
333
+ self._sock_without_fds_reader = self._sock.recv
334
+ self._endian = 0
335
+
336
+ def _next_message(self) -> None:
337
+ """Reset the unmarshaller to its initial state.
338
+
339
+ Call this before processing a new message.
340
+ """
341
+ if self._unix_fds:
342
+ self._unix_fds = []
343
+ to_clear = HEADER_SIGNATURE_SIZE + self._msg_len
344
+ if self._buf_len == to_clear:
345
+ self._buf = bytearray.__new__(bytearray)
346
+ self._buf_len = 0
347
+ else:
348
+ del self._buf[:to_clear]
349
+ self._buf_len -= to_clear
350
+ self._buf_ustr = self._buf
351
+ self._msg_len = 0 # used to check if we have ready the header
352
+ self._read_complete = False # used to check if we have ready the message
353
+ # No need to reset the unpack functions, they are set in _read_header
354
+ # every time a new message is processed.
355
+
356
+ @property
357
+ def message(self) -> Message | None:
358
+ """Return the message that has been unmarshalled."""
359
+ if self._read_complete:
360
+ return self._message
361
+ return None
362
+
363
+ def _has_another_message_in_buffer(self) -> bool:
364
+ """Check if there is another message in the buffer."""
365
+ return self._buf_len > HEADER_SIGNATURE_SIZE + self._msg_len
366
+
367
+ def _read_sock_with_fds(self, pos: _int, missing_bytes: _int) -> None:
368
+ """reads from the socket, storing any fds sent and handling errors
369
+ from the read itself.
370
+
371
+ This function is greedy and will read as much data as possible
372
+ from the underlying socket.
373
+ """
374
+ # This will raise BlockingIOError if there is no data to read
375
+ # which we store in the MARSHALL_STREAM_END_ERROR object
376
+ try:
377
+ recv = self._sock_with_fds_reader(missing_bytes, UNIX_FDS_CMSG_LENGTH)
378
+ except OSError as e:
379
+ errno = e.errno
380
+ if errno == EAGAIN or errno == EWOULDBLOCK:
381
+ raise MARSHALL_STREAM_END_ERROR
382
+ raise
383
+ msg = recv[0]
384
+ ancdata = recv[1]
385
+ if ancdata:
386
+ for level, type_, data in ancdata:
387
+ if not (level == SOL_SOCKET and type_ == SCM_RIGHTS):
388
+ continue
389
+ self._unix_fds.extend(
390
+ ARRAY("i", data[: len(data) - (len(data) % MAX_UNIX_FDS_SIZE)])
391
+ )
392
+ if not msg:
393
+ raise EOFError
394
+ self._buf += msg
395
+ self._buf_len = len(self._buf)
396
+ if self._buf_len < pos:
397
+ raise MARSHALL_STREAM_END_ERROR
398
+
399
+ def _read_sock_without_fds(self, pos: _int) -> None:
400
+ """reads from the socket and handling errors from the read itself.
401
+
402
+ This function is greedy and will read as much data as possible
403
+ from the underlying socket.
404
+ """
405
+ # This will raise BlockingIOError if there is no data to read
406
+ # which we store in the MARSHALL_STREAM_END_ERROR object
407
+ while True:
408
+ try:
409
+ data = self._sock_without_fds_reader(DEFAULT_BUFFER_SIZE)
410
+ except OSError as e:
411
+ errno = e.errno
412
+ if errno == EAGAIN or errno == EWOULDBLOCK:
413
+ raise MARSHALL_STREAM_END_ERROR
414
+ raise
415
+ if not data:
416
+ raise EOFError
417
+ self._buf += data
418
+ self._buf_len = len(self._buf)
419
+ if self._buf_len >= pos:
420
+ return
421
+
422
+ def _read_stream(self, pos: _int, missing_bytes: _int) -> None:
423
+ """Read from the stream."""
424
+ data = self._stream_reader(missing_bytes)
425
+ if data is None:
426
+ raise MARSHALL_STREAM_END_ERROR
427
+ if not data:
428
+ raise EOFError
429
+ self._buf += data
430
+ self._buf_len = len(self._buf)
431
+ if self._buf_len < pos:
432
+ raise MARSHALL_STREAM_END_ERROR
433
+
434
+ def _read_to_pos(self, pos: _int) -> None:
435
+ """
436
+ Read from underlying socket into buffer.
437
+
438
+ Raises BlockingIOError if there is not enough data to be read.
439
+
440
+ :arg pos:
441
+ The pos to read to. If not enough bytes are available in the
442
+ buffer, read more from it.
443
+
444
+ :returns:
445
+ None
446
+ """
447
+ missing_bytes = pos - self._buf_len
448
+ if missing_bytes <= 0:
449
+ return
450
+ if self._sock is None:
451
+ self._read_stream(pos, missing_bytes)
452
+ elif self._negotiate_unix_fd:
453
+ self._read_sock_with_fds(pos, missing_bytes)
454
+ else:
455
+ self._read_sock_without_fds(pos)
456
+ self._buf_ustr = self._buf
457
+
458
+ def read_uint32_unpack(self, type_: _SignatureType) -> int:
459
+ return self._read_uint32_unpack()
460
+
461
+ def _read_uint32_unpack(self) -> int:
462
+ self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
463
+ if cython.compiled:
464
+ if self._buf_len < self._pos:
465
+ raise IndexError("Not enough data to read uint32")
466
+ return _ustr_uint32(self._buf_ustr, self._pos - UINT32_SIZE, self._endian)
467
+ return self._uint32_unpack(self._buf, self._pos - UINT32_SIZE)[0]
468
+
469
+ def read_uint16_unpack(self, type_: _SignatureType) -> int:
470
+ return self._read_uint16_unpack()
471
+
472
+ def _read_uint16_unpack(self) -> int:
473
+ self._pos += UINT16_SIZE + (-self._pos & (UINT16_SIZE - 1)) # align
474
+ if cython.compiled:
475
+ if self._buf_len < self._pos:
476
+ raise IndexError("Not enough data to read uint16")
477
+ return _ustr_uint16(self._buf_ustr, self._pos - UINT16_SIZE, self._endian)
478
+ return self._uint16_unpack(self._buf, self._pos - UINT16_SIZE)[0]
479
+
480
+ def read_int16_unpack(self, type_: _SignatureType) -> int:
481
+ return self._read_int16_unpack()
482
+
483
+ def _read_int16_unpack(self) -> int:
484
+ self._pos += INT16_SIZE + (-self._pos & (INT16_SIZE - 1)) # align
485
+ if cython.compiled:
486
+ if self._buf_len < self._pos:
487
+ raise IndexError("Not enough data to read int16")
488
+ return _ustr_int16(self._buf_ustr, self._pos - INT16_SIZE, self._endian)
489
+ return self._int16_unpack(self._buf, self._pos - INT16_SIZE)[0]
490
+
491
+ def read_boolean(self, type_: _SignatureType) -> bool:
492
+ return self._read_boolean()
493
+
494
+ def _read_boolean(self) -> bool:
495
+ return bool(self._read_uint32_unpack())
496
+
497
+ def read_string_unpack(self, type_: _SignatureType) -> str:
498
+ return self._read_string_unpack()
499
+
500
+ def _read_string_unpack(self) -> str:
501
+ """Read a string using unpack."""
502
+ self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
503
+ str_start = self._pos
504
+ # read terminating '\0' byte as well (str_length + 1)
505
+ if cython.compiled:
506
+ if self._buf_len < self._pos:
507
+ raise IndexError("Not enough data to read uint32")
508
+ self._pos += (
509
+ _ustr_uint32(self._buf_ustr, str_start - UINT32_SIZE, self._endian) + 1
510
+ )
511
+ if self._buf_len < self._pos:
512
+ raise IndexError("Not enough data to read string")
513
+ else:
514
+ self._pos += self._uint32_unpack(self._buf, str_start - UINT32_SIZE)[0] + 1
515
+ return self._buf_ustr[str_start : self._pos - 1].decode()
516
+
517
+ def read_signature(self, type_: _SignatureType) -> str:
518
+ return self._read_signature()
519
+
520
+ def _read_signature(self) -> str:
521
+ if cython.compiled:
522
+ if self._buf_len < self._pos:
523
+ raise IndexError("Not enough data to read signature")
524
+ signature_len = self._buf_ustr[self._pos] # byte
525
+ o = self._pos + 1
526
+ # read terminating '\0' byte as well (str_length + 1)
527
+ self._pos = o + signature_len + 1
528
+ if cython.compiled:
529
+ if self._buf_len < self._pos:
530
+ raise IndexError("Not enough data to read signature")
531
+ return self._buf_ustr[o : o + signature_len].decode()
532
+
533
+ def read_variant(self, type_: _SignatureType) -> Variant:
534
+ return self._read_variant()
535
+
536
+ def _read_variant(self) -> Variant:
537
+ signature = self._read_signature()
538
+ token_as_int = ord(signature[0])
539
+ # verify in Variant is only useful on construction not unmarshalling
540
+ if len(signature) == 1:
541
+ if token_as_int == TOKEN_N_AS_INT:
542
+ return Variant._factory(SIGNATURE_TREE_N, self._read_int16_unpack())
543
+ if token_as_int == TOKEN_S_AS_INT:
544
+ return Variant._factory(SIGNATURE_TREE_S, self._read_string_unpack())
545
+ if token_as_int == TOKEN_B_AS_INT:
546
+ return VARIANT_BOOL_TRUE if self._read_boolean() else VARIANT_BOOL_FALSE
547
+ if token_as_int == TOKEN_O_AS_INT:
548
+ return Variant._factory(SIGNATURE_TREE_O, self._read_string_unpack())
549
+ if token_as_int == TOKEN_U_AS_INT:
550
+ return Variant._factory(SIGNATURE_TREE_U, self._read_uint32_unpack())
551
+ if token_as_int == TOKEN_Y_AS_INT:
552
+ if cython.compiled:
553
+ if self._buf_len < self._pos:
554
+ raise IndexError("Not enough data to read byte")
555
+ self._pos += 1
556
+ return Variant._factory(SIGNATURE_TREE_Y, self._buf_ustr[self._pos - 1])
557
+ elif token_as_int == TOKEN_A_AS_INT:
558
+ if signature == "ay":
559
+ return Variant._factory(
560
+ SIGNATURE_TREE_AY, self.read_array(SIGNATURE_TREE_AY_TYPES_0)
561
+ )
562
+ if signature == "a{qv}":
563
+ return Variant._factory(
564
+ SIGNATURE_TREE_A_QV, self.read_array(SIGNATURE_TREE_A_QV_TYPES_0)
565
+ )
566
+ if signature == "as":
567
+ return Variant._factory(
568
+ SIGNATURE_TREE_AS, self.read_array(SIGNATURE_TREE_AS_TYPES_0)
569
+ )
570
+ if signature == "a{sv}":
571
+ return Variant._factory(
572
+ SIGNATURE_TREE_A_SV, self.read_array(SIGNATURE_TREE_A_SV_TYPES_0)
573
+ )
574
+ if signature == "ao":
575
+ return Variant._factory(
576
+ SIGNATURE_TREE_AO, self.read_array(SIGNATURE_TREE_AO_TYPES_0)
577
+ )
578
+ tree = get_signature_tree(signature)
579
+ signature_type = tree.root_type
580
+ return Variant._factory(
581
+ tree, self._readers[signature_type.token](self, signature_type)
582
+ )
583
+
584
+ def read_struct(self, type_: _SignatureType) -> list[Any]:
585
+ self._pos += -self._pos & 7 # align 8
586
+ readers = self._readers
587
+ return [
588
+ readers[child_type.token](self, child_type) for child_type in type_.children
589
+ ]
590
+
591
+ def read_dict_entry(self, type_: _SignatureType) -> tuple[Any, Any]:
592
+ self._pos += -self._pos & 7 # align 8
593
+ return self._readers[type_.children[0].token](
594
+ self, type_.children[0]
595
+ ), self._readers[type_.children[1].token](self, type_.children[1])
596
+
597
+ def read_array(self, type_: _SignatureType) -> Iterable[Any]:
598
+ self._pos += -self._pos & 3 # align 4 for the array
599
+ self._pos += (
600
+ -self._pos & (UINT32_SIZE - 1)
601
+ ) + UINT32_SIZE # align for the uint32
602
+ if cython.compiled:
603
+ if self._buf_len < self._pos:
604
+ raise IndexError("Not enough data to read uint32")
605
+ array_length = _ustr_uint32(
606
+ self._buf_ustr, self._pos - UINT32_SIZE, self._endian
607
+ )
608
+ else:
609
+ array_length = self._uint32_unpack(self._buf, self._pos - UINT32_SIZE)[0]
610
+ child_type = type_._child_0
611
+ token_as_int = child_type.token_as_int
612
+
613
+ if token_as_int in {
614
+ TOKEN_X_AS_INT,
615
+ TOKEN_T_AS_INT,
616
+ TOKEN_D_AS_INT,
617
+ TOKEN_LEFT_CURLY_AS_INT,
618
+ TOKEN_LEFT_PAREN_AS_INT,
619
+ }:
620
+ # the first alignment is not included in the array size
621
+ self._pos += -self._pos & 7 # align 8
622
+
623
+ if token_as_int == TOKEN_Y_AS_INT:
624
+ self._pos += array_length
625
+ if cython.compiled:
626
+ if self._buf_len < self._pos:
627
+ raise IndexError("Not enough data to read byte")
628
+ return self._buf_ustr[self._pos - array_length : self._pos]
629
+
630
+ if token_as_int == TOKEN_LEFT_CURLY_AS_INT:
631
+ result_dict: dict[Any, Any] = {}
632
+ key: str | int
633
+ beginning_pos = self._pos
634
+ child_0 = child_type._child_0
635
+ child_1 = child_type._child_1
636
+ child_0_token_as_int = child_0.token_as_int
637
+ child_1_token_as_int = child_1.token_as_int
638
+ # Strings with variant values are the most common case
639
+ # so we optimize for that by inlining the string reading
640
+ # and the variant reading here
641
+ if (
642
+ child_0_token_as_int in {TOKEN_O_AS_INT, TOKEN_S_AS_INT}
643
+ and child_1_token_as_int == TOKEN_V_AS_INT
644
+ ):
645
+ while self._pos - beginning_pos < array_length:
646
+ self._pos += -self._pos & 7 # align 8
647
+ key = self._read_string_unpack()
648
+ result_dict[key] = self._read_variant()
649
+ elif (
650
+ child_0_token_as_int == TOKEN_Q_AS_INT
651
+ and child_1_token_as_int == TOKEN_V_AS_INT
652
+ ):
653
+ while self._pos - beginning_pos < array_length:
654
+ self._pos += -self._pos & 7 # align 8
655
+ key = self._read_uint16_unpack()
656
+ result_dict[key] = self._read_variant()
657
+ elif (
658
+ child_0_token_as_int in {TOKEN_O_AS_INT, TOKEN_S_AS_INT}
659
+ and child_1_token_as_int == TOKEN_A_AS_INT
660
+ ):
661
+ while self._pos - beginning_pos < array_length:
662
+ self._pos += -self._pos & 7 # align 8
663
+ key = self._read_string_unpack()
664
+ result_dict[key] = self.read_array(child_1)
665
+ else:
666
+ reader_1 = self._readers[child_1.token]
667
+ reader_0 = self._readers[child_0.token]
668
+ while self._pos - beginning_pos < array_length:
669
+ self._pos += -self._pos & 7 # align 8
670
+ key = reader_0(self, child_0)
671
+ result_dict[key] = reader_1(self, child_1)
672
+
673
+ return result_dict
674
+
675
+ if array_length == 0:
676
+ return []
677
+
678
+ result_list = []
679
+ beginning_pos = self._pos
680
+ if token_as_int == TOKEN_O_AS_INT or token_as_int == TOKEN_S_AS_INT:
681
+ while self._pos - beginning_pos < array_length:
682
+ result_list.append(self._read_string_unpack())
683
+ return result_list
684
+ reader = self._readers[child_type.token]
685
+ while self._pos - beginning_pos < array_length:
686
+ result_list.append(reader(self, child_type))
687
+ return result_list
688
+
689
+ def _header_fields(self, header_length: _int) -> list[Any]:
690
+ """Header fields are always a(yv)."""
691
+ beginning_pos = self._pos
692
+ headers = _EMPTY_HEADERS.copy()
693
+ if cython.compiled:
694
+ if self._buf_len < self._pos + header_length:
695
+ raise IndexError("Not enough data to read header")
696
+ while self._pos - beginning_pos < header_length:
697
+ # Now read the y (byte) of struct (yv)
698
+ self._pos += (-self._pos & 7) + 1 # align 8 + 1 for 'y' byte
699
+ field_0 = self._buf_ustr[self._pos - 1]
700
+
701
+ # Now read the v (variant) of struct (yv)
702
+ # first we read the signature
703
+ signature_len = self._buf_ustr[self._pos] # byte
704
+ o = self._pos + 1
705
+ if cython.compiled:
706
+ if self._buf_len < o + signature_len:
707
+ raise IndexError("Not enough data to read signature")
708
+ self._pos += signature_len + 2 # one for the byte, one for the '\0'
709
+ if field_0 == HEADER_UNIX_FDS_IDX: # defined by self._unix_fds
710
+ continue
711
+ token_as_int = self._buf_ustr[o]
712
+ # Now that we have the token we can read the variant value
713
+ # Strings and signatures are the most common types
714
+ # so we inline them for performance
715
+ if token_as_int == TOKEN_O_AS_INT or token_as_int == TOKEN_S_AS_INT:
716
+ headers[field_0] = self._read_string_unpack()
717
+ elif token_as_int == TOKEN_G_AS_INT:
718
+ headers[field_0] = self._read_signature()
719
+ else:
720
+ token = self._buf_ustr[o : o + signature_len].decode()
721
+ # There shouldn't be any other types in the header
722
+ # but just in case, we'll read it using the slow path
723
+ headers[field_0] = self._readers[token](
724
+ self, get_signature_tree(token).root_type
725
+ )
726
+ return headers
727
+
728
+ def _read_header(self) -> None:
729
+ """Read the header of the message."""
730
+ # Signature is of the header is
731
+ # BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT)
732
+ self._read_to_pos(HEADER_SIGNATURE_SIZE)
733
+ endian = self._buf_ustr[0]
734
+ self._message_type = self._buf_ustr[1]
735
+ self._flag = self._buf_ustr[2]
736
+ protocol_version = self._buf_ustr[3]
737
+
738
+ if protocol_version != PROTOCOL_VERSION:
739
+ raise InvalidMessageError(
740
+ f"got unknown protocol version: {protocol_version}"
741
+ )
742
+
743
+ if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN:
744
+ raise InvalidMessageError(
745
+ f"Expecting endianness as the first byte, got {endian} from {self._buf}"
746
+ )
747
+
748
+ if cython.compiled:
749
+ self._body_len = _ustr_uint32(self._buf_ustr, 4, endian)
750
+ self._serial = _ustr_uint32(self._buf_ustr, 8, endian)
751
+ self._header_len = _ustr_uint32(self._buf_ustr, 12, endian)
752
+ elif endian == LITTLE_ENDIAN:
753
+ (
754
+ self._body_len,
755
+ self._serial,
756
+ self._header_len,
757
+ ) = UNPACK_HEADER_LITTLE_ENDIAN(self._buf, 4)
758
+ self._uint32_unpack = UINT32_UNPACK_LITTLE_ENDIAN
759
+ self._int16_unpack = INT16_UNPACK_LITTLE_ENDIAN
760
+ self._uint16_unpack = UINT16_UNPACK_LITTLE_ENDIAN
761
+ else: # BIG_ENDIAN
762
+ self._body_len, self._serial, self._header_len = UNPACK_HEADER_BIG_ENDIAN(
763
+ self._buf, 4
764
+ )
765
+ self._uint32_unpack = UINT32_UNPACK_BIG_ENDIAN
766
+ self._int16_unpack = INT16_UNPACK_BIG_ENDIAN
767
+ self._uint16_unpack = UINT16_UNPACK_BIG_ENDIAN
768
+
769
+ # align 8
770
+ self._msg_len = self._header_len + (-self._header_len & 7) + self._body_len
771
+ if self._endian != endian:
772
+ self._readers = self._readers_by_type[endian]
773
+ self._endian = endian
774
+
775
+ def _read_body(self) -> None:
776
+ """Read the body of the message."""
777
+ self._read_to_pos(HEADER_SIGNATURE_SIZE + self._msg_len)
778
+ self._pos = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
779
+ header_fields = self._header_fields(self._header_len)
780
+ self._pos += -self._pos & 7 # align 8
781
+ signature: str = header_fields[HEADER_SIGNATURE_IDX]
782
+ if not self._body_len:
783
+ tree = SIGNATURE_TREE_EMPTY
784
+ body: list[Any] = []
785
+ else:
786
+ token_as_int = ord(signature[0])
787
+ if len(signature) == 1:
788
+ if token_as_int == TOKEN_O_AS_INT:
789
+ tree = SIGNATURE_TREE_O
790
+ body = [self._read_string_unpack()]
791
+ elif token_as_int == TOKEN_S_AS_INT:
792
+ tree = SIGNATURE_TREE_S
793
+ body = [self._read_string_unpack()]
794
+ else:
795
+ tree = get_signature_tree(signature)
796
+ body = [self._readers[t.token](self, t) for t in tree.types]
797
+ elif token_as_int == TOKEN_S_AS_INT and signature == "sa{sv}as":
798
+ tree = SIGNATURE_TREE_SA_SV_AS
799
+ body = [
800
+ self._read_string_unpack(),
801
+ self.read_array(SIGNATURE_TREE_SA_SV_AS_TYPES_1),
802
+ self.read_array(SIGNATURE_TREE_SA_SV_AS_TYPES_2),
803
+ ]
804
+ elif token_as_int == TOKEN_O_AS_INT and signature == "oa{sa{sv}}":
805
+ tree = SIGNATURE_TREE_OA_SA_SV
806
+ body = [
807
+ self._read_string_unpack(),
808
+ self.read_array(SIGNATURE_TREE_OA_SA_SV_TYPES_1),
809
+ ]
810
+ elif token_as_int == TOKEN_O_AS_INT and signature == "oas":
811
+ tree = SIGNATURE_TREE_OAS
812
+ body = [
813
+ self._read_string_unpack(),
814
+ self.read_array(SIGNATURE_TREE_OAS_TYPES_1),
815
+ ]
816
+ elif token_as_int == TOKEN_A_AS_INT and signature == "a{oa{sa{sv}}}":
817
+ tree = SIGNATURE_TREE_A_OA_SA_SV
818
+ body = [self.read_array(SIGNATURE_TREE_A_OA_SA_SV_TYPES_0)]
819
+ else:
820
+ tree = get_signature_tree(signature)
821
+ body = [self._readers[t.token](self, t) for t in tree.types]
822
+
823
+ flags = MESSAGE_FLAG_MAP.get(self._flag)
824
+ if flags is None:
825
+ flags = MESSAGE_FLAG_INTENUM(self._flag)
826
+ message = Message.__new__(Message)
827
+ message._fast_init(
828
+ header_fields[HEADER_DESTINATION_IDX],
829
+ header_fields[HEADER_PATH_IDX],
830
+ header_fields[HEADER_INTERFACE_IDX],
831
+ header_fields[HEADER_MEMBER_IDX],
832
+ MESSAGE_TYPE_MAP[self._message_type],
833
+ flags,
834
+ header_fields[HEADER_ERROR_NAME_IDX],
835
+ header_fields[HEADER_REPLY_SERIAL_IDX] or 0,
836
+ header_fields[HEADER_SENDER_IDX],
837
+ self._unix_fds,
838
+ tree,
839
+ body,
840
+ self._serial,
841
+ # The D-Bus implementation already validates the message,
842
+ # so we don't need to do it again.
843
+ False,
844
+ )
845
+ self._message = message
846
+ self._read_complete = True
847
+
848
+ def unmarshall(self) -> Message | None:
849
+ """Unmarshall the message.
850
+
851
+ The underlying read function will raise BlockingIOError if the
852
+ if there are not enough bytes in the buffer. This allows unmarshall
853
+ to be resumed when more data comes in over the wire.
854
+ """
855
+ return self._unmarshall()
856
+
857
+ def _unmarshall(self) -> Message | None:
858
+ """Unmarshall the message.
859
+
860
+ The underlying read function will raise BlockingIOError if the
861
+ if there are not enough bytes in the buffer. This allows unmarshall
862
+ to be resumed when more data comes in over the wire.
863
+ """
864
+ if self._read_complete:
865
+ self._next_message()
866
+ try:
867
+ if not self._msg_len:
868
+ self._read_header()
869
+ self._read_body()
870
+ except MARSHALL_STREAM_END_ERROR:
871
+ return None
872
+ return self._message
873
+
874
+ _complex_parsers_unpack: dict[str, Callable[[Unmarshaller, SignatureType], Any]] = {
875
+ "b": read_boolean,
876
+ "o": read_string_unpack,
877
+ "s": read_string_unpack,
878
+ "g": read_signature,
879
+ "a": read_array,
880
+ "(": read_struct,
881
+ "{": read_dict_entry,
882
+ "v": read_variant,
883
+ "h": read_uint32_unpack,
884
+ UINT32_DBUS_TYPE: read_uint32_unpack,
885
+ INT16_DBUS_TYPE: read_int16_unpack,
886
+ UINT16_DBUS_TYPE: read_uint16_unpack,
887
+ }
888
+
889
+ _ctype_by_endian: dict[int, dict[str, READER_TYPE]] = {
890
+ endian: build_simple_parsers(endian) for endian in (LITTLE_ENDIAN, BIG_ENDIAN)
891
+ }
892
+
893
+ _readers_by_type: dict[int, dict[str, READER_TYPE]] = {
894
+ LITTLE_ENDIAN: {
895
+ **_ctype_by_endian[LITTLE_ENDIAN],
896
+ **_complex_parsers_unpack,
897
+ },
898
+ BIG_ENDIAN: {
899
+ **_ctype_by_endian[BIG_ENDIAN],
900
+ **_complex_parsers_unpack,
901
+ },
902
+ }