frida 17.15.4 → 17.16.0
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.
- package/Makefile +1 -1
- package/build/src/frida.d.ts +13 -2
- package/build/src/frida.js +4 -1
- package/build/src/frida_binding.d.ts +21 -1
- package/frida-bindgen/frida_bindgen_core/__init__.py +8 -0
- package/frida-bindgen/frida_bindgen_core/loader.py +57 -0
- package/frida-bindgen/frida_bindgen_core/model.py +853 -0
- package/frida-bindgen/frida_bindgen_core/naming.py +40 -0
- package/package.json +2 -1
- package/releng/deps.toml +1 -1
- package/releng/env_generic.py +12 -2
- package/releng/machine_spec.py +8 -5
- package/src/frida_bindgen/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/frida_bindgen/__pycache__/__main__.cpython-312.pyc +0 -0
- package/src/frida_bindgen/__pycache__/cli.cpython-312.pyc +0 -0
- package/src/frida_bindgen/__pycache__/codegen.cpython-312.pyc +0 -0
- package/src/frida_bindgen/__pycache__/customization.cpython-312.pyc +0 -0
- package/src/frida_bindgen/__pycache__/loader.cpython-312.pyc +0 -0
- package/src/frida_bindgen/__pycache__/model.cpython-312.pyc +0 -0
- package/src/frida_bindgen/loader.py +12 -27
- package/src/frida_bindgen/model.py +97 -830
- package/src/meson.build +8 -2
- package/subprojects/frida-core.wrap +1 -1
|
@@ -1,81 +1,20 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import xml.etree.ElementTree as ET
|
|
4
3
|
from collections import OrderedDict, defaultdict
|
|
5
4
|
from dataclasses import dataclass, field
|
|
6
5
|
from enum import Enum
|
|
7
6
|
from functools import cached_property
|
|
8
|
-
from typing import
|
|
9
|
-
Tuple, Union)
|
|
10
|
-
|
|
11
|
-
CORE_NAMESPACE = "http://www.gtk.org/introspection/core/1.0"
|
|
12
|
-
C_NAMESPACE = "http://www.gtk.org/introspection/c/1.0"
|
|
13
|
-
GLIB_NAMESPACE = "http://www.gtk.org/introspection/glib/1.0"
|
|
14
|
-
GIR_NAMESPACES = {"": CORE_NAMESPACE, "glib": GLIB_NAMESPACE}
|
|
15
|
-
|
|
16
|
-
CORE_TAG_PREFIX = f"{{{CORE_NAMESPACE}}}"
|
|
17
|
-
|
|
18
|
-
NUMERIC_GIR_TYPES = {
|
|
19
|
-
"gsize",
|
|
20
|
-
"gssize",
|
|
21
|
-
"gint",
|
|
22
|
-
"guint",
|
|
23
|
-
"glong",
|
|
24
|
-
"gulong",
|
|
25
|
-
"gint8",
|
|
26
|
-
"gint16",
|
|
27
|
-
"gint32",
|
|
28
|
-
"gint64",
|
|
29
|
-
"guint8",
|
|
30
|
-
"guint16",
|
|
31
|
-
"guint32",
|
|
32
|
-
"guint64",
|
|
33
|
-
"gfloat",
|
|
34
|
-
"gdouble",
|
|
35
|
-
"GType",
|
|
36
|
-
"GQuark",
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
PRIMITIVE_GIR_TYPES = NUMERIC_GIR_TYPES | {
|
|
40
|
-
"gpointer",
|
|
41
|
-
"gboolean",
|
|
42
|
-
"gchar",
|
|
43
|
-
"utf8",
|
|
44
|
-
"utf8[]",
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
ResolveTypeCallback = Callable[[str], Tuple[str, ET.Element]]
|
|
7
|
+
from typing import List, Mapping, Optional, Tuple, Union
|
|
48
8
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
56
|
-
facade_exports: List[str] = field(default_factory=list)
|
|
57
|
-
facade_code: str = ""
|
|
58
|
-
helper_imports: List[str] = field(default_factory=list)
|
|
59
|
-
helper_code: str = ""
|
|
9
|
+
import frida_bindgen_core as core
|
|
10
|
+
from frida_bindgen_core import (Direction, Namespace, Procedure,
|
|
11
|
+
TransferOwnership, Type)
|
|
12
|
+
from frida_bindgen_core.model import NUMERIC_GIR_TYPES
|
|
13
|
+
from frida_bindgen_core.naming import (to_camel_case, to_macro_case,
|
|
14
|
+
to_pascal_case, to_snake_case)
|
|
60
15
|
|
|
61
16
|
|
|
62
|
-
|
|
63
|
-
class Model:
|
|
64
|
-
namespace: Namespace
|
|
65
|
-
_object_types: OrderedDict[str, ObjectType]
|
|
66
|
-
enumerations: OrderedDict[str, Enumeration]
|
|
67
|
-
customizations: Customizations = field(default_factory=Customizations)
|
|
68
|
-
|
|
69
|
-
@cached_property
|
|
70
|
-
def object_types(self) -> OrderedDict[str, ObjectType]:
|
|
71
|
-
result = OrderedDict()
|
|
72
|
-
type_customizations = self.customizations.type_customizations
|
|
73
|
-
for k, v in self._object_types.items():
|
|
74
|
-
custom = type_customizations.get(k)
|
|
75
|
-
if custom is None or not custom.drop:
|
|
76
|
-
result[k] = v
|
|
77
|
-
return result
|
|
78
|
-
|
|
17
|
+
class Model(core.Model):
|
|
79
18
|
@cached_property
|
|
80
19
|
def public_types(self) -> OrderedDict[str, Union[ObjectType, Enumeration]]:
|
|
81
20
|
return OrderedDict(
|
|
@@ -91,10 +30,6 @@ class Model:
|
|
|
91
30
|
if isinstance(t, InterfaceObjectType) and t.has_abstract_base
|
|
92
31
|
]
|
|
93
32
|
|
|
94
|
-
def resolve_object_type(self, name: str) -> ObjectType:
|
|
95
|
-
bare_name = name.split(".", maxsplit=1)[-1]
|
|
96
|
-
return self.object_types[bare_name]
|
|
97
|
-
|
|
98
33
|
def resolve_js_type(self, t: Type) -> str:
|
|
99
34
|
js = js_type_from_gir(t.name)
|
|
100
35
|
otype = self.object_types.get(js)
|
|
@@ -103,38 +38,7 @@ class Model:
|
|
|
103
38
|
return js
|
|
104
39
|
|
|
105
40
|
|
|
106
|
-
|
|
107
|
-
class Namespace:
|
|
108
|
-
name: str
|
|
109
|
-
identifier_prefixes: str
|
|
110
|
-
element: ET.Element
|
|
111
|
-
|
|
112
|
-
@cached_property
|
|
113
|
-
def type_elements(self) -> Mapping[str, ET.Element]:
|
|
114
|
-
result = {}
|
|
115
|
-
for toplevel in self.element.findall("./*[@name]", GIR_NAMESPACES):
|
|
116
|
-
name = toplevel.get("name")
|
|
117
|
-
result[name] = toplevel
|
|
118
|
-
for callback in toplevel.findall("./callback", GIR_NAMESPACES):
|
|
119
|
-
result[name + callback.get("name")] = callback
|
|
120
|
-
return result
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@dataclass
|
|
124
|
-
class ObjectType:
|
|
125
|
-
name: str
|
|
126
|
-
c_type: str
|
|
127
|
-
get_type: str
|
|
128
|
-
type_struct: str
|
|
129
|
-
_parent: Optional[str]
|
|
130
|
-
_constructors: List[ET.Element]
|
|
131
|
-
_methods: List[ET.Element]
|
|
132
|
-
_properties: List[ET.Element]
|
|
133
|
-
_signals: List[ET.Element]
|
|
134
|
-
resolve_type: ResolveTypeCallback
|
|
135
|
-
|
|
136
|
-
model: Optional[Model]
|
|
137
|
-
|
|
41
|
+
class ObjectType(core.ObjectType):
|
|
138
42
|
@cached_property
|
|
139
43
|
def js_name(self) -> str:
|
|
140
44
|
custom = self.customizations
|
|
@@ -150,24 +54,10 @@ class ObjectType:
|
|
|
150
54
|
def abstract_base_c_type(self) -> str:
|
|
151
55
|
return f"FdnAbstract{self.name}"
|
|
152
56
|
|
|
153
|
-
@cached_property
|
|
154
|
-
def parent(self) -> ObjectType:
|
|
155
|
-
if self._parent is None:
|
|
156
|
-
return None
|
|
157
|
-
return self.model.resolve_object_type(self._parent)
|
|
158
|
-
|
|
159
57
|
@property
|
|
160
58
|
def is_public(self) -> bool:
|
|
161
59
|
return not self.is_frida_list
|
|
162
60
|
|
|
163
|
-
@cached_property
|
|
164
|
-
def is_frida_options(self) -> bool:
|
|
165
|
-
return self.c_type.startswith("Frida") and self.c_type.endswith("Options")
|
|
166
|
-
|
|
167
|
-
@cached_property
|
|
168
|
-
def is_frida_list(self) -> bool:
|
|
169
|
-
return self.c_type.startswith("Frida") and self.c_type.endswith("List")
|
|
170
|
-
|
|
171
61
|
@cached_property
|
|
172
62
|
def needs_wrapper(self) -> bool:
|
|
173
63
|
custom = self.customizations
|
|
@@ -180,10 +70,6 @@ class ObjectType:
|
|
|
180
70
|
return True
|
|
181
71
|
return self.wrapped_methods or self.wrapped_signals
|
|
182
72
|
|
|
183
|
-
@cached_property
|
|
184
|
-
def customizations(self) -> Optional[ObjectTypeCustomizations]:
|
|
185
|
-
return self.model.customizations.type_customizations.get(self.name)
|
|
186
|
-
|
|
187
73
|
@cached_property
|
|
188
74
|
def c_symbol_prefix(self) -> str:
|
|
189
75
|
return f"fdn_{to_snake_case(self.name)}"
|
|
@@ -200,190 +86,10 @@ class ObjectType:
|
|
|
200
86
|
def abstract_base_c_cast_macro(self) -> str:
|
|
201
87
|
return to_macro_case(self.abstract_base_c_type)
|
|
202
88
|
|
|
203
|
-
@cached_property
|
|
204
|
-
def constructors(self) -> List[Constructor]:
|
|
205
|
-
constructors = []
|
|
206
|
-
custom = self.customizations
|
|
207
|
-
for element in self._constructors:
|
|
208
|
-
if element.get("introspectable") == "0" or element.get("deprecated") == "1":
|
|
209
|
-
continue
|
|
210
|
-
|
|
211
|
-
name = element.get("name")
|
|
212
|
-
|
|
213
|
-
if custom is not None:
|
|
214
|
-
ccust = custom.constructor
|
|
215
|
-
if ccust is not None and ccust.drop:
|
|
216
|
-
continue
|
|
217
|
-
|
|
218
|
-
(
|
|
219
|
-
c_identifier,
|
|
220
|
-
finish_c_identifier,
|
|
221
|
-
param_list,
|
|
222
|
-
has_closure_param,
|
|
223
|
-
throws,
|
|
224
|
-
result_element,
|
|
225
|
-
) = extract_callable_details(element, element, self, self.resolve_type)
|
|
226
|
-
if has_closure_param or finish_c_identifier is not None:
|
|
227
|
-
continue
|
|
228
|
-
|
|
229
|
-
constructors.append(
|
|
230
|
-
Constructor(
|
|
231
|
-
name, c_identifier, finish_c_identifier, param_list, throws, self
|
|
232
|
-
)
|
|
233
|
-
)
|
|
234
|
-
return constructors
|
|
235
|
-
|
|
236
|
-
@cached_property
|
|
237
|
-
def methods(self) -> List[Method]:
|
|
238
|
-
methods = []
|
|
239
|
-
c_prop_names = {prop.c_name for prop in self.properties}
|
|
240
|
-
custom = self.customizations
|
|
241
|
-
for element in self._methods:
|
|
242
|
-
name = element.get("name")
|
|
243
|
-
|
|
244
|
-
if (
|
|
245
|
-
element.get("introspectable") == "0"
|
|
246
|
-
or name.startswith("_")
|
|
247
|
-
or name.endswith("_sync")
|
|
248
|
-
or name.endswith("_finish")
|
|
249
|
-
):
|
|
250
|
-
continue
|
|
251
|
-
|
|
252
|
-
if custom is not None:
|
|
253
|
-
mcust = custom.methods.get(name, None)
|
|
254
|
-
if mcust is not None and mcust.drop:
|
|
255
|
-
continue
|
|
256
|
-
|
|
257
|
-
finish_func = element.get(f"{{{GLIB_NAMESPACE}}}finish-func")
|
|
258
|
-
if finish_func is None:
|
|
259
|
-
finish_func = f"{name}_finish"
|
|
260
|
-
result_element = next(
|
|
261
|
-
(m for m in self._methods if m.get("name") == finish_func), element
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
(
|
|
265
|
-
c_identifier,
|
|
266
|
-
finish_c_identifier,
|
|
267
|
-
param_list,
|
|
268
|
-
has_closure_param,
|
|
269
|
-
throws,
|
|
270
|
-
result_element,
|
|
271
|
-
) = extract_callable_details(
|
|
272
|
-
element, result_element, self, self.resolve_type
|
|
273
|
-
)
|
|
274
|
-
if has_closure_param:
|
|
275
|
-
continue
|
|
276
|
-
|
|
277
|
-
retval_element = result_element.find(".//return-value", GIR_NAMESPACES)
|
|
278
|
-
rettype = extract_type_from_entity(retval_element, self.resolve_type)
|
|
279
|
-
if rettype is not None:
|
|
280
|
-
if rettype.is_frida_options:
|
|
281
|
-
continue
|
|
282
|
-
|
|
283
|
-
nullable = retval_element.get("nullable") == "1"
|
|
284
|
-
|
|
285
|
-
ownership_val = retval_element.get("transfer-ownership")
|
|
286
|
-
transfer_ownership = (
|
|
287
|
-
TransferOwnership[ownership_val]
|
|
288
|
-
if ownership_val is not None
|
|
289
|
-
else TransferOwnership.none
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
retval = ReturnValue(rettype, nullable, transfer_ownership, self)
|
|
293
|
-
else:
|
|
294
|
-
retval = None
|
|
295
|
-
|
|
296
|
-
if element.get(f"{{{GLIB_NAMESPACE}}}get-property") is not None:
|
|
297
|
-
is_property_accessor = True
|
|
298
|
-
else:
|
|
299
|
-
tokens = name.split("_", maxsplit=1)
|
|
300
|
-
is_property_accessor = (
|
|
301
|
-
len(tokens) == 2
|
|
302
|
-
and tokens[0] in {"get", "set"}
|
|
303
|
-
and tokens[1] in c_prop_names
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
methods.append(
|
|
307
|
-
Method(
|
|
308
|
-
name,
|
|
309
|
-
c_identifier,
|
|
310
|
-
finish_c_identifier,
|
|
311
|
-
param_list,
|
|
312
|
-
throws,
|
|
313
|
-
retval,
|
|
314
|
-
is_property_accessor,
|
|
315
|
-
self,
|
|
316
|
-
)
|
|
317
|
-
)
|
|
318
|
-
return methods
|
|
319
|
-
|
|
320
89
|
@cached_property
|
|
321
90
|
def wrapped_methods(self) -> List[Method]:
|
|
322
91
|
return [m for m in self.methods if m.needs_wrapper]
|
|
323
92
|
|
|
324
|
-
@cached_property
|
|
325
|
-
def properties(self) -> List[Property]:
|
|
326
|
-
properties = []
|
|
327
|
-
custom = self.customizations
|
|
328
|
-
for element in self._properties:
|
|
329
|
-
name = element.get("name")
|
|
330
|
-
|
|
331
|
-
if custom is not None:
|
|
332
|
-
pcust = custom.properties.get(name, None)
|
|
333
|
-
if pcust is not None and pcust.drop:
|
|
334
|
-
continue
|
|
335
|
-
|
|
336
|
-
c_name = name.replace("-", "_")
|
|
337
|
-
type = extract_type_from_entity(element, self.resolve_type)
|
|
338
|
-
if type.is_frida_options:
|
|
339
|
-
continue
|
|
340
|
-
writable = element.get("writable") == "1"
|
|
341
|
-
construct_only = element.get("construct-only") == "1"
|
|
342
|
-
|
|
343
|
-
getter = element.get("getter")
|
|
344
|
-
if getter is None:
|
|
345
|
-
getter = f"get_{c_name}"
|
|
346
|
-
|
|
347
|
-
setter = element.get("setter")
|
|
348
|
-
if setter is None and writable and not construct_only:
|
|
349
|
-
setter = f"set_{c_name}"
|
|
350
|
-
|
|
351
|
-
properties.append(
|
|
352
|
-
Property(
|
|
353
|
-
name,
|
|
354
|
-
c_name,
|
|
355
|
-
type,
|
|
356
|
-
writable,
|
|
357
|
-
construct_only,
|
|
358
|
-
getter,
|
|
359
|
-
setter,
|
|
360
|
-
self,
|
|
361
|
-
)
|
|
362
|
-
)
|
|
363
|
-
return properties
|
|
364
|
-
|
|
365
|
-
@cached_property
|
|
366
|
-
def signals(self) -> List[Signal]:
|
|
367
|
-
signals = []
|
|
368
|
-
custom = self.customizations
|
|
369
|
-
for element in self._signals:
|
|
370
|
-
name = element.get("name")
|
|
371
|
-
|
|
372
|
-
if custom is not None:
|
|
373
|
-
scust = custom.signals.get(name, None)
|
|
374
|
-
if scust is not None and scust.drop:
|
|
375
|
-
continue
|
|
376
|
-
|
|
377
|
-
c_name = name.replace("-", "_")
|
|
378
|
-
param_list = extract_parameters(
|
|
379
|
-
element.findall("./parameters/parameter", GIR_NAMESPACES),
|
|
380
|
-
nullable_implies_optional=False,
|
|
381
|
-
object_type=self,
|
|
382
|
-
resolve_type=self.resolve_type,
|
|
383
|
-
)
|
|
384
|
-
signals.append(Signal(name, c_name, param_list, self))
|
|
385
|
-
return signals
|
|
386
|
-
|
|
387
93
|
@cached_property
|
|
388
94
|
def wrapped_signals(self) -> List[Signal]:
|
|
389
95
|
return [s for s in self.signals if s.needs_wrapper]
|
|
@@ -391,14 +97,13 @@ class ObjectType:
|
|
|
391
97
|
|
|
392
98
|
@dataclass
|
|
393
99
|
class ClassObjectType(ObjectType):
|
|
394
|
-
_implements: List[str]
|
|
100
|
+
_implements: List[str] = field(default_factory=list)
|
|
395
101
|
|
|
396
102
|
@cached_property
|
|
397
103
|
def implements(self) -> List[InterfaceObjectType]:
|
|
398
104
|
return [self.model.resolve_object_type(i) for i in self._implements]
|
|
399
105
|
|
|
400
106
|
|
|
401
|
-
@dataclass
|
|
402
107
|
class InterfaceObjectType(ObjectType):
|
|
403
108
|
@cached_property
|
|
404
109
|
def has_abstract_base(self) -> bool:
|
|
@@ -408,27 +113,7 @@ class InterfaceObjectType(ObjectType):
|
|
|
408
113
|
return not custom.drop_abstract_base
|
|
409
114
|
|
|
410
115
|
|
|
411
|
-
|
|
412
|
-
class Procedure:
|
|
413
|
-
name: str
|
|
414
|
-
c_identifier: str
|
|
415
|
-
finish_c_identifier: Optional[str]
|
|
416
|
-
parameters: List[Parameter]
|
|
417
|
-
throws: bool
|
|
418
|
-
|
|
419
|
-
@property
|
|
420
|
-
def is_async(self) -> bool:
|
|
421
|
-
return self.finish_c_identifier is not None
|
|
422
|
-
|
|
423
|
-
@cached_property
|
|
424
|
-
def input_parameters(self) -> List[Parameter]:
|
|
425
|
-
return [p for p in self.parameters if p.direction != Direction.OUT]
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
@dataclass
|
|
429
|
-
class Constructor(Procedure):
|
|
430
|
-
object_type: ObjectType
|
|
431
|
-
|
|
116
|
+
class Constructor(core.Constructor):
|
|
432
117
|
@cached_property
|
|
433
118
|
def param_typings(self) -> List[str]:
|
|
434
119
|
custom = self.customizations
|
|
@@ -451,13 +136,7 @@ class Constructor(Procedure):
|
|
|
451
136
|
return custom.constructor
|
|
452
137
|
|
|
453
138
|
|
|
454
|
-
|
|
455
|
-
class Method(Procedure):
|
|
456
|
-
return_value: Optional[ReturnValue]
|
|
457
|
-
is_property_accessor: bool
|
|
458
|
-
|
|
459
|
-
object_type: ObjectType
|
|
460
|
-
|
|
139
|
+
class Method(core.Method):
|
|
461
140
|
@cached_property
|
|
462
141
|
def js_name(self) -> str:
|
|
463
142
|
custom = self.customizations
|
|
@@ -568,18 +247,7 @@ class Method(Procedure):
|
|
|
568
247
|
return self.parameters[0].type
|
|
569
248
|
|
|
570
249
|
|
|
571
|
-
|
|
572
|
-
class Property:
|
|
573
|
-
name: str
|
|
574
|
-
c_name: str
|
|
575
|
-
type: Type
|
|
576
|
-
writable: bool
|
|
577
|
-
construct_only: bool
|
|
578
|
-
getter: Optional[str]
|
|
579
|
-
setter: Optional[str]
|
|
580
|
-
|
|
581
|
-
object_type: ObjectType
|
|
582
|
-
|
|
250
|
+
class Property(core.Property):
|
|
583
251
|
@cached_property
|
|
584
252
|
def js_name(self) -> str:
|
|
585
253
|
custom = self.customizations
|
|
@@ -604,14 +272,7 @@ class Property:
|
|
|
604
272
|
return custom.properties.get(self.name)
|
|
605
273
|
|
|
606
274
|
|
|
607
|
-
|
|
608
|
-
class Signal:
|
|
609
|
-
name: str
|
|
610
|
-
c_name: str
|
|
611
|
-
parameters: List[Parameter]
|
|
612
|
-
|
|
613
|
-
object_type: ObjectType
|
|
614
|
-
|
|
275
|
+
class Signal(core.Signal):
|
|
615
276
|
@cached_property
|
|
616
277
|
def js_name(self) -> str:
|
|
617
278
|
return to_camel_case(self.c_name)
|
|
@@ -664,20 +325,7 @@ class Signal:
|
|
|
664
325
|
return custom.signals.get(self.name)
|
|
665
326
|
|
|
666
327
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
@dataclass
|
|
671
|
-
class Parameter:
|
|
672
|
-
name: str
|
|
673
|
-
type: Type
|
|
674
|
-
optional: bool
|
|
675
|
-
nullable: bool
|
|
676
|
-
transfer_ownership: TransferOwnership
|
|
677
|
-
direction: Direction
|
|
678
|
-
|
|
679
|
-
object_type: ObjectType
|
|
680
|
-
|
|
328
|
+
class Parameter(core.Parameter):
|
|
681
329
|
@cached_property
|
|
682
330
|
def js_name(self) -> str:
|
|
683
331
|
return to_camel_case(self.name)
|
|
@@ -703,14 +351,7 @@ class Parameter:
|
|
|
703
351
|
return self.type.destroy_func
|
|
704
352
|
|
|
705
353
|
|
|
706
|
-
|
|
707
|
-
class ReturnValue:
|
|
708
|
-
type: Type
|
|
709
|
-
nullable: bool
|
|
710
|
-
transfer_ownership: TransferOwnership
|
|
711
|
-
|
|
712
|
-
object_type: ObjectType
|
|
713
|
-
|
|
354
|
+
class ReturnValue(core.ReturnValue):
|
|
714
355
|
@cached_property
|
|
715
356
|
def ctyping(self) -> str:
|
|
716
357
|
return self.type.c
|
|
@@ -729,55 +370,7 @@ class ReturnValue:
|
|
|
729
370
|
return self.type.destroy_func
|
|
730
371
|
|
|
731
372
|
|
|
732
|
-
|
|
733
|
-
class Type:
|
|
734
|
-
name: str
|
|
735
|
-
nick: str
|
|
736
|
-
c: str
|
|
737
|
-
default_value: Optional[str]
|
|
738
|
-
copy_func: Optional[str]
|
|
739
|
-
destroy_func: Optional[str]
|
|
740
|
-
|
|
741
|
-
@cached_property
|
|
742
|
-
def from_pointer_func(self) -> Optional[str]:
|
|
743
|
-
if self.name in {"gssize", "gsize", "glong", "gulong", "gint64", "guint64"}:
|
|
744
|
-
return "GPOINTER_TO_SIZE"
|
|
745
|
-
if self.name in {"gint", "gint8", "gint16", "gint32"}:
|
|
746
|
-
return "GPOINTER_TO_INT"
|
|
747
|
-
if self.name in {"gboolean", "guint", "guint8", "guint16", "guint32"}:
|
|
748
|
-
return "GPOINTER_TO_UINT"
|
|
749
|
-
return None
|
|
750
|
-
|
|
751
|
-
@cached_property
|
|
752
|
-
def to_pointer_func(self) -> Optional[str]:
|
|
753
|
-
if self.name in {"gssize", "gsize", "glong", "gulong", "gint64", "guint64"}:
|
|
754
|
-
return "GSIZE_TO_POINTER"
|
|
755
|
-
if self.name in {"gint", "gint8", "gint16", "gint32"}:
|
|
756
|
-
return "GINT_TO_POINTER"
|
|
757
|
-
if self.name in {"gboolean", "guint", "guint8", "guint16", "guint32"}:
|
|
758
|
-
return "GUINT_TO_POINTER"
|
|
759
|
-
return None
|
|
760
|
-
|
|
761
|
-
@cached_property
|
|
762
|
-
def is_frida_options(self) -> bool:
|
|
763
|
-
return self.c.startswith("Frida") and self.c.endswith("Options *")
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
class Direction(Enum):
|
|
767
|
-
IN = "in"
|
|
768
|
-
OUT = "out"
|
|
769
|
-
INOUT = "inout"
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
@dataclass
|
|
773
|
-
class Enumeration:
|
|
774
|
-
name: str
|
|
775
|
-
c_type: str
|
|
776
|
-
get_type: str
|
|
777
|
-
_members: List[ET.Element]
|
|
778
|
-
|
|
779
|
-
model: Optional[Model]
|
|
780
|
-
|
|
373
|
+
class Enumeration(core.Enumeration):
|
|
781
374
|
@property
|
|
782
375
|
def js_name(self) -> str:
|
|
783
376
|
return self.name
|
|
@@ -786,32 +379,16 @@ class Enumeration:
|
|
|
786
379
|
def prefixed_js_name(self) -> str:
|
|
787
380
|
return self.name
|
|
788
381
|
|
|
789
|
-
@cached_property
|
|
790
|
-
def members(self) -> List[EnumerationMember]:
|
|
791
|
-
members = []
|
|
792
|
-
for element in self._members:
|
|
793
|
-
members.append(EnumerationMember(element.get("name"), self))
|
|
794
|
-
return members
|
|
795
|
-
|
|
796
382
|
@property
|
|
797
383
|
def is_frida_options(self) -> bool:
|
|
798
384
|
return False
|
|
799
385
|
|
|
800
|
-
@cached_property
|
|
801
|
-
def customizations(self) -> Optional[EnumerationCustomizations]:
|
|
802
|
-
return self.model.customizations.type_customizations.get(self.name)
|
|
803
|
-
|
|
804
386
|
@cached_property
|
|
805
387
|
def c_symbol_prefix(self) -> str:
|
|
806
388
|
return f"fdn_{to_snake_case(self.name)}"
|
|
807
389
|
|
|
808
390
|
|
|
809
|
-
|
|
810
|
-
class EnumerationMember:
|
|
811
|
-
name: str
|
|
812
|
-
|
|
813
|
-
enumeration: Enumeration
|
|
814
|
-
|
|
391
|
+
class EnumerationMember(core.EnumerationMember):
|
|
815
392
|
@cached_property
|
|
816
393
|
def js_name(self) -> str:
|
|
817
394
|
custom = self.customizations
|
|
@@ -831,6 +408,18 @@ class EnumerationMember:
|
|
|
831
408
|
return custom.members.get(self.name)
|
|
832
409
|
|
|
833
410
|
|
|
411
|
+
@dataclass
|
|
412
|
+
class Customizations:
|
|
413
|
+
custom_types: Mapping[str, CustomType] = field(default_factory=OrderedDict)
|
|
414
|
+
type_customizations: Mapping[str, TypeCustomizations] = field(
|
|
415
|
+
default_factory=OrderedDict
|
|
416
|
+
)
|
|
417
|
+
facade_exports: List[str] = field(default_factory=list)
|
|
418
|
+
facade_code: str = ""
|
|
419
|
+
helper_imports: List[str] = field(default_factory=list)
|
|
420
|
+
helper_code: str = ""
|
|
421
|
+
|
|
422
|
+
|
|
834
423
|
@dataclass
|
|
835
424
|
class CustomType:
|
|
836
425
|
kind: CustomTypeKind
|
|
@@ -940,359 +529,79 @@ class EnumerationMemberCustomizations:
|
|
|
940
529
|
js_name: Optional[str] = None
|
|
941
530
|
|
|
942
531
|
|
|
943
|
-
def
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
532
|
+
def _make_class(
|
|
533
|
+
*,
|
|
534
|
+
name,
|
|
535
|
+
c_type,
|
|
536
|
+
get_type,
|
|
537
|
+
type_struct,
|
|
538
|
+
parent,
|
|
539
|
+
constructors,
|
|
540
|
+
methods,
|
|
541
|
+
properties,
|
|
542
|
+
signals,
|
|
543
|
+
implements,
|
|
544
|
+
resolve_type,
|
|
545
|
+
model,
|
|
546
|
+
):
|
|
547
|
+
return ClassObjectType(
|
|
548
|
+
name,
|
|
549
|
+
c_type,
|
|
550
|
+
get_type,
|
|
551
|
+
type_struct,
|
|
552
|
+
parent,
|
|
553
|
+
constructors,
|
|
554
|
+
methods,
|
|
555
|
+
properties,
|
|
556
|
+
signals,
|
|
557
|
+
resolve_type,
|
|
558
|
+
model,
|
|
559
|
+
implements,
|
|
949
560
|
)
|
|
950
561
|
|
|
951
|
-
def resolve_type(name: str) -> Tuple[str, ET.Element]:
|
|
952
|
-
assert (
|
|
953
|
-
name not in PRIMITIVE_GIR_TYPES
|
|
954
|
-
), f"unexpectedly asked to resolve primitive type: {name}"
|
|
955
|
-
|
|
956
|
-
tokens = name.split(".", maxsplit=1)
|
|
957
|
-
if len(tokens) == 2:
|
|
958
|
-
ns_name, bare_name = tokens
|
|
959
|
-
if ns_name == namespace.name:
|
|
960
|
-
ns = namespace
|
|
961
|
-
else:
|
|
962
|
-
ns = next(
|
|
963
|
-
(
|
|
964
|
-
dep.namespace
|
|
965
|
-
for dep in dependencies
|
|
966
|
-
if dep.namespace.name == ns_name
|
|
967
|
-
),
|
|
968
|
-
None,
|
|
969
|
-
)
|
|
970
|
-
if ns is None:
|
|
971
|
-
assert ns is not None, f"unable to resolve namespace {ns_name}"
|
|
972
|
-
else:
|
|
973
|
-
ns = namespace
|
|
974
|
-
bare_name = name
|
|
975
|
-
qualified_name = f"{ns.name}.{bare_name}"
|
|
976
|
-
|
|
977
|
-
element = ns.type_elements.get(bare_name)
|
|
978
|
-
assert element is not None, f"unable to resolve type {bare_name}"
|
|
979
|
-
|
|
980
|
-
return (qualified_name, element)
|
|
981
562
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
type_struct,
|
|
1009
|
-
parent,
|
|
1010
|
-
constructors,
|
|
1011
|
-
methods,
|
|
1012
|
-
properties,
|
|
1013
|
-
signals,
|
|
1014
|
-
resolve_type,
|
|
1015
|
-
None,
|
|
1016
|
-
implements,
|
|
1017
|
-
)
|
|
1018
|
-
|
|
1019
|
-
for element in namespace.element.findall("./interface", GIR_NAMESPACES):
|
|
1020
|
-
name = element.get("name")
|
|
1021
|
-
c_type = element.get(f"{{{C_NAMESPACE}}}type")
|
|
1022
|
-
get_type = element.get(f"{{{GLIB_NAMESPACE}}}get-type")
|
|
1023
|
-
type_struct = element.get(f"{{{GLIB_NAMESPACE}}}type-struct")
|
|
1024
|
-
if type_struct is not None:
|
|
1025
|
-
type_struct = namespace.identifier_prefixes + type_struct
|
|
1026
|
-
else:
|
|
1027
|
-
type_struct = c_type + "Iface"
|
|
1028
|
-
prereq = element.find(".//prerequisite", GIR_NAMESPACES)
|
|
1029
|
-
parent = prereq.get("name") if prereq is not None else None
|
|
1030
|
-
if parent is not None:
|
|
1031
|
-
parent, _ = resolve_type(parent)
|
|
1032
|
-
constructors = []
|
|
1033
|
-
methods = element.findall(".//method", GIR_NAMESPACES)
|
|
1034
|
-
properties = element.findall(".//property", GIR_NAMESPACES)
|
|
1035
|
-
signals = element.findall(".//glib:signal", GIR_NAMESPACES)
|
|
1036
|
-
|
|
1037
|
-
object_types[name] = InterfaceObjectType(
|
|
1038
|
-
name,
|
|
1039
|
-
c_type,
|
|
1040
|
-
get_type,
|
|
1041
|
-
type_struct,
|
|
1042
|
-
parent,
|
|
1043
|
-
constructors,
|
|
1044
|
-
methods,
|
|
1045
|
-
properties,
|
|
1046
|
-
signals,
|
|
1047
|
-
resolve_type,
|
|
1048
|
-
None,
|
|
1049
|
-
)
|
|
1050
|
-
|
|
1051
|
-
enumerations = OrderedDict()
|
|
1052
|
-
|
|
1053
|
-
for element in namespace.element.findall("./enumeration", GIR_NAMESPACES):
|
|
1054
|
-
if element.get(f"{{{GLIB_NAMESPACE}}}error-domain") is not None:
|
|
1055
|
-
continue
|
|
1056
|
-
enum_name = element.get("name")
|
|
1057
|
-
enum_c_type = element.get(f"{{{C_NAMESPACE}}}type")
|
|
1058
|
-
get_type = element.get(f"{{{GLIB_NAMESPACE}}}get-type")
|
|
1059
|
-
members = element.findall(".//member", GIR_NAMESPACES)
|
|
1060
|
-
enumerations[enum_name] = Enumeration(
|
|
1061
|
-
enum_name, enum_c_type, get_type, members, None
|
|
1062
|
-
)
|
|
1063
|
-
|
|
1064
|
-
model = Model(namespace, object_types, enumerations)
|
|
1065
|
-
|
|
1066
|
-
for t in object_types.values():
|
|
1067
|
-
t.model = model
|
|
1068
|
-
for t in enumerations.values():
|
|
1069
|
-
t.model = model
|
|
1070
|
-
|
|
1071
|
-
return model
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
def extract_callable_details(
|
|
1075
|
-
element: ET.Element,
|
|
1076
|
-
result_element: ET.Element,
|
|
1077
|
-
object_type: ObjectType,
|
|
1078
|
-
resolve_type: ResolveTypeCallback,
|
|
1079
|
-
) -> Tuple[str, Optional[str], List[Parameter], bool, bool, ET.Element]:
|
|
1080
|
-
c_identifier = element.get(f"{{{C_NAMESPACE}}}identifier")
|
|
1081
|
-
|
|
1082
|
-
parameters = element.findall("./parameters/parameter", GIR_NAMESPACES)
|
|
1083
|
-
full_param_list = extract_parameters(
|
|
1084
|
-
parameters,
|
|
1085
|
-
nullable_implies_optional=True,
|
|
1086
|
-
object_type=object_type,
|
|
1087
|
-
resolve_type=resolve_type,
|
|
1088
|
-
)
|
|
1089
|
-
param_list = list(all_regular_parameters(full_param_list))
|
|
1090
|
-
has_closure_param = any((param.get("closure") == "1" for param in parameters))
|
|
1091
|
-
|
|
1092
|
-
is_async = any(
|
|
1093
|
-
param.type.name == "Gio.AsyncReadyCallback" for param in full_param_list
|
|
1094
|
-
)
|
|
1095
|
-
if not is_async:
|
|
1096
|
-
result_element = element
|
|
1097
|
-
|
|
1098
|
-
finish_c_identifier = (
|
|
1099
|
-
result_element.get(f"{{{C_NAMESPACE}}}identifier") if is_async else None
|
|
563
|
+
def _make_interface(
|
|
564
|
+
*,
|
|
565
|
+
name,
|
|
566
|
+
c_type,
|
|
567
|
+
get_type,
|
|
568
|
+
type_struct,
|
|
569
|
+
parent,
|
|
570
|
+
constructors,
|
|
571
|
+
methods,
|
|
572
|
+
properties,
|
|
573
|
+
signals,
|
|
574
|
+
resolve_type,
|
|
575
|
+
model,
|
|
576
|
+
):
|
|
577
|
+
return InterfaceObjectType(
|
|
578
|
+
name,
|
|
579
|
+
c_type,
|
|
580
|
+
get_type,
|
|
581
|
+
type_struct,
|
|
582
|
+
parent,
|
|
583
|
+
constructors,
|
|
584
|
+
methods,
|
|
585
|
+
properties,
|
|
586
|
+
signals,
|
|
587
|
+
resolve_type,
|
|
588
|
+
model,
|
|
1100
589
|
)
|
|
1101
590
|
|
|
1102
|
-
throws = result_element.get("throws") == "1"
|
|
1103
|
-
|
|
1104
|
-
return (
|
|
1105
|
-
c_identifier,
|
|
1106
|
-
finish_c_identifier,
|
|
1107
|
-
param_list,
|
|
1108
|
-
has_closure_param,
|
|
1109
|
-
throws,
|
|
1110
|
-
result_element,
|
|
1111
|
-
)
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
def extract_parameters(
|
|
1115
|
-
parameter_elements: List[ET.Element],
|
|
1116
|
-
nullable_implies_optional: bool,
|
|
1117
|
-
object_type: ObjectType,
|
|
1118
|
-
resolve_type: ResolveTypeCallback,
|
|
1119
|
-
) -> List[Parameter]:
|
|
1120
|
-
entries = []
|
|
1121
|
-
for param in parameter_elements:
|
|
1122
|
-
nullable = param.get("nullable") == "1"
|
|
1123
|
-
entries.append((param, nullable))
|
|
1124
|
-
|
|
1125
|
-
last_required_index = None
|
|
1126
|
-
for i, (param, nullable) in enumerate(entries):
|
|
1127
|
-
optional = nullable and nullable_implies_optional
|
|
1128
|
-
if not optional:
|
|
1129
|
-
last_required_index = i
|
|
1130
|
-
|
|
1131
|
-
param_list = []
|
|
1132
|
-
for i, (param, nullable) in enumerate(entries):
|
|
1133
|
-
name = param.get("name")
|
|
1134
|
-
type = extract_type_from_entity(param, resolve_type)
|
|
1135
|
-
|
|
1136
|
-
if last_required_index is None or i > last_required_index:
|
|
1137
|
-
optional = nullable and nullable_implies_optional
|
|
1138
|
-
else:
|
|
1139
|
-
optional = False
|
|
1140
|
-
|
|
1141
|
-
ownership_val = param.get("transfer-ownership")
|
|
1142
|
-
transfer_ownership = (
|
|
1143
|
-
TransferOwnership[ownership_val]
|
|
1144
|
-
if ownership_val is not None
|
|
1145
|
-
else TransferOwnership.none
|
|
1146
|
-
)
|
|
1147
|
-
|
|
1148
|
-
raw_direction = param.get("direction")
|
|
1149
|
-
direction = (
|
|
1150
|
-
Direction(raw_direction) if raw_direction is not None else Direction.IN
|
|
1151
|
-
)
|
|
1152
|
-
|
|
1153
|
-
param_list.append(
|
|
1154
|
-
Parameter(
|
|
1155
|
-
name,
|
|
1156
|
-
type,
|
|
1157
|
-
optional,
|
|
1158
|
-
nullable,
|
|
1159
|
-
transfer_ownership,
|
|
1160
|
-
direction,
|
|
1161
|
-
object_type,
|
|
1162
|
-
)
|
|
1163
|
-
)
|
|
1164
|
-
return param_list
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
def all_regular_parameters(parameters: List[Parameter]) -> Iterator[Parameter]:
|
|
1168
|
-
callback_index = None
|
|
1169
|
-
for i, param in enumerate(parameters):
|
|
1170
|
-
if param.type.name == "Gio.AsyncReadyCallback":
|
|
1171
|
-
callback_index = i
|
|
1172
|
-
continue
|
|
1173
|
-
|
|
1174
|
-
if callback_index is not None and i == callback_index + 1:
|
|
1175
|
-
continue
|
|
1176
|
-
|
|
1177
|
-
yield param
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
def extract_type_from_entity(
|
|
1181
|
-
parent_element: ET.Element, resolve_type: ResolveTypeCallback
|
|
1182
|
-
) -> Optional[Type]:
|
|
1183
|
-
child = parent_element.find("type", GIR_NAMESPACES)
|
|
1184
|
-
if child is None:
|
|
1185
|
-
child = parent_element.find("array", GIR_NAMESPACES)
|
|
1186
|
-
assert child is not None
|
|
1187
|
-
element_type = extract_type_from_entity(child, resolve_type)
|
|
1188
|
-
if element_type.name == "utf8":
|
|
1189
|
-
return Type(
|
|
1190
|
-
"utf8[]",
|
|
1191
|
-
"strv",
|
|
1192
|
-
"gchar **",
|
|
1193
|
-
"NULL",
|
|
1194
|
-
"g_strdupv",
|
|
1195
|
-
"g_strfreev",
|
|
1196
|
-
)
|
|
1197
|
-
elif element_type.name == "gchar":
|
|
1198
|
-
return Type("char[]", "chararray", "gchar *", "NULL", "NULL", "NULL")
|
|
1199
|
-
elif element_type.name == "GObject.Value":
|
|
1200
|
-
return Type("Value[]", "valuearray", "GValue *", "NULL", "NULL", "NULL")
|
|
1201
|
-
else:
|
|
1202
|
-
assert (
|
|
1203
|
-
element_type.name == "guint8"
|
|
1204
|
-
), f"unsupported array type: {element_type.name}"
|
|
1205
|
-
return Type("uint8[]", "bytearray", "guint8 *", "NULL", "NULL", "NULL")
|
|
1206
|
-
|
|
1207
|
-
return parse_type(child, resolve_type)
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
def parse_type(
|
|
1211
|
-
element: ET.Element, resolve_type: ResolveTypeCallback
|
|
1212
|
-
) -> Optional[Type]:
|
|
1213
|
-
name = element.get("name")
|
|
1214
|
-
assert name is not None
|
|
1215
|
-
if name == "none":
|
|
1216
|
-
return None
|
|
1217
|
-
|
|
1218
|
-
is_primitive = name in PRIMITIVE_GIR_TYPES
|
|
1219
|
-
c_type = element.get(f"{{{C_NAMESPACE}}}type")
|
|
1220
|
-
|
|
1221
|
-
core_tag = None
|
|
1222
|
-
if is_primitive:
|
|
1223
|
-
type_element = element
|
|
1224
|
-
if c_type is None:
|
|
1225
|
-
c_type = name
|
|
1226
|
-
else:
|
|
1227
|
-
name, type_element = resolve_type(name)
|
|
1228
|
-
if type_element.tag.startswith(CORE_TAG_PREFIX):
|
|
1229
|
-
core_tag = type_element.tag[len(CORE_TAG_PREFIX) :]
|
|
1230
|
-
c_type = type_element.get(f"{{{C_NAMESPACE}}}type")
|
|
1231
|
-
if core_tag in {"class", "interface", "record"}:
|
|
1232
|
-
c_type += "*"
|
|
1233
|
-
|
|
1234
|
-
nick = type_nick_from_name(name, element, resolve_type)
|
|
1235
|
-
c = c_type.replace("*", " *")
|
|
1236
|
-
|
|
1237
|
-
default_value = "NULL" if "*" in c else None
|
|
1238
|
-
|
|
1239
|
-
if name == "utf8":
|
|
1240
|
-
copy_func = "g_strdup"
|
|
1241
|
-
destroy_func = "g_free"
|
|
1242
|
-
elif name == "utf8[]":
|
|
1243
|
-
copy_func = "g_strdupv"
|
|
1244
|
-
destroy_func = "g_strfreev"
|
|
1245
|
-
elif name == "GLib.HashTable":
|
|
1246
|
-
copy_func = "g_hash_table_ref"
|
|
1247
|
-
destroy_func = "g_hash_table_unref"
|
|
1248
|
-
elif name == "GLib.Quark":
|
|
1249
|
-
copy_func = None
|
|
1250
|
-
destroy_func = None
|
|
1251
|
-
elif name == "GObject.Value":
|
|
1252
|
-
copy_func = "g_value_copy"
|
|
1253
|
-
destroy_func = "g_value_reset"
|
|
1254
|
-
elif name == "GObject.Closure":
|
|
1255
|
-
copy_func = "g_closure_ref"
|
|
1256
|
-
destroy_func = "g_closure_unref"
|
|
1257
|
-
elif core_tag in {"class", "interface"}:
|
|
1258
|
-
copy_func = "g_object_ref"
|
|
1259
|
-
destroy_func = "g_object_unref"
|
|
1260
|
-
elif is_primitive or core_tag in {"bitfield", "callback", "enumeration"}:
|
|
1261
|
-
copy_func = None
|
|
1262
|
-
destroy_func = None
|
|
1263
|
-
else:
|
|
1264
|
-
copy_func = type_element.get("copy-function")
|
|
1265
|
-
destroy_func = type_element.get("free-function")
|
|
1266
|
-
assert (
|
|
1267
|
-
destroy_func is not None
|
|
1268
|
-
), f"unable to resolve destroy function for {name}, core_tag={core_tag}"
|
|
1269
|
-
|
|
1270
|
-
return Type(name, nick, c, default_value, copy_func, destroy_func)
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
def type_nick_from_name(
|
|
1274
|
-
name: str, element: ET.Element, resolve_type: ResolveTypeCallback
|
|
1275
|
-
) -> str:
|
|
1276
|
-
if name == "GLib.PollFD":
|
|
1277
|
-
return "pollfd"
|
|
1278
|
-
|
|
1279
|
-
tokens = name.split(".", maxsplit=1)
|
|
1280
|
-
if len(tokens) == 1:
|
|
1281
|
-
result = tokens[0]
|
|
1282
|
-
if result.startswith("g"):
|
|
1283
|
-
result = result[1:]
|
|
1284
|
-
else:
|
|
1285
|
-
result = to_snake_case(tokens[1])
|
|
1286
|
-
|
|
1287
|
-
if result == "hash_table":
|
|
1288
|
-
key_type = parse_type(element[0], resolve_type)
|
|
1289
|
-
value_type = parse_type(element[1], resolve_type)
|
|
1290
|
-
assert (
|
|
1291
|
-
key_type.name == "utf8" and value_type.name == "GLib.Variant"
|
|
1292
|
-
), "only GHashTable<string, Variant> is supported for now"
|
|
1293
|
-
result = "vardict"
|
|
1294
591
|
|
|
1295
|
-
|
|
592
|
+
FACTORY = core.Factory(
|
|
593
|
+
class_object_type=_make_class,
|
|
594
|
+
interface_object_type=_make_interface,
|
|
595
|
+
constructor=Constructor,
|
|
596
|
+
method=Method,
|
|
597
|
+
parameter=Parameter,
|
|
598
|
+
return_value=ReturnValue,
|
|
599
|
+
signal=Signal,
|
|
600
|
+
property_=Property,
|
|
601
|
+
enumeration=Enumeration,
|
|
602
|
+
enumeration_member=EnumerationMember,
|
|
603
|
+
model=Model,
|
|
604
|
+
)
|
|
1296
605
|
|
|
1297
606
|
|
|
1298
607
|
def js_type_from_gir(name: str) -> str:
|
|
@@ -1315,45 +624,3 @@ def js_type_from_gir(name: str) -> str:
|
|
|
1315
624
|
if name.startswith("Frida.") and name.endswith("List"):
|
|
1316
625
|
return name[6:-4] + "[]"
|
|
1317
626
|
return name.split(".")[-1]
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
def to_snake_case(name: str) -> str:
|
|
1321
|
-
result = []
|
|
1322
|
-
i = 0
|
|
1323
|
-
n = len(name)
|
|
1324
|
-
while i < n:
|
|
1325
|
-
if name[i].isupper():
|
|
1326
|
-
if i > 0:
|
|
1327
|
-
result.append("_")
|
|
1328
|
-
start = i
|
|
1329
|
-
if i + 1 < n and name[i + 1].islower():
|
|
1330
|
-
while i + 1 < n and name[i + 1].islower():
|
|
1331
|
-
i += 1
|
|
1332
|
-
else:
|
|
1333
|
-
while i + 1 < n and name[i + 1].isupper():
|
|
1334
|
-
i += 1
|
|
1335
|
-
if i + 1 < n:
|
|
1336
|
-
i -= 1
|
|
1337
|
-
result.append(name[start : i + 1].lower())
|
|
1338
|
-
else:
|
|
1339
|
-
result.append(name[i])
|
|
1340
|
-
i += 1
|
|
1341
|
-
return "".join(result)
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
def to_pascal_case(name: str) -> str:
|
|
1345
|
-
return "".join(word.capitalize() for word in name.split("_"))
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
def to_camel_case(name: str) -> str:
|
|
1349
|
-
words = name.split("_")
|
|
1350
|
-
return words[0] + "".join(word.capitalize() for word in words[1:])
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
def to_macro_case(identifier: str) -> str:
|
|
1354
|
-
result = []
|
|
1355
|
-
for i, char in enumerate(identifier):
|
|
1356
|
-
if char.isupper() and i != 0:
|
|
1357
|
-
result.append("_")
|
|
1358
|
-
result.append(char)
|
|
1359
|
-
return "".join(result).upper()
|