diff --git a/ionc/ion_reader.c b/ionc/ion_reader.c index ab457b6..b41fb93 100644 --- a/ionc/ion_reader.c +++ b/ionc/ion_reader.c @@ -1986,6 +1986,11 @@ iERR _ion_reader_get_position_helper(ION_READER *preader, int64_t *p_bytes, int3 * ion version marker and the initial local symbol table (if one * is present). At that point the symbol table will be current * and later seek's will have an appropriate symbol table to use. + * + * Note that when seeking directly into a struct, the offsets + * provided by calls to ion_reader_get_value_offset point to the + * beginning of the value, not the field, and therefore the field + * name will not be accessible via ion_reader_get_field_name. */ iERR ion_reader_seek(hREADER hreader, POSITION offset, SIZE length) { diff --git a/ionc/ion_reader_text.c b/ionc/ion_reader_text.c index e34cc5b..f156559 100644 --- a/ionc/ion_reader_text.c +++ b/ionc/ion_reader_text.c @@ -281,6 +281,10 @@ iERR _ion_reader_text_next(ION_READER *preader, ION_TYPE *p_value_type) // The start position of the value was not known at the start of this function. At this point it must be known. text->_value_start = text->_scanner._value_start; } + else if (text->_state == IPS_BEFORE_FIELDNAME) { + // In latter fields in a struct, value_start will be positive, but positioned at the field name, not the value + text->_value_start = text->_scanner._value_start; + } else { text->_value_start = value_start; } diff --git a/test/test_ion_reader_seek.cpp b/test/test_ion_reader_seek.cpp index d8e2975..5febdd5 100644 --- a/test/test_ion_reader_seek.cpp +++ b/test/test_ion_reader_seek.cpp @@ -679,4 +679,82 @@ TEST_P(TextAndBinary, ReaderHandlesInitialUnannotatedContainerValueOffsetSeek) { ION_ASSERT_OK(ion_reader_seek(reader, pos_second, -1)); ION_ASSERT_OK(ion_reader_next(reader, &type)); ASSERT_EQ(tid_SYMBOL, type); +} + +TEST_P(TextAndBinary, ReaderPopulatesStructFieldsOnSeek) { + // Write! + + hWRITER writer = NULL; + ION_STREAM *ion_stream = NULL; + ION_STRING field1, field2, value1, value2; + BYTE *data; + SIZE data_length; + + // {field1:val1,field2:val2} + ion_string_from_cstr("field1", &field1); + ion_string_from_cstr("value1", &value1); + ion_string_from_cstr("field2", &field2); + ion_string_from_cstr("value2", &value2); + ION_ASSERT_OK(ion_test_new_writer(&writer, &ion_stream, is_binary)); + ION_ASSERT_OK(ion_writer_start_container(writer, tid_STRUCT)); + ION_ASSERT_OK(ion_writer_write_field_name(writer, &field1)); + ION_ASSERT_OK(ion_writer_write_symbol(writer, &value1)); + ION_ASSERT_OK(ion_writer_write_field_name(writer, &field2)); + ION_ASSERT_OK(ion_writer_write_symbol(writer, &value2)); + ION_ASSERT_OK(ion_writer_finish_container(writer)); + ION_ASSERT_OK(ion_test_writer_get_bytes(writer, ion_stream, &data, &data_length)); + + // Read! + + hREADER reader = NULL; + ION_TYPE type; + POSITION pos_field1, pos_field2; + ION_STRING read_field1, read_val1, read_field2, read_val2; + + // We use this reader to capture offsets + ION_ASSERT_OK(ion_test_new_reader(data, data_length, &reader)); + + // Assemble: Take one pass through the document to capture value offsets and field names + + ION_ASSERT_OK(ion_reader_next(reader, &type)); + + ION_ASSERT_OK(ion_reader_step_in(reader)); + + ION_ASSERT_OK(ion_reader_next(reader, &type)); + ASSERT_EQ(tid_SYMBOL, type); + ION_ASSERT_OK(ion_reader_get_value_offset(reader, &pos_field1)); + + ION_ASSERT_OK(ion_reader_next(reader, &type)); + ASSERT_EQ(tid_SYMBOL, type); + ION_ASSERT_OK(ion_reader_get_value_offset(reader, &pos_field2)); + + ION_ASSERT_OK(ion_reader_step_out(reader)); + + // Act: Move back to the original offsets and then re-assemble values + + // Seek to first field + ION_ASSERT_OK(ion_reader_seek(reader, pos_field1, -1)); + ION_ASSERT_OK(ion_reader_next(reader, &type)); + ASSERT_EQ(tid_SYMBOL, type); + + // Read field value + ION_ASSERT_OK(ion_reader_read_string(reader, &read_val1)); + char *cread_val1 = ion_string_strdup(&read_val1); + + // Seek to second field + ION_ASSERT_OK(ion_reader_seek(reader, pos_field2, -1)); + ION_ASSERT_OK(ion_reader_next(reader, &type)); + ASSERT_EQ(tid_SYMBOL, type); + + // Read field value + ION_ASSERT_OK(ion_reader_read_string(reader, &read_val2)); + char *cread_val2 = ion_string_strdup(&read_val2); + + ION_ASSERT_OK(ion_reader_close(reader)); + + // Assert: + + // Easy assertions: there's only one value, "value," and we should have read it both times + assertStringsEqual((char *)value1.value, cread_val1, strlen(cread_val1)); + assertStringsEqual((char *)value2.value, cread_val2, strlen(cread_val2)); } \ No newline at end of file