Tomas Johansen
/
nanopb_test
Nanopb (lightweight version of googles protobuf) test. It is not working as it should yet.
Embed:
(wiki syntax)
Show/hide line numbers
pb_encode.c
00001 /* pb_encode.c -- encode a protobuf using minimal resources 00002 * 00003 * 2011 Petteri Aimonen <jpa@kapsi.fi> 00004 */ 00005 00006 #define NANOPB_INTERNALS 00007 #include "pb.h" 00008 #include "pb_encode.h" 00009 00010 /* Use the GCC warn_unused_result attribute to check that all return values 00011 * are propagated correctly. On other compilers and gcc before 3.4.0 just 00012 * ignore the annotation. 00013 */ 00014 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) 00015 #define checkreturn 00016 #else 00017 #define checkreturn __attribute__((warn_unused_result)) 00018 #endif 00019 00020 /************************************** 00021 * Declarations internal to this file * 00022 **************************************/ 00023 typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; 00024 00025 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); 00026 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); 00027 static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); 00028 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); 00029 static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); 00030 static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00031 static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00032 static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00033 static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00034 static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00035 static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00036 static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00037 static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); 00038 00039 /* --- Function pointers to field encoders --- 00040 * Order in the array must match pb_action_t LTYPE numbering. 00041 */ 00042 static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { 00043 &pb_enc_varint, 00044 &pb_enc_uvarint, 00045 &pb_enc_svarint, 00046 &pb_enc_fixed32, 00047 &pb_enc_fixed64, 00048 00049 &pb_enc_bytes, 00050 &pb_enc_string, 00051 &pb_enc_submessage, 00052 NULL /* extensions */ 00053 }; 00054 00055 /******************************* 00056 * pb_ostream_t implementation * 00057 *******************************/ 00058 00059 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) 00060 { 00061 uint8_t *dest = (uint8_t*)stream->state; 00062 stream->state = dest + count; 00063 00064 while (count--) 00065 *dest++ = *buf++; 00066 00067 return true; 00068 } 00069 00070 pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize) 00071 { 00072 pb_ostream_t stream; 00073 #ifdef PB_BUFFER_ONLY 00074 stream.callback = (void*)1; /* Just a marker value */ 00075 #else 00076 stream.callback = &buf_write; 00077 #endif 00078 stream.state = buf; 00079 stream.max_size = bufsize; 00080 stream.bytes_written = 0; 00081 #ifndef PB_NO_ERRMSG 00082 stream.errmsg = NULL; 00083 #endif 00084 return stream; 00085 } 00086 00087 bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) 00088 { 00089 if (stream->callback != NULL) 00090 { 00091 if (stream->bytes_written + count > stream->max_size) 00092 PB_RETURN_ERROR(stream, "stream full"); 00093 00094 #ifdef PB_BUFFER_ONLY 00095 if (!buf_write(stream, buf, count)) 00096 PB_RETURN_ERROR(stream, "io error"); 00097 #else 00098 if (!stream->callback(stream, buf, count)) 00099 PB_RETURN_ERROR(stream, "io error"); 00100 #endif 00101 } 00102 00103 stream->bytes_written += count; 00104 return true; 00105 } 00106 00107 /************************* 00108 * Encode a single field * 00109 *************************/ 00110 00111 /* Encode a static array. Handles the size calculations and possible packing. */ 00112 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, 00113 const void *pData, size_t count, pb_encoder_t func) 00114 { 00115 size_t i; 00116 const void *p; 00117 size_t size; 00118 00119 if (count == 0) 00120 return true; 00121 00122 if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) 00123 PB_RETURN_ERROR(stream, "array max size exceeded"); 00124 00125 /* We always pack arrays if the datatype allows it. */ 00126 if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) 00127 { 00128 if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) 00129 return false; 00130 00131 /* Determine the total size of packed array. */ 00132 if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) 00133 { 00134 size = 4 * count; 00135 } 00136 else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) 00137 { 00138 size = 8 * count; 00139 } 00140 else 00141 { 00142 pb_ostream_t sizestream = PB_OSTREAM_SIZING; 00143 p = pData; 00144 for (i = 0; i < count; i++) 00145 { 00146 if (!func(&sizestream, field, p)) 00147 return false; 00148 p = (const char*)p + field->data_size; 00149 } 00150 size = sizestream.bytes_written; 00151 } 00152 00153 if (!pb_encode_varint(stream, (uint64_t)size)) 00154 return false; 00155 00156 if (stream->callback == NULL) 00157 return pb_write(stream, NULL, size); /* Just sizing.. */ 00158 00159 /* Write the data */ 00160 p = pData; 00161 for (i = 0; i < count; i++) 00162 { 00163 if (!func(stream, field, p)) 00164 return false; 00165 p = (const char*)p + field->data_size; 00166 } 00167 } 00168 else 00169 { 00170 p = pData; 00171 for (i = 0; i < count; i++) 00172 { 00173 if (!pb_encode_tag_for_field(stream, field)) 00174 return false; 00175 00176 /* Normally the data is stored directly in the array entries, but 00177 * for pointer-type string fields, the array entries are actually 00178 * string pointers. So we have to dereference once more to get to 00179 * the character data. */ 00180 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && 00181 PB_LTYPE(field->type) == PB_LTYPE_STRING) 00182 { 00183 if (!func(stream, field, *(const void* const*)p)) 00184 return false; 00185 } 00186 else 00187 { 00188 if (!func(stream, field, p)) 00189 return false; 00190 } 00191 p = (const char*)p + field->data_size; 00192 } 00193 } 00194 00195 return true; 00196 } 00197 00198 /* Encode a field with static or pointer allocation, i.e. one whose data 00199 * is available to the encoder directly. */ 00200 static bool checkreturn encode_basic_field(pb_ostream_t *stream, 00201 const pb_field_t *field, const void *pData) 00202 { 00203 pb_encoder_t func; 00204 const void *pSize; 00205 bool implicit_has = true; 00206 00207 func = PB_ENCODERS[PB_LTYPE(field->type)]; 00208 00209 if (field->size_offset) 00210 pSize = (const char*)pData + field->size_offset; 00211 else 00212 pSize = &implicit_has; 00213 00214 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 00215 { 00216 /* pData is a pointer to the field, which contains pointer to 00217 * the data. If the 2nd pointer is NULL, it is interpreted as if 00218 * the has_field was false. 00219 */ 00220 00221 pData = *(const void* const*)pData; 00222 implicit_has = (pData != NULL); 00223 } 00224 00225 switch (PB_HTYPE(field->type)) 00226 { 00227 case PB_HTYPE_REQUIRED: 00228 if (!pData) 00229 PB_RETURN_ERROR(stream, "missing required field"); 00230 if (!pb_encode_tag_for_field(stream, field)) 00231 return false; 00232 if (!func(stream, field, pData)) 00233 return false; 00234 break; 00235 00236 case PB_HTYPE_OPTIONAL: 00237 if (*(const bool*)pSize) 00238 { 00239 if (!pb_encode_tag_for_field(stream, field)) 00240 return false; 00241 00242 if (!func(stream, field, pData)) 00243 return false; 00244 } 00245 break; 00246 00247 case PB_HTYPE_REPEATED: 00248 if (!encode_array(stream, field, pData, *(const size_t*)pSize, func)) 00249 return false; 00250 break; 00251 00252 default: 00253 PB_RETURN_ERROR(stream, "invalid field type"); 00254 } 00255 00256 return true; 00257 } 00258 00259 /* Encode a field with callback semantics. This means that a user function is 00260 * called to provide and encode the actual data. */ 00261 static bool checkreturn encode_callback_field(pb_ostream_t *stream, 00262 const pb_field_t *field, const void *pData) 00263 { 00264 const pb_callback_t *callback = (const pb_callback_t*)pData; 00265 00266 #ifdef PB_OLD_CALLBACK_STYLE 00267 const void *arg = callback->arg; 00268 #else 00269 void * const *arg = &(callback->arg); 00270 #endif 00271 00272 if (callback->funcs.encode != NULL) 00273 { 00274 if (!callback->funcs.encode(stream, field, arg)) 00275 PB_RETURN_ERROR(stream, "callback error"); 00276 } 00277 return true; 00278 } 00279 00280 /* Encode a single field of any callback or static type. */ 00281 static bool checkreturn encode_field(pb_ostream_t *stream, 00282 const pb_field_t *field, const void *pData) 00283 { 00284 switch (PB_ATYPE(field->type)) 00285 { 00286 case PB_ATYPE_STATIC: 00287 case PB_ATYPE_POINTER: 00288 return encode_basic_field(stream, field, pData); 00289 00290 case PB_ATYPE_CALLBACK: 00291 return encode_callback_field(stream, field, pData); 00292 00293 default: 00294 PB_RETURN_ERROR(stream, "invalid field type"); 00295 } 00296 } 00297 00298 /* Default handler for extension fields. Expects to have a pb_field_t 00299 * pointer in the extension->type->arg field. */ 00300 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, 00301 const pb_extension_t *extension) 00302 { 00303 const pb_field_t *field = (const pb_field_t*)extension->type->arg; 00304 return encode_field(stream, field, extension->dest); 00305 } 00306 00307 /* Walk through all the registered extensions and give them a chance 00308 * to encode themselves. */ 00309 static bool checkreturn encode_extension_field(pb_ostream_t *stream, 00310 const pb_field_t *field, const void *pData) 00311 { 00312 const pb_extension_t *extension = *(const pb_extension_t* const *)pData; 00313 UNUSED(field); 00314 00315 while (extension) 00316 { 00317 bool status; 00318 if (extension->type->encode) 00319 status = extension->type->encode(stream, extension); 00320 else 00321 status = default_extension_encoder(stream, extension); 00322 00323 if (!status) 00324 return false; 00325 00326 extension = extension->next; 00327 } 00328 00329 return true; 00330 } 00331 00332 /********************* 00333 * Encode all fields * 00334 *********************/ 00335 00336 bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) 00337 { 00338 const pb_field_t *field = fields; 00339 const void *pData = src_struct; 00340 size_t prev_size = 0; 00341 00342 while (field->tag != 0) 00343 { 00344 pData = (const char*)pData + prev_size + field->data_offset; 00345 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 00346 prev_size = sizeof(const void*); 00347 else 00348 prev_size = field->data_size; 00349 00350 /* Special case for static arrays */ 00351 if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && 00352 PB_HTYPE(field->type) == PB_HTYPE_REPEATED) 00353 { 00354 prev_size *= field->array_size; 00355 } 00356 00357 if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION) 00358 { 00359 /* Special case for the extension field placeholder */ 00360 if (!encode_extension_field(stream, field, pData)) 00361 return false; 00362 } 00363 else 00364 { 00365 /* Regular field */ 00366 if (!encode_field(stream, field, pData)) 00367 return false; 00368 } 00369 00370 field++; 00371 } 00372 00373 return true; 00374 } 00375 00376 bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) 00377 { 00378 return pb_encode_submessage(stream, fields, src_struct); 00379 } 00380 00381 /******************** 00382 * Helper functions * 00383 ********************/ 00384 bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) 00385 { 00386 uint8_t buffer[10]; 00387 size_t i = 0; 00388 00389 if (value == 0) 00390 return pb_write(stream, (uint8_t*)&value, 1); 00391 00392 while (value) 00393 { 00394 buffer[i] = (uint8_t)((value & 0x7F) | 0x80); 00395 value >>= 7; 00396 i++; 00397 } 00398 buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ 00399 00400 return pb_write(stream, buffer, i); 00401 } 00402 00403 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) 00404 { 00405 uint64_t zigzagged; 00406 if (value < 0) 00407 zigzagged = (uint64_t)(~(value << 1)); 00408 else 00409 zigzagged = (uint64_t)(value << 1); 00410 00411 return pb_encode_varint(stream, zigzagged); 00412 } 00413 00414 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) 00415 { 00416 #ifdef __BIG_ENDIAN__ 00417 const uint8_t *bytes = value; 00418 uint8_t lebytes[4]; 00419 lebytes[0] = bytes[3]; 00420 lebytes[1] = bytes[2]; 00421 lebytes[2] = bytes[1]; 00422 lebytes[3] = bytes[0]; 00423 return pb_write(stream, lebytes, 4); 00424 #else 00425 return pb_write(stream, (const uint8_t*)value, 4); 00426 #endif 00427 } 00428 00429 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) 00430 { 00431 #ifdef __BIG_ENDIAN__ 00432 const uint8_t *bytes = value; 00433 uint8_t lebytes[8]; 00434 lebytes[0] = bytes[7]; 00435 lebytes[1] = bytes[6]; 00436 lebytes[2] = bytes[5]; 00437 lebytes[3] = bytes[4]; 00438 lebytes[4] = bytes[3]; 00439 lebytes[5] = bytes[2]; 00440 lebytes[6] = bytes[1]; 00441 lebytes[7] = bytes[0]; 00442 return pb_write(stream, lebytes, 8); 00443 #else 00444 return pb_write(stream, (const uint8_t*)value, 8); 00445 #endif 00446 } 00447 00448 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) 00449 { 00450 uint64_t tag = wiretype | (field_number << 3); 00451 return pb_encode_varint(stream, tag); 00452 } 00453 00454 bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) 00455 { 00456 pb_wire_type_t wiretype; 00457 switch (PB_LTYPE(field->type)) 00458 { 00459 case PB_LTYPE_VARINT: 00460 case PB_LTYPE_UVARINT: 00461 case PB_LTYPE_SVARINT: 00462 wiretype = PB_WT_VARINT; 00463 break; 00464 00465 case PB_LTYPE_FIXED32: 00466 wiretype = PB_WT_32BIT; 00467 break; 00468 00469 case PB_LTYPE_FIXED64: 00470 wiretype = PB_WT_64BIT; 00471 break; 00472 00473 case PB_LTYPE_BYTES: 00474 case PB_LTYPE_STRING: 00475 case PB_LTYPE_SUBMESSAGE: 00476 wiretype = PB_WT_STRING; 00477 break; 00478 00479 default: 00480 PB_RETURN_ERROR(stream, "invalid field type"); 00481 } 00482 00483 return pb_encode_tag(stream, wiretype, field->tag); 00484 } 00485 00486 bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size) 00487 { 00488 if (!pb_encode_varint(stream, (uint64_t)size)) 00489 return false; 00490 00491 return pb_write(stream, buffer, size); 00492 } 00493 00494 bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) 00495 { 00496 /* First calculate the message size using a non-writing substream. */ 00497 pb_ostream_t substream = PB_OSTREAM_SIZING; 00498 size_t size; 00499 bool status; 00500 00501 if (!pb_encode(&substream, fields, src_struct)) 00502 { 00503 #ifndef PB_NO_ERRMSG 00504 stream->errmsg = substream.errmsg; 00505 #endif 00506 return false; 00507 } 00508 00509 size = substream.bytes_written; 00510 00511 if (!pb_encode_varint(stream, (uint64_t)size)) 00512 return false; 00513 00514 if (stream->callback == NULL) 00515 return pb_write(stream, NULL, size); /* Just sizing */ 00516 00517 if (stream->bytes_written + size > stream->max_size) 00518 PB_RETURN_ERROR(stream, "stream full"); 00519 00520 /* Use a substream to verify that a callback doesn't write more than 00521 * what it did the first time. */ 00522 substream.callback = stream->callback; 00523 substream.state = stream->state; 00524 substream.max_size = size; 00525 substream.bytes_written = 0; 00526 #ifndef PB_NO_ERRMSG 00527 substream.errmsg = NULL; 00528 #endif 00529 00530 status = pb_encode(&substream, fields, src_struct); 00531 00532 stream->bytes_written += substream.bytes_written; 00533 stream->state = substream.state; 00534 #ifndef PB_NO_ERRMSG 00535 stream->errmsg = substream.errmsg; 00536 #endif 00537 00538 if (substream.bytes_written != size) 00539 PB_RETURN_ERROR(stream, "submsg size changed"); 00540 00541 return status; 00542 } 00543 00544 /* Field encoders */ 00545 00546 bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00547 { 00548 int64_t value = 0; 00549 00550 /* Cases 1 and 2 are for compilers that have smaller types for bool 00551 * or enums. */ 00552 switch (field->data_size) 00553 { 00554 case 1: value = *(const int8_t*)src; break; 00555 case 2: value = *(const int16_t*)src; break; 00556 case 4: value = *(const int32_t*)src; break; 00557 case 8: value = *(const int64_t*)src; break; 00558 default: PB_RETURN_ERROR(stream, "invalid data_size"); 00559 } 00560 00561 return pb_encode_varint(stream, (uint64_t)value); 00562 } 00563 00564 bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00565 { 00566 uint64_t value = 0; 00567 00568 switch (field->data_size) 00569 { 00570 case 4: value = *(const uint32_t*)src; break; 00571 case 8: value = *(const uint64_t*)src; break; 00572 default: PB_RETURN_ERROR(stream, "invalid data_size"); 00573 } 00574 00575 return pb_encode_varint(stream, value); 00576 } 00577 00578 bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00579 { 00580 int64_t value = 0; 00581 00582 switch (field->data_size) 00583 { 00584 case 4: value = *(const int32_t*)src; break; 00585 case 8: value = *(const int64_t*)src; break; 00586 default: PB_RETURN_ERROR(stream, "invalid data_size"); 00587 } 00588 00589 return pb_encode_svarint(stream, value); 00590 } 00591 00592 bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00593 { 00594 UNUSED(field); 00595 return pb_encode_fixed64(stream, src); 00596 } 00597 00598 bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00599 { 00600 UNUSED(field); 00601 return pb_encode_fixed32(stream, src); 00602 } 00603 00604 bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00605 { 00606 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 00607 { 00608 const pb_bytes_ptr_t *bytes = (const pb_bytes_ptr_t*)src; 00609 return pb_encode_string(stream, bytes->bytes, bytes->size); 00610 } 00611 else 00612 { 00613 const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; 00614 if (bytes->size + offsetof(pb_bytes_array_t, bytes) > field->data_size) 00615 PB_RETURN_ERROR(stream, "bytes size exceeded"); 00616 00617 return pb_encode_string(stream, bytes->bytes, bytes->size); 00618 } 00619 } 00620 00621 bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00622 { 00623 /* strnlen() is not always available, so just use a loop */ 00624 size_t size = 0; 00625 size_t max_size = field->data_size; 00626 const char *p = (const char*)src; 00627 00628 if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) 00629 max_size = (size_t)-1; 00630 00631 while (size < max_size && *p != '\0') 00632 { 00633 size++; 00634 p++; 00635 } 00636 00637 return pb_encode_string(stream, (const uint8_t*)src, size); 00638 } 00639 00640 bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) 00641 { 00642 if (field->ptr == NULL) 00643 PB_RETURN_ERROR(stream, "invalid field descriptor"); 00644 00645 return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); 00646 } 00647 00648
Generated on Thu Jul 14 2022 19:55:28 by 1.7.2