Nanopb is a plain-C implementation of Google's Protocol Buffers data format. It is targeted at 32 bit microcontrollers, but is also fit for other embedded systems with tight (2-10 kB ROM, <1 kB RAM) memory constraints.
Dependents: FBRLogger Dumb_box_rev2
pb_decode.c
00001 /* pb_decode.c -- decode a protobuf using minimal resources 00002 * 00003 * 2011 Petteri Aimonen <jpa@kapsi.fi> 00004 */ 00005 00006 /* The warn_unused_result attribute appeared first in gcc-3.4.0 */ 00007 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) 00008 #define checkreturn 00009 #else 00010 /* Verify that we remember to check all return values for proper error propagation */ 00011 #define checkreturn __attribute__((warn_unused_result)) 00012 #endif 00013 00014 #define NANOPB_INTERNALS 00015 #include "pb.h" 00016 #include "pb_decode.h" 00017 #include <string.h> 00018 00019 typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; 00020 00021 /* --- Function pointers to field decoders --- 00022 * Order in the array must match pb_action_t LTYPE numbering. 00023 */ 00024 static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { 00025 &pb_dec_varint, 00026 &pb_dec_svarint, 00027 &pb_dec_fixed32, 00028 &pb_dec_fixed64, 00029 00030 &pb_dec_bytes, 00031 &pb_dec_string, 00032 &pb_dec_submessage 00033 }; 00034 00035 /************** 00036 * pb_istream * 00037 **************/ 00038 00039 static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) 00040 { 00041 uint8_t *source = (uint8_t*)stream->state; 00042 stream->state = source + count; 00043 00044 if (buf != NULL) 00045 { 00046 while (count--) 00047 *buf++ = *source++; 00048 } 00049 00050 return true; 00051 } 00052 00053 bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) 00054 { 00055 #ifndef PB_BUFFER_ONLY 00056 if (buf == NULL && stream->callback != buf_read) 00057 { 00058 /* Skip input bytes */ 00059 uint8_t tmp[16]; 00060 while (count > 16) 00061 { 00062 if (!pb_read(stream, tmp, 16)) 00063 return false; 00064 00065 count -= 16; 00066 } 00067 00068 return pb_read(stream, tmp, count); 00069 } 00070 #endif 00071 00072 if (stream->bytes_left < count) 00073 PB_RETURN_ERROR(stream, "end-of-stream"); 00074 00075 #ifndef PB_BUFFER_ONLY 00076 if (!stream->callback(stream, buf, count)) 00077 PB_RETURN_ERROR(stream, "io error"); 00078 #else 00079 if (!buf_read(stream, buf, count)) 00080 return false; 00081 #endif 00082 00083 stream->bytes_left -= count; 00084 return true; 00085 } 00086 00087 pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize) 00088 { 00089 pb_istream_t stream; 00090 #ifdef PB_BUFFER_ONLY 00091 stream.callback = NULL; 00092 #else 00093 stream.callback = &buf_read; 00094 #endif 00095 stream.state = buf; 00096 stream.bytes_left = bufsize; 00097 #ifndef PB_NO_ERRMSG 00098 stream.errmsg = NULL; 00099 #endif 00100 return stream; 00101 } 00102 00103 /******************** 00104 * Helper functions * 00105 ********************/ 00106 00107 static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) 00108 { 00109 uint8_t byte; 00110 uint32_t result; 00111 00112 if (!pb_read(stream, &byte, 1)) 00113 return false; 00114 00115 if (!(byte & 0x80)) 00116 { 00117 /* Quick case, 1 byte value */ 00118 result = byte; 00119 } 00120 else 00121 { 00122 /* Multibyte case */ 00123 uint8_t bitpos = 7; 00124 result = byte & 0x7F; 00125 00126 do 00127 { 00128 if (bitpos >= 32) 00129 PB_RETURN_ERROR(stream, "varint overflow"); 00130 00131 if (!pb_read(stream, &byte, 1)) 00132 return false; 00133 00134 result |= (uint32_t)(byte & 0x7F) << bitpos; 00135 bitpos = (uint8_t)(bitpos + 7); 00136 } while (byte & 0x80); 00137 } 00138 00139 *dest = result; 00140 return true; 00141 } 00142 00143 bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) 00144 { 00145 uint8_t byte; 00146 uint8_t bitpos = 0; 00147 uint64_t result = 0; 00148 00149 do 00150 { 00151 if (bitpos >= 64) 00152 PB_RETURN_ERROR(stream, "varint overflow"); 00153 00154 if (!pb_read(stream, &byte, 1)) 00155 return false; 00156 00157 result |= (uint64_t)(byte & 0x7F) << bitpos; 00158 bitpos = (uint8_t)(bitpos + 7); 00159 } while (byte & 0x80); 00160 00161 *dest = result; 00162 return true; 00163 } 00164 00165 bool checkreturn pb_skip_varint(pb_istream_t *stream) 00166 { 00167 uint8_t byte; 00168 do 00169 { 00170 if (!pb_read(stream, &byte, 1)) 00171 return false; 00172 } while (byte & 0x80); 00173 return true; 00174 } 00175 00176 bool checkreturn pb_skip_string(pb_istream_t *stream) 00177 { 00178 uint32_t length; 00179 if (!pb_decode_varint32(stream, &length)) 00180 return false; 00181 00182 return pb_read(stream, NULL, length); 00183 } 00184 00185 bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) 00186 { 00187 uint32_t temp; 00188 *eof = false; 00189 *wire_type = (pb_wire_type_t) 0; 00190 *tag = 0; 00191 00192 if (!pb_decode_varint32(stream, &temp)) 00193 { 00194 if (stream->bytes_left == 0) 00195 *eof = true; 00196 00197 return false; 00198 } 00199 00200 if (temp == 0) 00201 { 00202 *eof = true; /* Special feature: allow 0-terminated messages. */ 00203 return false; 00204 } 00205 00206 *tag = temp >> 3; 00207 *wire_type = (pb_wire_type_t)(temp & 7); 00208 return true; 00209 } 00210 00211 bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) 00212 { 00213 switch (wire_type) 00214 { 00215 case PB_WT_VARINT: return pb_skip_varint(stream); 00216 case PB_WT_64BIT: return pb_read(stream, NULL, 8); 00217 case PB_WT_STRING: return pb_skip_string(stream); 00218 case PB_WT_32BIT: return pb_read(stream, NULL, 4); 00219 default: PB_RETURN_ERROR(stream, "invalid wire_type"); 00220 } 00221 } 00222 00223 /* Read a raw value to buffer, for the purpose of passing it to callback as 00224 * a substream. Size is maximum size on call, and actual size on return. 00225 */ 00226 static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size) 00227 { 00228 size_t max_size = *size; 00229 switch (wire_type) 00230 { 00231 case PB_WT_VARINT: 00232 *size = 0; 00233 do 00234 { 00235 (*size)++; 00236 if (*size > max_size) return false; 00237 if (!pb_read(stream, buf, 1)) return false; 00238 } while (*buf++ & 0x80); 00239 return true; 00240 00241 case PB_WT_64BIT: 00242 *size = 8; 00243 return pb_read(stream, buf, 8); 00244 00245 case PB_WT_32BIT: 00246 *size = 4; 00247 return pb_read(stream, buf, 4); 00248 00249 default: PB_RETURN_ERROR(stream, "invalid wire_type"); 00250 } 00251 } 00252 00253 /* Decode string length from stream and return a substream with limited length. 00254 * Remember to close the substream using pb_close_string_substream(). 00255 */ 00256 bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) 00257 { 00258 uint32_t size; 00259 if (!pb_decode_varint32(stream, &size)) 00260 return false; 00261 00262 *substream = *stream; 00263 if (substream->bytes_left < size) 00264 PB_RETURN_ERROR(stream, "parent stream too short"); 00265 00266 substream->bytes_left = size; 00267 stream->bytes_left -= size; 00268 return true; 00269 } 00270 00271 void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) 00272 { 00273 stream->state = substream->state; 00274 00275 #ifndef PB_NO_ERRMSG 00276 stream->errmsg = substream->errmsg; 00277 #endif 00278 } 00279 00280 /* Iterator for pb_field_t list */ 00281 typedef struct { 00282 const pb_field_t *start; /* Start of the pb_field_t array */ 00283 const pb_field_t *current; /* Current position of the iterator */ 00284 unsigned field_index; /* Zero-based index of the field. */ 00285 unsigned required_field_index; /* Zero-based index that counts only the required fields */ 00286 void *dest_struct; /* Pointer to the destination structure to decode to */ 00287 void *pData; /* Pointer where to store current field value */ 00288 void *pSize; /* Pointer where to store the size of current array field */ 00289 } pb_field_iterator_t; 00290 00291 static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) 00292 { 00293 iter->start = iter->current = fields; 00294 iter->field_index = 0; 00295 iter->required_field_index = 0; 00296 iter->pData = (char*)dest_struct + iter->current->data_offset; 00297 iter->pSize = (char*)iter->pData + iter->current->size_offset; 00298 iter->dest_struct = dest_struct; 00299 } 00300 00301 static bool pb_field_next(pb_field_iterator_t *iter) 00302 { 00303 bool notwrapped = true; 00304 size_t prev_size = iter->current->data_size; 00305 00306 if (PB_HTYPE(iter->current->type) == PB_HTYPE_ARRAY) 00307 prev_size *= iter->current->array_size; 00308 00309 if (PB_HTYPE(iter->current->type) == PB_HTYPE_REQUIRED) 00310 iter->required_field_index++; 00311 00312 iter->current++; 00313 iter->field_index++; 00314 if (iter->current->tag == 0) 00315 { 00316 iter->current = iter->start; 00317 iter->field_index = 0; 00318 iter->required_field_index = 0; 00319 iter->pData = iter->dest_struct; 00320 prev_size = 0; 00321 notwrapped = false; 00322 } 00323 00324 iter->pData = (char*)iter->pData + prev_size + iter->current->data_offset; 00325 iter->pSize = (char*)iter->pData + iter->current->size_offset; 00326 return notwrapped; 00327 } 00328 00329 static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) 00330 { 00331 unsigned start = iter->field_index; 00332 00333 do { 00334 if (iter->current->tag == tag) 00335 return true; 00336 pb_field_next(iter); 00337 } while (iter->field_index != start); 00338 00339 return false; 00340 } 00341 00342 /************************* 00343 * Decode a single field * 00344 *************************/ 00345 00346 static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) 00347 { 00348 pb_decoder_t func = PB_DECODERS[PB_LTYPE(iter->current->type)]; 00349 00350 switch (PB_HTYPE(iter->current->type)) 00351 { 00352 case PB_HTYPE_REQUIRED: 00353 return func(stream, iter->current, iter->pData); 00354 00355 case PB_HTYPE_OPTIONAL: 00356 *(bool*)iter->pSize = true; 00357 return func(stream, iter->current, iter->pData); 00358 00359 case PB_HTYPE_ARRAY: 00360 if (wire_type == PB_WT_STRING 00361 && PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE) 00362 { 00363 /* Packed array */ 00364 bool status = true; 00365 size_t *size = (size_t*)iter->pSize; 00366 pb_istream_t substream; 00367 if (!pb_make_string_substream(stream, &substream)) 00368 return false; 00369 00370 while (substream.bytes_left && *size < iter->current->array_size) 00371 { 00372 void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size); 00373 if (!func(&substream, iter->current, pItem)) 00374 { 00375 status = false; 00376 break; 00377 } 00378 (*size)++; 00379 } 00380 pb_close_string_substream(stream, &substream); 00381 00382 if (substream.bytes_left != 0) 00383 PB_RETURN_ERROR(stream, "array overflow"); 00384 00385 return status; 00386 } 00387 else 00388 { 00389 /* Repeated field */ 00390 size_t *size = (size_t*)iter->pSize; 00391 void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size); 00392 if (*size >= iter->current->array_size) 00393 PB_RETURN_ERROR(stream, "array overflow"); 00394 00395 (*size)++; 00396 return func(stream, iter->current, pItem); 00397 } 00398 00399 case PB_HTYPE_CALLBACK: 00400 { 00401 pb_callback_t *pCallback = (pb_callback_t*)iter->pData; 00402 00403 if (pCallback->funcs.decode == NULL) 00404 return pb_skip_field(stream, wire_type); 00405 00406 if (wire_type == PB_WT_STRING) 00407 { 00408 pb_istream_t substream; 00409 00410 if (!pb_make_string_substream(stream, &substream)) 00411 return false; 00412 00413 while (substream.bytes_left) 00414 { 00415 if (!pCallback->funcs.decode(&substream, iter->current, pCallback->arg)) 00416 PB_RETURN_ERROR(stream, "callback failed"); 00417 } 00418 00419 pb_close_string_substream(stream, &substream); 00420 return true; 00421 } 00422 else 00423 { 00424 /* Copy the single scalar value to stack. 00425 * This is required so that we can limit the stream length, 00426 * which in turn allows to use same callback for packed and 00427 * not-packed fields. */ 00428 pb_istream_t substream; 00429 uint8_t buffer[10]; 00430 size_t size = sizeof(buffer); 00431 00432 if (!read_raw_value(stream, wire_type, buffer, &size)) 00433 return false; 00434 substream = pb_istream_from_buffer(buffer, size); 00435 00436 return pCallback->funcs.decode(&substream, iter->current, pCallback->arg); 00437 } 00438 } 00439 00440 default: 00441 PB_RETURN_ERROR(stream, "invalid field type"); 00442 } 00443 } 00444 00445 /* Initialize message fields to default values, recursively */ 00446 static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) 00447 { 00448 pb_field_iterator_t iter; 00449 pb_field_init(&iter, fields, dest_struct); 00450 00451 /* Initialize size/has fields and apply default values */ 00452 do 00453 { 00454 if (iter.current->tag == 0) 00455 continue; 00456 00457 /* Initialize the size field for optional/repeated fields to 0. */ 00458 if (PB_HTYPE(iter.current->type) == PB_HTYPE_OPTIONAL) 00459 { 00460 *(bool*)iter.pSize = false; 00461 } 00462 else if (PB_HTYPE(iter.current->type) == PB_HTYPE_ARRAY) 00463 { 00464 *(size_t*)iter.pSize = 0; 00465 continue; /* Array is empty, no need to initialize contents */ 00466 } 00467 00468 /* Initialize field contents to default value */ 00469 if (PB_HTYPE(iter.current->type) == PB_HTYPE_CALLBACK) 00470 { 00471 continue; /* Don't overwrite callback */ 00472 } 00473 else if (PB_LTYPE(iter.current->type) == PB_LTYPE_SUBMESSAGE) 00474 { 00475 pb_message_set_to_defaults((const pb_field_t *) iter.current->ptr, iter.pData); 00476 } 00477 else if (iter.current->ptr != NULL) 00478 { 00479 memcpy(iter.pData, iter.current->ptr, iter.current->data_size); 00480 } 00481 else 00482 { 00483 memset(iter.pData, 0, iter.current->data_size); 00484 } 00485 } while (pb_field_next(&iter)); 00486 } 00487 00488 /********************* 00489 * Decode all fields * 00490 *********************/ 00491 00492 bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 00493 { 00494 uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0}; /* Used to check for required fields */ 00495 pb_field_iterator_t iter; 00496 00497 pb_field_init(&iter, fields, dest_struct); 00498 00499 while (stream->bytes_left) 00500 { 00501 uint32_t tag; 00502 pb_wire_type_t wire_type; 00503 bool eof; 00504 00505 if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) 00506 { 00507 if (eof) 00508 break; 00509 else 00510 return false; 00511 } 00512 00513 if (!pb_field_find(&iter, tag)) 00514 { 00515 /* No match found, skip data */ 00516 if (!pb_skip_field(stream, wire_type)) 00517 return false; 00518 continue; 00519 } 00520 00521 if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED 00522 && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) 00523 { 00524 fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); 00525 } 00526 00527 if (!decode_field(stream, wire_type, &iter)) 00528 return false; 00529 } 00530 00531 /* Check that all required fields were present. */ 00532 { 00533 /* First figure out the number of required fields by 00534 * seeking to the end of the field array. Usually we 00535 * are already close to end after decoding. 00536 */ 00537 unsigned req_field_count; 00538 pb_type_t last_type; 00539 unsigned i; 00540 do { 00541 req_field_count = iter.required_field_index; 00542 last_type = iter.current->type; 00543 } while (pb_field_next(&iter)); 00544 00545 /* Fixup if last field was also required. */ 00546 if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED) 00547 req_field_count++; 00548 00549 /* Check the whole bytes */ 00550 for (i = 0; i < (req_field_count >> 3); i++) 00551 { 00552 if (fields_seen[i] != 0xFF) 00553 PB_RETURN_ERROR(stream, "missing required field"); 00554 } 00555 00556 /* Check the remaining bits */ 00557 if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7)))) 00558 PB_RETURN_ERROR(stream, "missing required field"); 00559 } 00560 00561 return true; 00562 } 00563 00564 bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) 00565 { 00566 pb_message_set_to_defaults(fields, dest_struct); 00567 return pb_decode_noinit(stream, fields, dest_struct); 00568 } 00569 00570 /* Field decoders */ 00571 00572 bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) 00573 { 00574 uint64_t value; 00575 if (!pb_decode_varint(stream, &value)) 00576 return false; 00577 00578 if (value & 1) 00579 *dest = (int64_t)(~(value >> 1)); 00580 else 00581 *dest = (int64_t)(value >> 1); 00582 00583 return true; 00584 } 00585 00586 bool pb_decode_fixed32(pb_istream_t *stream, void *dest) 00587 { 00588 #ifdef __BIG_ENDIAN__ 00589 uint8_t *bytes = (uint8_t*)dest; 00590 uint8_t lebytes[4]; 00591 00592 if (!pb_read(stream, lebytes, 4)) 00593 return false; 00594 00595 bytes[0] = lebytes[3]; 00596 bytes[1] = lebytes[2]; 00597 bytes[2] = lebytes[1]; 00598 bytes[3] = lebytes[0]; 00599 return true; 00600 #else 00601 return pb_read(stream, (uint8_t*)dest, 4); 00602 #endif 00603 } 00604 00605 bool pb_decode_fixed64(pb_istream_t *stream, void *dest) 00606 { 00607 #ifdef __BIG_ENDIAN__ 00608 uint8_t *bytes = (uint8_t*)dest; 00609 uint8_t lebytes[8]; 00610 00611 if (!pb_read(stream, lebytes, 8)) 00612 return false; 00613 00614 bytes[0] = lebytes[7]; 00615 bytes[1] = lebytes[6]; 00616 bytes[2] = lebytes[5]; 00617 bytes[3] = lebytes[4]; 00618 bytes[4] = lebytes[3]; 00619 bytes[5] = lebytes[2]; 00620 bytes[6] = lebytes[1]; 00621 bytes[7] = lebytes[0]; 00622 return true; 00623 #else 00624 return pb_read(stream, (uint8_t*)dest, 8); 00625 #endif 00626 } 00627 00628 bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) 00629 { 00630 uint64_t value; 00631 bool status = pb_decode_varint(stream, &value); 00632 00633 switch (field->data_size) 00634 { 00635 case 1: *(uint8_t*)dest = (uint8_t)value; break; 00636 case 2: *(uint16_t*)dest = (uint16_t)value; break; 00637 case 4: *(uint32_t*)dest = (uint32_t)value; break; 00638 case 8: *(uint64_t*)dest = value; break; 00639 default: PB_RETURN_ERROR(stream, "invalid data_size"); 00640 } 00641 00642 return status; 00643 } 00644 00645 bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) 00646 { 00647 int64_t value; 00648 bool status = pb_decode_svarint(stream, &value); 00649 00650 switch (field->data_size) 00651 { 00652 case 4: *(int32_t*)dest = (int32_t)value; break; 00653 case 8: *(int64_t*)dest = value; break; 00654 default: PB_RETURN_ERROR(stream, "invalid data_size"); 00655 } 00656 00657 return status; 00658 } 00659 00660 bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) 00661 { 00662 UNUSED(field); 00663 return pb_decode_fixed32(stream, dest); 00664 } 00665 00666 bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) 00667 { 00668 UNUSED(field); 00669 return pb_decode_fixed64(stream, dest); 00670 } 00671 00672 bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) 00673 { 00674 pb_bytes_array_t *x = (pb_bytes_array_t*)dest; 00675 00676 uint32_t temp; 00677 if (!pb_decode_varint32(stream, &temp)) 00678 return false; 00679 x->size = temp; 00680 00681 /* Check length, noting the space taken by the size_t header. */ 00682 if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) 00683 PB_RETURN_ERROR(stream, "bytes overflow"); 00684 00685 return pb_read(stream, x->bytes, x->size); 00686 } 00687 00688 bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) 00689 { 00690 uint32_t size; 00691 bool status; 00692 if (!pb_decode_varint32(stream, &size)) 00693 return false; 00694 00695 /* Check length, noting the null terminator */ 00696 if (size + 1 > field->data_size) 00697 PB_RETURN_ERROR(stream, "string overflow"); 00698 00699 status = pb_read(stream, (uint8_t*)dest, size); 00700 *((uint8_t*)dest + size) = 0; 00701 return status; 00702 } 00703 00704 bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) 00705 { 00706 bool status; 00707 pb_istream_t substream; 00708 const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; 00709 00710 if (!pb_make_string_substream(stream, &substream)) 00711 return false; 00712 00713 if (field->ptr == NULL) 00714 PB_RETURN_ERROR(stream, "invalid field descriptor"); 00715 00716 /* New array entries need to be initialized, while required and optional 00717 * submessages have already been initialized in the top-level pb_decode. */ 00718 if (PB_HTYPE(field->type) == PB_HTYPE_ARRAY) 00719 status = pb_decode(&substream, submsg_fields, dest); 00720 else 00721 status = pb_decode_noinit(&substream, submsg_fields, dest); 00722 00723 pb_close_string_substream(stream, &substream); 00724 return status; 00725 }
Generated on Tue Jul 12 2022 21:22:20 by 1.7.2