| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 | 
							- /* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
 
-  *
 
-  * 2014 Petteri Aimonen <jpa@kapsi.fi>
 
-  */
 
- #include "pb_common.h"
 
- static bool load_descriptor_values(pb_field_iter_t *iter)
 
- {
 
-     uint32_t word0;
 
-     uint32_t data_offset;
 
-     int_least8_t size_offset;
 
-     if (iter->index >= iter->descriptor->field_count)
 
-         return false;
 
-     word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
 
-     iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
 
-     switch(word0 & 3)
 
-     {
 
-         case 0: {
 
-             /* 1-word format */
 
-             iter->array_size = 1;
 
-             iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
 
-             size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
 
-             data_offset = (word0 >> 16) & 0xFF;
 
-             iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
 
-             break;
 
-         }
 
-         case 1: {
 
-             /* 2-word format */
 
-             uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
 
-             iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
 
-             iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
 
-             size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
 
-             data_offset = word1 & 0xFFFF;
 
-             iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
 
-             break;
 
-         }
 
-         case 2: {
 
-             /* 4-word format */
 
-             uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
 
-             uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
 
-             uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
 
-             iter->array_size = (pb_size_t)(word0 >> 16);
 
-             iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
 
-             size_offset = (int_least8_t)(word1 & 0xFF);
 
-             data_offset = word2;
 
-             iter->data_size = (pb_size_t)word3;
 
-             break;
 
-         }
 
-         default: {
 
-             /* 8-word format */
 
-             uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
 
-             uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
 
-             uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
 
-             uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
 
-             iter->array_size = (pb_size_t)word4;
 
-             iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
 
-             size_offset = (int_least8_t)(word1 & 0xFF);
 
-             data_offset = word2;
 
-             iter->data_size = (pb_size_t)word3;
 
-             break;
 
-         }
 
-     }
 
-     if (!iter->message)
 
-     {
 
-         /* Avoid doing arithmetic on null pointers, it is undefined */
 
-         iter->pField = NULL;
 
-         iter->pSize = NULL;
 
-     }
 
-     else
 
-     {
 
-         iter->pField = (char*)iter->message + data_offset;
 
-         if (size_offset)
 
-         {
 
-             iter->pSize = (char*)iter->pField - size_offset;
 
-         }
 
-         else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
 
-                  (PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
 
-                   PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
 
-         {
 
-             /* Fixed count array */
 
-             iter->pSize = &iter->array_size;
 
-         }
 
-         else
 
-         {
 
-             iter->pSize = NULL;
 
-         }
 
-         if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
 
-         {
 
-             iter->pData = *(void**)iter->pField;
 
-         }
 
-         else
 
-         {
 
-             iter->pData = iter->pField;
 
-         }
 
-     }
 
-     if (PB_LTYPE_IS_SUBMSG(iter->type))
 
-     {
 
-         iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
 
-     }
 
-     else
 
-     {
 
-         iter->submsg_desc = NULL;
 
-     }
 
-     return true;
 
- }
 
- static void advance_iterator(pb_field_iter_t *iter)
 
- {
 
-     iter->index++;
 
-     if (iter->index >= iter->descriptor->field_count)
 
-     {
 
-         /* Restart */
 
-         iter->index = 0;
 
-         iter->field_info_index = 0;
 
-         iter->submessage_index = 0;
 
-         iter->required_field_index = 0;
 
-     }
 
-     else
 
-     {
 
-         /* Increment indexes based on previous field type.
 
-          * All field info formats have the following fields:
 
-          * - lowest 2 bits tell the amount of words in the descriptor (2^n words)
 
-          * - bits 2..7 give the lowest bits of tag number.
 
-          * - bits 8..15 give the field type.
 
-          */
 
-         uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
 
-         pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
 
-         pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
 
-         /* Add to fields.
 
-          * The cast to pb_size_t is needed to avoid -Wconversion warning.
 
-          * Because the data is is constants from generator, there is no danger of overflow.
 
-          */
 
-         iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
 
-         iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
 
-         iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
 
-     }
 
- }
 
- bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
 
- {
 
-     memset(iter, 0, sizeof(*iter));
 
-     iter->descriptor = desc;
 
-     iter->message = message;
 
-     return load_descriptor_values(iter);
 
- }
 
- bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
 
- {
 
-     const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
 
-     bool status;
 
-     uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
 
-     if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
 
-     {
 
-         /* For pointer extensions, the pointer is stored directly
 
-          * in the extension structure. This avoids having an extra
 
-          * indirection. */
 
-         status = pb_field_iter_begin(iter, msg, &extension->dest);
 
-     }
 
-     else
 
-     {
 
-         status = pb_field_iter_begin(iter, msg, extension->dest);
 
-     }
 
-     iter->pSize = &extension->found;
 
-     return status;
 
- }
 
- bool pb_field_iter_next(pb_field_iter_t *iter)
 
- {
 
-     advance_iterator(iter);
 
-     (void)load_descriptor_values(iter);
 
-     return iter->index != 0;
 
- }
 
- bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
 
- {
 
-     if (iter->tag == tag)
 
-     {
 
-         return true; /* Nothing to do, correct field already. */
 
-     }
 
-     else if (tag > iter->descriptor->largest_tag)
 
-     {
 
-         return false;
 
-     }
 
-     else
 
-     {
 
-         pb_size_t start = iter->index;
 
-         uint32_t fieldinfo;
 
-         if (tag < iter->tag)
 
-         {
 
-             /* Fields are in tag number order, so we know that tag is between
 
-              * 0 and our start position. Setting index to end forces
 
-              * advance_iterator() call below to restart from beginning. */
 
-             iter->index = iter->descriptor->field_count;
 
-         }
 
-         do
 
-         {
 
-             /* Advance iterator but don't load values yet */
 
-             advance_iterator(iter);
 
-             /* Do fast check for tag number match */
 
-             fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
 
-             if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
 
-             {
 
-                 /* Good candidate, check further */
 
-                 (void)load_descriptor_values(iter);
 
-                 if (iter->tag == tag &&
 
-                     PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
 
-                 {
 
-                     /* Found it */
 
-                     return true;
 
-                 }
 
-             }
 
-         } while (iter->index != start);
 
-         /* Searched all the way back to start, and found nothing. */
 
-         (void)load_descriptor_values(iter);
 
-         return false;
 
-     }
 
- }
 
- bool pb_field_iter_find_extension(pb_field_iter_t *iter)
 
- {
 
-     if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
 
-     {
 
-         return true;
 
-     }
 
-     else
 
-     {
 
-         pb_size_t start = iter->index;
 
-         uint32_t fieldinfo;
 
-         do
 
-         {
 
-             /* Advance iterator but don't load values yet */
 
-             advance_iterator(iter);
 
-             /* Do fast check for field type */
 
-             fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
 
-             if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
 
-             {
 
-                 return load_descriptor_values(iter);
 
-             }
 
-         } while (iter->index != start);
 
-         /* Searched all the way back to start, and found nothing. */
 
-         (void)load_descriptor_values(iter);
 
-         return false;
 
-     }
 
- }
 
- static void *pb_const_cast(const void *p)
 
- {
 
-     /* Note: this casts away const, in order to use the common field iterator
 
-      * logic for both encoding and decoding. The cast is done using union
 
-      * to avoid spurious compiler warnings. */
 
-     union {
 
-         void *p1;
 
-         const void *p2;
 
-     } t;
 
-     t.p2 = p;
 
-     return t.p1;
 
- }
 
- bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
 
- {
 
-     return pb_field_iter_begin(iter, desc, pb_const_cast(message));
 
- }
 
- bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
 
- {
 
-     return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
 
- }
 
- bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
 
- {
 
-     if (field->data_size == sizeof(pb_callback_t))
 
-     {
 
-         pb_callback_t *pCallback = (pb_callback_t*)field->pData;
 
-         if (pCallback != NULL)
 
-         {
 
-             if (istream != NULL && pCallback->funcs.decode != NULL)
 
-             {
 
-                 return pCallback->funcs.decode(istream, field, &pCallback->arg);
 
-             }
 
-             if (ostream != NULL && pCallback->funcs.encode != NULL)
 
-             {
 
-                 return pCallback->funcs.encode(ostream, field, &pCallback->arg);
 
-             }
 
-         }
 
-     }
 
-     return true; /* Success, but didn't do anything */
 
- }
 
- #ifdef PB_VALIDATE_UTF8
 
- /* This function checks whether a string is valid UTF-8 text.
 
-  *
 
-  * Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
 
-  * Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
 
-  * Licensed under "Short code license", which allows use under MIT license or
 
-  * any compatible with it.
 
-  */
 
- bool pb_validate_utf8(const char *str)
 
- {
 
-     const pb_byte_t *s = (const pb_byte_t*)str;
 
-     while (*s)
 
-     {
 
-         if (*s < 0x80)
 
-         {
 
-             /* 0xxxxxxx */
 
-             s++;
 
-         }
 
-         else if ((s[0] & 0xe0) == 0xc0)
 
-         {
 
-             /* 110XXXXx 10xxxxxx */
 
-             if ((s[1] & 0xc0) != 0x80 ||
 
-                 (s[0] & 0xfe) == 0xc0)                        /* overlong? */
 
-                 return false;
 
-             else
 
-                 s += 2;
 
-         }
 
-         else if ((s[0] & 0xf0) == 0xe0)
 
-         {
 
-             /* 1110XXXX 10Xxxxxx 10xxxxxx */
 
-             if ((s[1] & 0xc0) != 0x80 ||
 
-                 (s[2] & 0xc0) != 0x80 ||
 
-                 (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) ||    /* overlong? */
 
-                 (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) ||    /* surrogate? */
 
-                 (s[0] == 0xef && s[1] == 0xbf &&
 
-                 (s[2] & 0xfe) == 0xbe))                 /* U+FFFE or U+FFFF? */
 
-                 return false;
 
-             else
 
-                 s += 3;
 
-         }
 
-         else if ((s[0] & 0xf8) == 0xf0)
 
-         {
 
-             /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
 
-             if ((s[1] & 0xc0) != 0x80 ||
 
-                 (s[2] & 0xc0) != 0x80 ||
 
-                 (s[3] & 0xc0) != 0x80 ||
 
-                 (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) ||    /* overlong? */
 
-                 (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
 
-                 return false;
 
-             else
 
-                 s += 4;
 
-         }
 
-         else
 
-         {
 
-             return false;
 
-         }
 
-     }
 
-     return true;
 
- }
 
- #endif
 
 
  |