Coverage Report

Created: 2025-11-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nanopb/pb_common.c
Line
Count
Source
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
48.0M
{
10
48.0M
    uint32_t word0;
11
48.0M
    uint32_t data_offset;
12
48.0M
    int_least8_t size_offset;
13
14
48.0M
    if (iter->index >= iter->descriptor->field_count)
15
667k
        return false;
16
17
47.3M
    word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
18
47.3M
    iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
19
20
47.3M
    switch(word0 & 3)
21
47.3M
    {
22
16.2M
        case 0: {
23
            /* 1-word format */
24
16.2M
            iter->array_size = 1;
25
16.2M
            iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
26
16.2M
            size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
27
16.2M
            data_offset = (word0 >> 16) & 0xFF;
28
16.2M
            iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
29
16.2M
            break;
30
0
        }
31
32
29.5M
        case 1: {
33
            /* 2-word format */
34
29.5M
            uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
35
36
29.5M
            iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
37
29.5M
            iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
38
29.5M
            size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
39
29.5M
            data_offset = word1 & 0xFFFF;
40
29.5M
            iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
41
29.5M
            break;
42
0
        }
43
44
1.27M
        case 2: {
45
            /* 4-word format */
46
1.27M
            uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
47
1.27M
            uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
48
1.27M
            uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
49
50
1.27M
            iter->array_size = (pb_size_t)(word0 >> 16);
51
1.27M
            iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
52
1.27M
            size_offset = (int_least8_t)(word1 & 0xFF);
53
1.27M
            data_offset = word2;
54
1.27M
            iter->data_size = (pb_size_t)word3;
55
1.27M
            break;
56
0
        }
57
58
281k
        default: {
59
            /* 8-word format */
60
281k
            uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
61
281k
            uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
62
281k
            uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
63
281k
            uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
64
65
281k
            iter->array_size = (pb_size_t)word4;
66
281k
            iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
67
281k
            size_offset = (int_least8_t)(word1 & 0xFF);
68
281k
            data_offset = word2;
69
281k
            iter->data_size = (pb_size_t)word3;
70
281k
            break;
71
0
        }
72
47.3M
    }
73
74
47.3M
    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
47.3M
    else
81
47.3M
    {
82
47.3M
        iter->pField = (char*)iter->message + data_offset;
83
84
47.3M
        if (size_offset)
85
4.94M
        {
86
4.94M
            iter->pSize = (char*)iter->pField - size_offset;
87
4.94M
        }
88
42.4M
        else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
89
549k
                 (PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
90
451k
                  PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
91
210k
        {
92
            /* Fixed count array */
93
210k
            iter->pSize = &iter->array_size;
94
210k
        }
95
42.2M
        else
96
42.2M
        {
97
42.2M
            iter->pSize = NULL;
98
42.2M
        }
99
100
47.3M
        if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
101
36.5M
        {
102
36.5M
            iter->pData = *(void**)iter->pField;
103
36.5M
        }
104
10.8M
        else
105
10.8M
        {
106
10.8M
            iter->pData = iter->pField;
107
10.8M
        }
108
47.3M
    }
109
110
47.3M
    if (PB_LTYPE_IS_SUBMSG(iter->type))
111
2.33M
    {
112
2.33M
        iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
113
2.33M
    }
114
45.0M
    else
115
45.0M
    {
116
45.0M
        iter->submsg_desc = NULL;
117
45.0M
    }
118
119
47.3M
    return true;
120
47.3M
}
121
122
static void advance_iterator(pb_field_iter_t *iter)
123
105M
{
124
105M
    iter->index++;
125
126
105M
    if (iter->index >= iter->descriptor->field_count)
127
10.6M
    {
128
        /* Restart */
129
10.6M
        iter->index = 0;
130
10.6M
        iter->field_info_index = 0;
131
10.6M
        iter->submessage_index = 0;
132
10.6M
        iter->required_field_index = 0;
133
10.6M
    }
134
95.0M
    else
135
95.0M
    {
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
95.0M
        uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
143
95.0M
        pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
144
95.0M
        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
95.0M
        iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
151
95.0M
        iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
152
95.0M
        iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
153
95.0M
    }
154
105M
}
155
156
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
157
9.06M
{
158
9.06M
    memset(iter, 0, sizeof(*iter));
159
160
9.06M
    iter->descriptor = desc;
161
9.06M
    iter->message = message;
162
163
9.06M
    return load_descriptor_values(iter);
164
9.06M
}
165
166
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
167
269k
{
168
269k
    const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
169
269k
    bool status;
170
171
269k
    uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
172
269k
    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
269k
    else
180
269k
    {
181
269k
        status = pb_field_iter_begin(iter, msg, extension->dest);
182
269k
    }
183
184
269k
    iter->pSize = &extension->found;
185
269k
    return status;
186
269k
}
187
188
bool pb_field_iter_next(pb_field_iter_t *iter)
189
32.4M
{
190
32.4M
    advance_iterator(iter);
191
32.4M
    (void)load_descriptor_values(iter);
192
32.4M
    return iter->index != 0;
193
32.4M
}
194
195
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
196
66.6M
{
197
66.6M
    if (iter->tag == tag)
198
58.1M
    {
199
58.1M
        return true; /* Nothing to do, correct field already. */
200
58.1M
    }
201
8.54M
    else if (tag > iter->descriptor->largest_tag)
202
2.77M
    {
203
2.77M
        return false;
204
2.77M
    }
205
5.77M
    else
206
5.77M
    {
207
5.77M
        pb_size_t start = iter->index;
208
5.77M
        uint32_t fieldinfo;
209
210
5.77M
        if (tag < iter->tag)
211
1.97M
        {
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
1.97M
            iter->index = iter->descriptor->field_count;
216
1.97M
        }
217
218
5.77M
        do
219
72.3M
        {
220
            /* Advance iterator but don't load values yet */
221
72.3M
            advance_iterator(iter);
222
223
            /* Do fast check for tag number match */
224
72.3M
            fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
225
226
72.3M
            if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
227
5.86M
            {
228
                /* Good candidate, check further */
229
5.86M
                (void)load_descriptor_values(iter);
230
231
5.86M
                if (iter->tag == tag &&
232
5.15M
                    PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
233
5.12M
                {
234
                    /* Found it */
235
5.12M
                    return true;
236
5.12M
                }
237
5.86M
            }
238
72.3M
        } while (iter->index != start);
239
240
        /* Searched all the way back to start, and found nothing. */
241
648k
        (void)load_descriptor_values(iter);
242
648k
        return false;
243
5.77M
    }
244
66.6M
}
245
246
bool pb_field_iter_find_extension(pb_field_iter_t *iter)
247
57.3k
{
248
57.3k
    if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
249
0
    {
250
0
        return true;
251
0
    }
252
57.3k
    else
253
57.3k
    {
254
57.3k
        pb_size_t start = iter->index;
255
57.3k
        uint32_t fieldinfo;
256
257
57.3k
        do
258
948k
        {
259
            /* Advance iterator but don't load values yet */
260
948k
            advance_iterator(iter);
261
262
            /* Do fast check for field type */
263
948k
            fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
264
265
948k
            if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
266
14.8k
            {
267
14.8k
                return load_descriptor_values(iter);
268
14.8k
            }
269
948k
        } while (iter->index != start);
270
271
        /* Searched all the way back to start, and found nothing. */
272
42.4k
        (void)load_descriptor_values(iter);
273
42.4k
        return false;
274
57.3k
    }
275
57.3k
}
276
277
static void *pb_const_cast(const void *p)
278
3.93M
{
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
3.93M
    union {
283
3.93M
        void *p1;
284
3.93M
        const void *p2;
285
3.93M
    } t;
286
3.93M
    t.p2 = p;
287
3.93M
    return t.p1;
288
3.93M
}
289
290
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
291
3.92M
{
292
3.92M
    return pb_field_iter_begin(iter, desc, pb_const_cast(message));
293
3.92M
}
294
295
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
296
5.22k
{
297
5.22k
    return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
298
5.22k
}
299
300
bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
301
117k
{
302
117k
    if (field->data_size == sizeof(pb_callback_t))
303
117k
    {
304
117k
        pb_callback_t *pCallback = (pb_callback_t*)field->pData;
305
306
117k
        if (pCallback != NULL)
307
117k
        {
308
117k
            if (istream != NULL && pCallback->funcs.decode != NULL)
309
7.39k
            {
310
7.39k
                return pCallback->funcs.decode(istream, field, &pCallback->arg);
311
7.39k
            }
312
313
110k
            if (ostream != NULL && pCallback->funcs.encode != NULL)
314
0
            {
315
0
                return pCallback->funcs.encode(ostream, field, &pCallback->arg);
316
0
            }
317
110k
        }
318
117k
    }
319
320
110k
    return true; /* Success, but didn't do anything */
321
322
117k
}
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