LCOV - code coverage report
Current view: top level - flamenco/nanopb - pb_common.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 157 226 69.5 %
Date: 2024-11-13 11:58:15 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
       2             :  *
       3             :  * 2014 Petteri Aimonen <jpa@kapsi.fi>
       4             :  */
       5             : 
       6             : #include "pb_common.h"
       7             : 
       8             : static bool load_descriptor_values(pb_field_iter_t *iter)
       9    45590277 : {
      10    45590277 :     uint32_t word0;
      11    45590277 :     uint32_t data_offset;
      12    45590277 :     int_least8_t size_offset;
      13             : 
      14    45590277 :     if (iter->index >= iter->descriptor->field_count)
      15           0 :         return false;
      16             : 
      17    45590277 :     word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
      18    45590277 :     iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
      19             : 
      20    45590277 :     switch(word0 & 3)
      21    45590277 :     {
      22    18992265 :         case 0: {
      23             :             /* 1-word format */
      24    18992265 :             iter->array_size = 1;
      25    18992265 :             iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
      26    18992265 :             size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
      27    18992265 :             data_offset = (word0 >> 16) & 0xFF;
      28    18992265 :             iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
      29    18992265 :             break;
      30           0 :         }
      31             : 
      32    26598012 :         case 1: {
      33             :             /* 2-word format */
      34    26598012 :             uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
      35             : 
      36    26598012 :             iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
      37    26598012 :             iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
      38    26598012 :             size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
      39    26598012 :             data_offset = word1 & 0xFFFF;
      40    26598012 :             iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
      41    26598012 :             break;
      42           0 :         }
      43             : 
      44           0 :         case 2: {
      45             :             /* 4-word format */
      46           0 :             uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
      47           0 :             uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
      48           0 :             uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
      49             : 
      50           0 :             iter->array_size = (pb_size_t)(word0 >> 16);
      51           0 :             iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
      52           0 :             size_offset = (int_least8_t)(word1 & 0xFF);
      53           0 :             data_offset = word2;
      54           0 :             iter->data_size = (pb_size_t)word3;
      55           0 :             break;
      56           0 :         }
      57             : 
      58           0 :         default: {
      59             :             /* 8-word format */
      60           0 :             uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
      61           0 :             uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
      62           0 :             uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
      63           0 :             uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
      64             : 
      65           0 :             iter->array_size = (pb_size_t)word4;
      66           0 :             iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
      67           0 :             size_offset = (int_least8_t)(word1 & 0xFF);
      68           0 :             data_offset = word2;
      69           0 :             iter->data_size = (pb_size_t)word3;
      70           0 :             break;
      71           0 :         }
      72    45590277 :     }
      73             : 
      74    45590277 :     if (!iter->message)
      75           0 :     {
      76             :         /* Avoid doing arithmetic on null pointers, it is undefined */
      77           0 :         iter->pField = NULL;
      78           0 :         iter->pSize = NULL;
      79           0 :     }
      80    45590277 :     else
      81    45590277 :     {
      82    45590277 :         iter->pField = (char*)iter->message + data_offset;
      83             : 
      84    45590277 :         if (size_offset)
      85     5173899 :         {
      86     5173899 :             iter->pSize = (char*)iter->pField - size_offset;
      87     5173899 :         }
      88    40416378 :         else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
      89    40416378 :                  (PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
      90           0 :                   PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
      91           0 :         {
      92             :             /* Fixed count array */
      93           0 :             iter->pSize = &iter->array_size;
      94           0 :         }
      95    40416378 :         else
      96    40416378 :         {
      97    40416378 :             iter->pSize = NULL;
      98    40416378 :         }
      99             : 
     100    45590277 :         if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
     101     4653201 :         {
     102     4653201 :             iter->pData = *(void**)iter->pField;
     103     4653201 :         }
     104    40937076 :         else
     105    40937076 :         {
     106    40937076 :             iter->pData = iter->pField;
     107    40937076 :         }
     108    45590277 :     }
     109             : 
     110    45590277 :     if (PB_LTYPE_IS_SUBMSG(iter->type))
     111     4692555 :     {
     112     4692555 :         iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
     113     4692555 :     }
     114    40897722 :     else
     115    40897722 :     {
     116    40897722 :         iter->submsg_desc = NULL;
     117    40897722 :     }
     118             : 
     119    45590277 :     return true;
     120    45590277 : }
     121             : 
     122             : static void advance_iterator(pb_field_iter_t *iter)
     123    39541161 : {
     124    39541161 :     iter->index++;
     125             : 
     126    39541161 :     if (iter->index >= iter->descriptor->field_count)
     127     7189734 :     {
     128             :         /* Restart */
     129     7189734 :         iter->index = 0;
     130     7189734 :         iter->field_info_index = 0;
     131     7189734 :         iter->submessage_index = 0;
     132     7189734 :         iter->required_field_index = 0;
     133     7189734 :     }
     134    32351427 :     else
     135    32351427 :     {
     136             :         /* Increment indexes based on previous field type.
     137             :          * All field info formats have the following fields:
     138             :          * - lowest 2 bits tell the amount of words in the descriptor (2^n words)
     139             :          * - bits 2..7 give the lowest bits of tag number.
     140             :          * - bits 8..15 give the field type.
     141             :          */
     142    32351427 :         uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
     143    32351427 :         pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
     144    32351427 :         pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
     145             : 
     146             :         /* Add to fields.
     147             :          * The cast to pb_size_t is needed to avoid -Wconversion warning.
     148             :          * Because the data is is constants from generator, there is no danger of overflow.
     149             :          */
     150    32351427 :         iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
     151    32351427 :         iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
     152    32351427 :         iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
     153    32351427 :     }
     154    39541161 : }
     155             : 
     156             : bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
     157     8095596 : {
     158     8095596 :     memset(iter, 0, sizeof(*iter));
     159             : 
     160     8095596 :     iter->descriptor = desc;
     161     8095596 :     iter->message = message;
     162             : 
     163     8095596 :     return load_descriptor_values(iter);
     164     8095596 : }
     165             : 
     166             : bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
     167           0 : {
     168           0 :     const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
     169           0 :     bool status;
     170             : 
     171           0 :     uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
     172           0 :     if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
     173           0 :     {
     174             :         /* For pointer extensions, the pointer is stored directly
     175             :          * in the extension structure. This avoids having an extra
     176             :          * indirection. */
     177           0 :         status = pb_field_iter_begin(iter, msg, &extension->dest);
     178           0 :     }
     179           0 :     else
     180           0 :     {
     181           0 :         status = pb_field_iter_begin(iter, msg, extension->dest);
     182           0 :     }
     183             : 
     184           0 :     iter->pSize = &extension->found;
     185           0 :     return status;
     186           0 : }
     187             : 
     188             : bool pb_field_iter_next(pb_field_iter_t *iter)
     189    30984972 : {
     190    30984972 :     advance_iterator(iter);
     191    30984972 :     (void)load_descriptor_values(iter);
     192    30984972 :     return iter->index != 0;
     193    30984972 : }
     194             : 
     195             : bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
     196    11958273 : {
     197    11958273 :     if (iter->tag == tag)
     198     5427570 :     {
     199     5427570 :         return true; /* Nothing to do, correct field already. */
     200     5427570 :     }
     201     6530703 :     else if (tag > iter->descriptor->largest_tag)
     202       21027 :     {
     203       21027 :         return false;
     204       21027 :     }
     205     6509676 :     else
     206     6509676 :     {
     207     6509676 :         pb_size_t start = iter->index;
     208     6509676 :         uint32_t fieldinfo;
     209             : 
     210     6509676 :         if (tag < iter->tag)
     211           0 :         {
     212             :             /* Fields are in tag number order, so we know that tag is between
     213             :              * 0 and our start position. Setting index to end forces
     214             :              * advance_iterator() call below to restart from beginning. */
     215           0 :             iter->index = iter->descriptor->field_count;
     216           0 :         }
     217             : 
     218     6509676 :         do
     219     8556075 :         {
     220             :             /* Advance iterator but don't load values yet */
     221     8556075 :             advance_iterator(iter);
     222             : 
     223             :             /* Do fast check for tag number match */
     224     8556075 :             fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
     225             : 
     226     8556075 :             if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
     227     6509676 :             {
     228             :                 /* Good candidate, check further */
     229     6509676 :                 (void)load_descriptor_values(iter);
     230             : 
     231     6509676 :                 if (iter->tag == tag &&
     232     6509676 :                     PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
     233     6509676 :                 {
     234             :                     /* Found it */
     235     6509676 :                     return true;
     236     6509676 :                 }
     237     6509676 :             }
     238     8556075 :         } while (iter->index != start);
     239             : 
     240             :         /* Searched all the way back to start, and found nothing. */
     241           0 :         (void)load_descriptor_values(iter);
     242           0 :         return false;
     243     6509676 :     }
     244    11958273 : }
     245             : 
     246             : bool pb_field_iter_find_extension(pb_field_iter_t *iter)
     247          33 : {
     248          33 :     if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
     249           0 :     {
     250           0 :         return true;
     251           0 :     }
     252          33 :     else
     253          33 :     {
     254          33 :         pb_size_t start = iter->index;
     255          33 :         uint32_t fieldinfo;
     256             : 
     257          33 :         do
     258         114 :         {
     259             :             /* Advance iterator but don't load values yet */
     260         114 :             advance_iterator(iter);
     261             : 
     262             :             /* Do fast check for field type */
     263         114 :             fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
     264             : 
     265         114 :             if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
     266           0 :             {
     267           0 :                 return load_descriptor_values(iter);
     268           0 :             }
     269         114 :         } while (iter->index != start);
     270             : 
     271             :         /* Searched all the way back to start, and found nothing. */
     272          33 :         (void)load_descriptor_values(iter);
     273          33 :         return false;
     274          33 :     }
     275          33 : }
     276             : 
     277             : static void *pb_const_cast(const void *p)
     278       34116 : {
     279             :     /* Note: this casts away const, in order to use the common field iterator
     280             :      * logic for both encoding and decoding. The cast is done using union
     281             :      * to avoid spurious compiler warnings. */
     282       34116 :     union {
     283       34116 :         void *p1;
     284       34116 :         const void *p2;
     285       34116 :     } t;
     286       34116 :     t.p2 = p;
     287       34116 :     return t.p1;
     288       34116 : }
     289             : 
     290             : bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
     291       34116 : {
     292       34116 :     return pb_field_iter_begin(iter, desc, pb_const_cast(message));
     293       34116 : }
     294             : 
     295             : bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
     296           0 : {
     297           0 :     return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
     298           0 : }
     299             : 
     300             : bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
     301      280929 : {
     302      280929 :     if (field->data_size == sizeof(pb_callback_t))
     303      280929 :     {
     304      280929 :         pb_callback_t *pCallback = (pb_callback_t*)field->pData;
     305             : 
     306      280929 :         if (pCallback != NULL)
     307      280929 :         {
     308      280929 :             if (istream != NULL && pCallback->funcs.decode != NULL)
     309           0 :             {
     310           0 :                 return pCallback->funcs.decode(istream, field, &pCallback->arg);
     311           0 :             }
     312             : 
     313      280929 :             if (ostream != NULL && pCallback->funcs.encode != NULL)
     314           0 :             {
     315           0 :                 return pCallback->funcs.encode(ostream, field, &pCallback->arg);
     316           0 :             }
     317      280929 :         }
     318      280929 :     }
     319             : 
     320      280929 :     return true; /* Success, but didn't do anything */
     321             : 
     322      280929 : }
     323             : 
     324             : #ifdef PB_VALIDATE_UTF8
     325             : 
     326             : /* This function checks whether a string is valid UTF-8 text.
     327             :  *
     328             :  * Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
     329             :  * Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
     330             :  * Licensed under "Short code license", which allows use under MIT license or
     331             :  * any compatible with it.
     332             :  */
     333             : 
     334             : bool pb_validate_utf8(const char *str)
     335             : {
     336             :     const pb_byte_t *s = (const pb_byte_t*)str;
     337             :     while (*s)
     338             :     {
     339             :         if (*s < 0x80)
     340             :         {
     341             :             /* 0xxxxxxx */
     342             :             s++;
     343             :         }
     344             :         else if ((s[0] & 0xe0) == 0xc0)
     345             :         {
     346             :             /* 110XXXXx 10xxxxxx */
     347             :             if ((s[1] & 0xc0) != 0x80 ||
     348             :                 (s[0] & 0xfe) == 0xc0)                        /* overlong? */
     349             :                 return false;
     350             :             else
     351             :                 s += 2;
     352             :         }
     353             :         else if ((s[0] & 0xf0) == 0xe0)
     354             :         {
     355             :             /* 1110XXXX 10Xxxxxx 10xxxxxx */
     356             :             if ((s[1] & 0xc0) != 0x80 ||
     357             :                 (s[2] & 0xc0) != 0x80 ||
     358             :                 (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) ||    /* overlong? */
     359             :                 (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) ||    /* surrogate? */
     360             :                 (s[0] == 0xef && s[1] == 0xbf &&
     361             :                 (s[2] & 0xfe) == 0xbe))                 /* U+FFFE or U+FFFF? */
     362             :                 return false;
     363             :             else
     364             :                 s += 3;
     365             :         }
     366             :         else if ((s[0] & 0xf8) == 0xf0)
     367             :         {
     368             :             /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
     369             :             if ((s[1] & 0xc0) != 0x80 ||
     370             :                 (s[2] & 0xc0) != 0x80 ||
     371             :                 (s[3] & 0xc0) != 0x80 ||
     372             :                 (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) ||    /* overlong? */
     373             :                 (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
     374             :                 return false;
     375             :             else
     376             :                 s += 4;
     377             :         }
     378             :         else
     379             :         {
     380             :             return false;
     381             :         }
     382             :     }
     383             : 
     384             :     return true;
     385             : }
     386             : 
     387             : #endif
     388             : 

Generated by: LCOV version 1.14