} END_TEST /* * Create a const-iterator over a oneof descriptor. */ START_TEST(test_oneof_iterator) { pb_oneof_descriptor_iter_t it = pb_oneof_descriptor_iter_create(&oneof_descriptor); /* Assert descriptor size */ fail_if(pb_oneof_descriptor_empty(&oneof_descriptor)); ck_assert_uint_eq(3, pb_oneof_descriptor_size(&oneof_descriptor)); /* Walk through descriptor fields forwards */ fail_unless(pb_oneof_descriptor_iter_begin(&it)); for (size_t f = 1; f <= 3; f++) { const pb_field_descriptor_t *descriptor = pb_oneof_descriptor_iter_current(&it); ck_assert_uint_eq(f - 1, pb_oneof_descriptor_iter_pos(&it)); /* Assemble field name */ char name[5]; snprintf(name, 5, "F%02d", pb_field_descriptor_tag(descriptor)); /* Assert field name and tag */ ck_assert_uint_eq(f, pb_field_descriptor_tag(descriptor)); fail_if(strcmp(name, pb_field_descriptor_name(descriptor))); /* Advance iterator */ ck_assert_uint_eq(f != 3, pb_oneof_descriptor_iter_next(&it)); } /* Assert descriptor iterator validity */ fail_if(pb_oneof_descriptor_iter_next(&it)); /* Walk through descriptor fields backwards */ fail_unless(pb_oneof_descriptor_iter_end(&it)); for (size_t f = 3; f >= 1; f--) { const pb_field_descriptor_t *descriptor = pb_oneof_descriptor_iter_current(&it); ck_assert_uint_eq(f - 1, pb_oneof_descriptor_iter_pos(&it)); /* Assemble field name */ char name[5]; snprintf(name, 5, "F%02d", pb_field_descriptor_tag(descriptor)); /* Assert field name and tag */ ck_assert_uint_eq(f, pb_field_descriptor_tag(descriptor)); fail_if(strcmp(name, pb_field_descriptor_name(descriptor))); /* Advance iterator */ ck_assert_uint_eq(f != 1, pb_oneof_descriptor_iter_prev(&it)); } /* Assert descriptor iterator validity again */ fail_if(pb_oneof_descriptor_iter_prev(&it)); /* Free all allocated memory */ pb_oneof_descriptor_iter_destroy(&it); } END_TEST
/*! * Move a cursor to the next field. * * \param[in,out] cursor Cursor * \return Test result */ static int next(pb_cursor_t *cursor) { assert(cursor); pb_offset_t *offset = &(cursor->current.offset), *packed = &(cursor->current.packed); /* Create temporary buffer to read the next value */ pb_buffer_t buffer = pb_buffer_create_zero_copy_internal( pb_journal_data_from(pb_cursor_journal(cursor), 0), pb_message_end(&(cursor->message))); /* Create stream over temporary buffer */ pb_stream_t stream = pb_stream_create_at(&buffer, offset->end); while (pb_stream_left(&stream)) { /* Adjust offsets */ offset->start = offset->end; offset->diff.origin = pb_message_start(&(cursor->message)); offset->diff.tag = pb_stream_offset(&stream); /* Read tag from stream */ pb_tag_t tag; uint32_t length; if ((cursor->error = pb_stream_read(&stream, PB_TYPE_UINT32, &tag))) break; /* Extract wiretype and tag */ pb_wiretype_t wiretype = tag & 7; tag >>= 3; /* Skip field contents to determine length */ offset->diff.length = pb_stream_offset(&stream); if (wiretype == PB_WIRETYPE_LENGTH) { if ((cursor->error = pb_stream_read(&stream, PB_TYPE_UINT32, &length))) break; offset->start = pb_stream_offset(&stream); if ((cursor->error = pb_stream_advance(&stream, length))) break; } else { offset->start = pb_stream_offset(&stream); if ((cursor->error = pb_stream_skip(&stream, wiretype))) break; } /* Adjust offsets */ offset->end = pb_stream_offset(&stream); offset->diff.origin -= offset->start; offset->diff.tag -= offset->start; offset->diff.length -= offset->start; /* If a tag is set check if the tags match or continue */ if (cursor->tag && cursor->tag != tag) { continue; /* Otherwise try to load descriptor for current tag */ } else if (!cursor->current.descriptor || pb_field_descriptor_tag(cursor->current.descriptor) != tag) { if (!(cursor->current.descriptor = pb_descriptor_field_by_tag( pb_message_descriptor(&(cursor->message)), tag))) continue; } /* Switch to packed context in case of packed field */ if (wiretype != pb_field_descriptor_wiretype(cursor->current.descriptor) && wiretype == PB_WIRETYPE_LENGTH) { *packed = *offset; /* Prepare offsets for packed field members */ offset->end = offset->start; offset->diff.tag = 0; offset->diff.length = 0; } /* Cleanup and return */ pb_stream_destroy(&stream); pb_buffer_destroy(&buffer); return !packed->end; } /* Invalidate cursor if at end */ if (!(pb_stream_left(&stream) && cursor->error)) cursor->error = PB_ERROR_EOM; /* Cleanup and return */ pb_stream_destroy(&stream); pb_buffer_destroy(&buffer); return 0; }
/*! * Initialize a part. * * The journal must be tested for writability before writing to the binary, as * the binary write is irreversible, while the journal could be reverted. * * \warning Some lines excluded from code coverage are impossible to occur, * but they are necessary to ensure application-wide proper error handling. * Others, especially those concerning the journal and binary, are not * testable within the context of a part. * * \param[in,out] part Part * \param[in] descriptor Field descriptor */ static void init(pb_part_t *part, const pb_field_descriptor_t *descriptor) { assert(part && descriptor); assert(pb_part_aligned(part)); /* Initialize field for writing */ pb_binary_buffer_t buffer = pb_binary_buffer_create(); do { pb_wiretype_t wiretype = pb_field_descriptor_wiretype(descriptor); pb_tag_t tag = pb_field_descriptor_tag(descriptor); /* Write tag to buffer and backup offsets */ uint32_t value = wiretype | (tag << 3); if (pb_binary_buffer_write_varint32(&buffer, &value)) break; /* LCOV_EXCL_LINE */ part->offset.diff.tag = part->offset.start; part->offset.diff.length = part->offset.start + pb_binary_buffer_size(&buffer); /* Write default length of zero for length-prefixed fields */ if (wiretype == PB_WIRETYPE_LENGTH) { uint32_t bytes = 0; if (pb_binary_buffer_write_varint32(&buffer, &bytes)) break; /* LCOV_EXCL_LINE */ } /* New data must be written to part, so obtain journal */ pb_journal_t *journal = pb_binary_journal(part->binary); assert(journal); /* Write buffer to binary and perform manual alignment */ pb_error_t error = pb_journal_log(journal, part->offset.start + part->offset.diff.origin, part->offset.end, pb_binary_buffer_size(&buffer)); if (!error) { size_t offset = pb_binary_buffer_size(&buffer); error = pb_binary_write(part->binary, part->offset.start, part->offset.end, pb_binary_buffer_data(&buffer), pb_binary_buffer_size(&buffer)); if (unlikely_(error)) { pb_journal_revert(journal); /* LCOV_EXCL_LINE */ /* Update offsets */ } else { /* LCOV_EXCL_LINE */ part->version++; part->offset.start += offset; part->offset.end += pb_binary_buffer_size(&buffer); part->offset.diff.origin -= offset; part->offset.diff.tag -= part->offset.start; part->offset.diff.length -= part->offset.start; /* Recursive length prefix update of parent messages */ if (!adjust(part, pb_binary_buffer_size(&buffer))) { pb_binary_buffer_destroy(&buffer); return; } } } /* LCOV_EXCL_LINE */ } while (0); /* LCOV_EXCL_LINE */ /* Yes. You pulled a Pobert */ pb_binary_buffer_destroy(&buffer); /* LCOV_EXCL_LINE */ pb_part_invalidate(part); /* LCOV_EXCL_LINE */ }