summaryrefslogtreecommitdiffstats
path: root/examples/using_union_messages/decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/using_union_messages/decode.c')
-rw-r--r--examples/using_union_messages/decode.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/examples/using_union_messages/decode.c b/examples/using_union_messages/decode.c
new file mode 100644
index 00000000..b9f4af55
--- /dev/null
+++ b/examples/using_union_messages/decode.c
@@ -0,0 +1,96 @@
+/* This program reads a message from stdin, detects its type and decodes it.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <pb_decode.h>
+#include "unionproto.pb.h"
+
+/* This function reads manually the first tag from the stream and finds the
+ * corresponding message type. It doesn't yet decode the actual message.
+ *
+ * Returns a pointer to the MsgType_fields array, as an identifier for the
+ * message type. Returns null if the tag is of unknown type or an error occurs.
+ */
+const pb_field_t* decode_unionmessage_type(pb_istream_t *stream)
+{
+ pb_wire_type_t wire_type;
+ uint32_t tag;
+ bool eof;
+
+ while (pb_decode_tag(stream, &wire_type, &tag, &eof))
+ {
+ if (wire_type == PB_WT_STRING)
+ {
+ const pb_field_t *field;
+ for (field = UnionMessage_fields; field->tag != 0; field++)
+ {
+ if (field->tag == tag && (field->type & PB_LTYPE_SUBMESSAGE))
+ {
+ /* Found our field. */
+ return field->ptr;
+ }
+ }
+ }
+
+ /* Wasn't our field.. */
+ pb_skip_field(stream, wire_type);
+ }
+
+ return NULL;
+}
+
+bool decode_unionmessage_contents(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
+{
+ pb_istream_t substream;
+ bool status;
+ if (!pb_make_string_substream(stream, &substream))
+ return false;
+
+ status = pb_decode(&substream, fields, dest_struct);
+ pb_close_string_substream(stream, &substream);
+ return status;
+}
+
+int main()
+{
+ /* Read the data into buffer */
+ uint8_t buffer[512];
+ size_t count = fread(buffer, 1, sizeof(buffer), stdin);
+ pb_istream_t stream = pb_istream_from_buffer(buffer, count);
+
+ const pb_field_t *type = decode_unionmessage_type(&stream);
+ bool status = false;
+
+ if (type == MsgType1_fields)
+ {
+ MsgType1 msg = {};
+ status = decode_unionmessage_contents(&stream, MsgType1_fields, &msg);
+ printf("Got MsgType1: %d\n", msg.value);
+ }
+ else if (type == MsgType2_fields)
+ {
+ MsgType2 msg = {};
+ status = decode_unionmessage_contents(&stream, MsgType2_fields, &msg);
+ printf("Got MsgType2: %s\n", msg.value ? "true" : "false");
+ }
+ else if (type == MsgType3_fields)
+ {
+ MsgType3 msg = {};
+ status = decode_unionmessage_contents(&stream, MsgType3_fields, &msg);
+ printf("Got MsgType3: %d %d\n", msg.value1, msg.value2);
+ }
+
+ if (!status)
+ {
+ printf("Decode failed: %s\n", PB_GET_ERROR(&stream));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+