From a9c18456b59060207834f41c18d10921990b96bc Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Sat, 5 Sep 2020 12:00:20 +0200 Subject: [PATCH] Support for encoding nullable properties This patch makes it possible to encode properties set to null, e.g.: ``` { "BlockSizeBytes": null } ``` if the schema allows a property to be null. Signed-off-by: Konrad Sztyber --- rdebej/_internal_utils.py | 5 ++++- rdebej/encode.py | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/rdebej/_internal_utils.py b/rdebej/_internal_utils.py index b9a6a54..3fb032b 100644 --- a/rdebej/_internal_utils.py +++ b/rdebej/_internal_utils.py @@ -31,6 +31,7 @@ DICTIONARY_ENTRY_OFFSET = 2 DICTIONARY_ENTRY_CHILD_COUNT = 3 DICTIONARY_ENTRY_NAME = 4 +DICTIONARY_ENTRY_NULLABLE_PROPERTY = 5 BEJ_DICTIONARY_SELECTOR_MAJOR_SCHEMA = 0x00 BEJ_DICTIONARY_SELECTOR_ANNOTATION = 0x01 @@ -71,8 +72,9 @@ def get_next_entry(self): entry = [] current_entry = 0 if self._current_entry < self._child_count or self._child_count == -1: + format = self.get_int(1) - entry.append(self.get_int(1) >> 4) # format + entry.append(format >> 4) # value format entry.append(self.get_int(2)) # sequence entry.append(self.get_int(2)) # offset entry.append(self.get_int(2)) # child_count @@ -86,6 +88,7 @@ def get_next_entry(self): name = "".join(map(chr, self._byte_array[name_offset:name_offset+name_length-1])) # -1 to skip null terminator entry.append(name) + entry.append((format & (1 << 2)) != 0) # nullable_property flag if self._child_count != -1: self._current_entry += 1 diff --git a/rdebej/encode.py b/rdebej/encode.py index 4b42d4b..eb8c81b 100644 --- a/rdebej/encode.py +++ b/rdebej/encode.py @@ -448,6 +448,9 @@ def bej_encode_sflv(output_stream, schema_dict, annot_dict, dict_to_use, dict_en bej_pack_array_done(nested_stream, seq) + elif format == BEJ_FORMAT_NULL: + bej_pack_sfl(output_stream, seq, BEJ_FORMAT_NULL, 0) + else: if verbose: print('Failed to encode value:', json_value) @@ -486,6 +489,14 @@ def bej_encode_stream(output_stream, json_data, schema_dict, annot_dict, dict_to if dict_to_use == schema_dict else BEJ_DICTIONARY_SELECTOR_ANNOTATION prop_format = entry[DICTIONARY_ENTRY_FORMAT] + json_value = json_data[prop] + if json_value is None: + if not entry[DICTIONARY_ENTRY_NULLABLE_PROPERTY]: + if verbose: + print('Property {} cannot be null'.format(prop)) + return False + prop_format = BEJ_FORMAT_NULL + sequence_number_with_dictionary_selector = (entry[DICTIONARY_ENTRY_SEQUENCE_NUMBER] << 1) \ | dictionary_selector_bit_value @@ -506,11 +517,10 @@ def bej_encode_stream(output_stream, json_data, schema_dict, annot_dict, dict_to success = bej_encode_sflv(nested_stream, schema_dict, annot_dict, tmp_dict_to_use, entry, sequence_number_with_dictionary_selector, entry[DICTIONARY_ENTRY_FORMAT], - json_data[prop], pdr_map, 0, verbose) + json_value, pdr_map, 0, verbose) bej_pack_property_annotation_done(nested_stream, prop_seq) else: - json_value = json_data[prop] format_flags = 0 # Special handling for '@odata.id' deferred binding string if prop == '@odata.id' and prop_format == BEJ_FORMAT_STRING: