Coverage Report

Created: 2025-08-26 06:59

/src/S2OPC/src/Common/helpers/sopc_helper_string.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 "sopc_helper_string.h"
21
22
#include <ctype.h>
23
#include <errno.h>
24
#include <float.h>
25
#include <limits.h>
26
#include <stdio.h>
27
#include <stdlib.h> /* strtoul */
28
#include <string.h>
29
30
#include "sopc_assert.h"
31
#include "sopc_mem_alloc.h"
32
33
0
#define STR_ZERO_TERMINATED_SIZE 1u
34
35
int SOPC_strncmp_ignore_case(const char* s1, const char* s2, size_t size)
36
0
{
37
0
    int lc1, lc2;
38
0
    size_t idx;
39
0
    int res = -1000;
40
0
    if (NULL == s1 || NULL == s2)
41
0
    {
42
0
        return res;
43
0
    }
44
45
0
    res = 0;
46
0
    for (idx = 0; idx < size && res == 0; idx++)
47
0
    {
48
0
        lc1 = tolower((unsigned char) s1[idx]);
49
0
        lc2 = tolower((unsigned char) s2[idx]);
50
0
        if (lc1 < lc2)
51
0
        {
52
0
            res = -1;
53
0
        }
54
0
        else if (lc1 > lc2)
55
0
        {
56
0
            res = +1;
57
0
        }
58
0
        else if (lc1 == '\0')
59
0
        {
60
            // In case we reached end of both strings, stop comparison here
61
0
            return res;
62
0
        }
63
0
    }
64
0
    return res;
65
0
}
66
67
int SOPC_strcmp_ignore_case(const char* s1, const char* s2)
68
0
{
69
0
    int res = -1000;
70
0
    if (NULL == s1 || NULL == s2)
71
0
    {
72
0
        return res;
73
0
    }
74
75
0
    size_t s1_len = strlen(s1);
76
0
    size_t s2_len = strlen(s2);
77
0
    if (s1_len == s2_len)
78
0
    {
79
0
        return SOPC_strncmp_ignore_case(s1, s2, s1_len);
80
0
    }
81
0
    else
82
0
    {
83
0
        if (s1_len < s2_len)
84
0
        {
85
0
            res = -1;
86
0
        }
87
0
        else
88
0
        {
89
0
            res = +1;
90
0
        }
91
0
    }
92
0
    return res;
93
0
}
94
95
int SOPC_strcmp_ignore_case_alt_end(const char* s1, const char* s2, char endCharacter)
96
0
{
97
0
    int lc1, lc2;
98
0
    int endChar = tolower((unsigned char) endCharacter);
99
0
    size_t idx;
100
0
    int res = -1000;
101
0
    bool lc1_is_endchar = false;
102
0
    bool lc2_is_endchar = false;
103
104
0
    if (NULL == s1 || NULL == s2)
105
0
    {
106
0
        return res;
107
0
    }
108
109
0
    res = 0;
110
0
    for (idx = 0; res == 0; idx++)
111
0
    {
112
0
        lc1 = tolower((unsigned char) s1[idx]);
113
0
        lc2 = tolower((unsigned char) s2[idx]);
114
0
        lc1_is_endchar = endChar == lc1 || '\0' == lc1;
115
0
        lc2_is_endchar = endChar == lc2 || '\0' == lc2;
116
117
0
        if (!lc1_is_endchar && !lc2_is_endchar)
118
0
        {
119
0
            if (lc1 < lc2)
120
0
            {
121
0
                res = -1;
122
0
            }
123
0
            else if (lc1 > lc2)
124
0
            {
125
0
                res = +1;
126
0
            }
127
0
        }
128
0
        else
129
0
        {
130
0
            if (lc1_is_endchar && lc2_is_endchar)
131
0
            {
132
                // In case we reached end of both strings, stop comparison here
133
0
                return res;
134
0
            }
135
0
            else if (lc1_is_endchar)
136
0
            {
137
0
                res = -1;
138
0
            }
139
0
            else
140
0
            {
141
0
                res = +1;
142
0
            }
143
0
        }
144
0
    }
145
0
    return res;
146
0
}
147
148
SOPC_ReturnStatus SOPC_strtouint8_t(const char* sz, uint8_t* n, int base, char cEnd)
149
0
{
150
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
151
0
    char* pEnd = NULL;
152
    /* ULONG_MAX is at least 2^32 - 1, so it will always be possible to store an uint8_t inside */
153
0
    unsigned long int value = 0;
154
155
0
    if (NULL == sz || NULL == n)
156
0
    {
157
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
158
0
    }
159
160
    /* 10 and 16 are the only supported bases */
161
0
    if (10 != base && 16 != base)
162
0
    {
163
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
164
0
    }
165
166
0
    if (SOPC_STATUS_OK == status)
167
0
    {
168
        /* ULONG_MAX is at least 2^32 - 1 (see C99 §5.2.4.2.1 Sizes of integer types)
169
         *  so it will always be possible to store an uint8_t inside value */
170
0
        value = strtoul(sz, &pEnd, base);
171
0
        if (NULL == pEnd || pEnd == sz || *pEnd != cEnd || value > UINT8_MAX)
172
0
        {
173
0
            status = SOPC_STATUS_NOK;
174
0
        }
175
0
        else
176
0
        {
177
0
            *n = (uint8_t) value;
178
0
        }
179
0
    }
180
181
0
    return status;
182
0
}
183
184
SOPC_ReturnStatus SOPC_strtouint16_t(const char* sz, uint16_t* n, int base, char cEnd)
185
0
{
186
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
187
0
    char* pEnd = NULL;
188
0
    unsigned long int value = 0;
189
190
0
    if (NULL == sz || NULL == n)
191
0
    {
192
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
193
0
    }
194
195
    /* 10 and 16 are the only supported bases */
196
0
    if (10 != base && 16 != base)
197
0
    {
198
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
199
0
    }
200
201
0
    if (SOPC_STATUS_OK == status)
202
0
    {
203
        /* ULONG_MAX is at least 2^32 - 1 (see C99 §5.2.4.2.1 Sizes of integer types)
204
         *  so it will always be possible to store an uint16_t inside value */
205
0
        value = strtoul(sz, &pEnd, base);
206
0
        if (NULL == pEnd || pEnd == sz || *pEnd != cEnd || value > UINT16_MAX)
207
0
        {
208
0
            status = SOPC_STATUS_NOK;
209
0
        }
210
0
        else
211
0
        {
212
0
            *n = (uint16_t) value;
213
0
        }
214
0
    }
215
216
0
    return status;
217
0
}
218
219
SOPC_ReturnStatus SOPC_strtouint32_t(const char* sz, uint32_t* n, int base, char cEnd)
220
0
{
221
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
222
0
    char* pEnd = NULL;
223
0
    unsigned long int value = 0;
224
225
0
    if (NULL == sz || NULL == n)
226
0
    {
227
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
228
0
    }
229
230
    /* 10 and 16 are the only supported bases */
231
0
    if (10 != base && 16 != base)
232
0
    {
233
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
234
0
    }
235
236
0
    if (SOPC_STATUS_OK == status)
237
0
    {
238
        /* ULONG_MAX is at least 2^32 - 1 (see C99 §5.2.4.2.1 Sizes of integer types)
239
         *  so it will always be possible to store an uint32_t inside value */
240
0
        errno = 0;
241
0
        value = strtoul(sz, &pEnd, base);
242
0
        if (NULL == pEnd || pEnd == sz || *pEnd != cEnd || (ULONG_MAX == value && ERANGE == errno) ||
243
0
            value > UINT32_MAX)
244
0
        {
245
0
            status = SOPC_STATUS_NOK;
246
0
        }
247
0
        else
248
0
        {
249
0
            *n = (uint32_t) value;
250
0
        }
251
0
    }
252
253
0
    return status;
254
0
}
255
256
bool SOPC_strtoint(const char* data, size_t len, uint8_t width, void* dest)
257
0
{
258
0
    char buf[21];
259
260
0
    if (NULL == dest || len == 0 || len > (sizeof(buf) / sizeof(char) - 1))
261
0
    {
262
0
        return false;
263
0
    }
264
265
0
    memcpy(buf, data, len);
266
0
    buf[len] = '\0';
267
268
0
    errno = 0;
269
270
0
    char* endptr;
271
0
    long long int val = strtoll(buf, &endptr, 10);
272
273
0
    if (endptr != (buf + len))
274
0
    {
275
0
        return false;
276
0
    }
277
278
0
    bool res = true;
279
0
    if (width == 8 && val >= INT8_MIN && val <= INT8_MAX)
280
0
    {
281
0
        *((int8_t*) dest) = (int8_t) val;
282
0
    }
283
0
    else if (width == 16 && val >= INT16_MIN && val <= INT16_MAX)
284
0
    {
285
0
        *((int16_t*) dest) = (int16_t) val;
286
0
    }
287
0
    else if (width == 32 && val >= INT32_MIN && val <= INT32_MAX)
288
0
    {
289
0
        *((int32_t*) dest) = (int32_t) val;
290
0
    }
291
0
    else if (width == 64 && val >= INT64_MIN && val <= INT64_MAX &&
292
0
             !((LLONG_MAX == val || LLONG_MIN == val) && ERANGE == errno))
293
0
    {
294
0
        *((int64_t*) dest) = (int64_t) val;
295
0
    }
296
0
    else
297
0
    {
298
        // Invalid width and/or out of bounds value
299
0
        res = false;
300
0
    }
301
302
0
    return res;
303
0
}
304
305
bool SOPC_strtouint(const char* data, size_t len, uint8_t width, void* dest)
306
0
{
307
0
    char buf[21];
308
309
0
    if (NULL == dest || len == 0 || len > (sizeof(buf) / sizeof(char) - 1))
310
0
    {
311
0
        return false;
312
0
    }
313
314
0
    memcpy(buf, data, len);
315
0
    buf[len] = '\0';
316
317
0
    char* endptr;
318
0
    errno = 0;
319
0
    unsigned long long int val = strtoull(buf, &endptr, 10);
320
321
0
    if (endptr != (buf + len))
322
0
    {
323
0
        return false;
324
0
    }
325
326
0
    bool res = true;
327
0
    if (width == 8 && val <= UINT8_MAX)
328
0
    {
329
0
        *((uint8_t*) dest) = (uint8_t) val;
330
0
    }
331
0
    else if (width == 16 && val <= UINT16_MAX)
332
0
    {
333
0
        *((uint16_t*) dest) = (uint16_t) val;
334
0
    }
335
0
    else if (width == 32 && val <= UINT32_MAX)
336
0
    {
337
0
        *((uint32_t*) dest) = (uint32_t) val;
338
0
    }
339
0
    else if (width == 64 && val <= UINT64_MAX && !(ULLONG_MAX == val && ERANGE == errno))
340
0
    {
341
0
        *((uint64_t*) dest) = (uint64_t) val;
342
0
    }
343
0
    else
344
0
    {
345
        // Invalid width and/or out of bounds value
346
0
        res = false;
347
0
    }
348
349
0
    return res;
350
0
}
351
352
bool SOPC_strtodouble(const char* data, size_t len, uint8_t width, void* dest)
353
0
{
354
0
    char buf[340];
355
356
0
    if (NULL == dest || len <= 0 || len > (sizeof(buf) / sizeof(char) - 1))
357
0
    {
358
0
        return false;
359
0
    }
360
361
0
    memcpy(buf, data, len);
362
0
    buf[len] = '\0';
363
364
0
    char* endptr;
365
0
    errno = 0;
366
0
    double val = strtod(buf, &endptr);
367
368
0
    if (endptr != (buf + len))
369
0
    {
370
0
        return false;
371
0
    }
372
373
0
    bool res = true;
374
0
    if (width == 32 && val >= (double) -FLT_MAX && val <= (double) FLT_MAX && ERANGE != errno)
375
0
    {
376
0
        *((float*) dest) = (float) val;
377
0
    }
378
0
    else if (width == 64 && val >= -DBL_MAX && val <= DBL_MAX && ERANGE != errno)
379
0
    {
380
0
        *((double*) dest) = val;
381
0
    }
382
0
    else
383
0
    {
384
        // Invalid width and/or out of bounds value
385
0
        res = false;
386
0
    }
387
388
0
    return res;
389
0
}
390
391
char* SOPC_strdup(const char* s)
392
0
{
393
0
    if (NULL == s)
394
0
    {
395
0
        return NULL;
396
0
    }
397
398
0
    size_t len = strlen(s);
399
0
    char* res = SOPC_Calloc(1 + len, sizeof(char));
400
401
0
    if (res == NULL)
402
0
    {
403
0
        return NULL;
404
0
    }
405
406
0
    memcpy(res, s, len * sizeof(char));
407
0
    return res;
408
0
}
409
410
SOPC_ReturnStatus SOPC_StrConcat(const char* left, const char* right, char** str)
411
0
{
412
0
    if (NULL == left || NULL == right || NULL == str)
413
0
    {
414
0
        return SOPC_STATUS_INVALID_PARAMETERS;
415
0
    }
416
417
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
418
0
    size_t size_path = strlen(left) + strlen(right) + STR_ZERO_TERMINATED_SIZE; // \0
419
0
    char* pOut = SOPC_Calloc(size_path, sizeof(char));
420
0
    if (NULL == pOut)
421
0
    {
422
0
        return SOPC_STATUS_OUT_OF_MEMORY;
423
0
    }
424
425
0
    int res = snprintf(pOut, size_path, "%s%s", left, right);
426
0
    if (0 > res)
427
0
    {
428
0
        SOPC_Free(pOut);
429
0
        pOut = NULL;
430
0
        status = SOPC_STATUS_OUT_OF_MEMORY;
431
0
    }
432
433
0
    *str = pOut;
434
0
    return status;
435
0
}