5 from .. import LOG as _LOG
6 from ..binarywave import TYPE_TABLE as _TYPE_TABLE
7 from ..binarywave import NullStaticStringField as _NullStaticStringField
8 from ..binarywave import DynamicStringField as _DynamicStringField
9 from ..struct import Structure as _Structure
10 from ..struct import DynamicStructure as _DynamicStructure
11 from ..struct import Field as _Field
12 from ..struct import DynamicField as _DynamicField
13 from ..util import byte_order as _byte_order
14 from ..util import need_to_reorder_bytes as _need_to_reorder_bytes
15 from .base import Record
18 class ListedStaticStringField (_NullStaticStringField):
19 """Handle string conversions for multi-count dynamic parents.
21 If a field belongs to a multi-count dynamic parent, the parent is
22 called multiple times to parse each count, and the field's
23 post-unpack hook gets called after the field is unpacked during
24 each iteration. This requires alternative logic for getting and
25 setting the string data. The actual string formatting code is not
28 def post_unpack(self, parents, data):
29 parent_structure = parents[-1]
30 parent_data = self._get_structure_data(parents, data, parent_structure)
31 d = self._normalize_string(parent_data[-1][self.name])
32 parent_data[-1][self.name] = d
35 class ListedStaticStringField (_NullStaticStringField):
36 """Handle string conversions for multi-count dynamic parents.
38 If a field belongs to a multi-count dynamic parent, the parent is
39 called multiple times to parse each count, and the field's
40 post-unpack hook gets called after the field is unpacked during
41 each iteration. This requires alternative logic for getting and
42 setting the string data. The actual string formatting code is not
45 def post_unpack(self, parents, data):
46 parent_structure = parents[-1]
47 parent_data = self._get_structure_data(parents, data, parent_structure)
48 d = self._normalize_string(parent_data[-1][self.name])
49 parent_data[-1][self.name] = d
52 class ListedDynamicStrDataField (_DynamicStringField, ListedStaticStringField):
53 _size_field = 'strLen'
54 _null_terminated = False
56 def _get_size_data(self, parents, data):
57 parent_structure = parents[-1]
58 parent_data = self._get_structure_data(parents, data, parent_structure)
59 return parent_data[-1][self._size_field]
62 class DynamicVarDataField (_DynamicField):
63 def pre_pack(self, parents, data):
64 raise NotImplementedError()
66 def post_unpack(self, parents, data):
67 var_structure = parents[-1]
68 var_data = self._get_structure_data(parents, data, var_structure)
69 data = var_data[self.name]
71 for i,value in enumerate(data):
72 key,value = self._normalize_item(i, value)
74 var_data[self.name] = d
76 def _normalize_item(self, index, value):
77 raise NotImplementedError()
80 class DynamicSysVarField (DynamicVarDataField):
81 def _normalize_item(self, index, value):
82 name = 'K{}'.format(index)
86 class DynamicUserVarField (DynamicVarDataField):
87 def _normalize_item(self, index, value):
93 class DynamicUserStrField (DynamicVarDataField):
94 def _normalize_item(self, index, value):
100 class DynamicVarNumField (_DynamicField):
101 def post_unpack(self, parents, data):
102 parent_structure = parents[-1]
103 parent_data = self._get_structure_data(parents, data, parent_structure)
104 d = self._normalize_numeric_variable(parent_data[-1][self.name])
105 parent_data[-1][self.name] = d
107 def _normalize_numeric_variable(self, num_var):
108 t = _TYPE_TABLE[num_var['numType']]
109 if num_var['numType'] % 2: # complex number
110 return t(complex(num_var['realPart'], num_var['imagPart']))
112 return t(num_var['realPart'])
115 class DynamicFormulaField (_DynamicStringField):
116 _size_field = 'formulaLen'
117 _null_terminated = True
121 VarHeader1 = _Structure( # `version` field pulled out into VariablesRecord
124 _Field('h', 'numSysVars', help='Number of system variables (K0, K1, ...).'),
125 _Field('h', 'numUserVars', help='Number of user numeric variables -- may be zero.'),
126 _Field('h', 'numUserStrs', help='Number of user string variables -- may be zero.'),
130 VarHeader2 = _Structure( # `version` field pulled out into VariablesRecord
133 _Field('h', 'numSysVars', help='Number of system variables (K0, K1, ...).'),
134 _Field('h', 'numUserVars', help='Number of user numeric variables -- may be zero.'),
135 _Field('h', 'numUserStrs', help='Number of user string variables -- may be zero.'),
136 _Field('h', 'numDependentVars', help='Number of dependent numeric variables -- may be zero.'),
137 _Field('h', 'numDependentStrs', help='Number of dependent string variables -- may be zero.'),
141 UserStrVarRec1 = _DynamicStructure(
142 name='UserStrVarRec1',
144 ListedStaticStringField('c', 'name', help='Name of the string variable.', count=32),
145 _Field('h', 'strLen', help='The real size of the following array.'),
146 ListedDynamicStrDataField('c', 'data'),
150 UserStrVarRec2 = _DynamicStructure(
151 name='UserStrVarRec2',
153 ListedStaticStringField('c', 'name', help='Name of the string variable.', count=32),
154 _Field('l', 'strLen', help='The real size of the following array.'),
159 VarNumRec = _Structure(
162 _Field('h', 'numType', help='Type from binarywave.TYPE_TABLE'),
163 _Field('d', 'realPart', help='The real part of the number.'),
164 _Field('d', 'imagPart', help='The imag part if the number is complex.'),
165 _Field('l', 'reserved', help='Reserved - set to zero.'),
169 UserNumVarRec = _DynamicStructure(
170 name='UserNumVarRec',
172 ListedStaticStringField('c', 'name', help='Name of the string variable.', count=32),
173 _Field('h', 'type', help='0 = string, 1 = numeric.'),
174 DynamicVarNumField(VarNumRec, 'num', help='Type and value of the variable if it is numeric. Not used for string.'),
178 UserDependentVarRec = _DynamicStructure(
179 name='UserDependentVarRec',
181 ListedStaticStringField('c', 'name', help='Name of the string variable.', count=32),
182 _Field('h', 'type', help='0 = string, 1 = numeric.'),
183 _Field(VarNumRec, 'num', help='Type and value of the variable if it is numeric. Not used for string.'),
184 _Field('h', 'formulaLen', help='The length of the dependency formula.'),
185 DynamicFormulaField('c', 'formula', help='Start of the dependency formula. A C string including null terminator.'),
189 class DynamicVarHeaderField (_DynamicField):
190 def pre_pack(self, parents, data):
191 raise NotImplementedError()
193 def post_unpack(self, parents, data):
194 var_structure = parents[-1]
195 var_data = self._get_structure_data(
196 parents, data, var_structure)
197 var_header_structure = self.format
198 data = var_data['var_header']
199 sys_vars_field = var_structure.get_field('sysVars')
200 sys_vars_field.count = data['numSysVars']
201 sys_vars_field.setup()
202 user_vars_field = var_structure.get_field('userVars')
203 user_vars_field.count = data['numUserVars']
204 user_vars_field.setup()
205 user_strs_field = var_structure.get_field('userStrs')
206 user_strs_field.count = data['numUserStrs']
207 user_strs_field.setup()
208 if 'numDependentVars' in data:
209 dependent_vars_field = var_structure.get_field('dependentVars')
210 dependent_vars_field.count = data['numDependentVars']
211 dependent_vars_field.setup()
212 dependent_strs_field = var_structure.get_field('dependentStrs')
213 dependent_strs_field.count = data['numDependentStrs']
214 dependent_strs_field.setup()
215 var_structure.setup()
218 Variables1 = _DynamicStructure(
221 DynamicVarHeaderField(VarHeader1, 'var_header', help='Variables header'),
222 DynamicSysVarField('f', 'sysVars', help='System variables', count=0),
223 DynamicUserVarField(UserNumVarRec, 'userVars', help='User numeric variables', count=0),
224 DynamicUserStrField(UserStrVarRec1, 'userStrs', help='User string variables', count=0),
228 Variables2 = _DynamicStructure(
231 DynamicVarHeaderField(VarHeader2, 'var_header', help='Variables header'),
232 DynamicSysVarField('f', 'sysVars', help='System variables', count=0),
233 DynamicUserVarField(UserNumVarRec, 'userVars', help='User numeric variables', count=0),
234 DynamicUserStrField(UserStrVarRec2, 'userStrs', help='User string variables', count=0),
235 _Field(UserDependentVarRec, 'dependentVars', help='Dependent numeric variables.', count=0),
236 _Field(UserDependentVarRec, 'dependentStrs', help='Dependent string variables.', count=0),
240 class DynamicVersionField (_DynamicField):
241 def pre_pack(self, parents, byte_order):
242 raise NotImplementedError()
244 def post_unpack(self, parents, data):
245 variables_structure = parents[-1]
246 variables_data = self._get_structure_data(
247 parents, data, variables_structure)
248 version = variables_data['version']
249 if variables_structure.byte_order in '@=':
250 need_to_reorder_bytes = _need_to_reorder_bytes(version)
251 variables_structure.byte_order = _byte_order(need_to_reorder_bytes)
253 'get byte order from version: {} (reorder? {})'.format(
254 variables_structure.byte_order, need_to_reorder_bytes))
256 need_to_reorder_bytes = False
258 old_format = variables_structure.fields[-1].format
260 variables_structure.fields[-1].format = Variables1
262 variables_structure.fields[-1].format = Variables2
263 elif not need_to_reorder_bytes:
265 'invalid variables record version: {}'.format(version))
267 if variables_structure.fields[-1].format != old_format:
268 _LOG.debug('change variables record from {} to {}'.format(
269 old_format, variables_structure.fields[-1].format))
270 variables_structure.setup()
271 elif need_to_reorder_bytes:
272 variables_structure.setup()
274 # we might need to unpack again with the new byte order
275 return need_to_reorder_bytes
278 VariablesRecordStructure = _DynamicStructure(
279 name='VariablesRecord',
281 DynamicVersionField('h', 'version', help='Version number for this header.'),
282 _Field(Variables1, 'variables', help='The rest of the variables data.'),
286 class VariablesRecord (Record):
287 def __init__(self, *args, **kwargs):
288 super(VariablesRecord, self).__init__(*args, **kwargs)
289 # self.header['version'] # record version always 0?
290 VariablesRecordStructure.byte_order = '='
291 VariablesRecordStructure.setup()
292 stream = _io.BytesIO(bytes(self.data))
293 self.variables = VariablesRecordStructure.unpack_stream(stream)
295 for key,value in self.variables['variables'].items():
296 if key not in ['var_header']:
297 _LOG.debug('update namespace {} with {} for {}'.format(
298 self.namespace, value, key))
299 self.namespace.update(value)