raw_decode.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* A small tool that decodes a raw binary message, while providing useful
  2. * info on corrupted messages also. */
  3. /* Define _ISOC99_SOURCE to get snprintf() even though otherwise in ansi-C mode */
  4. #define _ISOC99_SOURCE 1
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <pb_decode.h>
  8. #include "test_helpers.h"
  9. #define HISTORY_LEN 32
  10. static pb_byte_t g_history[HISTORY_LEN];
  11. static int g_position;
  12. /* This binds the pb_istream_t to stdin and logs the most recent bytes read. */
  13. bool callback(pb_istream_t *stream, uint8_t *buf, size_t count)
  14. {
  15. FILE *file = (FILE*)stream->state;
  16. size_t len = fread(buf, 1, count, file);
  17. if (len < HISTORY_LEN)
  18. {
  19. memmove(g_history, g_history + len, HISTORY_LEN - len);
  20. memcpy(g_history + HISTORY_LEN - len, buf, len);
  21. }
  22. else
  23. {
  24. memcpy(g_history, buf + len - HISTORY_LEN, HISTORY_LEN);
  25. }
  26. g_position += len;
  27. if (len == count)
  28. {
  29. return true;
  30. }
  31. else
  32. {
  33. stream->bytes_left = 0;
  34. return false;
  35. }
  36. }
  37. void print_history(int position)
  38. {
  39. int i;
  40. if (position < g_position - HISTORY_LEN)
  41. position = g_position - HISTORY_LEN;
  42. printf("LATEST BYTES READ (%d to %d): ", position, g_position);
  43. for (i = HISTORY_LEN - (g_position - position); i < HISTORY_LEN; i++)
  44. {
  45. printf("%02x ", g_history[i]);
  46. }
  47. printf("\n");
  48. }
  49. bool raw_decode(pb_istream_t *stream, const char *indent)
  50. {
  51. const char *wiretypes[8] = {"VARINT", "64BIT", "STRING", "SGRP", "EGRP", "32BIT", "????", "????"};
  52. while (stream->bytes_left)
  53. {
  54. uint32_t tag;
  55. pb_wire_type_t wire_type;
  56. bool eof;
  57. int position = g_position;
  58. if (!pb_decode_tag(stream, &wire_type, &tag, &eof))
  59. {
  60. if (eof)
  61. {
  62. break;
  63. }
  64. else
  65. {
  66. printf("ERROR: Failed to parse tag: %s\n", PB_GET_ERROR(stream));
  67. print_history(position);
  68. return false;
  69. }
  70. }
  71. if (tag == 0)
  72. {
  73. printf("%sterminating on zero tag\n", indent);
  74. return true;
  75. }
  76. printf("%sAt %d: field tag %d, wire type %d (%s)",
  77. indent, position, (int)tag, wire_type, wiretypes[wire_type]);
  78. if (wire_type == PB_WT_VARINT)
  79. {
  80. uint64_t value;
  81. position = g_position;
  82. if (!pb_decode_varint(stream, &value))
  83. {
  84. printf("\n%sERROR: Failed to parse varint: %s\n", indent, PB_GET_ERROR(stream));
  85. print_history(position);
  86. return false;
  87. }
  88. printf(", varint value (%d bytes): %llu\n",
  89. g_position - position, (unsigned long long)value);
  90. }
  91. else if (wire_type == PB_WT_64BIT)
  92. {
  93. uint64_t value;
  94. position = g_position;
  95. if (!pb_decode_fixed64(stream, &value))
  96. {
  97. printf("\n%sERROR: Failed to parse fixed64: %s\n", indent, PB_GET_ERROR(stream));
  98. print_history(position);
  99. return false;
  100. }
  101. printf(", fixed64 value (%d bytes): 0x%016llx\n",
  102. g_position - position, (unsigned long long)value);
  103. }
  104. else if (wire_type == PB_WT_32BIT)
  105. {
  106. uint32_t value;
  107. position = g_position;
  108. if (!pb_decode_fixed32(stream, &value))
  109. {
  110. printf("\n%sERROR: Failed to parse fixed32: %s\n", indent, PB_GET_ERROR(stream));
  111. print_history(position);
  112. return false;
  113. }
  114. printf(", fixed32 value (%d bytes): 0x%08lx\n",
  115. g_position - position, (unsigned long)value);
  116. }
  117. else if (wire_type == PB_WT_STRING)
  118. {
  119. pb_istream_t substream;
  120. position = g_position;
  121. if (!pb_make_string_substream(stream, &substream))
  122. {
  123. printf("ERROR: Failed to parse string length: %s\n", PB_GET_ERROR(stream));
  124. print_history(position);
  125. return false;
  126. }
  127. else
  128. {
  129. if (substream.bytes_left == 0)
  130. {
  131. printf(", empty string\n");
  132. }
  133. else
  134. {
  135. char prefix[8];
  136. snprintf(prefix, sizeof(prefix), "f%d> ", (int)tag);
  137. printf(", string len %d bytes, attempting recursive decode\n",
  138. (int)substream.bytes_left);
  139. if (!raw_decode(&substream, prefix))
  140. {
  141. printf("%sfield %d: recursive decode failed, continuing with upper level\n\n",
  142. indent, (int)tag);
  143. }
  144. pb_close_string_substream(stream, &substream);
  145. }
  146. }
  147. }
  148. else
  149. {
  150. printf("\n");
  151. }
  152. }
  153. return true;
  154. }
  155. int main()
  156. {
  157. pb_istream_t stream = {&callback, NULL, SIZE_MAX};
  158. stream.state = stdin;
  159. SET_BINARY_MODE(stdin);
  160. if (!raw_decode(&stream, ""))
  161. {
  162. return 1;
  163. } else {
  164. return 0;
  165. }
  166. }