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