1/* This program reads a message from stdin, detects its type and decodes it.
2 */
3
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7
8#include <pb_decode.h>
9#include "unionproto.pb.h"
10
11/* This function reads manually the first tag from the stream and finds the
12 * corresponding message type. It doesn't yet decode the actual message.
13 *
14 * Returns a pointer to the MsgType_fields array, as an identifier for the
15 * message type. Returns null if the tag is of unknown type or an error occurs.
16 */
17const pb_field_t* decode_unionmessage_type(pb_istream_t *stream)
18{
19    pb_wire_type_t wire_type;
20    uint32_t tag;
21    bool eof;
22
23    while (pb_decode_tag(stream, &wire_type, &tag, &eof))
24    {
25        if (wire_type == PB_WT_STRING)
26        {
27            const pb_field_t *field;
28            for (field = UnionMessage_fields; field->tag != 0; field++)
29            {
30                if (field->tag == tag && (field->type & PB_LTYPE_SUBMESSAGE))
31                {
32                    /* Found our field. */
33                    return field->ptr;
34                }
35            }
36        }
37
38        /* Wasn't our field.. */
39        pb_skip_field(stream, wire_type);
40    }
41
42    return NULL;
43}
44
45bool decode_unionmessage_contents(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
46{
47    pb_istream_t substream;
48    bool status;
49    if (!pb_make_string_substream(stream, &substream))
50        return false;
51
52    status = pb_decode(&substream, fields, dest_struct);
53    pb_close_string_substream(stream, &substream);
54    return status;
55}
56
57int main()
58{
59    /* Read the data into buffer */
60    uint8_t buffer[512];
61    size_t count = fread(buffer, 1, sizeof(buffer), stdin);
62    pb_istream_t stream = pb_istream_from_buffer(buffer, count);
63
64    const pb_field_t *type = decode_unionmessage_type(&stream);
65    bool status = false;
66
67    if (type == MsgType1_fields)
68    {
69        MsgType1 msg = {};
70        status = decode_unionmessage_contents(&stream, MsgType1_fields, &msg);
71        printf("Got MsgType1: %d\n", msg.value);
72    }
73    else if (type == MsgType2_fields)
74    {
75        MsgType2 msg = {};
76        status = decode_unionmessage_contents(&stream, MsgType2_fields, &msg);
77        printf("Got MsgType2: %s\n", msg.value ? "true" : "false");
78    }
79    else if (type == MsgType3_fields)
80    {
81        MsgType3 msg = {};
82        status = decode_unionmessage_contents(&stream, MsgType3_fields, &msg);
83        printf("Got MsgType3: %d %d\n", msg.value1, msg.value2);
84    }
85
86    if (!status)
87    {
88        printf("Decode failed: %s\n", PB_GET_ERROR(&stream));
89        return 1;
90    }
91
92    return 0;
93}
94
95
96
97