@@ -101,17 +101,26 @@ def emplace_atomic_value(
101
101
odxraise (f"{ internal_value !r} is not a bytefield" , EncodeError )
102
102
return
103
103
104
- odxassert (base_type_encoding in (None , Encoding .NONE , Encoding .BCD_P , Encoding .BCD_UP ))
104
+ odxassert (
105
+ base_type_encoding in (None , Encoding .NONE , Encoding .BCD_P , Encoding .BCD_UP ),
106
+ f"Illegal encoding '{ base_type_encoding } ' for A_BYTEFIELD" )
105
107
106
108
# note that we do not ensure that BCD-encoded byte fields
107
109
# only represent "legal" values
108
110
raw_value = bytes (internal_value )
109
111
112
+ if 8 * len (raw_value ) > bit_length :
113
+ odxraise (
114
+ f"The value '{ internal_value !r} ' cannot be encoded using "
115
+ f"{ bit_length } bits." , EncodeError )
116
+ raw_value = raw_value [0 :bit_length // 8 ]
117
+
110
118
# ... string types, ...
111
119
elif base_data_type in (DataType .A_UTF8STRING , DataType .A_ASCIISTRING ,
112
120
DataType .A_UNICODE2STRING ):
113
121
if not isinstance (internal_value , str ):
114
- odxraise (f"The internal value { internal_value !r} is not a string" , EncodeError )
122
+ odxraise (f"The internal value '{ internal_value !r} ' is not a string" , EncodeError )
123
+ internal_value = str (internal_value )
115
124
116
125
str_encoding = get_string_encoding (base_data_type , base_type_encoding ,
117
126
is_highlow_byte_order )
@@ -122,16 +131,17 @@ def emplace_atomic_value(
122
131
123
132
if 8 * len (raw_value ) > bit_length :
124
133
odxraise (
125
- f"The internal representation { raw_value !r} is too large "
126
- f"to be encoded. The maximum number of bytes is { ( bit_length + 7 ) // 8 } ." ,
127
- EncodeError )
134
+ f"The value ' { internal_value !r} ' cannot be encoded using "
135
+ f"{ bit_length } bits ." , EncodeError )
136
+ raw_value = raw_value [ 0 : bit_length // 8 ]
128
137
129
138
# ... signed integers, ...
130
139
elif base_data_type == DataType .A_INT32 :
131
140
if not isinstance (internal_value , int ):
132
141
odxraise (
133
142
f"Internal value must be of integer type, not { type (internal_value ).__name__ } " ,
134
143
EncodeError )
144
+ internal_value = int (internal_value )
135
145
136
146
if base_type_encoding == Encoding .ONEC :
137
147
# one-complement
@@ -154,34 +164,35 @@ def emplace_atomic_value(
154
164
else :
155
165
raw_value = (1 << (bit_length - 1 )) + abs (internal_value )
156
166
else :
157
- odxraise (f"Illegal encoding ({ base_type_encoding } ) specified for "
158
- f"{ base_data_type .value } " )
167
+ odxraise (
168
+ f"Illegal encoding ({ base_type_encoding and base_type_encoding .value } ) specified for "
169
+ f"{ base_data_type .value } " )
159
170
160
- raw_value = internal_value
171
+ if base_type_encoding == Encoding .BCD_P :
172
+ raw_value = self .__encode_bcd_p (abs (internal_value ))
173
+ elif base_type_encoding == Encoding .BCD_UP :
174
+ raw_value = self .__encode_bcd_up (abs (internal_value ))
175
+ else :
176
+ raw_value = internal_value
177
+
178
+ if raw_value .bit_length () > bit_length :
179
+ odxraise (
180
+ f"The value '{ internal_value !r} ' cannot be encoded using "
181
+ f"{ bit_length } bits." , EncodeError )
182
+ raw_value &= (1 << bit_length ) - 1
161
183
162
184
# ... unsigned integers, ...
163
185
elif base_data_type == DataType .A_UINT32 :
164
186
if not isinstance (internal_value , int ) or internal_value < 0 :
165
187
odxraise (f"Internal value must be a positive integer, not { internal_value !r} " )
188
+ internal_value = abs (int (internal_value ))
166
189
167
190
if base_type_encoding == Encoding .BCD_P :
168
191
# packed BCD
169
- tmp2 = internal_value
170
- raw_value = 0
171
- shift = 0
172
- while tmp2 > 0 :
173
- raw_value |= (tmp2 % 10 ) << shift
174
- shift += 4
175
- tmp2 //= 10
192
+ raw_value = self .__encode_bcd_p (internal_value )
176
193
elif base_type_encoding == Encoding .BCD_UP :
177
194
# unpacked BCD
178
- tmp2 = internal_value
179
- raw_value = 0
180
- shift = 0
181
- while tmp2 > 0 :
182
- raw_value |= (tmp2 % 10 ) << shift
183
- shift += 8
184
- tmp2 //= 10
195
+ raw_value = self .__encode_bcd_up (internal_value )
185
196
elif base_type_encoding in (None , Encoding .NONE ):
186
197
# no encoding
187
198
raw_value = internal_value
@@ -191,6 +202,12 @@ def emplace_atomic_value(
191
202
192
203
raw_value = internal_value
193
204
205
+ if raw_value .bit_length () > bit_length :
206
+ odxraise (
207
+ f"The value '{ internal_value !r} ' cannot be encoded using "
208
+ f"{ bit_length } bits." , EncodeError )
209
+ raw_value &= (1 << bit_length ) - 1
210
+
194
211
# ... and others (floating point values)
195
212
else :
196
213
odxassert (base_data_type in (DataType .A_FLOAT32 , DataType .A_FLOAT64 ))
@@ -210,15 +227,15 @@ def emplace_atomic_value(
210
227
self .emplace_bytes (b'' )
211
228
return
212
229
213
- char = base_data_type .bitstruct_format_letter
230
+ format_char = base_data_type .bitstruct_format_letter
214
231
padding = (8 - ((bit_length + self .cursor_bit_position ) % 8 )) % 8
215
232
odxassert ((0 <= padding and padding < 8 and
216
233
(padding + bit_length + self .cursor_bit_position ) % 8 == 0 ),
217
234
f"Incorrect padding { padding } " )
218
235
left_pad = f"p{ padding } " if padding > 0 else ""
219
236
220
237
# actually encode the value
221
- coded = bitstruct .pack (f"{ left_pad } { char } { bit_length } " , raw_value )
238
+ coded = bitstruct .pack (f"{ left_pad } { format_char } { bit_length } " , raw_value )
222
239
223
240
# create the raw mask of used bits for numeric objects
224
241
used_mask_raw = used_mask
@@ -290,3 +307,25 @@ def emplace_bytes(self,
290
307
self .used_mask [pos + i ] |= obj_used_mask [i ]
291
308
292
309
self .cursor_byte_position += len (new_data )
310
+
311
+ @staticmethod
312
+ def __encode_bcd_p (value : int ) -> int :
313
+ result = 0
314
+ shift = 0
315
+ while value > 0 :
316
+ result |= (value % 10 ) << shift
317
+ shift += 4
318
+ value //= 10
319
+
320
+ return result
321
+
322
+ @staticmethod
323
+ def __encode_bcd_up (value : int ) -> int :
324
+ result = 0
325
+ shift = 0
326
+ while value > 0 :
327
+ result |= (value % 10 ) << shift
328
+ shift += 8
329
+ value //= 10
330
+
331
+ return result
0 commit comments