Coverage Report

Created: 2025-07-11 06:29

/src/S2OPC/src/Common/helpers/sopc_buffer.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include <math.h>
21
#include <stdio.h>
22
#include <string.h>
23
24
#include <inttypes.h>
25
#include "sopc_assert.h"
26
#include "sopc_buffer.h"
27
#include "sopc_common_constants.h"
28
#include "sopc_macros.h"
29
#include "sopc_mem_alloc.h"
30
31
/* 2^32 = 4294967296 maximum number you could represent plus \0 at the end */
32
0
#define SOPC_MAX_LENGTH_UINT32_TO_STRING 11
33
34
/* 2^31 = 2147483648 maximum number you could represent plus \0 at the end plus '-'*/
35
0
#define SOPC_MAX_LENGTH_INT32_TO_STRING 12
36
37
/* A MINIMUM of 4 is required  ! (or problems such as infinite management appear.) */
38
0
#define SOPC_PRECISION_PRINTING_FLOAT_NUMBERS 10
39
40
static SOPC_ReturnStatus SOPC_Buffer_Init(SOPC_Buffer* buffer, uint32_t initial_size, uint32_t maximum_size)
41
12.3k
{
42
12.3k
    if (buffer == NULL || initial_size <= 0 || initial_size > maximum_size)
43
0
    {
44
0
        return SOPC_STATUS_INVALID_PARAMETERS;
45
0
    }
46
47
12.3k
    buffer->data = SOPC_Calloc((size_t) initial_size, sizeof(uint8_t));
48
12.3k
    if (NULL == buffer->data)
49
0
    {
50
0
        return SOPC_STATUS_OUT_OF_MEMORY;
51
0
    }
52
53
12.3k
    buffer->position = 0;
54
12.3k
    buffer->length = 0;
55
12.3k
    buffer->initial_size = initial_size;
56
12.3k
    buffer->current_size = initial_size;
57
12.3k
    buffer->maximum_size = maximum_size;
58
59
12.3k
    return SOPC_STATUS_OK;
60
12.3k
}
61
62
SOPC_Buffer* SOPC_Buffer_Create(uint32_t size)
63
4.62k
{
64
4.62k
    SOPC_Buffer* buf = NULL;
65
4.62k
    if (size > 0)
66
4.62k
    {
67
4.62k
        buf = SOPC_Malloc(sizeof(SOPC_Buffer));
68
4.62k
        if (buf != NULL)
69
4.62k
        {
70
4.62k
            SOPC_ReturnStatus status = SOPC_Buffer_Init(buf, size, size);
71
4.62k
            if (status != SOPC_STATUS_OK)
72
0
            {
73
0
                SOPC_Buffer_Delete(buf);
74
0
                buf = NULL;
75
0
            }
76
4.62k
        }
77
4.62k
    }
78
4.62k
    return buf;
79
4.62k
}
80
81
SOPC_Buffer* SOPC_Buffer_CreateResizable(uint32_t initial_size, uint32_t maximum_size)
82
7.69k
{
83
7.69k
    SOPC_Buffer* buf = NULL;
84
7.69k
    if (initial_size > 0)
85
7.69k
    {
86
7.69k
        buf = SOPC_Calloc(1, sizeof(SOPC_Buffer));
87
7.69k
        if (buf != NULL)
88
7.69k
        {
89
7.69k
            SOPC_ReturnStatus status = SOPC_Buffer_Init(buf, initial_size, maximum_size);
90
7.69k
            if (status != SOPC_STATUS_OK)
91
0
            {
92
0
                SOPC_Buffer_Delete(buf);
93
0
                buf = NULL;
94
0
            }
95
7.69k
        }
96
7.69k
    }
97
7.69k
    return buf;
98
7.69k
}
99
100
SOPC_Buffer* SOPC_Buffer_Attach(uint8_t* data, uint32_t size)
101
6.54k
{
102
6.54k
    SOPC_Buffer* b = SOPC_Calloc(1, sizeof(SOPC_Buffer));
103
104
6.54k
    if (b == NULL)
105
0
    {
106
0
        return NULL;
107
0
    }
108
109
6.54k
    b->data = data;
110
6.54k
    b->length = size;
111
6.54k
    b->initial_size = size;
112
6.54k
    b->current_size = size;
113
6.54k
    b->maximum_size = size;
114
115
6.54k
    return b;
116
6.54k
}
117
118
void SOPC_Buffer_Clear(SOPC_Buffer* buffer)
119
12.3k
{
120
12.3k
    if (buffer != NULL)
121
12.3k
    {
122
12.3k
        if (buffer->data != NULL)
123
12.3k
        {
124
12.3k
            SOPC_Free(buffer->data);
125
12.3k
            buffer->data = NULL;
126
12.3k
        }
127
12.3k
    }
128
12.3k
}
129
130
void SOPC_Buffer_Delete(SOPC_Buffer* buffer)
131
16.9k
{
132
16.9k
    if (buffer != NULL)
133
12.3k
    {
134
12.3k
        SOPC_Buffer_Clear(buffer);
135
12.3k
        SOPC_Free(buffer);
136
12.3k
    }
137
16.9k
}
138
139
void SOPC_Buffer_Reset(SOPC_Buffer* buffer)
140
0
{
141
0
    if (buffer != NULL && buffer->data != NULL)
142
0
    {
143
0
        buffer->position = 0;
144
0
        buffer->length = 0;
145
0
        memset(buffer->data, 0, buffer->current_size);
146
0
    }
147
0
}
148
149
SOPC_ReturnStatus SOPC_Buffer_ResetAfterPosition(SOPC_Buffer* buffer, uint32_t position)
150
0
{
151
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
152
0
    if (buffer != NULL && buffer->data != NULL && position <= buffer->length)
153
0
    {
154
0
        status = SOPC_STATUS_OK;
155
0
        buffer->position = position;
156
0
        buffer->length = position;
157
0
        memset(&(buffer->data[buffer->position]), 0, buffer->current_size - buffer->position);
158
0
    }
159
0
    return status;
160
0
}
161
162
SOPC_ReturnStatus SOPC_Buffer_GetPosition(SOPC_Buffer* buffer, uint32_t* position)
163
7.34k
{
164
7.34k
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
165
7.34k
    if (NULL != buffer && NULL != position)
166
7.34k
    {
167
7.34k
        status = SOPC_STATUS_OK;
168
7.34k
        *position = buffer->position;
169
7.34k
    }
170
171
7.34k
    return status;
172
7.34k
}
173
174
SOPC_ReturnStatus SOPC_Buffer_SetPosition(SOPC_Buffer* buffer, uint32_t position)
175
292k
{
176
292k
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
177
292k
    if (buffer != NULL && buffer->data != NULL && buffer->length >= position)
178
292k
    {
179
292k
        status = SOPC_STATUS_OK;
180
292k
        buffer->position = position;
181
292k
    }
182
292k
    return status;
183
292k
}
184
185
SOPC_ReturnStatus SOPC_Buffer_SetDataLength(SOPC_Buffer* buffer, uint32_t length)
186
0
{
187
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
188
0
    uint8_t* data = NULL;
189
0
    if (buffer != NULL && buffer->data != NULL && buffer->current_size >= length && buffer->position <= length)
190
0
    {
191
0
        status = SOPC_STATUS_OK;
192
0
        if (buffer->length > length)
193
0
        {
194
0
            data = &(buffer->data[length]);
195
            // Reset unused bytes to 0
196
0
            memset(data, 0, buffer->length - length);
197
0
        }
198
0
        buffer->length = length;
199
0
    }
200
0
    return status;
201
0
}
202
203
/**
204
 * \brief Check the size of buffer can contains \p totalNbBytes.
205
 *        If it does not and the buffer is resizable:
206
 *        - (if \p exactResize == false) Compute new size to be the first multiple of initial_size
207
 *          that contains \p totalNbBytes or maximum_size if greater than maximum_size
208
 *        - Resize the buffer to the new size
209
 *
210
 *  \return true if buffer is large enough to contains \p totalNbBytes (with or without resize operation),
211
 *          false otherwise
212
 */
213
static bool SOPC_Buffer_CheckSizeAndResize(SOPC_Buffer* buffer, uint32_t totalNbBytes, bool exactResize)
214
14.9M
{
215
14.9M
    SOPC_ASSERT(buffer != NULL);
216
14.9M
    if (totalNbBytes <= buffer->current_size)
217
14.9M
    {
218
        // Enough bytes available in current buffer allocated bytes
219
14.9M
        return true;
220
14.9M
    }
221
197
    else if (totalNbBytes <= buffer->maximum_size)
222
197
    {
223
        // Enough bytes available if buffer is resized
224
197
        uint8_t* newData = NULL;
225
197
        uint32_t newSize = 0;
226
197
        if (exactResize)
227
0
        {
228
            // Use the exact number of bytes necessary
229
0
            newSize = totalNbBytes;
230
0
        }
231
197
        else
232
197
        {
233
            // Search the first multiple of initial_size which contains totalNbBytes
234
197
            uint32_t requiredSteps = totalNbBytes / buffer->initial_size;
235
197
            if (totalNbBytes % buffer->initial_size != 0)
236
196
            {
237
196
                requiredSteps++;
238
196
            }
239
197
            if (requiredSteps > buffer->maximum_size / buffer->initial_size)
240
0
            {
241
                // The first multiple found is greater than maximum_size => use maximum_size
242
0
                newSize = buffer->maximum_size;
243
0
            }
244
197
            else
245
197
            {
246
                // Resize to the multiple of initial_size which contains totalNbBytes
247
197
                newSize = requiredSteps * buffer->initial_size;
248
197
            }
249
197
        }
250
        // Resize buffer with computed size
251
197
        newData = SOPC_Realloc(buffer->data, (size_t) buffer->current_size, (size_t) newSize);
252
197
        if (NULL != newData)
253
197
        {
254
197
            buffer->data = newData;
255
197
            buffer->current_size = newSize;
256
257
197
            return true;
258
197
        }
259
197
    }
260
0
    return false;
261
14.9M
}
262
263
SOPC_ReturnStatus SOPC_Buffer_Write(SOPC_Buffer* buffer, const uint8_t* data_src, uint32_t count)
264
14.9M
{
265
14.9M
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
266
14.9M
    if (NULL == data_src || NULL == buffer || NULL == buffer->data)
267
0
    {
268
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
269
0
    }
270
14.9M
    else
271
14.9M
    {
272
14.9M
        if (SOPC_Buffer_CheckSizeAndResize(buffer, buffer->position + count, false))
273
14.9M
        {
274
14.9M
            if (memcpy(&(buffer->data[buffer->position]), data_src, count) == &(buffer->data[buffer->position]))
275
14.9M
            {
276
14.9M
                buffer->position = buffer->position + count;
277
                // In case we write in existing buffer position: does not change length
278
14.9M
                if (buffer->position > buffer->length)
279
14.8M
                {
280
14.8M
                    buffer->length = buffer->position;
281
14.8M
                }
282
14.9M
                status = SOPC_STATUS_OK;
283
14.9M
            }
284
0
            else
285
0
            {
286
0
                status = SOPC_STATUS_INVALID_STATE;
287
0
            }
288
14.9M
        }
289
0
        else
290
0
        {
291
0
            status = SOPC_STATUS_OUT_OF_MEMORY;
292
0
        }
293
14.9M
    }
294
14.9M
    return status;
295
14.9M
}
296
297
SOPC_ReturnStatus SOPC_Buffer_Read(uint8_t* data_dest, SOPC_Buffer* buffer, uint32_t count)
298
21.7M
{
299
21.7M
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
300
21.7M
    if (buffer != NULL && buffer->data != NULL)
301
21.7M
    {
302
21.7M
        if (buffer->position + count <= buffer->length)
303
21.7M
        {
304
21.7M
            if (NULL == data_dest || memcpy(data_dest, &(buffer->data[buffer->position]), count) == data_dest)
305
21.7M
            {
306
21.7M
                buffer->position = buffer->position + count;
307
21.7M
                status = SOPC_STATUS_OK;
308
21.7M
            }
309
0
            else
310
0
            {
311
0
                status = SOPC_STATUS_INVALID_STATE;
312
0
            }
313
21.7M
        }
314
9.59k
        else
315
9.59k
        {
316
9.59k
            status = SOPC_STATUS_OUT_OF_MEMORY;
317
9.59k
        }
318
21.7M
    }
319
21.7M
    return status;
320
21.7M
}
321
322
SOPC_ReturnStatus SOPC_Buffer_CopyWithLength(SOPC_Buffer* dest, SOPC_Buffer* src, uint32_t limitedLength)
323
0
{
324
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
325
0
    if (dest != NULL && src != NULL && dest->data != NULL && src->data != NULL && src->length >= limitedLength &&
326
0
        src->position <= limitedLength)
327
0
    {
328
0
        SOPC_ASSERT(src->position <= src->length);
329
330
0
        if (SOPC_Buffer_CheckSizeAndResize(dest, limitedLength, true))
331
0
        {
332
0
            memcpy(dest->data, src->data, limitedLength);
333
0
            status = SOPC_Buffer_SetPosition(dest, 0);
334
335
0
            if (SOPC_STATUS_OK == status)
336
0
            {
337
0
                status = SOPC_Buffer_SetDataLength(dest, limitedLength);
338
0
            }
339
0
            if (SOPC_STATUS_OK == status)
340
0
            {
341
0
                status = SOPC_Buffer_SetPosition(dest, src->position);
342
0
            }
343
0
        }
344
0
        else
345
0
        {
346
0
            status = SOPC_STATUS_OUT_OF_MEMORY;
347
0
        }
348
0
    }
349
0
    return status;
350
0
}
351
352
SOPC_ReturnStatus SOPC_Buffer_Copy(SOPC_Buffer* dest, SOPC_Buffer* src)
353
0
{
354
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
355
0
    if (src != NULL)
356
0
    {
357
0
        status = SOPC_Buffer_CopyWithLength(dest, src, src->length);
358
0
    }
359
360
0
    return status;
361
0
}
362
363
uint32_t SOPC_Buffer_Remaining(SOPC_Buffer* buffer)
364
27.8k
{
365
27.8k
    SOPC_ASSERT(buffer != NULL);
366
27.8k
    return buffer->length - buffer->position;
367
27.8k
}
368
369
int64_t SOPC_Buffer_ReadFrom(SOPC_Buffer* buffer, SOPC_Buffer* src, uint32_t n)
370
7.90k
{
371
7.90k
    if (NULL == buffer || NULL == src || (buffer->current_size - buffer->length) < n)
372
0
    {
373
0
        return -1;
374
0
    }
375
376
7.90k
    uint32_t available = src->length - src->position;
377
378
7.90k
    if (available < n)
379
104
    {
380
104
        n = available;
381
104
    }
382
383
7.90k
    memcpy(buffer->data + buffer->length, src->data + src->position, n * sizeof(uint8_t));
384
7.90k
    buffer->length += n;
385
7.90k
    src->position += n;
386
7.90k
    return (int64_t) n;
387
7.90k
}
388
389
#if SOPC_HAS_FILESYSTEM
390
static long get_file_size(FILE* fd)
391
0
{
392
0
    if (fseek(fd, 0, SEEK_END) == -1)
393
0
    {
394
0
        return -1;
395
0
    }
396
397
0
    long sz = ftell(fd);
398
399
0
    if (sz == -1)
400
0
    {
401
0
        return -1;
402
0
    }
403
404
0
    if (fseek(fd, 0, SEEK_SET) == -1)
405
0
    {
406
0
        return -1;
407
0
    }
408
409
0
    return sz;
410
0
}
411
412
static bool read_file(FILE* fd, char* data, size_t len)
413
0
{
414
0
    size_t read = 0;
415
416
0
    while (true)
417
0
    {
418
0
        size_t res = fread(data + read, sizeof(char), len - read, fd);
419
420
0
        if (res == 0)
421
0
        {
422
0
            break;
423
0
        }
424
425
0
        read += res;
426
0
    }
427
428
0
    return ferror(fd) == 0;
429
0
}
430
431
SOPC_ReturnStatus SOPC_Buffer_ReadFile(const char* path, SOPC_Buffer** buf)
432
0
{
433
0
    FILE* fd = fopen(path, "rb");
434
435
0
    if (fd == NULL)
436
0
    {
437
0
        return SOPC_STATUS_NOK;
438
0
    }
439
440
0
    long size = get_file_size(fd);
441
442
0
    if ((-1 == size || 0 == size ||
443
0
         ((unsigned long) size) > UINT32_MAX)) // check future cast into uint32_t and size_t allowed
444
0
    {
445
0
        fclose(fd);
446
0
        return SOPC_STATUS_NOK;
447
0
    }
448
449
0
    SOPC_Buffer* buffer = SOPC_Buffer_Create((uint32_t) size);
450
451
0
    if (buffer == NULL)
452
0
    {
453
0
        fclose(fd);
454
0
        return SOPC_STATUS_OUT_OF_MEMORY;
455
0
    }
456
457
0
    bool ok = read_file(fd, (char*) buffer->data, (size_t) size);
458
0
    fclose(fd);
459
460
0
    if (!ok)
461
0
    {
462
0
        SOPC_Buffer_Delete(buffer);
463
0
        return SOPC_STATUS_NOK;
464
0
    }
465
466
0
    buffer->length = buffer->current_size;
467
0
    *buf = buffer;
468
0
    return SOPC_STATUS_OK;
469
0
}
470
#else
471
SOPC_ReturnStatus SOPC_Buffer_ReadFile(const char* path, SOPC_Buffer** buf)
472
{
473
    SOPC_UNUSED_ARG(path);
474
    SOPC_UNUSED_ARG(buf);
475
    return SOPC_STATUS_NOT_SUPPORTED;
476
}
477
478
#endif // SOPC_HAS_FILESYSTEM
479
480
SOPC_ReturnStatus SOPC_Buffer_PrintU32(SOPC_Buffer* buf, const uint32_t value)
481
0
{
482
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
483
0
    char buffer[SOPC_MAX_LENGTH_UINT32_TO_STRING];
484
0
    int res = snprintf(buffer, SOPC_MAX_LENGTH_UINT32_TO_STRING, "%" PRIu32, value);
485
0
    if (res > 0 && res < SOPC_MAX_LENGTH_UINT32_TO_STRING)
486
0
    {
487
0
        status = SOPC_Buffer_Write(buf, (const uint8_t*) buffer, (uint32_t) strlen(buffer));
488
0
    }
489
0
    return status;
490
0
}
491
492
SOPC_ReturnStatus SOPC_Buffer_PrintI32(SOPC_Buffer* buf, const int32_t value)
493
0
{
494
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
495
0
    char buffer[SOPC_MAX_LENGTH_INT32_TO_STRING];
496
0
    int res = snprintf(buffer, SOPC_MAX_LENGTH_INT32_TO_STRING, "%" PRIi32, value);
497
0
    if (res > 0 && res < SOPC_MAX_LENGTH_INT32_TO_STRING)
498
0
    {
499
0
        status = SOPC_Buffer_Write(buf, (const uint8_t*) buffer, (uint32_t) strlen(buffer));
500
0
    }
501
0
    return status;
502
0
}
503
504
SOPC_ReturnStatus SOPC_Buffer_PrintFloatDouble(SOPC_Buffer* buf, const double value)
505
0
{
506
0
    static const char* infinity_str_json_format = "\"Infinity\"";
507
0
    static const char* infinity_str_minus_json_format = "\"-Infinity\"";
508
0
    static const char* nan_str_json_format = "\"NaN\"";
509
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
510
0
    char buffer[SOPC_PRECISION_PRINTING_FLOAT_NUMBERS + 8]; // (decimal + '-.e+ddd' + '\0')
511
512
    /* Check if value is a special number */
513
    // If it's a NaN
514
0
    if (isnan(value))
515
0
    {
516
0
        status = SOPC_Buffer_Write(buf, (const uint8_t*) nan_str_json_format, (uint32_t) strlen(nan_str_json_format));
517
0
    }
518
    // If it's a +Inf
519
0
    else if (1 == isinf(value))
520
0
    {
521
0
        status = SOPC_Buffer_Write(buf, (const uint8_t*) infinity_str_json_format,
522
0
                                   (uint32_t) strlen(infinity_str_json_format));
523
0
    }
524
    // If it's a -Inf
525
0
    else if (-1 == isinf(value))
526
0
    {
527
0
        status = SOPC_Buffer_Write(buf, (const uint8_t*) infinity_str_minus_json_format,
528
0
                                   (uint32_t) strlen(infinity_str_minus_json_format));
529
0
    }
530
    // Else, it's a normal decimal number
531
0
    else
532
0
    {
533
0
        int res = snprintf(buffer, SOPC_PRECISION_PRINTING_FLOAT_NUMBERS + 8, "%.*g",
534
0
                           SOPC_PRECISION_PRINTING_FLOAT_NUMBERS, value);
535
0
        if (res > 0 && res < SOPC_PRECISION_PRINTING_FLOAT_NUMBERS + 8)
536
0
        {
537
0
            status = SOPC_Buffer_Write(buf, (const uint8_t*) buffer, (uint32_t) strlen(buffer));
538
0
        }
539
0
    }
540
541
0
    return status;
542
0
}
543
544
SOPC_ReturnStatus SOPC_Buffer_PrintCString(SOPC_Buffer* buf, const char* value)
545
0
{
546
0
    if (NULL == value)
547
0
    {
548
0
        value = "<null>";
549
0
    }
550
0
    return SOPC_Buffer_Write(buf, (const uint8_t*) value, (uint32_t) strlen(value));
551
0
}