| /* Decode a message using callbacks inside oneof fields */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <pb_decode.h> |
| #include <assert.h> |
| #include "oneof.pb.h" |
| #include "test_helpers.h" |
| #include "unittests.h" |
| |
| /* This is a nanopb-0.4 style global callback, that is referred by function name |
| * and does not have to be bound separately to the message. It also allows defining |
| * a custom data type for the field in the structure. |
| */ |
| bool SubMsg3_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field) |
| { |
| if (istream && field->tag == SubMsg3_strvalue_tag) |
| { |
| /* We could e.g. malloc some memory and assign it to our custom datatype |
| * in the message structure here, accessible by field->pData. But in |
| * this example we just print the string directly. |
| */ |
| |
| uint8_t buffer[64]; |
| int strlen = istream->bytes_left; |
| |
| if (strlen > sizeof(buffer) - 1) |
| return false; |
| |
| buffer[strlen] = '\0'; |
| |
| if (!pb_read(istream, buffer, strlen)) |
| return false; |
| |
| printf(" strvalue: \"%s\"\n", buffer); |
| } |
| |
| return true; |
| } |
| |
| /* The two callbacks below are traditional callbacks that use function pointers |
| * defined in pb_callback_t. |
| */ |
| bool print_int32(pb_istream_t *stream, const pb_field_t *field, void **arg) |
| { |
| uint64_t value; |
| if (!pb_decode_varint(stream, &value)) |
| return false; |
| |
| printf((char*)*arg, (int)value); |
| return true; |
| } |
| |
| bool print_string(pb_istream_t *stream, const pb_field_t *field, void **arg) |
| { |
| uint8_t buffer[64]; |
| int strlen = stream->bytes_left; |
| |
| if (strlen > sizeof(buffer) - 1) |
| return false; |
| |
| buffer[strlen] = '\0'; |
| |
| if (!pb_read(stream, buffer, strlen)) |
| return false; |
| |
| /* Print the string, in format comparable with protoc --decode. |
| * Format comes from the arg defined in main(). |
| */ |
| printf((char*)*arg, buffer); |
| return true; |
| } |
| |
| /* The callback below is a message-level callback which is called before each |
| * submessage is encoded. It is used to set the pb_callback_t callbacks inside |
| * the submessage. The reason we need this is that different submessages share |
| * storage inside oneof union, and before we know the message type we can't set |
| * the callbacks without overwriting each other. |
| */ |
| bool msg_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) |
| { |
| /* Print the prefix field before the submessages. |
| * This also demonstrates how to access the top level message fields |
| * from callbacks. |
| */ |
| OneOfMessage *topmsg = field->message; |
| printf("prefix: %d\n", (int)topmsg->prefix); |
| |
| if (field->tag == OneOfMessage_submsg1_tag) |
| { |
| SubMsg1 *msg = field->pData; |
| printf("submsg1 {\n"); |
| msg->array.funcs.decode = print_int32; |
| msg->array.arg = " array: %d\n"; |
| } |
| else if (field->tag == OneOfMessage_submsg2_tag) |
| { |
| SubMsg2 *msg = field->pData; |
| printf("submsg2 {\n"); |
| msg->strvalue.funcs.decode = print_string; |
| msg->strvalue.arg = " strvalue: \"%s\"\n"; |
| } |
| else if (field->tag == OneOfMessage_submsg3_tag) |
| { |
| /* Because SubMsg3 callback is bound by function name, we do not |
| * need to initialize anything here. But we just print a string |
| * to get protoc-equivalent formatted output from the testcase. |
| */ |
| printf("submsg3 {\n"); |
| } |
| |
| /* Once we return true, pb_dec_submessage() will go on to decode the |
| * submessage contents. But if we want, we can also decode it ourselves |
| * above and leave stream->bytes_left at 0 value, inhibiting automatic |
| * decoding. |
| */ |
| return true; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| uint8_t buffer[256]; |
| OneOfMessage msg = OneOfMessage_init_zero; |
| pb_istream_t stream; |
| size_t count; |
| |
| SET_BINARY_MODE(stdin); |
| count = fread(buffer, 1, sizeof(buffer), stdin); |
| |
| if (!feof(stdin)) |
| { |
| fprintf(stderr, "Message does not fit in buffer\n"); |
| return 1; |
| } |
| |
| /* Set up the cb_values callback, which will in turn set up the callbacks |
| * for each oneof field once the field tag is known. */ |
| msg.cb_values.funcs.decode = msg_callback; |
| stream = pb_istream_from_buffer(buffer, count); |
| if (!pb_decode(&stream, OneOfMessage_fields, &msg)) |
| { |
| fprintf(stderr, "Decoding failed: %s\n", PB_GET_ERROR(&stream)); |
| return 1; |
| } |
| |
| /* This is just printing for the test case logic */ |
| if (msg.which_values == OneOfMessage_intvalue_tag) |
| { |
| printf("prefix: %d\n", (int)msg.prefix); |
| printf("intvalue: %d\n", (int)msg.values.intvalue); |
| } |
| else if (msg.which_values == OneOfMessage_strvalue_tag) |
| { |
| printf("prefix: %d\n", (int)msg.prefix); |
| printf("strvalue: \"%s\"\n", msg.values.strvalue); |
| } |
| else if (msg.which_values == OneOfMessage_submsg3_tag && |
| msg.values.submsg3.which_values == SubMsg3_intvalue_tag) |
| { |
| printf(" intvalue: %d\n", (int)msg.values.submsg3.values.intvalue); |
| printf("}\n"); |
| } |
| else |
| { |
| printf("}\n"); |
| } |
| printf("suffix: %d\n", (int)msg.suffix); |
| |
| assert(msg.prefix == 123); |
| assert(msg.suffix == 321); |
| |
| return 0; |
| } |