openubmc-bingo 0.6.45__py3-none-any.whl → 0.6.99__py3-none-any.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 (96) hide show
  1. bmcgo/__init__.py +1 -1
  2. bmcgo/bmcgo.py +9 -3
  3. bmcgo/bmcgo_config.py +16 -0
  4. bmcgo/cli/cli.py +72 -21
  5. bmcgo/codegen/__init__.py +1 -1
  6. bmcgo/codegen/lua/codegen.py +2 -2
  7. bmcgo/codegen/lua/script/check_intfs.py +1 -0
  8. bmcgo/codegen/lua/script/dto/options.py +1 -0
  9. bmcgo/codegen/lua/script/gen_db_json.py +4 -3
  10. bmcgo/codegen/lua/script/gen_rpc_msg_json.py +78 -11
  11. bmcgo/codegen/lua/script/model_consistency_check.py +1 -1
  12. bmcgo/codegen/lua/script/render_utils/db_lua.py +5 -6
  13. bmcgo/codegen/lua/script/render_utils/model_lua.py +5 -1
  14. bmcgo/codegen/lua/script/template.py +5 -0
  15. bmcgo/codegen/lua/script/utils.py +50 -8
  16. bmcgo/codegen/lua/templates/apps/Makefile +2 -2
  17. bmcgo/codegen/lua/templates/apps/client.lua.mako +1 -1
  18. bmcgo/codegen/lua/templates/apps/model.lua.mako +4 -3
  19. bmcgo/codegen/lua/templates/apps/service.lua.mako +1 -1
  20. bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +4 -0
  21. bmcgo/codegen/lua/templates/new_app_v2/CMakeLists.txt.mako +26 -0
  22. bmcgo/codegen/lua/templates/new_app_v2/conanfile.py.mako +9 -0
  23. bmcgo/codegen/lua/v1/script/render_utils/db_lua.py +5 -6
  24. bmcgo/codegen/lua/v1/script/render_utils/model_lua.py +13 -1
  25. bmcgo/codegen/lua/v1/templates/apps/client.lua.mako +1 -1
  26. bmcgo/codegen/lua/v1/templates/apps/local_db.lua.mako +0 -4
  27. bmcgo/codegen/lua/v1/templates/apps/message.lua.mako +3 -0
  28. bmcgo/codegen/lua/v1/templates/apps/model.lua.mako +3 -0
  29. bmcgo/codegen/lua/v1/templates/apps/utils/mdb_intf.lua.mako +6 -4
  30. bmcgo/component/analysis/analysis.py +9 -4
  31. bmcgo/component/analysis/dep-rules.json +20 -8
  32. bmcgo/component/analysis/dep_node.py +2 -0
  33. bmcgo/component/analysis/intf_validation.py +8 -7
  34. bmcgo/component/analysis/sr_validation.py +5 -4
  35. bmcgo/component/busctl_log_parse/busctl_log_parser.py +809 -0
  36. bmcgo/component/busctl_log_parse/mock_data_save.py +170 -0
  37. bmcgo/component/busctl_log_parse/test_data_save.py +49 -0
  38. bmcgo/component/component_helper.py +29 -0
  39. bmcgo/component/coverage/incremental_cov.py +5 -0
  40. bmcgo/component/fixture/__init__.py +29 -0
  41. bmcgo/component/fixture/auto_case_generator.py +490 -0
  42. bmcgo/component/fixture/busctl_type_converter.py +1081 -0
  43. bmcgo/component/fixture/common_config.py +15 -0
  44. bmcgo/component/fixture/dbus_gateway.py +669 -0
  45. bmcgo/component/fixture/dbus_library.py +250 -0
  46. bmcgo/component/fixture/dbus_mock_utils.py +514 -0
  47. bmcgo/component/fixture/dbus_response_handler.py +138 -0
  48. bmcgo/component/fixture/dbus_signature.py +110 -0
  49. bmcgo/component/template_v2/conanbase.py.mako +1 -5
  50. bmcgo/component/test.py +69 -10
  51. bmcgo/error_analyzer/__init__.py +0 -0
  52. bmcgo/error_analyzer/case_matcher.py +114 -0
  53. bmcgo/error_analyzer/log_parser.py +128 -0
  54. bmcgo/error_analyzer/unified_error_analyzer.py +359 -0
  55. bmcgo/error_cases/cases.yml +59 -0
  56. bmcgo/error_cases/cases_template_valid.json +71 -0
  57. bmcgo/error_cases/conanfile.py +58 -0
  58. bmcgo/frame.py +0 -4
  59. bmcgo/functional/analysis.py +18 -12
  60. bmcgo/functional/bmc_studio_action.py +21 -10
  61. bmcgo/functional/check.py +86 -42
  62. bmcgo/functional/conan_index_build.py +1 -1
  63. bmcgo/functional/config.py +22 -18
  64. bmcgo/functional/csr_build.py +63 -34
  65. bmcgo/functional/deploy.py +4 -3
  66. bmcgo/functional/diff.py +51 -34
  67. bmcgo/functional/full_component.py +16 -5
  68. bmcgo/functional/hpm_signer.py +484 -0
  69. bmcgo/functional/new.py +8 -2
  70. bmcgo/functional/schema_valid.py +111 -15
  71. bmcgo/functional/upgrade.py +6 -6
  72. bmcgo/misc.py +1 -0
  73. bmcgo/tasks/task_build_conan.py +27 -6
  74. bmcgo/tasks/task_build_rootfs_img.py +120 -83
  75. bmcgo/tasks/task_buildgppbin.py +30 -13
  76. bmcgo/tasks/task_buildhpm_ext4.py +5 -3
  77. bmcgo/tasks/task_download_buildtools.py +20 -11
  78. bmcgo/tasks/task_download_dependency.py +29 -20
  79. bmcgo/tasks/task_hpm_envir_prepare.py +32 -53
  80. bmcgo/tasks/task_packet_to_supporte.py +12 -4
  81. bmcgo/tasks/task_prepare.py +1 -1
  82. bmcgo/tasks/task_sign_and_pack_hpm.py +15 -7
  83. bmcgo/utils/component_version_check.py +4 -4
  84. bmcgo/utils/config.py +3 -0
  85. bmcgo/utils/fetch_component_code.py +148 -17
  86. bmcgo/utils/install_manager.py +2 -2
  87. bmcgo/utils/installations/base_installer.py +10 -27
  88. bmcgo/utils/installations/install_plans/studio.yml +3 -0
  89. bmcgo/utils/mapping_config_patch.py +5 -4
  90. bmcgo/utils/tools.py +49 -7
  91. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/METADATA +1 -1
  92. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/RECORD +95 -74
  93. bmcgo/tasks/download_buildtools_hm.py +0 -124
  94. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/WHEEL +0 -0
  95. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/entry_points.txt +0 -0
  96. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1081 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ # Copyright (c) 2024 Huawei Technologies Co., Ltd.
4
+ # openUBMC is licensed under Mulan PSL v2.
5
+ # You can use this software according to the terms and conditions of the Mulan PSL v2.
6
+ # You may obtain a copy of Mulan PSL v2 at:
7
+ # http://license.coscl.org.cn/MulanPSL2
8
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9
+ # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10
+ # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11
+ # See the Mulan PSL v2 for more details.
12
+ import re
13
+ import logging
14
+ from dbus_next import Variant
15
+ from bmcgo.component.fixture.dbus_signature import DBusSignature
16
+
17
+ # 配置日志
18
+ logging.basicConfig(
19
+ level=logging.INFO,
20
+ format='%(asctime)s - %(levelname)s - %(name)s - %(message)s'
21
+ )
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class BusCtlTypeConverter:
26
+ """
27
+ BusCtl类型转换器,提供将BusCtl日志字符串转换为正确D-Bus类型的功能
28
+ 支持所有D-Bus标准数据类型,保持与DBusTypeConverter相同的对外接口
29
+ """
30
+ @staticmethod
31
+ def dbus_string_to_type(type_value_str):
32
+ """
33
+ 将BusCtl日志中的字符串转换为正确的D-Bus类型
34
+
35
+ Args:
36
+ type_value_str: BusCtl日志中的字符串,格式:类型 值
37
+
38
+ Returns:
39
+ 转换后的Python原生类型或Variant
40
+ """
41
+ if type_value_str is None:
42
+ return None
43
+ # 去除首尾的引号和空格
44
+ value_str = str(type_value_str).strip()
45
+ # 首先尝试转换基本类型
46
+ basic_result = BusCtlTypeConverter._convert_basic_type(value_str)
47
+ if basic_result is not None:
48
+ return basic_result
49
+ # 处理对象路径类型
50
+ if value_str.startswith('OBJECT_PATH '):
51
+ try:
52
+ value_str = BusCtlTypeConverter._trim_trailing_semicolon(value_str)
53
+ path = value_str[13:].strip('"\'')
54
+ return path # dbus-next使用普通字符串表示对象路径
55
+ except (IndexError, ValueError):
56
+ pass
57
+ # 处理签名类型
58
+ if value_str.startswith('SIGNATURE '):
59
+ try:
60
+ value_str = BusCtlTypeConverter._trim_trailing_semicolon(value_str)
61
+ sig = value_str[10:].strip('"\'')
62
+ return sig # dbus-next使用普通字符串表示签名
63
+ except (IndexError, ValueError):
64
+ pass
65
+ # 处理复杂类型
66
+
67
+ # 处理圆括号结构体类型 (ss) {STRING "A";STRING "B";}
68
+ if re.match(r'^\([^)]+\)\s*\{', value_str):
69
+ return BusCtlTypeConverter._convert_struct_with_no_quote(value_str)
70
+ # 1. 字典/映射类型 - 优先处理,因为它是特殊的数组格式
71
+ if value_str.startswith('ARRAY "{'):
72
+ # 专门处理busctl格式: ARRAY "{ss}" {...}
73
+ # 找到签名结束的引号位置
74
+ first_quote = value_str.find('"')
75
+ second_quote = value_str.find('"', first_quote + 1)
76
+ if second_quote != -1:
77
+ # 从签名结束引号之后查找数组内容的开始花括号
78
+ content_start = value_str.find('{', second_quote + 1)
79
+ if content_start != -1:
80
+ # 找到匹配的结束花括号
81
+ end_brace_pos = value_str.rfind('};')
82
+ if end_brace_pos != -1 and end_brace_pos > content_start:
83
+ # 提取完整的数组内容(包含花括号)
84
+ array_content = value_str[content_start:end_brace_pos + 2]
85
+ # 检查是否包含DICT_ENTRY
86
+ if 'DICT_ENTRY' in array_content:
87
+ # 调用字典转换函数
88
+ result = BusCtlTypeConverter._convert_dictionary_type(value_str)
89
+ # 如果结果是None(空字典),返回空字典而不是None
90
+ return result if result is not None else {}
91
+ else:
92
+ # 检查是否为空字典数组(去除空白后只有{}或{;})
93
+ stripped_content = array_content.strip()
94
+ # 移除所有空白字符(包括换行、空格等)后检查
95
+ normalized = re.sub(r'\s+', '', stripped_content)
96
+ # 匹配各种可能的空数组格式:{}, {;}, { };, { };}, 等
97
+ flag_norma = normalized in ['{}', '{;}', '{;};', '{};']
98
+ flag_start_end = normalized.startswith('{') and normalized.endswith('}')
99
+ flag_length = len(normalized) <= 5
100
+ if flag_norma or (flag_start_end and flag_length):
101
+ # 空字典数组,返回空字典
102
+ return {}
103
+ # 更精确地处理结构体数组格式: ARRAY "(ss)" { ... }
104
+ if value_str.startswith('ARRAY "('):
105
+ result = BusCtlTypeConverter._handle_struct_array(value_str)
106
+ if isinstance(result, list) and len(result) == 0:
107
+ logger.warning(f"结构体数组解析结果为空,输入字符串长度: {len(value_str)}")
108
+ return result
109
+ # 字节数组类型 - BusCtl格式可能与dbus-monitor不同
110
+ if value_str.startswith('ARRAY "y" '):
111
+ try:
112
+ result = BusCtlTypeConverter._convert_array_of_bytes(value_str)
113
+ if result is not None:
114
+ return result
115
+ except Exception as e:
116
+ logger.error(f"字节数组解析错误: {e}")
117
+ pass
118
+ # 普通数组类型放最后处理 - 支持嵌套结构
119
+ if value_str.startswith('ARRAY '):
120
+ try:
121
+ result = BusCtlTypeConverter._convert_array_type(value_str)
122
+ if result is not None:
123
+ return result
124
+ except Exception as e:
125
+ logger.error(f"数组解析错误: {e}")
126
+ pass
127
+ # 3. 结构体类型
128
+ if value_str.startswith('STRUCT '):
129
+ try:
130
+ result = BusCtlTypeConverter._convert_struct_type(value_str)
131
+ if result is not None:
132
+ return result
133
+ except Exception as e:
134
+ logger.error(f"结构体解析错误: {e}", exc_info=True)
135
+ pass
136
+ # 4. 变体类型
137
+ if value_str.startswith('VARIANT '):
138
+ explicit_sig = None
139
+ try:
140
+ # 先尝试直接从VARIANT描述中提取显式签名,例如:VARIANT "s" STRING "foo";
141
+ match = re.match(r'^VARIANT\s+"([^"]+)"\s*(.*)$', value_str, re.DOTALL)
142
+ variant_payload = None
143
+ if match:
144
+ explicit_sig = match.group(1).strip()
145
+ variant_payload = match.group(2).strip()
146
+ # 处理特殊格式:VARIANT "v" <userdata>; 表示无法序列化的 Variant
147
+ if variant_payload.startswith('<userdata>'):
148
+ # 对于 <userdata>,创建一个 Variant("v", Variant("v", None))
149
+ # 或者创建一个 Variant("v", Variant("s", "<userdata>"))
150
+ # 这里我们使用一个字符串作为占位符
151
+ inner_variant = Variant("s", "<userdata>")
152
+ return Variant("v", inner_variant)
153
+ # 如果 payload 为空或仍然是 { ... } 包裹的内容,则回退到统一的内容提取逻辑
154
+ if (not variant_payload
155
+ or variant_payload.startswith('{')
156
+ or variant_payload.startswith('VARIANT ')):
157
+ variant_payload = BusCtlTypeConverter.extract_content_from_type(value_str, "VARIANT")
158
+ else:
159
+ variant_payload = BusCtlTypeConverter.extract_content_from_type(value_str, "VARIANT")
160
+ # 检查提取的内容是否仍然是 <userdata>
161
+ if variant_payload and variant_payload.strip().startswith('<userdata>'):
162
+ inner_variant = Variant("s", "<userdata>")
163
+ return Variant(explicit_sig or "v", inner_variant)
164
+
165
+ converted_value = BusCtlTypeConverter.dbus_string_to_type(variant_payload)
166
+ signature = explicit_sig or DBusSignature.get_dbus_signature(converted_value)
167
+ return Variant(signature, converted_value)
168
+ except Exception as e:
169
+ logger.error(f"变体解析错误: {e}")
170
+ pass
171
+ # 默认返回原始字符串
172
+ return value_str
173
+
174
+ @staticmethod
175
+ def extract_content_from_type(value_str, type_name):
176
+ """
177
+ 公共函数:提取指定类型数据结构中的内容部分,去除类型名称和可选的类型签名。
178
+ 支持两种格式:
179
+ 1. 带大括号的格式:'TYPE_NAME "signature" { content }'
180
+ 2. VARIANT特殊格式:'VARIANT "signature" content'
181
+
182
+ Args:
183
+ value_str: 包含数据结构内容的字符串
184
+ type_name: 数据结构类型名称,如'STRUCT'、'ARRAY'、'DICT_ENTRY'、'VARIANT'等
185
+
186
+ Returns:
187
+ str: 提取出的内容字符串,如果无法提取则返回None
188
+ """
189
+ import re
190
+ # 先尝试匹配带大括号的标准格式
191
+ pattern = r'{}\s*(?:"[^"]*")?\s*\{{'.format(type_name)
192
+ match = re.search(pattern, value_str)
193
+ if match:
194
+ # 处理带大括号的格式,使用括号平衡算法找到匹配的右花括号
195
+ # match.end() 是匹配结束的位置(即 { 之后),所以 match.end() - 1 是 { 的位置
196
+ start_brace = match.end() - 1
197
+ if start_brace != -1:
198
+ # 使用括号平衡算法找到匹配的右花括号
199
+ brace_count = 1
200
+ end_brace = start_brace + 1
201
+ in_quotes = False
202
+ quote_char = None
203
+ while end_brace < len(value_str) and brace_count > 0:
204
+ char = value_str[end_brace]
205
+ # 处理引号
206
+ if char in ['"', "'"] and (end_brace == 0 or value_str[end_brace - 1] != '\\'):
207
+ if in_quotes and char == quote_char:
208
+ in_quotes = False
209
+ quote_char = None
210
+ elif not in_quotes:
211
+ in_quotes = True
212
+ quote_char = char
213
+ elif not in_quotes:
214
+ if char == '{':
215
+ brace_count += 1
216
+ elif char == '}':
217
+ brace_count -= 1
218
+ end_brace += 1
219
+ if brace_count == 0:
220
+ # 找到了匹配的右花括号,提取内容(不包括花括号本身)
221
+ extracted = value_str[start_brace + 1:end_brace - 1].strip()
222
+ return extracted
223
+ else:
224
+ logger.warning(f"extract_content_from_type: 括号不平衡,brace_count={ \
225
+ brace_count}, end_brace={end_brace}, value_str长度={len(value_str)}")
226
+ elif type_name == "VARIANT":
227
+ # 特殊处理VARIANT类型,没有大括号的格式
228
+ # 匹配VARIANT后跟可选的签名,然后提取剩余内容
229
+ variant_pattern = r'VARIANT\s*(?:"[^"]*")?\s*(.*?);?$'
230
+ variant_match = re.search(variant_pattern, value_str)
231
+ if variant_match:
232
+ return variant_match.group(1).strip()
233
+ else:
234
+ logger.warning(f"extract_content_from_type: 正则匹配失败,pattern={pattern}, value_str前200字符={value_str[:200]}")
235
+ return None
236
+
237
+ @staticmethod
238
+ def compare_dbus_objects(obj1, obj2):
239
+ """
240
+ 比较两个 D-Bus 对象是否相等
241
+
242
+ 在dbus-next中,我们比较Python原生类型
243
+ """
244
+ # 对于变体类型特殊处理
245
+ if isinstance(obj1, Variant) and isinstance(obj2, Variant):
246
+ return BusCtlTypeConverter.compare_dbus_objects(obj1.value, obj2.value)
247
+ elif isinstance(obj1, Variant):
248
+ return BusCtlTypeConverter.compare_dbus_objects(obj1.value, obj2)
249
+ elif isinstance(obj2, Variant):
250
+ return BusCtlTypeConverter.compare_dbus_objects(obj1, obj2.value)
251
+
252
+ # 检查类型是否匹配
253
+ if type(obj1) != type(obj2):
254
+ # 处理数值类型的兼容性(例如int和float)
255
+ if isinstance(obj1, (int, float)) and isinstance(obj2, (int, float)):
256
+ return abs(obj1 - obj2) < 1e-10 # 浮点数比较需要容差
257
+ return False
258
+ # 对于基本类型,直接比较
259
+ if isinstance(obj1, (int, float, str, bool)):
260
+ if isinstance(obj1, float) and isinstance(obj2, float):
261
+ return abs(obj1 - obj2) < 1e-10 # 浮点数比较需要容差
262
+ return obj1 == obj2
263
+ # 对于列表/数组类型,递归比较每个元素
264
+ elif isinstance(obj1, list):
265
+ if len(obj1) != len(obj2):
266
+ return False
267
+
268
+ # 空列表直接返回 True
269
+ if len(obj1) == 0:
270
+ return True
271
+
272
+ # 特殊处理:如果两个列表都只包含字符串,进行集合比较(忽略顺序)
273
+ # 这对于字符串数组(as类型)很有用
274
+ if (all(isinstance(x, str) for x in obj1) and
275
+ all(isinstance(x, str) for x in obj2)):
276
+ # 对于字符串数组,使用集合比较
277
+ return set(obj1) == set(obj2)
278
+
279
+ # 对于其他类型的列表,逐个比较元素(保持顺序)
280
+ for i in range(len(obj1)):
281
+ if not BusCtlTypeConverter.compare_dbus_objects(obj1[i], obj2[i]):
282
+ return False
283
+ return True
284
+ # 对于字典类型,递归比较每个键值对
285
+ elif isinstance(obj1, dict):
286
+ if len(obj1) != len(obj2):
287
+ return False
288
+ for key in obj1:
289
+ if key not in obj2:
290
+ return False
291
+ if not BusCtlTypeConverter.compare_dbus_objects(obj1[key], obj2[key]):
292
+ return False
293
+ return True
294
+ # 对于元组/结构体类型,递归比较每个元素
295
+ elif isinstance(obj1, tuple):
296
+ if len(obj1) != len(obj2):
297
+ return False
298
+ for i in range(len(obj1)):
299
+ if not BusCtlTypeConverter.compare_dbus_objects(obj1[i], obj2[i]):
300
+ return False
301
+ return True
302
+ # 对于其他类型,尝试字符串比较
303
+ else:
304
+ return str(obj1) == str(obj2)
305
+
306
+ @staticmethod
307
+ def _get_value(value_str):
308
+ """
309
+ 从字符串中提取值,通过空格分割,返回分割后的第二个部分,分割后去掉首尾空格
310
+
311
+ Args:
312
+ value_str: 包含值的字符串,格式:类型 值 比如'string "Requestor"'
313
+
314
+ Returns:
315
+ 提取出的值,字符串类型
316
+ """
317
+ # 处理带引号的字符串
318
+ parts = value_str.split(' ', 1)
319
+ if len(parts) < 2:
320
+ # 如果没有空格分隔,返回原字符串
321
+ return value_str.strip()
322
+ return parts[1].strip() # 使用空格分割并去掉首尾空格
323
+
324
+ @staticmethod
325
+ def _convert_basic_type(type_value_str):
326
+ """
327
+ 转换D-Bus基本类型
328
+
329
+ Args:
330
+ type_value_str: 要转换的基本类型字符串,格式:类型 值,比如STRING "Slot";
331
+
332
+ Returns:
333
+ 转换后的Python原生类型,如果无法转换则返回None
334
+ """
335
+ # 先处理末尾分号
336
+ type_value_str = type_value_str.strip()
337
+ if type_value_str.endswith(';'):
338
+ type_value_str = type_value_str[:-1].strip()
339
+ value_str = BusCtlTypeConverter._get_value(type_value_str)
340
+ # 1. 字节类型: "BYTE 1" -> 1 (Python int)
341
+ if type_value_str.upper().startswith('BYTE '):
342
+ try:
343
+ # BusCtl中字节值可能是十六进制或十进制
344
+ if value_str.startswith('0x'):
345
+ return int(value_str, 16)
346
+ return int(value_str)
347
+ except (IndexError, ValueError):
348
+ pass
349
+ # 2. 字符串类型处理
350
+ if type_value_str.upper().startswith('STRING '):
351
+ try:
352
+ string_value = value_str
353
+ flag_dpuble = string_value.startswith('"') and string_value.endswith('"')
354
+ flag_single = string_value.startswith("'") and string_value.endswith("'")
355
+ # 处理带引号的情况
356
+ if flag_dpuble or flag_single:
357
+ string_value = string_value[1:-1]
358
+ # 处理转义字符
359
+ string_value = string_value.replace(r'\\n', '\n').replace(r'\\t', '\t').replace(r'\\\\', '\\')
360
+ return string_value
361
+ except (IndexError, ValueError):
362
+ pass
363
+ # 3. 布尔类型: "BOOLEAN true" -> True
364
+ if type_value_str.upper().startswith('BOOLEAN '):
365
+ bool_value = value_str.lower()
366
+ return bool_value == 'true'
367
+ elif type_value_str.lower() == 'true':
368
+ return True
369
+ elif type_value_str.lower() == 'false':
370
+ return False
371
+ # 4. 整数类型
372
+ # 4.1 有符号16位整数
373
+ if type_value_str.upper().startswith('INT16 '):
374
+ try:
375
+ # 处理十六进制表示
376
+ if value_str.startswith('0x'):
377
+ return int(value_str, 16)
378
+ return int(value_str)
379
+ except (IndexError, ValueError):
380
+ pass
381
+ # 4.2 无符号16位整数
382
+ elif type_value_str.upper().startswith('UINT16 '):
383
+ try:
384
+ # 处理十六进制表示
385
+ if value_str.startswith('0x'):
386
+ return int(value_str, 16)
387
+ return int(value_str)
388
+ except (IndexError, ValueError):
389
+ pass
390
+ # 4.3 有符号32位整数
391
+ elif type_value_str.upper().startswith('INT32 '):
392
+ try:
393
+ # 处理十六进制表示
394
+ if value_str.startswith('0x'):
395
+ return int(value_str, 16)
396
+ return int(value_str)
397
+ except (IndexError, ValueError):
398
+ pass
399
+ # 4.4 无符号32位整数
400
+ elif type_value_str.upper().startswith('UINT32 '):
401
+ try:
402
+ # 处理十六进制表示
403
+ if value_str.startswith('0x'):
404
+ return int(value_str, 16)
405
+ return int(value_str)
406
+ except (IndexError, ValueError):
407
+ pass
408
+ # 4.5 有符号64位整数
409
+ elif type_value_str.upper().startswith('INT64 '):
410
+ try:
411
+ # 处理十六进制表示
412
+ if value_str.startswith('0x'):
413
+ return int(value_str, 16)
414
+ return int(value_str)
415
+ except (IndexError, ValueError):
416
+ pass
417
+ # 4.6 无符号64位整数
418
+ elif type_value_str.upper().startswith('UINT64 '):
419
+ try:
420
+ # 处理十六进制表示
421
+ if value_str.startswith('0x'):
422
+ return int(value_str, 16)
423
+ return int(value_str)
424
+ except (IndexError, ValueError):
425
+ pass
426
+ # 5. 浮点数类型
427
+ # 5.1 double类型
428
+ if type_value_str.upper().startswith('DOUBLE '):
429
+ try:
430
+ return float(value_str)
431
+ except (IndexError, ValueError):
432
+ pass
433
+ # 5.2 float类型
434
+ elif type_value_str.upper().startswith('FLOAT '):
435
+ try:
436
+ return float(value_str)
437
+ except (IndexError, ValueError):
438
+ pass
439
+ # 无法识别为基本类型
440
+ return None
441
+
442
+ @staticmethod
443
+ def _convert_struct_with_no_quote(value_str):
444
+ """
445
+ 转换不带STRUCT关键字的结构体字符串为dbus-next可识别的格式,只是有圆括号
446
+ 例如: "(ss) {STRING "A";STRING "B";}" -> ["A", "B"]
447
+ 支持嵌套结构,如 "(ssayay) { STRING "A"; ARRAY "y" { BYTE 1; }; }"
448
+ """
449
+ import re
450
+ # 找到第一个花括号的位置
451
+ brace_start = value_str.find('{')
452
+ if brace_start == -1:
453
+ return value_str
454
+
455
+ # 使用括号平衡算法提取完整的花括号内容
456
+ brace_balance = 0
457
+ in_quotes = False
458
+ quote_char = None
459
+ brace_end = -1
460
+ for i in range(brace_start, len(value_str)):
461
+ char = value_str[i]
462
+ # 处理引号状态
463
+ if char in ['"', "'"] and (i == 0 or value_str[i-1] != '\\'):
464
+ if in_quotes and char == quote_char:
465
+ in_quotes = False
466
+ quote_char = None
467
+ elif not in_quotes:
468
+ in_quotes = True
469
+ quote_char = char
470
+ continue
471
+ # 只在非引号内处理括号
472
+ if not in_quotes:
473
+ if char == '{':
474
+ brace_balance += 1
475
+ elif char == '}':
476
+ brace_balance -= 1
477
+ if brace_balance == 0:
478
+ brace_end = i
479
+ break
480
+ if brace_end == -1:
481
+ return value_str
482
+ # 提取花括号内的内容(不包括花括号本身)
483
+ inner_content = value_str[brace_start + 1:brace_end].strip()
484
+ if not inner_content:
485
+ return []
486
+ # 使用智能分割函数分割字段(考虑嵌套结构和引号)
487
+ fields = BusCtlTypeConverter._split_elements_by_semicolon(inner_content)
488
+ # 转换每个字段
489
+ struct_fields = []
490
+ for field in fields:
491
+ field = field.strip()
492
+ if field:
493
+ converted_field = BusCtlTypeConverter.dbus_string_to_type(field)
494
+ struct_fields.append(converted_field)
495
+ return struct_fields
496
+
497
+ @staticmethod
498
+ def _split_elements_by_semicolon(content):
499
+ """
500
+ 智能分割带分号的内容,考虑括号嵌套和引号状态
501
+
502
+ Args:
503
+ content: 需要分割的内容字符串
504
+
505
+ Returns:
506
+ 分割后的元素列表
507
+ """
508
+ if not content:
509
+ return []
510
+
511
+ elements = []
512
+ current_element = []
513
+ brace_count = 0 # 花括号计数 {}
514
+ paren_count = 0 # 圆括号计数 ()
515
+ bracket_count = 0 # 方括号计数 []
516
+ in_quotes = False
517
+ for i, char in enumerate(content):
518
+ # 处理引号状态
519
+ if char == '"' and (i == 0 or content[i-1] != '\\'):
520
+ in_quotes = not in_quotes
521
+ # 只在非引号内处理括号计数
522
+ if not in_quotes:
523
+ if char == '{':
524
+ brace_count += 1
525
+ elif char == '}':
526
+ brace_count -= 1
527
+ elif char == '(':
528
+ paren_count += 1
529
+ elif char == ')':
530
+ paren_count -= 1
531
+ elif char == '[':
532
+ bracket_count += 1
533
+ elif char == ']':
534
+ bracket_count -= 1
535
+ # 当遇到分号且所有括号已匹配且不在引号内时,分割元素
536
+ if char == ';' and brace_count == 0 and paren_count == 0 and bracket_count == 0 and not in_quotes:
537
+ # 不包含分号本身
538
+ element = ''.join(current_element).strip()
539
+ if element:
540
+ elements.append(element)
541
+ current_element = []
542
+ else:
543
+ # 不是分隔符时才添加字符
544
+ current_element.append(char)
545
+ # 处理最后一个元素
546
+ if current_element:
547
+ element = ''.join(current_element).strip()
548
+ if element:
549
+ elements.append(element)
550
+ return elements
551
+
552
+ # 然后修复 _handle_struct_array 方法
553
+ @staticmethod
554
+ def _handle_struct_array(value_str):
555
+ """
556
+ value_str: 包含结构体数组内容的字符串,格式为 'ARRAY "(ss)" {...}'
557
+ 示例字符串:"ARRAY \"(ss)\" { (ss) { STRING \"a\"; STRING \"b\"; }; (ss) { STRING \"c\"; STRING \"d\"; }; };"
558
+ return_type: 转换后的dbus-next结构体数组
559
+ """
560
+ try:
561
+ # 提取ARRAY大括号内的内容
562
+ content = BusCtlTypeConverter.extract_content_from_type(value_str, 'ARRAY')
563
+ if not content:
564
+ logger.warning(f"无法从结构体数组中提取内容,输入前500字符: {value_str[:500]}")
565
+ return []
566
+
567
+ # 专门处理结构体数组:每个元素格式是 (signature) { ... };
568
+ # 使用括号平衡算法找到每个结构体元素的边界
569
+ elements = []
570
+ i = 0
571
+ struct_count = 0
572
+ while i < len(content):
573
+ # 跳过空白字符
574
+ while i < len(content) and content[i].isspace():
575
+ i += 1
576
+ if i >= len(content):
577
+ break
578
+
579
+ # 查找结构体开始:应该是 (signature) {
580
+ if content[i] == '(':
581
+ # 找到匹配的右括号
582
+ paren_end = i + 1
583
+ paren_count = 1
584
+ while paren_end < len(content) and paren_count > 0:
585
+ if content[paren_end] == '(':
586
+ paren_count += 1
587
+ elif content[paren_end] == ')':
588
+ paren_count -= 1
589
+ paren_end += 1
590
+
591
+ # 跳过空白字符,查找左花括号
592
+ brace_start = paren_end
593
+ while brace_start < len(content) and content[brace_start].isspace():
594
+ brace_start += 1
595
+ if brace_start < len(content) and content[brace_start] == '{':
596
+ # 找到匹配的右花括号
597
+ brace_end = brace_start + 1
598
+ brace_count = 1
599
+ in_quotes = False
600
+ quote_char = None
601
+ while brace_end < len(content) and brace_count > 0:
602
+ char = content[brace_end]
603
+
604
+ # 处理引号
605
+ if char in ['"', "'"] and (brace_end == 0 or content[brace_end-1] != '\\'):
606
+ if in_quotes and char == quote_char:
607
+ in_quotes = False
608
+ quote_char = None
609
+ elif not in_quotes:
610
+ in_quotes = True
611
+ quote_char = char
612
+ elif not in_quotes:
613
+ if char == '{':
614
+ brace_count += 1
615
+ elif char == '}':
616
+ brace_count -= 1
617
+
618
+ brace_end += 1
619
+
620
+ # 如果括号平衡没有归零,说明没有找到匹配的右花括号
621
+ if brace_count > 0:
622
+ logger.warning(f"结构体数组元素括号不平衡: brace_count={brace_count}, 位置={i}, brace_end={brace_end}")
623
+ break
624
+
625
+ # 查找分号:可能在 brace_end-1 之后(即 }; 的情况),也可能在跳过空白后
626
+ # 首先检查 brace_end-1 之后是否有分号(}; 的情况)
627
+ semicolon_pos = -1
628
+ if brace_end > 0 and brace_end <= len(content):
629
+ # 检查 brace_end-1 位置之后是否有分号
630
+ check_pos = brace_end - 1 # 这是 } 的位置
631
+ # 跳过 } 本身,检查之后是否有分号
632
+ next_pos = check_pos + 1
633
+ while next_pos < len(content) and content[next_pos].isspace():
634
+ next_pos += 1
635
+ if next_pos < len(content) and content[next_pos] == ';':
636
+ semicolon_pos = next_pos
637
+
638
+ # 如果没找到,尝试从 brace_end 开始查找
639
+ if semicolon_pos == -1:
640
+ semicolon_pos = brace_end
641
+ while semicolon_pos < len(content) and content[semicolon_pos].isspace():
642
+ semicolon_pos += 1
643
+ if semicolon_pos < len(content) and content[semicolon_pos] == ';':
644
+ pass # 找到了
645
+ else:
646
+ semicolon_pos = -1
647
+
648
+ if semicolon_pos >= 0:
649
+ # 提取完整的结构体元素(包括分号)
650
+ struct_element = content[i:semicolon_pos + 1].strip()
651
+ if struct_element:
652
+ elements.append(struct_element)
653
+ struct_count += 1
654
+ i = semicolon_pos + 1
655
+ else:
656
+ # 没有找到分号,可能是最后一个元素,尝试提取结构体元素
657
+ if brace_count == 0:
658
+ struct_element = content[i:brace_end].strip()
659
+ if struct_element:
660
+ elements.append(struct_element)
661
+ struct_count += 1
662
+ i = brace_end # 继续处理,不要 break
663
+ else:
664
+ break
665
+ else:
666
+ break
667
+ else:
668
+ # 没有找到左花括号,跳过这个字符
669
+ i += 1
670
+ else:
671
+ # 不是结构体开始,跳过这个字符
672
+ i += 1
673
+
674
+ if len(elements) == 0:
675
+ logger.warning(f"结构体数组分割结果为空,content长度={len(content)}, 前500字符={content[:500]}")
676
+
677
+ # 转换每个结构体元素
678
+ converted_elements = []
679
+ for idx, elem in enumerate(elements):
680
+ elem = elem.strip()
681
+ # 确保elem是完整的结构体格式
682
+ if elem and '(' in elem and '{' in elem:
683
+ # 递归转换每个结构体
684
+ try:
685
+ converted_value = BusCtlTypeConverter.dbus_string_to_type(elem)
686
+ converted_elements.append(converted_value)
687
+ except Exception as e:
688
+ logger.error(f"转换第 {idx + 1} 个结构体元素时出错: {e}", exc_info=True)
689
+ # 对于单个元素的错误,跳过该元素继续处理
690
+
691
+ # 确保始终返回列表类型
692
+ return converted_elements
693
+
694
+ except Exception as e:
695
+ logger.error(f"处理结构体数组时出错: {e}", exc_info=True)
696
+
697
+ # 错误情况下也返回空列表而不是原始字符串
698
+ return []
699
+
700
+ @staticmethod
701
+ def _trim_trailing_semicolon(value_str):
702
+ """
703
+ 移除字符串末尾的分号(如果存在)
704
+
705
+ Args:
706
+ value_str: 输入字符串
707
+
708
+ Returns:
709
+ 移除分号后的字符串
710
+ """
711
+ if value_str.endswith(';'):
712
+ return value_str[:-1].strip()
713
+ return value_str
714
+
715
+ @staticmethod
716
+ def _convert_dictionary_type(value_str):
717
+ """
718
+ 转换字典类型
719
+
720
+ Args:
721
+ value_str: 字典类型的字符串表示
722
+
723
+ Returns:
724
+ 转换后的Python字典对象,如果无法转换则返回None
725
+ """
726
+ try:
727
+ # 直接使用括号平衡算法提取DICT_ENTRY内容,因为正则表达式无法处理嵌套结构
728
+ dict_entries = BusCtlTypeConverter._extract_dict_entries_with_bracket_balance(value_str)
729
+
730
+ result_dict = {}
731
+ for entry in dict_entries:
732
+ # DICT_ENTRY格式: DICT_ENTRY "signature" { key; value; }
733
+ # 需要跳过 DICT_ENTRY "signature" { 部分,提取key和value
734
+
735
+ # 找到第一个不在引号内的大括号,这是内容开始的位置
736
+ content_start = -1
737
+ in_quotes = False
738
+ quote_char = None
739
+
740
+ for i, char in enumerate(entry):
741
+ # 处理引号状态
742
+ if char in ['"', "'"] and (i == 0 or entry[i-1] != '\\'):
743
+ if in_quotes and char == quote_char:
744
+ in_quotes = False
745
+ quote_char = None
746
+ elif not in_quotes:
747
+ in_quotes = True
748
+ quote_char = char
749
+ continue
750
+
751
+ # 只在非引号内查找大括号
752
+ if not in_quotes and char == '{':
753
+ content_start = i + 1
754
+ break
755
+
756
+ if content_start == -1:
757
+ continue
758
+
759
+ # 提取大括号内的内容(去掉最后的};或})
760
+ content_end = entry.rfind('}')
761
+ if content_end == -1:
762
+ continue
763
+ # 提取内容,去掉最后的};或}
764
+ inner_content = entry[content_start:content_end].strip()
765
+ # 使用智能分割函数分割key和value
766
+ # 在字典中,key和value之间用分号分隔,但要注意嵌套结构
767
+ brace_count = 0
768
+ paren_count = 0
769
+ bracket_count = 0
770
+ in_quotes = False
771
+ semicolon_pos = -1
772
+
773
+ # 查找第一个不在括号内且不在引号内的分号作为key-value分隔符
774
+ for i, char in enumerate(inner_content):
775
+ # 处理引号状态
776
+ if char in ['"', "'"] and (i == 0 or inner_content[i-1] != '\\'):
777
+ if in_quotes and char == quote_char:
778
+ in_quotes = False
779
+ quote_char = None
780
+ elif not in_quotes:
781
+ in_quotes = True
782
+ quote_char = char
783
+ continue
784
+
785
+ if not in_quotes:
786
+ if char == '{':
787
+ brace_count += 1
788
+ elif char == '}':
789
+ brace_count -= 1
790
+ elif char == '(':
791
+ paren_count += 1
792
+ elif char == ')':
793
+ paren_count -= 1
794
+ elif char == '[':
795
+ bracket_count += 1
796
+ elif char == ']':
797
+ bracket_count -= 1
798
+
799
+ # 找到有效的分隔符(第一个不在嵌套结构内的分号)
800
+ if char == ';' and brace_count == 0 and paren_count == 0 and bracket_count == 0 and not in_quotes:
801
+ semicolon_pos = i
802
+ break # 找到第一个有效分号就停止
803
+
804
+ if semicolon_pos == -1:
805
+ # 如果没有找到分号,尝试使用_split_elements_by_semicolon
806
+ elements = BusCtlTypeConverter._split_elements_by_semicolon(inner_content)
807
+ if len(elements) >= 2:
808
+ key_line = elements[0].strip()
809
+ value_content = '; '.join(elements[1:]).strip()
810
+ else:
811
+ continue
812
+ else:
813
+ # 找到了有效的分号分隔符
814
+ key_line = inner_content[:semicolon_pos].strip()
815
+ value_content = inner_content[semicolon_pos + 1:].strip()
816
+
817
+ # 处理key和value
818
+ converted_key = BusCtlTypeConverter.dbus_string_to_type(key_line)
819
+ converted_value = BusCtlTypeConverter.dbus_string_to_type(value_content)
820
+
821
+ # 确保值不是原始字符串,除非它确实是字符串类型
822
+ if isinstance(converted_value, str):
823
+ # 检查是否是嵌套的数组或字典格式
824
+ if converted_value.strip().startswith('ARRAY ') or converted_value.strip().startswith('DICT_ENTRY '):
825
+ # 尝试再次转换
826
+ converted_value = BusCtlTypeConverter.dbus_string_to_type(converted_value)
827
+
828
+ # 如果转换后的值是空列表,但原始value_content是字典数组格式,应该转换为空字典
829
+ if isinstance(converted_value, list) and len(converted_value) == 0:
830
+ if value_content.strip().startswith('ARRAY "{'):
831
+ # 这是空字典数组,应该返回空字典
832
+ converted_value = {}
833
+
834
+ # 确保key不是None
835
+ if converted_key is None:
836
+ logger.warning(f"无法转换字典key: {key_line}")
837
+ continue
838
+ result_dict[converted_key] = converted_value
839
+
840
+ return result_dict if result_dict else None
841
+ except Exception as e:
842
+ logger.error(f"busctl字典转换错误: {e}", exc_info=True)
843
+ return None
844
+
845
+ @staticmethod
846
+ def _extract_dict_entries_with_bracket_balance(value_str):
847
+ """
848
+ 提取所有的DICT_ENTRY条目,确保提取完整条目
849
+ 使用括号平衡算法处理嵌套结构,正确处理引号内的内容
850
+ """
851
+ result = []
852
+ pos = 0
853
+ while pos < len(value_str):
854
+ # 查找下一个DICT_ENTRY
855
+ dict_entry_start = value_str.find('DICT_ENTRY', pos)
856
+ if dict_entry_start == -1:
857
+ break
858
+ # 从DICT_ENTRY开始查找第一个不在引号内的大括号
859
+ brace_start = -1
860
+ in_quotes = False
861
+ quote_char = None
862
+ for i in range(dict_entry_start, len(value_str)):
863
+ char = value_str[i]
864
+ # 处理引号状态
865
+ if char in ['"', "'"] and (i == 0 or value_str[i - 1] != '\\'):
866
+ if in_quotes and char == quote_char:
867
+ in_quotes = False
868
+ quote_char = None
869
+ elif not in_quotes:
870
+ in_quotes = True
871
+ quote_char = char
872
+ continue
873
+ # 只在非引号内查找大括号
874
+ if not in_quotes and char == '{':
875
+ brace_start = i
876
+ break
877
+ if brace_start == -1:
878
+ pos = dict_entry_start + 10 # 跳过当前DICT_ENTRY,继续查找
879
+ continue
880
+ # 计算括号平衡,正确处理引号
881
+ brace_count = 1
882
+ end_brace_pos = brace_start + 1
883
+ in_quotes = False
884
+ quote_char = None
885
+ while end_brace_pos < len(value_str):
886
+ char = value_str[end_brace_pos]
887
+ # 处理引号状态
888
+ if char in ['"', "'"] and (end_brace_pos == 0 or value_str[end_brace_pos - 1] != '\\'):
889
+ if in_quotes and char == quote_char:
890
+ in_quotes = False
891
+ quote_char = None
892
+ elif not in_quotes:
893
+ in_quotes = True
894
+ quote_char = char
895
+ end_brace_pos += 1
896
+ continue
897
+ # 只在非引号内处理大括号
898
+ if not in_quotes:
899
+ if char == '{':
900
+ brace_count += 1
901
+ elif char == '}':
902
+ brace_count -= 1
903
+ # 当括号平衡时,我们找到了匹配的结束大括号
904
+ if brace_count == 0:
905
+ break
906
+ end_brace_pos += 1
907
+ # 确保找到了匹配的结束大括号
908
+ if brace_count == 0:
909
+ # 提取完整的DICT_ENTRY条目(包含结束的};)
910
+ # 查找是否还有分号和结束大括号
911
+ if end_brace_pos + 1 < len(value_str) and value_str[end_brace_pos + 1] == ';':
912
+ dict_entry = value_str[dict_entry_start:end_brace_pos + 2]
913
+ else:
914
+ dict_entry = value_str[dict_entry_start:end_brace_pos + 1]
915
+ result.append(dict_entry)
916
+ pos = end_brace_pos + 2 # 继续查找下一个DICT_ENTRY
917
+ else:
918
+ # 没有找到匹配的括号,跳过这个DICT_ENTRY
919
+ pos = dict_entry_start + 10
920
+ return result
921
+
922
+ @staticmethod
923
+ def _find_matching_brace(text, start_pos):
924
+ """
925
+ 查找匹配的结束大括号,处理引号和嵌套括号
926
+ """
927
+ depth = 0
928
+ in_quote = False
929
+ quote_char = None
930
+ for i in range(start_pos, len(text)):
931
+ char = text[i]
932
+ # 处理引号
933
+ if char in ['"', "'"] and (i == 0 or text[i-1] != '\\'):
934
+ if in_quote and char == quote_char:
935
+ in_quote = False
936
+ elif not in_quote:
937
+ in_quote = True
938
+ quote_char = char
939
+ continue
940
+ # 在引号内,跳过括号处理
941
+ if in_quote:
942
+ continue
943
+ # 处理括号
944
+ if char == '{':
945
+ depth += 1
946
+ elif char == '}':
947
+ depth -= 1
948
+ if depth == 0:
949
+ return i
950
+ return -1 # 没有找到匹配的括号
951
+
952
+ @staticmethod
953
+ def _convert_array_type(value_str):
954
+ """
955
+ 转换D-Bus数组类型,不包括字节数组
956
+
957
+ Args:
958
+ value_str: 包含数组内容的字符串
959
+
960
+ Returns:
961
+ 转换后的Python列表对象,如果无法转换则返回None
962
+ """
963
+ # 对于简单的ARRAY格式,使用通用函数提取内容
964
+ if value_str.startswith('ARRAY ') and '{' in value_str:
965
+ elements = BusCtlTypeConverter._extract_and_split_content(value_str, 'ARRAY')
966
+ if elements is None:
967
+ return []
968
+ # 转换每个元素
969
+ converted_elements = []
970
+ for elem in elements:
971
+ converted_elements.append(BusCtlTypeConverter.dbus_string_to_type(elem))
972
+ return converted_elements
973
+ # 对于没有ARRAY关键字的简单花括号格式
974
+ start_brace = value_str.find('{')
975
+ end_brace = value_str.rfind('}')
976
+ if start_brace == -1 or end_brace == -1 or start_brace >= end_brace:
977
+ return [] # 格式不正确,返回空列表
978
+ # 提取大括号内的内容并去除首尾空白
979
+ content = value_str[start_brace + 1:end_brace].strip()
980
+ if not content:
981
+ return [] # 空数组
982
+ # 使用分割函数
983
+ elements = BusCtlTypeConverter._split_elements_by_semicolon(content)
984
+ # 转换每个元素
985
+ converted_elements = []
986
+ for elem in elements:
987
+ converted_elements.append(BusCtlTypeConverter.dbus_string_to_type(elem))
988
+ return converted_elements
989
+
990
+ @staticmethod
991
+ def _convert_struct_type(value_str):
992
+ """
993
+ 转换D-Bus结构体类型
994
+
995
+ Args:
996
+ value_str: 包含结构体内容的字符串,格式为 'STRUCT {...}' 或 'STRUCT "ysss" {...}'
997
+
998
+ Returns:
999
+ 转换后的Python列表对象,如果无法转换则返回None
1000
+ """
1001
+ # 使用通用函数提取内容
1002
+ elements = BusCtlTypeConverter._extract_and_split_content(value_str, 'STRUCT')
1003
+ if elements is None:
1004
+ return None
1005
+
1006
+ # 转换每个元素
1007
+ converted_elements = []
1008
+ for elem in elements:
1009
+ converted_elem = BusCtlTypeConverter.dbus_string_to_type(elem)
1010
+ if converted_elem is not None:
1011
+ converted_elements.append(converted_elem)
1012
+ # 返回列表,对应dbus-next中的结构体表示
1013
+ return converted_elements
1014
+
1015
+
1016
+
1017
+ @staticmethod
1018
+ def _convert_array_of_bytes(value_str):
1019
+ """转换字节数组类型的值"""
1020
+ try:
1021
+ # 假设输入格式为 "ARRAY "y" { BYTE 1; BYTE 2; BYTE 3; };" 或类似格式
1022
+ # 直接提取大括号内的内容
1023
+ start_index = value_str.find('{')
1024
+ end_index = value_str.rfind('}')
1025
+ if start_index == -1 or end_index == -1 or start_index >= end_index:
1026
+ # 如果找不到有效格式,尝试处理空数组
1027
+ if '{ }' in value_str or '{}' in value_str:
1028
+ return b''
1029
+ raise ValueError(f"Invalid byte array format: {value_str}")
1030
+ # 提取大括号内的内容,去掉前后空格
1031
+ content = value_str[start_index + 1:end_index].strip()
1032
+ # 如果内容为空,返回空字节数组
1033
+ if not content:
1034
+ return b''
1035
+ # 按分号分割元素
1036
+ elements = [elem.strip() for elem in content.split(';') if elem.strip()]
1037
+ # 提取每个BYTE值并转换为整数
1038
+ valid_values = []
1039
+ for elem in elements:
1040
+ # 简化逻辑:使用空格分割并取第二个元素(数字部分)
1041
+ parts = elem.split()
1042
+ if len(parts) >= 2 and parts[0].upper() == 'BYTE':
1043
+ try:
1044
+ # 直接取空格分割后的第二个部分作为数字
1045
+ byte_value = int(parts[1])
1046
+ # 确保值在有效范围内
1047
+ if 0 <= byte_value <= 255:
1048
+ valid_values.append(byte_value)
1049
+ else:
1050
+ logging.warning(f"Byte value {byte_value} out of range, clamping to 0-255")
1051
+ valid_values.append(max(0, min(255, byte_value)))
1052
+ except ValueError:
1053
+ logging.warning(f"Invalid byte value format: {elem}")
1054
+ valid_values.append(0)
1055
+ else:
1056
+ logging.warning(f"Unexpected element format in byte array: {elem}")
1057
+ valid_values.append(0)
1058
+ # 转换为bytes对象返回
1059
+ return bytes(valid_values)
1060
+ except Exception as e:
1061
+ logging.error(f"Error converting byte array: {str(e)}")
1062
+ return b''
1063
+
1064
+ @staticmethod
1065
+ def _extract_and_split_content(value_str, type_name):
1066
+ """
1067
+ 公共函数:提取并分割指定类型的数据结构内容,针对复杂类型(STRUCT、ARRAY),用最外层的;进行分割分割成独立的数据
1068
+
1069
+ Args:
1070
+ value_str: 包含数据结构内容的字符串
1071
+ type_name: 数据结构类型名称,如'STRUCT'、'ARRAY'
1072
+
1073
+ Returns:
1074
+ 分割后的元素列表,如果无法提取则返回None
1075
+ """
1076
+ # 提取大括号内的内容
1077
+ content = BusCtlTypeConverter.extract_content_from_type(value_str, type_name)
1078
+ if not content:
1079
+ return []
1080
+ # 使用之前创建的元素分割函数
1081
+ return BusCtlTypeConverter._split_elements_by_semicolon(content)