MOS Source Code
Loading...
Searching...
No Matches
decode_oneof.c
Go to the documentation of this file.
1/* Decode a message using callbacks inside oneof fields */
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <pb_decode.h>
7#include <assert.h>
8#include "oneof.pb.h"
9#include "test_helpers.h"
10#include "unittests.h"
11
12/* This is a nanopb-0.4 style global callback, that is referred by function name
13 * and does not have to be bound separately to the message. It also allows defining
14 * a custom data type for the field in the structure.
15 */
16bool SubMsg3_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
17{
18 if (istream && field->tag == SubMsg3_strvalue_tag)
19 {
20 /* We could e.g. malloc some memory and assign it to our custom datatype
21 * in the message structure here, accessible by field->pData. But in
22 * this example we just print the string directly.
23 */
24
25 uint8_t buffer[64];
26 int strlen = istream->bytes_left;
27
28 if (strlen > sizeof(buffer) - 1)
29 return false;
30
31 buffer[strlen] = '\0';
32
33 if (!pb_read(istream, buffer, strlen))
34 return false;
35
36 printf(" strvalue: \"%s\"\n", buffer);
37 }
38
39 return true;
40}
41
42/* The two callbacks below are traditional callbacks that use function pointers
43 * defined in pb_callback_t.
44 */
45bool print_int32(pb_istream_t *stream, const pb_field_t *field, void **arg)
46{
47 uint64_t value;
48 if (!pb_decode_varint(stream, &value))
49 return false;
50
51 printf((char*)*arg, (int)value);
52 return true;
53}
54
55bool print_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
56{
57 uint8_t buffer[64];
58 int strlen = stream->bytes_left;
59
60 if (strlen > sizeof(buffer) - 1)
61 return false;
62
63 buffer[strlen] = '\0';
64
65 if (!pb_read(stream, buffer, strlen))
66 return false;
67
68 /* Print the string, in format comparable with protoc --decode.
69 * Format comes from the arg defined in main().
70 */
71 printf((char*)*arg, buffer);
72 return true;
73}
74
75/* The callback below is a message-level callback which is called before each
76 * submessage is encoded. It is used to set the pb_callback_t callbacks inside
77 * the submessage. The reason we need this is that different submessages share
78 * storage inside oneof union, and before we know the message type we can't set
79 * the callbacks without overwriting each other.
80 */
81bool msg_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
82{
83 /* Print the prefix field before the submessages.
84 * This also demonstrates how to access the top level message fields
85 * from callbacks.
86 */
87 OneOfMessage *topmsg = field->message;
88 printf("prefix: %d\n", (int)topmsg->prefix);
89
90 if (field->tag == OneOfMessage_submsg1_tag)
91 {
92 SubMsg1 *msg = field->pData;
93 printf("submsg1 {\n");
94 msg->array.funcs.decode = print_int32;
95 msg->array.arg = " array: %d\n";
96 }
97 else if (field->tag == OneOfMessage_submsg2_tag)
98 {
99 SubMsg2 *msg = field->pData;
100 printf("submsg2 {\n");
101 msg->strvalue.funcs.decode = print_string;
102 msg->strvalue.arg = " strvalue: \"%s\"\n";
103 }
104 else if (field->tag == OneOfMessage_submsg3_tag)
105 {
106 /* Because SubMsg3 callback is bound by function name, we do not
107 * need to initialize anything here. But we just print a string
108 * to get protoc-equivalent formatted output from the testcase.
109 */
110 printf("submsg3 {\n");
111 }
112
113 /* Once we return true, pb_dec_submessage() will go on to decode the
114 * submessage contents. But if we want, we can also decode it ourselves
115 * above and leave stream->bytes_left at 0 value, inhibiting automatic
116 * decoding.
117 */
118 return true;
119}
120
121int main(int argc, char **argv)
122{
123 uint8_t buffer[256];
124 OneOfMessage msg = OneOfMessage_init_zero;
125 pb_istream_t stream;
126 size_t count;
127
129 count = fread(buffer, 1, sizeof(buffer), stdin);
130
131 if (!feof(stdin))
132 {
133 fprintf(stderr, "Message does not fit in buffer\n");
134 return 1;
135 }
136
137 /* Set up the cb_values callback, which will in turn set up the callbacks
138 * for each oneof field once the field tag is known. */
139 msg.cb_values.funcs.decode = msg_callback;
140 stream = pb_istream_from_buffer(buffer, count);
141 if (!pb_decode(&stream, OneOfMessage_fields, &msg))
142 {
143 fprintf(stderr, "Decoding failed: %s\n", PB_GET_ERROR(&stream));
144 return 1;
145 }
146
147 /* This is just printing for the test case logic */
148 if (msg.which_values == OneOfMessage_intvalue_tag)
149 {
150 printf("prefix: %d\n", (int)msg.prefix);
151 printf("intvalue: %d\n", (int)msg.values.intvalue);
152 }
153 else if (msg.which_values == OneOfMessage_strvalue_tag)
154 {
155 printf("prefix: %d\n", (int)msg.prefix);
156 printf("strvalue: \"%s\"\n", msg.values.strvalue);
157 }
158 else if (msg.which_values == OneOfMessage_submsg3_tag &&
159 msg.values.submsg3.which_values == SubMsg3_intvalue_tag)
160 {
161 printf(" intvalue: %d\n", (int)msg.values.submsg3.values.intvalue);
162 printf("}\n");
163 }
164 else
165 {
166 printf("}\n");
167 }
168 printf("suffix: %d\n", (int)msg.suffix);
169
170 assert(msg.prefix == 123);
171 assert(msg.suffix == 321);
172
173 return 0;
174}
size_t fread(void *__restrict ptr, size_t size, size_t nmemb, FILE *__restrict stream)
#define stderr
Definition mos_stdio.h:32
#define stdin
Definition mos_stdio.h:30
const char ** argv
Definition kmain.c:44
size_t argc
Definition kmain.c:43
bool print_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
bool msg_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
bool SubMsg3_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
bool print_int32(pb_istream_t *stream, const pb_field_t *field, void **arg)
#define PB_GET_ERROR(stream)
Definition pb.h:891
pb_field_iter_t pb_field_t
Definition pb.h:359
bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
Definition pb_decode.c:82
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
Definition pb_decode.c:243
bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct)
Definition pb_decode.c:1182
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen)
Definition pb_decode.c:143
static size_t strlen(const char *s)
Definition pb_syshdr.h:80
unsigned long long uint64_t
Definition pb_syshdr.h:26
unsigned char uint8_t
Definition pb_syshdr.h:20
int main()
Definition simple.cpp:6
#define SET_BINARY_MODE(file)
static char buffer[2048]
Definition test_printf.c:7