| /* 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 |
| |