Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of LinkNode-Test by
pb_decode.c
00001 /* pb_decode.c -- decode a protobuf using minimal resources 00002 * 00003 * 2011 Petteri Aimonen <jpa@kapsi.fi> 00004 */ 00005 00006 /* Use the GCC warn_unused_result attribute to check that all return values 00007 * are propagated correctly. On other compilers and gcc before 3.4.0 just 00008 * ignore the annotation. 00009 */ 00010 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) 00011 #define checkreturn 00012 #else 00013 #define checkreturn __attribute__((warn_unused_result)) 00014 #endif 00015 00016 #include "pb.h" 00017 #include "pb_decode.h" 00018 #include "pb_common.h" 00019 00020 /************************************** 00021 * Declarations internal to this file * 00022 **************************************/ 00023 00024 typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; 00025 00026 static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); 00027 static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); 00028 static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); 00029 static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); 00030 static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); 00031 static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); 00032 static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); 00033 static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); 00034 static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); 00035 static bool checkreturn find_extension_field(pb_field_iter_t *iter); 00036 static void pb_field_set_to_default(pb_field_iter_t *iter); 00037 static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); 00038 static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); 00039 static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); 00040 static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); 00041 static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); 00042 static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); 00043 static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); 00044 static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); 00045 static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); 00046 static bool checkreturn pb_skip_varint(pb_istream_t *stream); 00047 static bool checkreturn pb_skip_string(pb_istream_t *stream); 00048 00049 #ifdef PB_ENABLE_MALLOC 00050 static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); 00051 static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); 00052 static void pb_release_single_field(const pb_field_iter_t *iter); 00053 #endif 00054 00055 /* --- Function pointers to field decoders --- 00056 * Order in the array must match pb_action_t LTYPE numbering. 00057 */ 00058 static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { 00059 &pb_dec_varint, 00060 &pb_dec_uvarint, 00061 &pb_dec_svarint, 00062 &pb_dec_fixed32, 00063 &pb_dec_fixed64, 00064 00065 &pb_dec_bytes, 00066 &pb_dec_string, 00067 &pb_dec_submessage, 00068 NULL /* extensions */ 00069 }; 00070 00071 /******************************* 00072 * pb_istream_t implementation * 00073 *******************************/ 00074 00075 static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) 00076 { 00077 const pb_byte_t *source = (const pb_byte_t*)stream->state; 00078 stream->state = (pb_byte_t*)stream->state + count; 00079 00080 if (buf != NULL) 00081 { 00082 while (count--) 00083 *buf++ = *source++; 00084 } 00085 00086 return true; 00087 } 00088 00089 bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) 00090 { 00091 #ifndef PB_BUFFER_ONLY 00092 if (buf == NULL && stream->callback != buf_read) 00093 { 00094 /* Skip input bytes */ 00095 pb_byte_t tmp[16]; 00096 while (count > 16) 00097 { 00098 if (!pb_read(stream, tmp, 16)) 00099 return false; 00100 00101 count -= 16; 00102 } 00103 00104 return pb_read(stream, tmp, count); 00105 } 00106 #endif 00107 00108 if (stream->bytes_left < count) 00109 PB_RETURN_ERROR(stream, "end-of-stream"); 00110 00111 #ifndef PB_BUFFER_ONLY 00112 if (!stream->callback(stream, buf, count)) 00113 PB_RETURN_ERROR(stream, "io error"); 00114 #else 00115 if (!buf_read(stream, buf, count)) 00116 return false; 00117 #endif 00118 00119 stream->bytes_left -= count; 00120 return true; 00121 } 00122 00123 /* Read a single byte from input stream. buf may not be NULL. 00124 * This is an optimization for the varint decoding. */ 00125 static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) 00126 { 00127 if (stream->bytes_left == 0) 00128 PB_RETURN_ERROR(stream, "end-of-stream"); 00129 00130 #ifndef PB_BUFFER_ONLY 00131 if (!stream->callback(stream, buf, 1)) 00132 PB_RETURN_ERROR(stream, "io error"); 00133 #else 00134 *buf = *(const pb_byte_t*)stream->state; 00135 stream->state = (pb_byte_t*)stream->state + 1; 00136 #endif 00137 00138 stream->bytes_left--; 00139 00140 return true; 00141 } 00142 00143 pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) 00144 { 00145 pb_istream_t stream; 00146 /* Cast away the const from buf without a compiler error. We are 00147 * careful to use it only in a const manner in the callbacks. 00148 */ 00149 union { 00150 void *state; 00151 const void *c_state; 00152 } state; 00153 #ifdef PB_BUFFER_ONLY 00154 stream.callback = NULL; 00155 #else 00156 stream.callback = &buf_read; 00157 #endif 00158 state.c_state = buf; 00159 stream.state = state.state; 00160 stream.bytes_left = bufsize; 00161 #ifndef PB_NO_ERRMSG 00162 stream.errmsg = NULL; 00163 #endif 00164 return stream; 00165 } 00166 00167 /******************** 00168 * Helper functions * 00169 ********************/ 00170 00171 static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) 00172 { 00173 pb_byte_t byte; 00174 uint32_t result; 00175 00176 if (!pb_readbyte(stream, &byte)) 00177 return false; 00178 00179 if ((byte & 0x80) == 0) 00180 { 00181 /* Quick case, 1 byte value */ 00182 result = byte; 00183 } 00184 else 00185 { 00186 /* Multibyte case */ 00187 uint_fast8_t bitpos = 7; 00188 result = byte & 0x7F; 00189 00190 do 00191 { 00192 if (bitpos >= 32) 00193 PB_RETURN_ERROR(stream, "varint overflow"); 00194 00195 if (!pb_readbyte(stream, &byte)) 00196 return false; 00197 00198 result |= (uint32_t)(byte & 0x7F) << bitpos; 00199 bitpos = (uint_fast8_t)(bitpos + 7); 00200 } while (byte & 0x80); 00201 } 00202 00203 *dest = result; 00204 return true; 00205 } 00206 00207 bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) 00208 { 00209 pb_byte_t byte; 00210 uint_fast8_t bitpos = 0; 00211 uint64_t result = 0; 00212 00213 do 00214 { 00215 if (bitpos >= 64) 00216 PB_RETURN_ERROR(stream, "varint overflow"); 00217 00218 if (!pb_readbyte(stream, &byte)) 00219 return false; 00220 00221 result |= (uint64_t)(byte & 0x7F) << bitpos; 00222 bitpos = (uint_fast8_t)(bitpos + 7); 00223 } while (byte & 0x80); 00224 00225 *dest = result; 00226 return true; 00227 } 00228 00229 bool checkreturn pb_skip_varint(pb_istream_t *stream) 00230 { 00231 pb_byte_t byte; 00232 do 00233 { 00234 if (!pb_read(stream, &byte, 1)) 00235 return false; 00236 } while (byte & 0x80); 00237 return true; 00238 } 00239 00240 bool checkreturn pb_skip_string(pb_istream_t *stream) 00241 { 00242 uint32_t length; 00243 if (!pb_decode_varint32(stream, &length)) 00244 return false; 00245 00246 return pb_read(stream, NULL, length); 00247 } 00248 00249 bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) 00250 { 00251 uint32_t temp; 00252 *eof = false; 00253 *wire_type = (pb_wire_type_t) 0; 00254 *tag = 0; 00255 00256 if (!pb_decode_varint32(stream, &temp)) 00257 { 00258 if (stream->bytes_left == 0) 00259 *eof = true; 00260 00261 return false; 00262 } 00263 00264 if (temp == 0) 00265 { 00266 *eof = true; /* Special feature: allow 0-terminated messages. */ 00267 return false; 00268 } 00269 00270 *tag = temp >> 3; 00271 *wire_type = (pb_wire_type_t)(temp & 7); 00272 return true; 00273 } 00274 00275 bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) 00276 { 00277 switch (wire_type) 00278 { 00279 case PB_WT_VARINT: return pb_skip_varint(stream); 00280 case PB_WT_64BIT: return pb_read(stream, NULL, 8); 00281 case PB_WT_STRING: return pb_skip_string(stream); 00282 case PB_WT_32BIT: return pb_read(stream, NULL, 4); 00283 default: PB_RETURN_ERROR(stream, "invalid wire_type"); 00284 } 00285 } 00286 00287 /* Read a raw value to buffer, for the purpose of passing it to callback as 00288 * a substream. Size is maximum size on call, and actual size on return. 00289 */ 00290 static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) 00291 { 00292 size_t max_size = *size; 00293 switch (wire_type) 00294 { 00295 case PB_WT_VARINT: 00296 *size = 0; 00297 do 00298 { 00299 (*size)++; 00300 if (*size > max_size) return false; 00301 if (!pb_read(stream, buf, 1)) return false; 00302 } while (*buf++ & 0x80); 00303 return true; 00304 00305 case PB_WT_64BIT: 00306 *size = 8; 00307 return pb_read(stream, buf, 8); 00308 00309 case PB_WT_32BIT: 00310 *size = 4; 00311 return pb_read(stream, buf, 4); 00312 00313 default: PB_RETURN_ERROR(stream, "invalid wire_type"); 00314 } 00315 } 00316 00317 /* Decode string length from stream and return a substream with limited length. 00318 * Remember to close the substream using pb_close_string_substream(). 00319 */ 00320 bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) 00321 { 00322 uint32_t size; 00323 if (!pb_decode_varint32(stream, &size)) 00324 return false; 00325 00326 *substream = *stream; 00327 if (substream->bytes_left < size) 00328 PB_RETURN_ERROR(stream, "parent stream too short"); 00329 00330 substream->bytes_left = size; 00331 stream->bytes_left -= size; 00332 return true; 00333 } 00334 00335 void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) 00336 { 00337 stream->state = substream->state; 00338 00339 #ifndef PB_NO_ERRMSG 00340 stream->errmsg = substream->errmsg; 00341 #endif 00342 } 00343 00344 /************************* 00345 * Decode a single field * 00346 *************************/ 00347 00348 static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) 00349 { 00350 pb_type_t type; 00351 pb_decoder_t func; 00352 00353 type = iter->pos->type; 00354 func = PB_DECODERS[PB_LTYPE(type)]; 00355 00356 switch (PB_HTYPE(type)) 00357 { 00358 case PB_HTYPE_REQUIRED: 00359 return func(stream, iter->pos, iter->pData); 00360 00361 case PB_HTYPE_OPTIONAL: 00362 *(bool*)iter->pSize = true; 00363 return func(stream, iter->pos, iter->pData); 00364 00365 case PB_HTYPE_REPEATED: 00366 if (wire_type == PB_WT_STRING 00367 && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) 00368 { 00369 /* Packed array */ 00370 bool status = true; 00371 pb_size_t *size = (pb_size_t*)iter->pSize; 00372 pb_istream_t substream; 00373 if (!pb_make_string_substream(stream, &substream)) 00374 return false; 00375 00376 while (substream.bytes_left > 0 && *size < iter->pos->array_size) 00377 { 00378 void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); 00379 if (!func(&substream, iter->pos, pItem)) 00380 { 00381 status = false; 00382 break; 00383 } 00384 (*size)++; 00385 } 00386 pb_close_string_substream(stream, &substream); 00387 00388 if (substream.bytes_left != 0) 00389 PB_RETURN_ERROR(stream, "array overflow"); 00390 00391 return status; 00392 } 00393 else 00394 { 00395 /* Repeated field */ 00396 pb_size_t *size = (pb_size_t*)iter->pSize; 00397 void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); 00398 if (*size >= iter->pos->array_size) 00399 PB_RETURN_ERROR(stream, "array overflow"); 00400 00401 (*size)++; 00402 return func(stream, iter->pos, pItem); 00403 } 00404 00405 case PB_HTYPE_ONEOF: 00406 *(pb_size_t*)iter->pSize = iter->pos->tag; 00407 if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) 00408 { 00409 /* We memset to zero so that any callbacks are set to NULL. 00410 * Then set any default values. */ 00411 memset(iter->pData, 0, iter->pos->data_size); 00412 pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); 00413 } 00414 return func(stream, iter->pos, iter->pData); 00415 00416 default: 00417 PB_RETURN_ERROR(stream, "invalid field type"); 00418 } 00419 } 00420 00421 #ifdef PB_ENABLE_MALLOC 00422 /* Allocate storage for the field and store the pointer at iter->pData. 00423 * array_size is the number of entries to reserve in an array. 00424 * Zero size is not allowed, use pb_free() for releasing. 00425 */ 00426 static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) 00427 { 00428 void *ptr = *(void**)pData; 00429 00430 if (data_size == 0 || array_size == 0) 00431 PB_RETURN_ERROR(stream, "invalid size"); 00432 00433 /* Check for multiplication overflows. 00434 * This code avoids the costly division if the sizes are small enough. 00435 * Multiplication is safe as long as only half of bits are set 00436 * in either multiplicand. 00437 */ 00438 { 00439 const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); 00440 if (data_size >= check_limit || array_size >= check_limit) 00441 { 00442 const size_t size_max = (size_t)-1; 00443 if (size_max / array_size < data_size) 00444 { 00445 PB_RETURN_ERROR(stream, "size too large"); 00446 } 00447 } 00448 } 00449 00450 /* Allocate new or expand previous allocation */ 00451 /* Note: on failure the old pointer will remain in the structure, 00452 * the message must be freed by caller also on error return. */ 00453 ptr = pb_realloc(ptr, array_size * data_size); 00454 if (ptr == NULL) 00455 PB_RETURN_ERROR(stream, "realloc failed"); 00456 00457 *(void**)pData = ptr; 00458 return true; 00459 } 00460 00461 /* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ 00462 static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) 00463 { 00464 if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || 00465 PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) 00466 { 00467 *(void**)pItem = NULL; 00468 } 00469 else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) 00470 { 00471 pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); 00472 } 00473 } 00474 #endif 00475 00476 static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) 00477 { 00478 #ifndef PB_ENABLE_MALLOC 00479 PB_UNUSED(wire_type); 00480 PB_UNUSED(iter); 00481 PB_RETURN_ERROR(stream, "no malloc support"); 00482 #else 00483 pb_type_t type; 00484 pb_decoder_t func; 00485 00486 type = iter->pos->type; 00487 func = PB_DECODERS[PB_LTYPE(type)]; 00488 00489 switch (PB_HTYPE(type)) 00490 { 00491 case PB_HTYPE_REQUIRED: 00492 case PB_HTYPE_OPTIONAL: 00493 case PB_HTYPE_ONEOF: 00494 if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && 00495 *(void**)iter->pData != NULL) 00496 { 00497 /* Duplicate field, have to release the old allocation first. */ 00498 pb_release_single_field(iter); 00499 } 00500 00501 if (PB_HTYPE(type) == PB_HTYPE_ONEOF) 00502 { 00503 *(pb_size_t*)iter->pSize = iter->pos->tag; 00504 } 00505 00506 if (PB_LTYPE(type) == PB_LTYPE_STRING || 00507 PB_LTYPE(type) == PB_LTYPE_BYTES) 00508 { 00509 return func(stream, iter->pos, iter->pData); 00510 } 00511 else 00512 { 00513 if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) 00514 return false; 00515 00516 initialize_pointer_field(*(void**)iter->pData, iter); 00517 return func(stream, iter->pos, *(void**)iter->pData); 00518 } 00519 00520 case PB_HTYPE_REPEATED: 00521 if (wire_type == PB_WT_STRING 00522 && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) 00523 { 00524 /* Packed array, multiple items come in at once. */ 00525 bool status = true; 00526 pb_size_t *size = (pb_size_t*)iter->pSize; 00527 size_t allocated_size = *size; 00528 void *pItem; 00529 pb_istream_t substream; 00530 00531 if (!pb_make_string_substream(stream, &substream)) 00532 return false; 00533 00534 while (substream.bytes_left) 00535 { 00536 if ((size_t)*size + 1 > allocated_size) 00537 { 00538 /* Allocate more storage. This tries to guess the 00539 * number of remaining entries. Round the division 00540 * upwards. */ 00541 allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; 00542 00543 if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) 00544 { 00545 status = false; 00546 break; 00547 } 00548 } 00549 00550 /* Decode the array entry */ 00551 pItem = *(char**)iter->pData + iter->pos->data_size * (*size); 00552 initialize_pointer_field(pItem, iter); 00553 if (!func(&substream, iter->pos, pItem)) 00554 { 00555 status = false; 00556 break; 00557 } 00558 00559 if (*size == PB_SIZE_MAX) 00560 { 00561 #ifndef PB_NO_ERRMSG 00562 stream->errmsg = "too many array entries"; 00563 #endif 00564 status = false; 00565 break; 00566 } 00567 00568 (*size)++; 00569 } 00570 pb_close_string_substream(stream, &substream); 00571 00572 return status; 00573 } 00574 else 00575 { 00576 /* Normal repeated field, i.e. only one item at a time. */ 00577 pb_size_t *size = (pb_size_t*)iter->pSize; 00578 void *pItem; 00579 00580 if (*size == PB_SIZE_MAX) 00581 PB_RETURN_ERROR(stream, "too many array entries"); 00582 00583 (*size)++; 00584 if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) 00585 return false; 00586 00587 pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1); 00588 initialize_pointer_field(pItem, iter); 00589 return func(stream, iter->pos, pItem); 00590 } 00591 00592 default: 00593 PB_RETURN_ERROR(stream, "invalid field type"); 00594 } 00595 #endif 00596 } 00597 00598 static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) 00599 { 00600 pb_callback_t *pCallback = (pb_callback_t*)iter->pData; 00601 00602 #ifdef PB_OLD_CALLBACK_STYLE 00603 void *arg = pCallback->arg; 00604 #else 00605 void **arg = &(pCallback->arg); 00606 #endif 00607 00608 if (pCallback->funcs.decode == NULL) 00609 return pb_skip_field(stream, wire_type); 00610 00611 if (wire_type == PB_WT_STRING) 00612 { 00613 pb_istream_t substream; 00614 00615 if (!pb_make_string_substream(stream, &substream)) 00616 return false; 00617 00618 do 00619 { 00620 if (!pCallback->funcs.decode(&substream, iter->pos, arg)) 00621 PB_RETURN_ERROR(stream, "callback failed"); 00622 } while (substream.bytes_left); 00623 00624 pb_close_string_substream(stream, &substream); 00625 return true; 00626 } 00627 else 00628 { 00629 /* Copy the single scalar value to stack. 00630 * This is required so that we can limit the stream length, 00631 * which in turn allows to use same callback for packed and 00632 * not-packed fields. */ 00633 pb_istream_t substream; 00634 pb_byte_t buffer[10]; 00635 size_t size = sizeof(buffer); 00636 00637 if (!read_raw_value(stream, wire_type, buffer, &size)) 00638 return false; 00639 substream = pb_istream_from_buffer(buffer, size); 00640 00641 return pCallback->funcs.decode(&substream, iter->pos, arg); 00642 } 00643 } 00644 00645 static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) 00646 { 00647 #ifdef PB_ENABLE_MALLOC 00648 /* When decoding an oneof field, check if there is old data that must be 00649 * released first. */ 00650 if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) 00651 { 00652 if (!pb_release_union_field(stream, iter)) 00653 return false; 00654 } 00655 #endif 00656 00657 switch (PB_ATYPE(iter->pos->type)) 00658 { 00659 case PB_ATYPE_STATIC: 00660 return decode_static_field(stream, wire_type, iter); 00661 00662 case PB_ATYPE_POINTER: 00663 return decode_pointer_field(stream, wire_type, iter); 00664 00665 case PB_ATYPE_CALLBACK: 00666 return decode_callback_field(stream, wire_type, iter); 00667 00668 default: 00669 PB_RETURN_ERROR(stream, "invalid field type"); 00670 } 00671 } 00672 00673 static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) 00674 { 00675 /* Fake a field iterator for the extension field. 00676 * It is not actually safe to advance this iterator, but decode_field 00677 * will not even try to. */ 00678 const pb_field_t *field = (const pb_field_t*)extension->type->arg; 00679 (void)pb_field_iter_begin(iter, field, extension->dest); 00680 iter->pData = extension->dest; 00681 iter->pSize = &extension->found; 00682 00683 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 00684 { 00685 /* For pointer extensions, the pointer is stored directly 00686 * in the extension structure. This avoids having an extra 00687 * indirection. */ 00688 iter->pData = &extension->dest; 00689 } 00690 } 00691 00692 /* Default handler for extension fields. Expects a pb_field_t structure 00693 * in extension->type->arg. */ 00694 static bool checkreturn default_extension_decoder(pb_istream_t *stream, 00695 pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) 00696 { 00697 const pb_field_t *field = (const pb_field_t*)extension->type->arg; 00698 pb_field_iter_t iter; 00699 00700 if (field->tag != tag) 00701 return true; 00702 00703 iter_from_extension(&iter, extension); 00704 extension->found = true; 00705 return decode_field(stream, wire_type, &iter); 00706 } 00707 00708 /* Try to decode an unknown field as an extension field. Tries each extension 00709 * decoder in turn, until one of them handles the field or loop ends. */ 00710 static bool checkreturn decode_extension(pb_istream_t *stream, 00711 uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) 00712 { 00713 pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; 00714 size_t pos = stream->bytes_left; 00715 00716 while (extension != NULL && pos == stream->bytes_left) 00717 { 00718 bool status; 00719 if (extension->type->decode) 00720 status = extension->type->decode(stream, extension, tag, wire_type); 00721 else 00722 status = default_extension_decoder(stream, extension, tag, wire_type); 00723 00724 if (!status) 00725 return false; 00726 00727 extension = extension->next; 00728 } 00729 00730 return true; 00731 } 00732 00733 /* Step through the iterator until an extension field is found or until all 00734 * entries have been checked. There can be only one extension field per 00735 * message. Returns false if no extension field is found. */ 00736 static bool checkreturn find_extension_field(pb_field_iter_t *iter) 00737 { 00738 const pb_field_t *start = iter->pos; 00739 00740 do { 00741 if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) 00742 return true; 00743 (void)pb_field_iter_next(iter); 00744 } while (iter->pos != start); 00745 00746 return false; 00747 } 00748 00749 /* Initialize message fields to default values, recursively */ 00750 static void pb_field_set_to_default(pb_field_iter_t *iter) 00751 { 00752 pb_type_t type; 00753 type = iter->pos->type; 00754 00755 if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) 00756 { 00757 pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; 00758 while (ext != NULL) 00759 { 00760 pb_field_iter_t ext_iter; 00761 ext->found = false; 00762 iter_from_extension(&ext_iter, ext); 00763 pb_field_set_to_default(&ext_iter); 00764 ext = ext->next; 00765 } 00766 } 00767 else if (PB_ATYPE(type) == PB_ATYPE_STATIC) 00768 { 00769 bool init_data = true; 00770 if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) 00771 { 00772 /* Set has_field to false. Still initialize the optional field 00773 * itself also. */ 00774 *(bool*)iter->pSize = false; 00775 } 00776 else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || 00777 PB_HTYPE(type) == PB_HTYPE_ONEOF) 00778 { 00779 /* REPEATED: Set array count to 0, no need to initialize contents. 00780 ONEOF: Set which_field to 0. */ 00781 *(pb_size_t*)iter->pSize = 0; 00782 init_data = false; 00783 } 00784 00785 if (init_data) 00786 { 00787 if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) 00788 { 00789 /* Initialize submessage to defaults */ 00790 pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); 00791 } 00792 else if (iter->pos->ptr != NULL) 00793 { 00794 /* Initialize to default value */ 00795 memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); 00796 } 00797 else 00798 { 00799 /* Initialize to zeros */ 00800 memset(iter->pData, 0, iter->pos->data_size); 00801 } 00802 } 00803 } 00804 else if (PB_ATYPE(type) == PB_ATYPE_POINTER) 00805 { 00806 /* Initialize the pointer to NULL. */ 00807 *(void**)iter->pData = NULL; 00808 00809 /* Initialize array count to 0. */ 00810 if (PB_HTYPE(type) == PB_HTYPE_REPEATED || 00811 PB_HTYPE(type) == PB_HTYPE_ONEOF) 00812 { 00813 *(pb_size_t*)iter->pSize = 0; 00814 } 00815 } 00816 else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) 00817 { 00818 /* Don't overwrite callback */ 00819 } 00820 } 00821 00822 static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) 00823 { 00824 pb_field_iter_t iter; 00825 00826 if (!pb_field_iter_begin(&iter, fields, dest_struct)) 00827 return; /* Empty message type */ 00828 00829 do 00830 { 00831 pb_field_set_to_default(&iter); 00832 } while (pb_field_iter_next(&iter)); 00833 } 00834 00835 /********************* 00836 * Decode all fields * 00837 *********************/ 00838 00839 bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 00840 { 00841 uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; 00842 const uint32_t allbits = ~(uint32_t)0; 00843 uint32_t extension_range_start = 0; 00844 pb_field_iter_t iter; 00845 00846 /* Return value ignored, as empty message types will be correctly handled by 00847 * pb_field_iter_find() anyway. */ 00848 (void)pb_field_iter_begin(&iter, fields, dest_struct); 00849 00850 while (stream->bytes_left) 00851 { 00852 uint32_t tag; 00853 pb_wire_type_t wire_type; 00854 bool eof; 00855 00856 if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) 00857 { 00858 if (eof) 00859 break; 00860 else 00861 return false; 00862 } 00863 00864 if (!pb_field_iter_find(&iter, tag)) 00865 { 00866 /* No match found, check if it matches an extension. */ 00867 if (tag >= extension_range_start) 00868 { 00869 if (!find_extension_field(&iter)) 00870 extension_range_start = (uint32_t)-1; 00871 else 00872 extension_range_start = iter.pos->tag; 00873 00874 if (tag >= extension_range_start) 00875 { 00876 size_t pos = stream->bytes_left; 00877 00878 if (!decode_extension(stream, tag, wire_type, &iter)) 00879 return false; 00880 00881 if (pos != stream->bytes_left) 00882 { 00883 /* The field was handled */ 00884 continue; 00885 } 00886 } 00887 } 00888 00889 /* No match found, skip data */ 00890 if (!pb_skip_field(stream, wire_type)) 00891 return false; 00892 continue; 00893 } 00894 00895 if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED 00896 && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) 00897 { 00898 uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); 00899 fields_seen[iter.required_field_index >> 5] |= tmp; 00900 } 00901 00902 if (!decode_field(stream, wire_type, &iter)) 00903 return false; 00904 } 00905 00906 /* Check that all required fields were present. */ 00907 { 00908 /* First figure out the number of required fields by 00909 * seeking to the end of the field array. Usually we 00910 * are already close to end after decoding. 00911 */ 00912 unsigned req_field_count; 00913 pb_type_t last_type; 00914 unsigned i; 00915 do { 00916 req_field_count = iter.required_field_index; 00917 last_type = iter.pos->type; 00918 } while (pb_field_iter_next(&iter)); 00919 00920 /* Fixup if last field was also required. */ 00921 if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) 00922 req_field_count++; 00923 00924 if (req_field_count > 0) 00925 { 00926 /* Check the whole words */ 00927 for (i = 0; i < (req_field_count >> 5); i++) 00928 { 00929 if (fields_seen[i] != allbits) 00930 PB_RETURN_ERROR(stream, "missing required field"); 00931 } 00932 00933 /* Check the remaining bits */ 00934 if (fields_seen[req_field_count >> 5] != (allbits >> (32 - (req_field_count & 31)))) 00935 PB_RETURN_ERROR(stream, "missing required field"); 00936 } 00937 } 00938 00939 return true; 00940 } 00941 00942 bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 00943 { 00944 bool status; 00945 pb_message_set_to_defaults(fields, dest_struct); 00946 status = pb_decode_noinit(stream, fields, dest_struct); 00947 00948 #ifdef PB_ENABLE_MALLOC 00949 if (!status) 00950 pb_release(fields, dest_struct); 00951 #endif 00952 00953 return status; 00954 } 00955 00956 bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 00957 { 00958 pb_istream_t substream; 00959 bool status; 00960 00961 if (!pb_make_string_substream(stream, &substream)) 00962 return false; 00963 00964 status = pb_decode(&substream, fields, dest_struct); 00965 pb_close_string_substream(stream, &substream); 00966 return status; 00967 } 00968 00969 #ifdef PB_ENABLE_MALLOC 00970 /* Given an oneof field, if there has already been a field inside this oneof, 00971 * release it before overwriting with a different one. */ 00972 static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) 00973 { 00974 pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ 00975 pb_size_t new_tag = iter->pos->tag; /* New which_ value */ 00976 00977 if (old_tag == 0) 00978 return true; /* Ok, no old data in union */ 00979 00980 if (old_tag == new_tag) 00981 return true; /* Ok, old data is of same type => merge */ 00982 00983 /* Release old data. The find can fail if the message struct contains 00984 * invalid data. */ 00985 if (!pb_field_iter_find(iter, old_tag)) 00986 PB_RETURN_ERROR(stream, "invalid union tag"); 00987 00988 pb_release_single_field(iter); 00989 00990 /* Restore iterator to where it should be. 00991 * This shouldn't fail unless the pb_field_t structure is corrupted. */ 00992 if (!pb_field_iter_find(iter, new_tag)) 00993 PB_RETURN_ERROR(stream, "iterator error"); 00994 00995 return true; 00996 } 00997 00998 static void pb_release_single_field(const pb_field_iter_t *iter) 00999 { 01000 pb_type_t type; 01001 type = iter->pos->type; 01002 01003 if (PB_HTYPE(type) == PB_HTYPE_ONEOF) 01004 { 01005 if (*(pb_size_t*)iter->pSize != iter->pos->tag) 01006 return; /* This is not the current field in the union */ 01007 } 01008 01009 /* Release anything contained inside an extension or submsg. 01010 * This has to be done even if the submsg itself is statically 01011 * allocated. */ 01012 if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) 01013 { 01014 /* Release fields from all extensions in the linked list */ 01015 pb_extension_t *ext = *(pb_extension_t**)iter->pData; 01016 while (ext != NULL) 01017 { 01018 pb_field_iter_t ext_iter; 01019 iter_from_extension(&ext_iter, ext); 01020 pb_release_single_field(&ext_iter); 01021 ext = ext->next; 01022 } 01023 } 01024 else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) 01025 { 01026 /* Release fields in submessage or submsg array */ 01027 void *pItem = iter->pData; 01028 pb_size_t count = 1; 01029 01030 if (PB_ATYPE(type) == PB_ATYPE_POINTER) 01031 { 01032 pItem = *(void**)iter->pData; 01033 } 01034 01035 if (PB_HTYPE(type) == PB_HTYPE_REPEATED) 01036 { 01037 count = *(pb_size_t*)iter->pSize; 01038 01039 if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) 01040 { 01041 /* Protect against corrupted _count fields */ 01042 count = iter->pos->array_size; 01043 } 01044 } 01045 01046 if (pItem) 01047 { 01048 while (count--) 01049 { 01050 pb_release((const pb_field_t*)iter->pos->ptr, pItem); 01051 pItem = (char*)pItem + iter->pos->data_size; 01052 } 01053 } 01054 } 01055 01056 if (PB_ATYPE(type) == PB_ATYPE_POINTER) 01057 { 01058 if (PB_HTYPE(type) == PB_HTYPE_REPEATED && 01059 (PB_LTYPE(type) == PB_LTYPE_STRING || 01060 PB_LTYPE(type) == PB_LTYPE_BYTES)) 01061 { 01062 /* Release entries in repeated string or bytes array */ 01063 void **pItem = *(void***)iter->pData; 01064 pb_size_t count = *(pb_size_t*)iter->pSize; 01065 while (count--) 01066 { 01067 pb_free(*pItem); 01068 *pItem++ = NULL; 01069 } 01070 } 01071 01072 if (PB_HTYPE(type) == PB_HTYPE_REPEATED) 01073 { 01074 /* We are going to release the array, so set the size to 0 */ 01075 *(pb_size_t*)iter->pSize = 0; 01076 } 01077 01078 /* Release main item */ 01079 pb_free(*(void**)iter->pData); 01080 *(void**)iter->pData = NULL; 01081 } 01082 } 01083 01084 void pb_release(const pb_field_t fields[], void *dest_struct) 01085 { 01086 pb_field_iter_t iter; 01087 01088 if (!dest_struct) 01089 return; /* Ignore NULL pointers, similar to free() */ 01090 01091 if (!pb_field_iter_begin(&iter, fields, dest_struct)) 01092 return; /* Empty message type */ 01093 01094 do 01095 { 01096 pb_release_single_field(&iter); 01097 } while (pb_field_iter_next(&iter)); 01098 } 01099 #endif 01100 01101 /* Field decoders */ 01102 01103 bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) 01104 { 01105 uint64_t value; 01106 if (!pb_decode_varint(stream, &value)) 01107 return false; 01108 01109 if (value & 1) 01110 *dest = (int64_t)(~(value >> 1)); 01111 else 01112 *dest = (int64_t)(value >> 1); 01113 01114 return true; 01115 } 01116 01117 bool pb_decode_fixed32(pb_istream_t *stream, void *dest) 01118 { 01119 pb_byte_t bytes[4]; 01120 01121 if (!pb_read(stream, bytes, 4)) 01122 return false; 01123 01124 *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | 01125 ((uint32_t)bytes[1] << 8) | 01126 ((uint32_t)bytes[2] << 16) | 01127 ((uint32_t)bytes[3] << 24); 01128 return true; 01129 } 01130 01131 bool pb_decode_fixed64(pb_istream_t *stream, void *dest) 01132 { 01133 pb_byte_t bytes[8]; 01134 01135 if (!pb_read(stream, bytes, 8)) 01136 return false; 01137 01138 *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | 01139 ((uint64_t)bytes[1] << 8) | 01140 ((uint64_t)bytes[2] << 16) | 01141 ((uint64_t)bytes[3] << 24) | 01142 ((uint64_t)bytes[4] << 32) | 01143 ((uint64_t)bytes[5] << 40) | 01144 ((uint64_t)bytes[6] << 48) | 01145 ((uint64_t)bytes[7] << 56); 01146 01147 return true; 01148 } 01149 01150 static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) 01151 { 01152 uint64_t value; 01153 int64_t svalue; 01154 int64_t clamped; 01155 if (!pb_decode_varint(stream, &value)) 01156 return false; 01157 01158 /* See issue 97: Google's C++ protobuf allows negative varint values to 01159 * be cast as int32_t, instead of the int64_t that should be used when 01160 * encoding. Previous nanopb versions had a bug in encoding. In order to 01161 * not break decoding of such messages, we cast <=32 bit fields to 01162 * int32_t first to get the sign correct. 01163 */ 01164 if (field->data_size == sizeof(int64_t)) 01165 svalue = (int64_t)value; 01166 else 01167 svalue = (int32_t)value; 01168 01169 /* Cast to the proper field size, while checking for overflows */ 01170 if (field->data_size == sizeof(int64_t)) 01171 clamped = *(int64_t*)dest = svalue; 01172 else if (field->data_size == sizeof(int32_t)) 01173 clamped = *(int32_t*)dest = (int32_t)svalue; 01174 else if (field->data_size == sizeof(int_least16_t)) 01175 clamped = *(int_least16_t*)dest = (int_least16_t)svalue; 01176 else if (field->data_size == sizeof(int_least8_t)) 01177 clamped = *(int_least8_t*)dest = (int_least8_t)svalue; 01178 else 01179 PB_RETURN_ERROR(stream, "invalid data_size"); 01180 01181 if (clamped != svalue) 01182 PB_RETURN_ERROR(stream, "integer too large"); 01183 01184 return true; 01185 } 01186 01187 static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) 01188 { 01189 uint64_t value, clamped; 01190 if (!pb_decode_varint(stream, &value)) 01191 return false; 01192 01193 /* Cast to the proper field size, while checking for overflows */ 01194 if (field->data_size == sizeof(uint64_t)) 01195 clamped = *(uint64_t*)dest = value; 01196 else if (field->data_size == sizeof(uint32_t)) 01197 clamped = *(uint32_t*)dest = (uint32_t)value; 01198 else if (field->data_size == sizeof(uint_least16_t)) 01199 clamped = *(uint_least16_t*)dest = (uint_least16_t)value; 01200 else if (field->data_size == sizeof(uint_least8_t)) 01201 clamped = *(uint_least8_t*)dest = (uint_least8_t)value; 01202 else 01203 PB_RETURN_ERROR(stream, "invalid data_size"); 01204 01205 if (clamped != value) 01206 PB_RETURN_ERROR(stream, "integer too large"); 01207 01208 return true; 01209 } 01210 01211 static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) 01212 { 01213 int64_t value, clamped; 01214 if (!pb_decode_svarint(stream, &value)) 01215 return false; 01216 01217 /* Cast to the proper field size, while checking for overflows */ 01218 if (field->data_size == sizeof(int64_t)) 01219 clamped = *(int64_t*)dest = value; 01220 else if (field->data_size == sizeof(int32_t)) 01221 clamped = *(int32_t*)dest = (int32_t)value; 01222 else if (field->data_size == sizeof(int_least16_t)) 01223 clamped = *(int_least16_t*)dest = (int_least16_t)value; 01224 else if (field->data_size == sizeof(int_least8_t)) 01225 clamped = *(int_least8_t*)dest = (int_least8_t)value; 01226 else 01227 PB_RETURN_ERROR(stream, "invalid data_size"); 01228 01229 if (clamped != value) 01230 PB_RETURN_ERROR(stream, "integer too large"); 01231 01232 return true; 01233 } 01234 01235 static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) 01236 { 01237 PB_UNUSED(field); 01238 return pb_decode_fixed32(stream, dest); 01239 } 01240 01241 static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) 01242 { 01243 PB_UNUSED(field); 01244 return pb_decode_fixed64(stream, dest); 01245 } 01246 01247 static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) 01248 { 01249 uint32_t size; 01250 size_t alloc_size; 01251 pb_bytes_array_t *bdest; 01252 01253 if (!pb_decode_varint32(stream, &size)) 01254 return false; 01255 01256 if (size > PB_SIZE_MAX) 01257 PB_RETURN_ERROR(stream, "bytes overflow"); 01258 01259 alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); 01260 if (size > alloc_size) 01261 PB_RETURN_ERROR(stream, "size too large"); 01262 01263 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 01264 { 01265 #ifndef PB_ENABLE_MALLOC 01266 PB_RETURN_ERROR(stream, "no malloc support"); 01267 #else 01268 if (!allocate_field(stream, dest, alloc_size, 1)) 01269 return false; 01270 bdest = *(pb_bytes_array_t**)dest; 01271 #endif 01272 } 01273 else 01274 { 01275 if (alloc_size > field->data_size) 01276 PB_RETURN_ERROR(stream, "bytes overflow"); 01277 bdest = (pb_bytes_array_t*)dest; 01278 } 01279 01280 bdest->size = (pb_size_t)size; 01281 return pb_read(stream, bdest->bytes, size); 01282 } 01283 01284 static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) 01285 { 01286 uint32_t size; 01287 size_t alloc_size; 01288 bool status; 01289 if (!pb_decode_varint32(stream, &size)) 01290 return false; 01291 01292 /* Space for null terminator */ 01293 alloc_size = size + 1; 01294 01295 if (alloc_size < size) 01296 PB_RETURN_ERROR(stream, "size too large"); 01297 01298 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 01299 { 01300 #ifndef PB_ENABLE_MALLOC 01301 PB_RETURN_ERROR(stream, "no malloc support"); 01302 #else 01303 if (!allocate_field(stream, dest, alloc_size, 1)) 01304 return false; 01305 dest = *(void**)dest; 01306 #endif 01307 } 01308 else 01309 { 01310 if (alloc_size > field->data_size) 01311 PB_RETURN_ERROR(stream, "string overflow"); 01312 } 01313 01314 status = pb_read(stream, (pb_byte_t*)dest, size); 01315 *((pb_byte_t*)dest + size) = 0; 01316 return status; 01317 } 01318 01319 static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) 01320 { 01321 bool status; 01322 pb_istream_t substream; 01323 const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; 01324 01325 if (!pb_make_string_substream(stream, &substream)) 01326 return false; 01327 01328 if (field->ptr == NULL) 01329 PB_RETURN_ERROR(stream, "invalid field descriptor"); 01330 01331 /* New array entries need to be initialized, while required and optional 01332 * submessages have already been initialized in the top-level pb_decode. */ 01333 if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) 01334 status = pb_decode(&substream, submsg_fields, dest); 01335 else 01336 status = pb_decode_noinit(&substream, submsg_fields, dest); 01337 01338 pb_close_string_substream(stream, &substream); 01339 return status; 01340 }
Generated on Tue Jul 12 2022 16:00:22 by
