123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /* 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;
- }
|