Skip to content

Commit a7a9352

Browse files
committed
Fix JSON reader in case of empty extern field
1 parent ca15049 commit a7a9352

File tree

6 files changed

+146
-12
lines changed

6 files changed

+146
-12
lines changed

compiler/extensions/cpp/runtime/src/zserio/JsonReader.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -261,18 +261,27 @@ template <typename ALLOC>
261261
void BitBufferAdapter<ALLOC>::beginArray()
262262
{
263263
if (m_state == BEGIN_ARRAY_BUFFER)
264+
{
264265
m_state = VISIT_VALUE_BUFFER;
266+
m_buffer = vector<uint8_t, ALLOC>(get_allocator());
267+
}
265268
else
269+
{
266270
throw CppRuntimeException("JsonReader: Unexpected beginArray in BitBuffer!");
271+
}
267272
}
268273

269274
template <typename ALLOC>
270275
void BitBufferAdapter<ALLOC>::endArray()
271276
{
272277
if (m_state == VISIT_VALUE_BUFFER)
278+
{
273279
m_state = VISIT_KEY;
280+
}
274281
else
282+
{
275283
throw CppRuntimeException("JsonReader: Unexpected endArray in BitBuffer!");
284+
}
276285
}
277286

278287
template <typename ALLOC>
@@ -322,10 +331,7 @@ void BitBufferAdapter<ALLOC>::visitValue(uint64_t uintValue)
322331
<< uintValue << "'!";
323332
}
324333

325-
if (!m_buffer.hasValue())
326-
m_buffer = vector<uint8_t, ALLOC>(1, static_cast<uint8_t>(uintValue), get_allocator());
327-
else
328-
m_buffer->push_back(static_cast<uint8_t>(uintValue));
334+
m_buffer->push_back(static_cast<uint8_t>(uintValue));
329335
}
330336
else if (m_state == VISIT_VALUE_BITSIZE)
331337
{

compiler/extensions/cpp/runtime/test/zserio/JsonReaderTest.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,50 @@ TEST(JsonReaderTest, readUnorderedBitBuffer)
444444
reflectable->find("nested.creatorBitmask")->getUInt8());
445445
}
446446

447+
TEST(JsonReaderTest, readEmptyBitBuffer)
448+
{
449+
std::stringstream str(
450+
"{\n"
451+
" \"value\": 13,\n"
452+
" \"nested\": {\n"
453+
" \"value\": 10,\n"
454+
" \"text\": \"nested\",\n"
455+
" \"externData\": {\n"
456+
" \"buffer\": [\n"
457+
" ],\n"
458+
" \"bitSize\": 0\n"
459+
" },\n"
460+
" \"bytesData\": {\n"
461+
" \"buffer\": [\n"
462+
" 202,\n"
463+
" 254\n"
464+
" ]\n"
465+
" },\n"
466+
" \"creatorEnum\": -1,\n"
467+
" \"creatorBitmask\": 1\n"
468+
" }\n"
469+
"}");
470+
471+
JsonReader jsonReader(str);
472+
auto reflectable = jsonReader.read(CreatorObject::typeInfo());
473+
ASSERT_TRUE(reflectable);
474+
475+
reflectable->initializeChildren();
476+
477+
ASSERT_EQ(13, reflectable->getField("value")->getUInt32());
478+
ASSERT_EQ(13, reflectable->getField("nested")->getParameter("param")->getUInt32());
479+
ASSERT_EQ(10, reflectable->find("nested.value")->getUInt32());
480+
ASSERT_EQ("nested"_sv, reflectable->find("nested.text")->getStringView());
481+
ASSERT_EQ(BitBuffer(), reflectable->find("nested.externData")->getBitBuffer());
482+
const Span<const uint8_t> bytesData = reflectable->find("nested.bytesData")->getBytes();
483+
ASSERT_EQ(2, bytesData.size());
484+
ASSERT_EQ(0xCA, bytesData[0]);
485+
ASSERT_EQ(0xFE, bytesData[1]);
486+
ASSERT_EQ(enumToValue(CreatorEnum::MinusOne), reflectable->find("nested.creatorEnum")->getInt8());
487+
ASSERT_EQ(CreatorBitmask(CreatorBitmask::Values::READ).getValue(),
488+
reflectable->find("nested.creatorBitmask")->getUInt8());
489+
}
490+
447491
TEST(JsonReaderTest, readStringifiedEnum)
448492
{
449493
checkReadStringifiedEnum("ONE", CreatorEnum::ONE);

compiler/extensions/java/runtime/src/zserio/runtime/json/JsonReader.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,27 @@ public void endObject()
130130
public void beginArray()
131131
{
132132
if (state == State.BEGIN_ARRAY_BUFFER)
133+
{
133134
state = State.VISIT_VALUE_BUFFER;
135+
buffer = new ArrayList<Byte>();
136+
}
134137
else
138+
{
135139
throw new ZserioError("JsonReader: Unexpected begin array in Bit Buffer!");
140+
}
136141
}
137142

138143
@Override
139144
public void endArray()
140145
{
141146
if (state == State.VISIT_VALUE_BUFFER)
147+
{
142148
state = State.VISIT_KEY;
149+
}
143150
else
151+
{
144152
throw new ZserioError("JsonReader: Unexpected end array in Bit Buffer!");
153+
}
145154
}
146155

147156
@Override
@@ -167,9 +176,6 @@ public void visitValue(Object value)
167176
{
168177
if (state == State.VISIT_VALUE_BUFFER && value instanceof BigInteger)
169178
{
170-
if (buffer == null)
171-
buffer = new ArrayList<Byte>();
172-
173179
// bit buffer stores 8-bit unsigned values in byte type
174180
final BigInteger intValue = (BigInteger)value;
175181
if (intValue.compareTo(BigInteger.ZERO) < 0 || intValue.compareTo(BigInteger.valueOf(255)) > 0)

compiler/extensions/java/runtime/test/zserio/runtime/json/JsonReaderTest.java

+41
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,47 @@ public void readUnonrderedBitBuffer() throws IOException
197197
jsonReader.close();
198198
}
199199

200+
@Test
201+
public void readEmptyBitBuffer() throws IOException
202+
{
203+
final Reader reader = new StringReader("{\n"
204+
+ " \"value\": 13,\n"
205+
+ " \"nested\": {\n"
206+
+ " \"value\": 10,\n"
207+
+ " \"text\": \"nested\",\n"
208+
+ " \"externData\": {\n"
209+
+ " \"buffer\": [\n"
210+
+ " ],\n"
211+
+ " \"bitSize\": 0\n"
212+
+ " },\n"
213+
+ " \"bytesData\": {\n"
214+
+ " \"buffer\": [\n"
215+
+ " 202,\n"
216+
+ " 254\n"
217+
+ " ]\n"
218+
+ " },\n"
219+
+ " \"creatorEnum\": -1,\n"
220+
+ " \"creatorBitmask\": 1\n"
221+
+ " }\n"
222+
+ "}");
223+
224+
final JsonReader jsonReader = new JsonReader(reader);
225+
final Object zserioObject = jsonReader.read(CreatorObject.typeInfo());
226+
assertTrue(zserioObject != null);
227+
final CreatorObject creatorObject = (CreatorObject)zserioObject;
228+
229+
assertEquals(13, creatorObject.getValue());
230+
assertEquals(13, creatorObject.getNested().getParam());
231+
assertEquals(10, creatorObject.getNested().getValue());
232+
assertEquals("nested", creatorObject.getNested().getText());
233+
assertEquals(new BitBuffer(new byte[] {}), creatorObject.getNested().getExternData());
234+
assertArrayEquals(new byte[] {(byte)0xCA, (byte)0xFE}, creatorObject.getNested().getBytesData());
235+
assertEquals(CreatorEnum.MinusOne, creatorObject.getNested().getCreatorEnum());
236+
assertEquals(CreatorBitmask.Values.READ, creatorObject.getNested().getCreatorBitmask());
237+
238+
jsonReader.close();
239+
}
240+
200241
@Test
201242
public void readStringifiedEnum() throws IOException
202243
{

compiler/extensions/python/runtime/src/zserio/json.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,7 @@ def end_object(self) -> None:
968968
def begin_array(self) -> None:
969969
if self._state == JsonReader._BitBufferAdapter._State.BEGIN_ARRAY_BUFFER:
970970
self._state = JsonReader._BitBufferAdapter._State.VISIT_VALUE_BUFFER
971+
self._buffer = []
971972
else:
972973
raise PythonRuntimeException("JsonReader: Unexpected begin array in Bit Buffer!")
973974

@@ -989,11 +990,9 @@ def visit_key(self, key: str) -> None:
989990
raise PythonRuntimeException(f"JsonReader: Unexpected key '{key}' in Bit Buffer!")
990991

991992
def visit_value(self, value: typing.Any) -> None:
992-
if self._state == JsonReader._BitBufferAdapter._State.VISIT_VALUE_BUFFER and isinstance(value, int):
993-
if self._buffer is None:
994-
self._buffer = [value]
995-
else:
996-
self._buffer.append(value)
993+
if (self._state == JsonReader._BitBufferAdapter._State.VISIT_VALUE_BUFFER and
994+
self._buffer is not None and isinstance(value, int)):
995+
self._buffer.append(value)
997996
elif (self._state == JsonReader._BitBufferAdapter._State.VISIT_VALUE_BITSIZE and
998997
isinstance(value, int)):
999998
self._bit_size = value

compiler/extensions/python/runtime/tests/test_json.py

+38
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,44 @@ def test_read_unordered_bit_buffer(self):
10311031
self.assertEqual(CreatorEnum.ONE, creator_object.nested.creator_enum)
10321032
self.assertEqual(CreatorBitmask.Values.READ, creator_object.nested.creator_bitmask)
10331033

1034+
def test_read_empty_bit_buffer(self):
1035+
text_io = io.StringIO(
1036+
"{\n" +
1037+
" \"value\": 13,\n" +
1038+
" \"nested\": {\n" +
1039+
" \"value\": 10,\n" +
1040+
" \"text\": \"nested\",\n" +
1041+
" \"externData\": {\n" +
1042+
" \"buffer\": [\n" +
1043+
" ],\n" +
1044+
" \"bitSize\": 0\n" +
1045+
" },\n" +
1046+
" \"bytesData\": {\n" +
1047+
" \"buffer\": [\n" +
1048+
" 202,\n" +
1049+
" 254\n" +
1050+
" ]\n" +
1051+
" },\n" +
1052+
" \"creatorEnum\": 0,\n" +
1053+
" \"creatorBitmask\": 1\n" +
1054+
" }\n" +
1055+
"}"
1056+
)
1057+
1058+
json_reader = JsonReader(text_io)
1059+
creator_object = json_reader.read(CreatorObject.type_info())
1060+
self.assertTrue(creator_object is not None)
1061+
self.assertTrue(isinstance(creator_object, CreatorObject))
1062+
1063+
self.assertEqual(13, creator_object.value)
1064+
self.assertEqual(13, creator_object.nested.param)
1065+
self.assertEqual(10, creator_object.nested.value)
1066+
self.assertEqual("nested", creator_object.nested.text)
1067+
self.assertEqual(BitBuffer(bytes()), creator_object.nested.extern_data)
1068+
self.assertEqual(bytes([0xCA, 0xFE]), creator_object.nested.bytes_data)
1069+
self.assertEqual(CreatorEnum.ONE, creator_object.nested.creator_enum)
1070+
self.assertEqual(CreatorBitmask.Values.READ, creator_object.nested.creator_bitmask)
1071+
10341072
def test_read_stringified_enum(self):
10351073
self._check_read_stringified_enum("ONE", CreatorEnum.ONE)
10361074
self._check_read_stringified_enum("MinusOne", CreatorEnum.MINUS_ONE)

0 commit comments

Comments
 (0)