17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* pb_decode.c -- decode a protobuf using minimal resources 27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * 37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * 2011 Petteri Aimonen <jpa@kapsi.fi> 47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Use the GCC warn_unused_result attribute to check that all return values 77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * are propagated correctly. On other compilers and gcc before 3.4.0 just 87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * ignore the annotation. 97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) 117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #define checkreturn 127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #define checkreturn __attribute__((warn_unused_result)) 147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "pb.h" 177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "pb_decode.h" 187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/************************************** 207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Declarations internal to this file * 217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen **************************************/ 227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Iterator for pb_field_t list */ 247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentypedef struct { 257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen const pb_field_t *start; /* Start of the pb_field_t array */ 267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen const pb_field_t *pos; /* Current position of the iterator */ 277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unsigned field_index; /* Zero-based index of the field. */ 287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unsigned required_field_index; /* Zero-based index that counts only the required fields */ 297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *dest_struct; /* Pointer to the destination structure to decode to */ 307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pData; /* Pointer where to store current field value */ 317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pSize; /* Pointer where to store the size of current array field */ 327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} pb_field_iterator_t; 337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentypedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; 357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count); 377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); 387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size); 397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct); 407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool pb_field_next(pb_field_iterator_t *iter); 417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); 427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); 437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); 447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); 457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); 467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); 477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn find_extension_field(pb_field_iterator_t *iter); 487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); 497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); 507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); 517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); 527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); 537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); 547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); 557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); 567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); 577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_skip_varint(pb_istream_t *stream); 587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_skip_string(pb_istream_t *stream); 597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* --- Function pointers to field decoders --- 617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Order in the array must match pb_action_t LTYPE numbering. 627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { 647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_varint, 657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_uvarint, 667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_svarint, 677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_fixed32, 687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_fixed64, 697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_bytes, 717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_string, 727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen &pb_dec_submessage, 737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen NULL /* extensions */ 747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}; 757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/******************************* 777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * pb_istream_t implementation * 787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *******************************/ 797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) 817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t *source = (uint8_t*)stream->state; 837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->state = source + count; 847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (buf != NULL) 867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (count--) 887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *buf++ = *source++; 897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) 957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_BUFFER_ONLY 977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (buf == NULL && stream->callback != buf_read) 987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Skip input bytes */ 1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t tmp[16]; 1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (count > 16) 1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_read(stream, tmp, 16)) 1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen count -= 16; 1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, tmp, count); 1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (stream->bytes_left < count) 1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "end-of-stream"); 1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_BUFFER_ONLY 1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!stream->callback(stream, buf, count)) 1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "io error"); 1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!buf_read(stream, buf, count)) 1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->bytes_left -= count; 1257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 1267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 1277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Read a single byte from input stream. buf may not be NULL. 1297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * This is an optimization for the varint decoding. */ 1307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) 1317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 1327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (stream->bytes_left == 0) 1337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "end-of-stream"); 1347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_BUFFER_ONLY 1367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!stream->callback(stream, buf, 1)) 1377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "io error"); 1387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 1397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *buf = *(uint8_t*)stream->state; 1407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->state = (uint8_t*)stream->state + 1; 1417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 1427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->bytes_left--; 1447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 1467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 1477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenpb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize) 1497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 1507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t stream; 1517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_BUFFER_ONLY 1527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream.callback = NULL; 1537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 1547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream.callback = &buf_read; 1557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 1567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream.state = buf; 1577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream.bytes_left = bufsize; 1587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_NO_ERRMSG 1597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream.errmsg = NULL; 1607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 1617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return stream; 1627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 1637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/******************** 1657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Helper functions * 1667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ********************/ 1677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) 1697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 1707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t byte; 1717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t result; 1727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_readbyte(stream, &byte)) 1747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 1757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if ((byte & 0x80) == 0) 1777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Quick case, 1 byte value */ 1797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = byte; 1807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 1827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Multibyte case */ 1847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t bitpos = 7; 1857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = byte & 0x7F; 1867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 1887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (bitpos >= 32) 1907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "varint overflow"); 1917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_readbyte(stream, &byte)) 1937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 1947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result |= (uint32_t)(byte & 0x7F) << bitpos; 1967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bitpos = (uint8_t)(bitpos + 7); 1977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (byte & 0x80); 1987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *dest = result; 2017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 2027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 2037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) 2057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 2067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t byte; 2077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t bitpos = 0; 2087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint64_t result = 0; 2097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 2117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (bitpos >= 64) 2137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "varint overflow"); 2147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_readbyte(stream, &byte)) 2167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 2177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result |= (uint64_t)(byte & 0x7F) << bitpos; 2197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bitpos = (uint8_t)(bitpos + 7); 2207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (byte & 0x80); 2217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *dest = result; 2237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 2247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 2257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_skip_varint(pb_istream_t *stream) 2277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 2287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t byte; 2297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 2307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_read(stream, &byte, 1)) 2327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 2337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (byte & 0x80); 2347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 2357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 2367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_skip_string(pb_istream_t *stream) 2387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 2397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t length; 2407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint32(stream, &length)) 2417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 2427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, NULL, length); 2447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 2457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) 2477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 2487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t temp; 2497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *eof = false; 2507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *wire_type = (pb_wire_type_t) 0; 2517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *tag = 0; 2527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint32(stream, &temp)) 2547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (stream->bytes_left == 0) 2567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *eof = true; 2577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 2597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 2607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (temp == 0) 2627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *eof = true; /* Special feature: allow 0-terminated messages. */ 2647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 2657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 2667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *tag = temp >> 3; 2687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *wire_type = (pb_wire_type_t)(temp & 7); 2697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 2707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 2717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) 2737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 2747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (wire_type) 2757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_VARINT: return pb_skip_varint(stream); 2777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_64BIT: return pb_read(stream, NULL, 8); 2787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_STRING: return pb_skip_string(stream); 2797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_32BIT: return pb_read(stream, NULL, 4); 2807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: PB_RETURN_ERROR(stream, "invalid wire_type"); 2817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 2827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 2837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Read a raw value to buffer, for the purpose of passing it to callback as 2857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * a substream. Size is maximum size on call, and actual size on return. 2867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 2877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size) 2887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 2897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t max_size = *size; 2907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (wire_type) 2917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_VARINT: 2937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *size = 0; 2947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 2957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 2967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (*size)++; 2977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (*size > max_size) return false; 2987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_read(stream, buf, 1)) return false; 2997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (*buf++ & 0x80); 3007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 3017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_64BIT: 3037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *size = 8; 3047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, buf, 8); 3057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_WT_32BIT: 3077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *size = 4; 3087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, buf, 4); 3097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: PB_RETURN_ERROR(stream, "invalid wire_type"); 3117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 3127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 3137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Decode string length from stream and return a substream with limited length. 3157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Remember to close the substream using pb_close_string_substream(). 3167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 3177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) 3187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 3197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t size; 3207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint32(stream, &size)) 3217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 3227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *substream = *stream; 3247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (substream->bytes_left < size) 3257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "parent stream too short"); 3267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen substream->bytes_left = size; 3287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->bytes_left -= size; 3297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 3307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 3317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenvoid pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) 3337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 3347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->state = substream->state; 3357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_NO_ERRMSG 3377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen stream->errmsg = substream->errmsg; 3387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 3397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 3407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) 3427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 3437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->start = iter->pos = fields; 3447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->field_index = 0; 3457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->required_field_index = 0; 3467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pData = (char*)dest_struct + iter->pos->data_offset; 3477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pSize = (char*)iter->pData + iter->pos->size_offset; 3487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->dest_struct = dest_struct; 3497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 3507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool pb_field_next(pb_field_iterator_t *iter) 3527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 3537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool notwrapped = true; 3547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t prev_size = iter->pos->data_size; 3557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC && 3577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED) 3587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 3597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen prev_size *= iter->pos->array_size; 3607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 3617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) 3627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 3637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen prev_size = sizeof(void*); 3647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 3657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (iter->pos->tag == 0) 3677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; /* Only happens with empty message types */ 3687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED) 3707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->required_field_index++; 3717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pos++; 3737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->field_index++; 3747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (iter->pos->tag == 0) 3757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 3767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pos = iter->start; 3777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->field_index = 0; 3787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->required_field_index = 0; 3797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pData = iter->dest_struct; 3807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen prev_size = 0; 3817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen notwrapped = false; 3827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 3837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; 3857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter->pSize = (char*)iter->pData + iter->pos->size_offset; 3867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return notwrapped; 3877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 3887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) 3907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 3917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unsigned start = iter->field_index; 3927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do { 3947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (iter->pos->tag == tag && 3957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) 3967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 3977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 3987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 3997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (void)pb_field_next(iter); 4007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (iter->field_index != start); 4017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 4037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 4047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/************************* 4067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Decode a single field * 4077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *************************/ 4087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) 4107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 4117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_type_t type; 4127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_decoder_t func; 4137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen type = iter->pos->type; 4157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen func = PB_DECODERS[PB_LTYPE(type)]; 4167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (PB_HTYPE(type)) 4187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 4197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_HTYPE_REQUIRED: 4207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return func(stream, iter->pos, iter->pData); 4217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_HTYPE_OPTIONAL: 4237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(bool*)iter->pSize = true; 4247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return func(stream, iter->pos, iter->pData); 4257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_HTYPE_REPEATED: 4277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (wire_type == PB_WT_STRING 4287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) 4297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 4307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Packed array */ 4317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status = true; 4327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t *size = (size_t*)iter->pSize; 4337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t substream; 4347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_make_string_substream(stream, &substream)) 4357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 4367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (substream.bytes_left > 0 && *size < iter->pos->array_size) 4387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 4397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); 4407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!func(&substream, iter->pos, pItem)) 4417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 4427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = false; 4437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen break; 4447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 4457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (*size)++; 4467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 4477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_close_string_substream(stream, &substream); 4487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (substream.bytes_left != 0) 4507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "array overflow"); 4517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return status; 4537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 4547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 4557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 4567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Repeated field */ 4577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t *size = (size_t*)iter->pSize; 4587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); 4597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (*size >= iter->pos->array_size) 4607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "array overflow"); 4617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (*size)++; 4637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return func(stream, iter->pos, pItem); 4647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 4657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: 4677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "invalid field type"); 4687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 4697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 4707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_ENABLE_MALLOC 4727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Allocate storage for the field and store the pointer at iter->pData. 4737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * array_size is the number of entries to reserve in an array. */ 4747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) 4757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 4767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *ptr = *(void**)pData; 4777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t size = array_size * data_size; 4787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Allocate new or expand previous allocation */ 4807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Note: on failure the old pointer will remain in the structure, 4817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * the message must be freed by caller also on error return. */ 4827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ptr = pb_realloc(ptr, size); 4837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (ptr == NULL) 4847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "realloc failed"); 4857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(void**)pData = ptr; 4877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 4887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 4897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ 4917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) 4927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 4937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || 4947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) 4957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 4967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(void**)pItem = NULL; 4977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 4987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) 4997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); 5017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 5037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 5047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) 5067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 5077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_ENABLE_MALLOC 5087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen UNUSED(wire_type); 5097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen UNUSED(iter); 5107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "no malloc support"); 5117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 5127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_type_t type; 5137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_decoder_t func; 5147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen type = iter->pos->type; 5167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen func = PB_DECODERS[PB_LTYPE(type)]; 5177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (PB_HTYPE(type)) 5197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_HTYPE_REQUIRED: 5217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_HTYPE_OPTIONAL: 5227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_LTYPE(type) == PB_LTYPE_STRING || 5237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_LTYPE(type) == PB_LTYPE_BYTES) 5247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return func(stream, iter->pos, iter->pData); 5267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 5287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) 5307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 5317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen initialize_pointer_field(*(void**)iter->pData, iter); 5337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return func(stream, iter->pos, *(void**)iter->pData); 5347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_HTYPE_REPEATED: 5377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (wire_type == PB_WT_STRING 5387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) 5397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Packed array, multiple items come in at once. */ 5417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status = true; 5427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t *size = (size_t*)iter->pSize; 5437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t allocated_size = *size; 5447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pItem; 5457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t substream; 5467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_make_string_substream(stream, &substream)) 5487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 5497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (substream.bytes_left) 5517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (*size + 1 > allocated_size) 5537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Allocate more storage. This tries to guess the 5557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * number of remaining entries. Round the division 5567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * upwards. */ 5577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; 5587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) 5607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = false; 5627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen break; 5637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Decode the array entry */ 5677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size); 5687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen initialize_pointer_field(pItem, iter); 5697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!func(&substream, iter->pos, pItem)) 5707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = false; 5727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen break; 5737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (*size)++; 5757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_close_string_substream(stream, &substream); 5777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return status; 5797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 5817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 5827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Normal repeated field, i.e. only one item at a time. */ 5837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t *size = (size_t*)iter->pSize; 5847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pItem; 5857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (*size)++; 5877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) 5887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 5897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1); 5917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen initialize_pointer_field(pItem, iter); 5927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return func(stream, iter->pos, pItem); 5937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: 5967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "invalid field type"); 5977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 5987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 5997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 6007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) 6027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 6037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_callback_t *pCallback = (pb_callback_t*)iter->pData; 6047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_OLD_CALLBACK_STYLE 6067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *arg = pCallback->arg; 6077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 6087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void **arg = &(pCallback->arg); 6097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 6107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (pCallback->funcs.decode == NULL) 6127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_skip_field(stream, wire_type); 6137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (wire_type == PB_WT_STRING) 6157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 6167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t substream; 6177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_make_string_substream(stream, &substream)) 6197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 6207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 6227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 6237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pCallback->funcs.decode(&substream, iter->pos, arg)) 6247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "callback failed"); 6257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (substream.bytes_left); 6267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_close_string_substream(stream, &substream); 6287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 6297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 6307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 6317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 6327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Copy the single scalar value to stack. 6337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * This is required so that we can limit the stream length, 6347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * which in turn allows to use same callback for packed and 6357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * not-packed fields. */ 6367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t substream; 6377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t buffer[10]; 6387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t size = sizeof(buffer); 6397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!read_raw_value(stream, wire_type, buffer, &size)) 6417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 6427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen substream = pb_istream_from_buffer(buffer, size); 6437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pCallback->funcs.decode(&substream, iter->pos, arg); 6457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 6467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 6477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) 6497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 6507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (PB_ATYPE(iter->pos->type)) 6517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 6527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_ATYPE_STATIC: 6537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return decode_static_field(stream, wire_type, iter); 6547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_ATYPE_POINTER: 6567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return decode_pointer_field(stream, wire_type, iter); 6577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case PB_ATYPE_CALLBACK: 6597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return decode_callback_field(stream, wire_type, iter); 6607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: 6627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "invalid field type"); 6637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 6647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 6657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Default handler for extension fields. Expects a pb_field_t structure 6677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * in extension->type->arg. */ 6687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn default_extension_decoder(pb_istream_t *stream, 6697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) 6707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 6717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen const pb_field_t *field = (const pb_field_t*)extension->type->arg; 6727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_iterator_t iter; 6737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (field->tag != tag) 6757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 6767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.start = field; 6787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.pos = field; 6797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.field_index = 0; 6807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.required_field_index = 0; 6817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.dest_struct = extension->dest; 6827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.pData = extension->dest; 6837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen iter.pSize = &extension->found; 6847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return decode_field(stream, wire_type, &iter); 6867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 6877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Try to decode an unknown field as an extension field. Tries each extension 6897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * decoder in turn, until one of them handles the field or loop ends. */ 6907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn decode_extension(pb_istream_t *stream, 6917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter) 6927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 6937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; 6947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t pos = stream->bytes_left; 6957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (extension != NULL && pos == stream->bytes_left) 6977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 6987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status; 6997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (extension->type->decode) 7007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = extension->type->decode(stream, extension, tag, wire_type); 7017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 7027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = default_extension_decoder(stream, extension, tag, wire_type); 7037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!status) 7057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 7067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen extension = extension->next; 7087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 7117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 7127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Step through the iterator until an extension field is found or until all 7147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * entries have been checked. There can be only one extension field per 7157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * message. Returns false if no extension field is found. */ 7167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn find_extension_field(pb_field_iterator_t *iter) 7177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 7187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unsigned start = iter->field_index; 7197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do { 7217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) 7227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 7237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (void)pb_field_next(iter); 7247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (iter->field_index != start); 7257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 7277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 7287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Initialize message fields to default values, recursively */ 7307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) 7317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 7327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_iterator_t iter; 7337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_init(&iter, fields, dest_struct); 7347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 7367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_type_t type; 7387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen type = iter.pos->type; 7397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Avoid crash on empty message types (zero fields) */ 7417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (iter.pos->tag == 0) 7427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen continue; 7437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_ATYPE(type) == PB_ATYPE_STATIC) 7457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) 7477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Set has_field to false. Still initialize the optional field 7497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * itself also. */ 7507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(bool*)iter.pSize = false; 7517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) 7537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Set array count to 0, no need to initialize contents. */ 7557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(size_t*)iter.pSize = 0; 7567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen continue; 7577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE) 7607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Initialize submessage to defaults */ 7627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_message_set_to_defaults((const pb_field_t *) iter.pos->ptr, iter.pData); 7637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (iter.pos->ptr != NULL) 7657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Initialize to default value */ 7677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen memcpy(iter.pData, iter.pos->ptr, iter.pos->data_size); 7687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 7707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Initialize to zeros */ 7727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen memset(iter.pData, 0, iter.pos->data_size); 7737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (PB_ATYPE(type) == PB_ATYPE_POINTER) 7767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Initialize the pointer to NULL. */ 7787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(void**)iter.pData = NULL; 7797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Initialize array count to 0. */ 7817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(type) == PB_HTYPE_REPEATED) 7827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(size_t*)iter.pSize = 0; 7847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) 7877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 7887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Don't overwrite callback */ 7897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 7907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (pb_field_next(&iter)); 7917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 7927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/********************* 7947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * Decode all fields * 7957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *********************/ 7967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 7987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 7997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; 8007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t extension_range_start = 0; 8017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_iterator_t iter; 8027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_init(&iter, fields, dest_struct); 8047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (stream->bytes_left) 8067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t tag; 8087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_wire_type_t wire_type; 8097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool eof; 8107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) 8127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (eof) 8147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen break; 8157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 8167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 8177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_field_find(&iter, tag)) 8207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* No match found, check if it matches an extension. */ 8227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (tag >= extension_range_start) 8237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!find_extension_field(&iter)) 8257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen extension_range_start = (uint32_t)-1; 8267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 8277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen extension_range_start = iter.pos->tag; 8287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (tag >= extension_range_start) 8307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t pos = stream->bytes_left; 8327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!decode_extension(stream, tag, wire_type, &iter)) 8347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 8357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (pos != stream->bytes_left) 8377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* The field was handled */ 8397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen continue; 8407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* No match found, skip data */ 8457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_skip_field(stream, wire_type)) 8467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 8477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen continue; 8487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED 8517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) 8527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); 8547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!decode_field(stream, wire_type, &iter)) 8577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 8587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Check that all required fields were present. */ 8617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* First figure out the number of required fields by 8637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * seeking to the end of the field array. Usually we 8647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * are already close to end after decoding. 8657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 8667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unsigned req_field_count; 8677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_type_t last_type; 8687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unsigned i; 8697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do { 8707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen req_field_count = iter.required_field_index; 8717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen last_type = iter.pos->type; 8727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (pb_field_next(&iter)); 8737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Fixup if last field was also required. */ 8757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) 8767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen req_field_count++; 8777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Check the whole bytes */ 8797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for (i = 0; i < (req_field_count >> 3); i++) 8807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 8817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (fields_seen[i] != 0xFF) 8827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "missing required field"); 8837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Check the remaining bits */ 8867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7)))) 8877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "missing required field"); 8887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 8897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 8917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 8927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 8947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 8957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status; 8967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_message_set_to_defaults(fields, dest_struct); 8977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = pb_decode_noinit(stream, fields, dest_struct); 8987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_ENABLE_MALLOC 9007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!status) 9017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_release(fields, dest_struct); 9027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 9037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return status; 9057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 9067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 9087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 9097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t substream; 9107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status; 9117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_make_string_substream(stream, &substream)) 9137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 9147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = pb_decode(&substream, fields, dest_struct); 9167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_close_string_substream(stream, &substream); 9177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return status; 9187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 9197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifdef PB_ENABLE_MALLOC 9217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenvoid pb_release(const pb_field_t fields[], void *dest_struct) 9227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 9237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_iterator_t iter; 9247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_field_init(&iter, fields, dest_struct); 9257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen do 9277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_type_t type; 9297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen type = iter.pos->type; 9307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Avoid crash on empty message types (zero fields) */ 9327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (iter.pos->tag == 0) 9337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen continue; 9347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_ATYPE(type) == PB_ATYPE_POINTER) 9367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(type) == PB_HTYPE_REPEATED && 9387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (PB_LTYPE(type) == PB_LTYPE_STRING || 9397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_LTYPE(type) == PB_LTYPE_BYTES)) 9407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Release entries in repeated string or bytes array */ 9427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void **pItem = *(void***)iter.pData; 9437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t count = *(size_t*)iter.pSize; 9447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (count--) 9457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_free(*pItem); 9477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *pItem++ = NULL; 9487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) 9517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Release fields in submessages */ 9537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen void *pItem = *(void**)iter.pData; 9547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t count = (pItem ? 1 : 0); 9557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(type) == PB_HTYPE_REPEATED) 9577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen count = *(size_t*)iter.pSize; 9597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while (count--) 9627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 9637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_release((const pb_field_t*)iter.pos->ptr, pItem); 9647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pItem = (uint8_t*)pItem + iter.pos->data_size; 9657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Release main item */ 9697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_free(*(void**)iter.pData); 9707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *(void**)iter.pData = NULL; 9717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } while (pb_field_next(&iter)); 9737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 9747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 9757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* Field decoders */ 9777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) 9797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 9807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint64_t value; 9817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint(stream, &value)) 9827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 9837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (value & 1) 9857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *dest = (int64_t)(~(value >> 1)); 9867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 9877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *dest = (int64_t)(value >> 1); 9887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 9907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 9917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool pb_decode_fixed32(pb_istream_t *stream, void *dest) 9937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 9947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #ifdef __BIG_ENDIAN__ 9957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t *bytes = (uint8_t*)dest; 9967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t lebytes[4]; 9977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_read(stream, lebytes, 4)) 9997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 10007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[0] = lebytes[3]; 10027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[1] = lebytes[2]; 10037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[2] = lebytes[1]; 10047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[3] = lebytes[0]; 10057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 10067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #else 10077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, (uint8_t*)dest, 4); 10087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #endif 10097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool pb_decode_fixed64(pb_istream_t *stream, void *dest) 10127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #ifdef __BIG_ENDIAN__ 10147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t *bytes = (uint8_t*)dest; 10157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint8_t lebytes[8]; 10167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_read(stream, lebytes, 8)) 10187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 10197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[0] = lebytes[7]; 10217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[1] = lebytes[6]; 10227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[2] = lebytes[5]; 10237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[3] = lebytes[4]; 10247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[4] = lebytes[3]; 10257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[5] = lebytes[2]; 10267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[6] = lebytes[1]; 10277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bytes[7] = lebytes[0]; 10287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 10297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #else 10307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, (uint8_t*)dest, 8); 10317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen #endif 10327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) 10357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint64_t value; 10377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint(stream, &value)) 10387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 10397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (field->data_size) 10417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 10427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 1: *(int8_t*)dest = (int8_t)value; break; 10437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 2: *(int16_t*)dest = (int16_t)value; break; 10447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 4: *(int32_t*)dest = (int32_t)value; break; 10457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 8: *(int64_t*)dest = (int64_t)value; break; 10467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: PB_RETURN_ERROR(stream, "invalid data_size"); 10477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 10487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 10507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) 10537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint64_t value; 10557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint(stream, &value)) 10567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 10577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (field->data_size) 10597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 10607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 4: *(uint32_t*)dest = (uint32_t)value; break; 10617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 8: *(uint64_t*)dest = value; break; 10627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: PB_RETURN_ERROR(stream, "invalid data_size"); 10637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 10647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 10667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) 10697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen int64_t value; 10717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_svarint(stream, &value)) 10727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 10737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen switch (field->data_size) 10757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 10767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 4: *(int32_t*)dest = (int32_t)value; break; 10777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen case 8: *(int64_t*)dest = value; break; 10787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default: PB_RETURN_ERROR(stream, "invalid data_size"); 10797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 10807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 10827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) 10857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen UNUSED(field); 10877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_decode_fixed32(stream, dest); 10887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) 10917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen UNUSED(field); 10937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_decode_fixed64(stream, dest); 10947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 10957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) 10977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 10987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t size; 10997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_bytes_array_t *bdest; 11007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint32(stream, &size)) 11027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 11037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 11057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 11067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_ENABLE_MALLOC 11077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "no malloc support"); 11087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 11097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!allocate_field(stream, dest, PB_BYTES_ARRAY_T_ALLOCSIZE(size), 1)) 11107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 11117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bdest = *(pb_bytes_array_t**)dest; 11127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 11137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 11147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 11157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 11167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_BYTES_ARRAY_T_ALLOCSIZE(size) > field->data_size) 11177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "bytes overflow"); 11187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bdest = (pb_bytes_array_t*)dest; 11197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 11207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bdest->size = size; 11227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return pb_read(stream, bdest->bytes, size); 11237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 11247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) 11267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 11277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen uint32_t size; 11287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size_t alloc_size; 11297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status; 11307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode_varint32(stream, &size)) 11317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 11327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* Space for null terminator */ 11347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen alloc_size = size + 1; 11357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 11377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 11387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#ifndef PB_ENABLE_MALLOC 11397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "no malloc support"); 11407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#else 11417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!allocate_field(stream, dest, alloc_size, 1)) 11427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 11437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen dest = *(void**)dest; 11447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#endif 11457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 11467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 11477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 11487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (alloc_size > field->data_size) 11497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "string overflow"); 11507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 11517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = pb_read(stream, (uint8_t*)dest, size); 11537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *((uint8_t*)dest + size) = 0; 11547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return status; 11557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 11567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenstatic bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) 11587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 11597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen bool status; 11607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t substream; 11617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; 11627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_make_string_substream(stream, &substream)) 11647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 11657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (field->ptr == NULL) 11677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen PB_RETURN_ERROR(stream, "invalid field descriptor"); 11687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen /* New array entries need to be initialized, while required and optional 11707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * submessages have already been initialized in the top-level pb_decode. */ 11717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) 11727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = pb_decode(&substream, submsg_fields, dest); 11737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 11747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = pb_decode_noinit(&substream, submsg_fields, dest); 11757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_close_string_substream(stream, &substream); 11777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return status; 11787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 1179