static inline int pb_decode_tag(pb_field_t *f) { if (pb_decode_varint(f)) { if(f->left == 0) f->eom = 1; // signal end-of-message return -1; } if (f->val.i64 == 0) { f->eom = 1; // Allow 0-terminated messages. PB_RETURN_ERROR(f, -2, "0-terminated msg"); } f->tag = f->val.i64 >> 3; f->type = (pb_wire_type_t)(f->val.i32 & 7); DBGOUT("tag %u, type %u\n", f->tag, f->type); switch (f->type) { case PB_WT_VARINT: return pb_decode_varint(f); case PB_WT_FIXED64: return pb_decode_fixed64(f); case PB_WT_STRING: return pb_decode_string(f); case PB_WT_FIXED32: return pb_decode_fixed32(f); default: PB_RETURN_ERROR(f, -3, "invalid wire_type"); } return 0; }
static bool read_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg) { uint32_t value; if (!pb_decode_fixed32(stream, &value)) return false; TEST(value == *(uint32_t*)*arg); return true; }
static bool read_repeated_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg) { uint32_t** expected = (uint32_t**)arg; uint32_t value; if (!pb_decode_fixed32(stream, &value)) return false; TEST(*(*expected)++ == value); return true; }
bool print_container(pb_istream_t *stream) { uint64_t type, msgtype; uint32_t length, tag; pb_wire_type_t wiretype; bool eof; // decode the type tag if (!pb_decode_tag(stream, &wiretype, &tag, &eof)) { printf("Parsing tag#1 failed: %s\n", PB_GET_ERROR(stream)); } if (!pb_decode_varint(stream, &type)) { printf("Parsing required type field#1 failed: %s\n", PB_GET_ERROR(stream)); } if (!pb_decode_tag(stream, &wiretype, &tag, &eof)) { printf("Parsing tag#2 failed: %s\n", PB_GET_ERROR(stream)); } assert(tag == 1); // tag number of length field assert(wiretype == 5); // encoding of length field = fixed32 if (!pb_decode_fixed32(stream, &length)) { printf("Parsing field#1 failed: %s\n", PB_GET_ERROR(stream)); } printf("wiretype=%d tag=%d fixed32=%d (total message length)\n", wiretype, tag, length); if (!pb_decode_tag(stream, &wiretype, &tag, &eof)) { printf("Parsing tag#2 failed: %s\n", PB_GET_ERROR(stream)); } assert(tag == 2); // tag number of type field assert(wiretype == 0); // encoding of length field = varint if (!pb_decode_varint(stream, &msgtype)) { printf("Parsing field#2 failed: %s\n", PB_GET_ERROR(stream)); } printf("wiretype=%d tag=%d varint=%llu (msgtype)\n", wiretype, tag, msgtype); // the actual message follows. // It is a submessage encoded in length-delimited format if (!pb_decode_tag(stream, &wiretype, &tag, &eof)) { printf("Parsing tag#3 failed: %s\n", PB_GET_ERROR(stream)); } printf("wiretype=%d tag=%d (submessage type)\n", wiretype, tag); assert(wiretype == 2); // length-delimited format printf("submessage: %s NML; %s Motion\n", is_NML_container(tag) ? "is" : "not", is_Motion_container(tag) ? "is" : "not"); // decoding the submessage left as exercise return true; }