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