Nanopb (lightweight version of googles protobuf) test. It is not working as it should yet.

Dependencies:   MODSERIAL mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pb_encode.c Source File

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