| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 | /* A small tool that decodes a raw binary message, while providing useful * info on corrupted messages also. *//* Define _ISOC99_SOURCE to get snprintf() even though otherwise in ansi-C mode */#define _ISOC99_SOURCE 1#include <stdio.h>#include <string.h>#include <pb_decode.h>#include "test_helpers.h"#define HISTORY_LEN 32static pb_byte_t g_history[HISTORY_LEN];static int g_position;/* This binds the pb_istream_t to stdin and logs the most recent bytes read. */bool callback(pb_istream_t *stream, uint8_t *buf, size_t count){    FILE *file = (FILE*)stream->state;    size_t len = fread(buf, 1, count, file);        if (len < HISTORY_LEN)    {        memmove(g_history, g_history + len, HISTORY_LEN - len);        memcpy(g_history + HISTORY_LEN - len, buf, len);    }    else    {        memcpy(g_history, buf + len - HISTORY_LEN, HISTORY_LEN);    }        g_position += len;        if (len == count)    {        return true;    }    else    {        stream->bytes_left = 0;        return false;    }}void print_history(int position){    int i;        if (position < g_position - HISTORY_LEN)        position = g_position - HISTORY_LEN;        printf("LATEST BYTES READ (%d to %d): ", position, g_position);        for (i = HISTORY_LEN - (g_position - position); i < HISTORY_LEN; i++)    {        printf("%02x ", g_history[i]);    }        printf("\n");}bool raw_decode(pb_istream_t *stream, const char *indent){    const char *wiretypes[8] = {"VARINT", "64BIT", "STRING", "SGRP", "EGRP", "32BIT", "????", "????"};    while (stream->bytes_left)    {        uint32_t tag;        pb_wire_type_t wire_type;        bool eof;        int position = g_position;        if (!pb_decode_tag(stream, &wire_type, &tag, &eof))        {            if (eof)            {                break;            }            else            {                printf("ERROR: Failed to parse tag: %s\n", PB_GET_ERROR(stream));                print_history(position);                return false;            }        }                if (tag == 0)        {            printf("%sterminating on zero tag\n", indent);            return true;        }        printf("%sAt %d: field tag %d, wire type %d (%s)",               indent, position, (int)tag, wire_type, wiretypes[wire_type]);                if (wire_type == PB_WT_VARINT)        {            uint64_t value;            position = g_position;            if (!pb_decode_varint(stream, &value))            {                printf("\n%sERROR: Failed to parse varint: %s\n", indent, PB_GET_ERROR(stream));                print_history(position);                return false;            }                        printf(", varint value (%d bytes): %llu\n",                   g_position - position, (unsigned long long)value);        }        else if (wire_type == PB_WT_64BIT)        {            uint64_t value;            position = g_position;            if (!pb_decode_fixed64(stream, &value))            {                printf("\n%sERROR: Failed to parse fixed64: %s\n", indent, PB_GET_ERROR(stream));                print_history(position);                return false;            }                        printf(", fixed64 value (%d bytes): 0x%016llx\n",                   g_position - position, (unsigned long long)value);        }        else if (wire_type == PB_WT_32BIT)        {            uint32_t value;            position = g_position;            if (!pb_decode_fixed32(stream, &value))            {                printf("\n%sERROR: Failed to parse fixed32: %s\n", indent, PB_GET_ERROR(stream));                print_history(position);                return false;            }                        printf(", fixed32 value (%d bytes): 0x%08lx\n",                   g_position - position, (unsigned long)value);        }        else if (wire_type == PB_WT_STRING)        {            pb_istream_t substream;            position = g_position;            if (!pb_make_string_substream(stream, &substream))            {                printf("ERROR: Failed to parse string length: %s\n", PB_GET_ERROR(stream));                print_history(position);                return false;            }            else            {                            if (substream.bytes_left == 0)                {                    printf(", empty string\n");                }                else                {                    char prefix[8];                    snprintf(prefix, sizeof(prefix), "f%d> ", (int)tag);                                        printf(", string len %d bytes, attempting recursive decode\n",                       (int)substream.bytes_left);                                    if (!raw_decode(&substream, prefix))                    {                        printf("%sfield %d: recursive decode failed, continuing with upper level\n\n",                               indent, (int)tag);                    }                                        pb_close_string_substream(stream, &substream);                }            }        }        else        {            printf("\n");        }    }        return true;}int main(){    pb_istream_t stream = {&callback, NULL, SIZE_MAX};    stream.state = stdin;    SET_BINARY_MODE(stdin);    if (!raw_decode(&stream, ""))    {        return 1;    } else {        return 0;    }}
 |