decode_oneof.c 5.2 KB

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