Coverage Report

Created: 2025-07-04 06:44

/src/libiec61850/src/common/conversions.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  conversions.c
3
 *
4
 *  Copyright 2013 Michael Zillgith
5
 *
6
 *  This file is part of libIEC61850.
7
 *
8
 *  libIEC61850 is free software: you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation, either version 3 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  libIEC61850 is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with libIEC61850.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 *  See COPYING file for the complete license text.
22
 */
23
24
#include "libiec61850_platform_includes.h"
25
#include "conversions.h"
26
27
#include <time.h>
28
29
#if defined TARGET
30
#if (TARGET == UCLINUX-WAGO)
31
time_t timegm (struct tm *tm)
32
{
33
    time_t ret;
34
    char *tz;
35
36
    tz = getenv ("TZ");
37
    setenv ("TZ", "", 1);
38
    tzset ();
39
    ret = mktime (tm);
40
    if (tz)
41
        setenv ("TZ", tz, 1);
42
    else
43
        unsetenv ("TZ");
44
    tzset ();
45
    return ret;
46
}
47
48
#endif
49
#endif
50
51
#ifdef _WIN32
52
53
#ifndef _MSC_VER
54
/* Algorithm: http://howardhinnant.github.io/date_algorithms.html */
55
static int 
56
days_from_civil(int y, int m, int d)
57
{
58
  y -= m <= 2;
59
  int era = y / 400;
60
  int yoe = y - era * 400;                                   /* [0, 399] */
61
  int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  /* [0, 365] */
62
  int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           /* [0, 146096] */
63
  return era * 146097 + doe - 719468;
64
}
65
66
/* from https://stackoverflow.com/questions/16647819/timegm-cross-platform */
67
time_t 
68
timegm(struct tm const* t) /* does not modify broken-down time */
69
{
70
  int year = t->tm_year + 1900;
71
  int month = t->tm_mon;          /* 0-11 */
72
  if (month > 11)
73
  {
74
    year += month / 12;
75
    month %= 12;
76
  }
77
  else if (month < 0)
78
  {
79
    int years_diff = (11 - month) / 12;
80
    year -= years_diff;
81
    month += 12 * years_diff;
82
  }
83
  int days_since_1970 = days_from_civil(year, month + 1, t->tm_mday);
84
85
  return 60 * (60 * (24L * days_since_1970 + t->tm_hour) + t->tm_min) + t->tm_sec;
86
}
87
#else
88
#define timegm _mkgmtime
89
#endif
90
91
#if defined(__MINGW32__)
92
93
static inline /* assuming gmtime is thread safe in windows! */
94
struct tm* gmtime_r(const time_t* timep, struct tm* result)
95
{
96
   struct tm* t;
97
98
   t = gmtime(timep);
99
100
   if (t != NULL)
101
       memcpy(result, t, sizeof (struct tm));
102
103
   return result;
104
}
105
106
#else
107
108
#if defined(_MSC_VER)
109
110
static inline
111
struct tm* gmtime_r(const time_t* timep, struct tm* result)
112
{
113
    gmtime_s(result, timep);
114
115
    return result;
116
}
117
118
#else
119
#error "No gmtime_r available for platform!"
120
#endif
121
122
123
#endif
124
125
126
#endif
127
128
void
129
Conversions_intToStringBuffer(int intValue, int numberOfDigits, uint8_t* buffer)
130
0
{
131
0
    int digitBase = 1;
132
133
0
    int i = 1;
134
135
0
    while (i < numberOfDigits) {
136
0
        digitBase = digitBase * 10;
137
0
        i++;
138
0
    }
139
140
0
    int remainder = intValue;
141
142
0
    for (i = 0; i < numberOfDigits; i++) {
143
0
        int digit = remainder / digitBase;
144
145
0
        buffer[i] = (uint8_t) (digit + 48);
146
147
0
        remainder = remainder % digitBase;
148
149
0
        digitBase = digitBase / 10;
150
0
    }
151
152
0
    buffer[i] = 0;
153
0
}
154
155
void
156
Conversions_msTimeToGeneralizedTime(uint64_t msTime, uint8_t* buffer)
157
0
{
158
0
    int msPart = (msTime % 1000);
159
160
0
    time_t unixTime = (msTime / 1000);
161
162
0
    struct tm tmTime;
163
164
0
    gmtime_r(&unixTime, &tmTime);
165
166
0
    Conversions_intToStringBuffer(tmTime.tm_year + 1900, 4, buffer);
167
168
0
    Conversions_intToStringBuffer(tmTime.tm_mon + 1, 2, buffer + 4);
169
0
    Conversions_intToStringBuffer(tmTime.tm_mday, 2, buffer + 6);
170
0
    Conversions_intToStringBuffer(tmTime.tm_hour, 2, buffer + 8);
171
0
    Conversions_intToStringBuffer(tmTime.tm_min, 2, buffer + 10);
172
0
    Conversions_intToStringBuffer(tmTime.tm_sec, 2, buffer + 12);
173
174
0
    buffer[14] = '.';
175
176
0
    Conversions_intToStringBuffer(msPart, 3, buffer + 15);
177
178
0
    buffer[18] = 'Z';
179
180
0
    buffer[19] = 0;
181
0
}
182
183
static int
184
getSecondsOffset(const char* offsetString)
185
0
{
186
0
    int hourOffset = StringUtils_digitsToInt(offsetString, 2);
187
188
0
    if (hourOffset < 0)
189
0
        return -1;
190
191
0
    int minOffset = StringUtils_digitsToInt(offsetString + 2, 2);
192
193
0
    if (minOffset < 0)
194
0
        return -1;
195
196
0
    int secondsOffset = (hourOffset * (60 * 60)) + (minOffset * 60);
197
198
0
    return secondsOffset;
199
0
}
200
201
uint64_t
202
Conversions_generalizedTimeToMsTime(const char* gtString)
203
0
{
204
0
    int gtStringLen = (int) strlen(gtString);
205
206
0
    if (gtStringLen < 14) return -1;
207
208
0
    int year = StringUtils_digitsToInt(gtString, 4);
209
210
0
    if (year < 0) return -1;
211
212
0
    int month = StringUtils_digitsToInt(gtString + 4, 2);
213
214
0
    if (month < 0) return -1;
215
216
0
    int day = StringUtils_digitsToInt(gtString + 6, 2);
217
218
0
    if (day < 0) return -1;
219
220
0
    int hour = StringUtils_digitsToInt(gtString + 8, 2);
221
222
0
    if (hour < 0) return -1;
223
224
0
    int min = StringUtils_digitsToInt(gtString + 10, 2);
225
226
0
    if (min < 0) return -1;
227
228
0
    int seconds = StringUtils_digitsToInt(gtString + 12, 2);
229
0
    if (seconds < 0) return -1;
230
231
0
    struct tm tmTime;
232
0
    tmTime.tm_year = year - 1900;
233
0
    tmTime.tm_mon = month - 1;
234
0
    tmTime.tm_mday = day;
235
0
    tmTime.tm_hour = hour;
236
0
    tmTime.tm_min = min;
237
0
    tmTime.tm_sec = seconds;
238
239
0
    int msOffset = 0;
240
241
0
    const char* parsePos = gtString + 14;
242
243
    /* parse optional fraction of second field */
244
0
    if (*(parsePos) == '.') {
245
0
        parsePos++;
246
0
        const char* fractionOfSecondStart = parsePos;
247
248
0
        int fractionOfSecondLen = 0;
249
250
0
        int secondValue = 1;
251
252
0
        while (StringUtils_isDigit(fractionOfSecondStart[fractionOfSecondLen])) {
253
0
            fractionOfSecondLen++;
254
255
0
            secondValue = secondValue * 10;
256
0
        }
257
258
0
        if (fractionOfSecondLen > 0) {
259
0
            int fractionOfSecond = StringUtils_digitsToInt(fractionOfSecondStart, fractionOfSecondLen);
260
0
            msOffset = (fractionOfSecond * 1000) / secondValue;
261
0
        }
262
263
0
        parsePos += fractionOfSecondLen;
264
0
    }
265
266
267
0
    time_t t = 0;
268
269
0
    switch (*parsePos) {
270
0
    case 0: /* treat time as localtime */
271
0
        t = mktime(&tmTime);
272
0
        break;
273
0
    case 'Z': /* treat time as GMT(UTC) time */
274
0
        t = timegm(&tmTime);
275
0
        break;
276
0
    case '+': /* subtract offset */
277
0
        {
278
0
            t = timegm(&tmTime);
279
0
            int secondsOffset = getSecondsOffset(parsePos + 1);
280
0
            t = t - secondsOffset;
281
0
        }
282
0
        break;
283
0
    case '-': /* add offset */
284
0
        {
285
0
            t = timegm(&tmTime);
286
0
            int secondsOffset = getSecondsOffset(parsePos + 1);
287
0
            t = t + secondsOffset;
288
0
        }
289
0
        break;
290
0
    default:
291
0
        return -1;
292
0
    }
293
294
0
    uint64_t msTime = (uint64_t) t * 1000LL;
295
296
0
    msTime += msOffset;
297
298
0
    return msTime;
299
0
}
300
301
void
302
memcpyReverseByteOrder(uint8_t* dst, const uint8_t* src, int size)
303
0
{
304
0
    int i = 0;
305
0
    for (i = 0; i < size; i++) {
306
0
        dst[i] = src[size - i - 1];
307
0
    }
308
0
}