LCOV - code coverage report
Current view: top level - raw_decode - raw_decode.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 65 77 84.4 %
Date: 2023-02-14 20:10:26 Functions: 4 4 100.0 %

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

Generated by: LCOV version 1.14