Coverage Report

Created: 2025-07-11 06:47

/src/gpsd/gpsd-3.26.2~dev/libgps/hex.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This file is Copyright 2010 by the GPSD project
3
 * SPDX-License-Identifier: BSD-2-clause
4
 */
5
6
#include "../include/gpsd_config.h"   // must be before all includes
7
8
#include <assert.h>
9
#include <ctype.h>
10
#include <string.h>
11
12
#include "../include/gpsd.h"
13
14
/*
15
 * gpsd_packetdump()
16
 *
17
 * if binbuf is printable, just return a copy of it
18
 * otherwise) convert a binary string to a hex string and return that
19
 *
20
 * *scbuf   -- the buffer to fill with hex
21
 * scbuflen -- sizeof(scbuf)
22
 * *binbuf  -- the binary to convert to hex and place in scbuf
23
 * binbuflen -- sizeof(binbuf)
24
 *
25
 * scbuflen needs to be 2x binbuflen to hold the hex conversion
26
 */
27
28
const char *gpsd_packetdump(char *scbuf, size_t scbuflen,
29
                            const unsigned char *binbuf,
30
                            size_t binbuflen)
31
0
{
32
0
    const unsigned char *cp;
33
34
0
    if (NULL == binbuf) {
35
0
        return "";
36
0
    }
37
0
    for (cp = binbuf; cp < binbuf + binbuflen; cp++) {
38
        // Careful, isprint() is locale specific.
39
0
        if (0x7f <= *cp ||
40
0
            (!isprint(*cp) &&
41
0
             !isspace(*cp))) {
42
            // some non-printable, do it the hard way.
43
0
            return gps_hexdump(scbuf, scbuflen, binbuf, binbuflen);
44
0
        }
45
0
    }
46
    // all printable
47
0
    memcpy(scbuf, binbuf, binbuflen);
48
0
    scbuf[binbuflen] = '\0';    // paranoia
49
0
    return (const char *)scbuf;
50
0
}
51
52
/* gps_hexdump()
53
 * convert binary in binbuf, of length binbuflen
54
 * into hex string at scbuf of length scbuflen
55
 *
56
 * Return scbuf
57
 */
58
const char *gps_hexdump(char *scbuf, size_t scbuflen,
59
                        const unsigned  char *binbuf, size_t binbuflen)
60
0
{
61
0
    size_t i, j = 0;
62
0
    size_t len =
63
0
        (size_t)((binbuflen >
64
0
                   MAX_PACKET_LENGTH) ? MAX_PACKET_LENGTH : binbuflen);
65
0
    const char *hexchar = "0123456789abcdef";
66
67
0
    if (NULL == binbuf ||
68
0
        0 == binbuflen) {
69
0
        scbuf[0] = '\0';
70
0
        return scbuf;
71
0
    }
72
73
0
    for (i = 0; i < len && j < (scbuflen - 3); i++) {
74
0
        scbuf[j++] = hexchar[(binbuf[i] >> 4) & 0x0f];
75
0
        scbuf[j++] = hexchar[binbuf[i] & 0x0f];
76
0
    }
77
0
    scbuf[j] = '\0';
78
0
    return scbuf;
79
0
}
80
81
static int hex2bin(const char *s)
82
0
{
83
0
    int a, b;
84
85
0
    a = s[0] & 0xff;
86
0
    b = s[1] & 0xff;
87
88
0
    if ((a >= 'a') &&
89
0
        (a <= 'f')) {
90
0
        a = a + 10 - 'a';
91
0
    } else if ((a >= 'A') &&
92
0
               (a <= 'F')) {
93
0
        a = a + 10 - 'A';
94
0
    } else if ((a >= '0') &&
95
0
               (a <= '9')) {
96
0
        a -= '0';
97
0
    } else {
98
0
        return -1;
99
0
    }
100
101
0
    if ((b >= 'a') &&
102
0
        (b <= 'f')) {
103
0
        b = b + 10 - 'a';
104
0
    } else if ((b >= 'A') &&
105
0
               (b <= 'F')) {
106
0
        b = b + 10 - 'A';
107
0
    } else if ((b >= '0') &&
108
0
               (b <= '9')) {
109
0
        b -= '0';
110
0
    } else {
111
0
        return -1;
112
0
    }
113
114
0
    return ((a << 4) + b);
115
0
}
116
117
// hex2bin source string to destination - destination can be same as source
118
ssize_t gps_hexpack(const char *src, unsigned char *dst, size_t len)
119
0
{
120
0
    ssize_t i, j;
121
122
0
    j = strnlen(src, BUFSIZ) / 2;
123
0
    if ((1 > j) ||
124
0
        ((size_t)j > len)) {
125
0
        return -2;
126
0
    }
127
128
0
    for (i = 0; i < j; i++) {
129
0
        int k;
130
0
        if (-1 == (k = hex2bin(src + i * 2))) {
131
0
            return -1;
132
0
        }
133
0
        dst[i] = (char)(k & 0xff);
134
0
    }
135
0
    (void)memset(dst + i, '\0', (size_t)(len - i));
136
0
    return j;
137
0
}
138
139
140
// interpret C-style hex escapes
141
ssize_t hex_escapes(char *cooked, const char *raw)
142
0
{
143
0
    char c, *cookend;
144
145
0
    for (cookend = cooked; *raw != '\0'; raw++) {
146
0
        if ('\\' != *raw) {
147
            // not an escape, just copy thje character
148
0
            *cookend++ = *raw;
149
0
            continue;
150
0
        }
151
0
        switch (*++raw) {
152
0
        case 'b':
153
0
            *cookend++ = '\b';
154
0
            break;
155
0
        case 'e':
156
0
            *cookend++ = '\x1b';
157
0
            break;
158
0
        case 'f':
159
0
            *cookend++ = '\f';
160
0
            break;
161
0
        case 'n':
162
0
            *cookend++ = '\n';
163
0
            break;
164
0
        case 'r':
165
0
            *cookend++ = '\r';
166
0
            break;
167
0
        case 't':
168
0
            *cookend++ = '\r';
169
0
            break;
170
0
        case 'v':
171
0
            *cookend++ = '\v';
172
0
            break;
173
0
        case 'x':
174
0
            switch (*++raw) {
175
0
            case '0':
176
0
                c = (char)0x00;
177
0
                break;
178
0
            case '1':
179
0
                c = (char)0x10;
180
0
                break;
181
0
            case '2':
182
0
                c = (char)0x20;
183
0
                break;
184
0
            case '3':
185
0
                c = (char)0x30;
186
0
                break;
187
0
            case '4':
188
0
                c = (char)0x40;
189
0
                break;
190
0
            case '5':
191
0
                c = (char)0x50;
192
0
                break;
193
0
            case '6':
194
0
                c = (char)0x60;
195
0
                break;
196
0
            case '7':
197
0
                c = (char)0x70;
198
0
                break;
199
0
            case '8':
200
0
                c = (char)0x80;
201
0
                break;
202
0
            case '9':
203
0
                c = (char)0x90;
204
0
                break;
205
0
            case 'A':
206
0
                FALLTHROUGH
207
0
            case 'a':
208
0
                c = (char)0xa0;
209
0
                break;
210
0
            case 'B':
211
0
                FALLTHROUGH
212
0
            case 'b':
213
0
                c = (char)0xb0;
214
0
                break;
215
0
            case 'C':
216
0
                FALLTHROUGH
217
0
            case 'c':
218
0
                c = (char)0xc0;
219
0
                break;
220
0
            case 'D':
221
0
                FALLTHROUGH
222
0
            case 'd':
223
0
                c = (char)0xd0;
224
0
                break;
225
0
            case 'E':
226
0
                FALLTHROUGH
227
0
            case 'e':
228
0
                c = (char)0xe0;
229
0
                break;
230
0
            case 'F':
231
0
                FALLTHROUGH
232
0
            case 'f':
233
0
                c = (char)0xf0;
234
0
                break;
235
0
            default:
236
0
                return -1;
237
0
            }
238
0
            switch (*++raw) {
239
0
            case '0':
240
0
                c += 0x00;
241
0
                break;
242
0
            case '1':
243
0
                c += 0x01;
244
0
                break;
245
0
            case '2':
246
0
                c += 0x02;
247
0
                break;
248
0
            case '3':
249
0
                c += 0x03;
250
0
                break;
251
0
            case '4':
252
0
                c += 0x04;
253
0
                break;
254
0
            case '5':
255
0
                c += 0x05;
256
0
                break;
257
0
            case '6':
258
0
                c += 0x06;
259
0
                break;
260
0
            case '7':
261
0
                c += 0x07;
262
0
                break;
263
0
            case '8':
264
0
                c += 0x08;
265
0
                break;
266
0
            case '9':
267
0
                c += 0x09;
268
0
                break;
269
0
            case 'A':
270
0
                FALLTHROUGH
271
0
            case 'a':
272
0
                c += 0x0a;
273
0
                break;
274
0
            case 'B':
275
0
                FALLTHROUGH
276
0
            case 'b':
277
0
                c += 0x0b;
278
0
                break;
279
0
            case 'C':
280
0
                FALLTHROUGH
281
0
            case 'c':
282
0
                c += 0x0c;
283
0
                break;
284
0
            case 'D':
285
0
                FALLTHROUGH
286
0
            case 'd':
287
0
                c += 0x0d;
288
0
                break;
289
0
            case 'E':
290
0
                FALLTHROUGH
291
0
            case 'e':
292
0
                c += 0x0e;
293
0
                break;
294
0
            case 'F':
295
0
                FALLTHROUGH
296
0
            case 'f':
297
0
                c += 0x0f;
298
0
                break;
299
0
            default:
300
0
                return -2;
301
0
            }
302
0
            *cookend++ = c;
303
0
            break;
304
0
        case '\\':
305
0
            *cookend++ = '\\';
306
0
            break;
307
0
        default:
308
0
            return -3;
309
0
        }
310
0
    }
311
0
    return (ssize_t)(cookend - cooked);
312
0
}
313
314
// copy inbuf string to outbuf, replacingg non-printing characters
315
// slow, but only used for debug output
316
char *gps_visibilize(char *outbuf, size_t outlen,
317
                      const char *inbuf, size_t inlen)
318
0
{
319
0
    const char *sp;
320
0
    size_t next = 0;
321
322
0
    outbuf[0] = '\0';
323
    // FIXME!! snprintf() when strlcat() will do!
324
0
    for (sp = inbuf; sp < inbuf + inlen && (next + 6) < outlen; sp++) {
325
0
        int ret;
326
0
        if (isprint((unsigned char)*sp)) {
327
0
            ret = snprintf(&outbuf[next], 2, "%c", *sp);
328
0
        } else {
329
0
            ret = snprintf(&outbuf[next], 6, "\\x%02x",
330
0
                           0x00ff & (unsigned)*sp);
331
0
        }
332
0
        if (1 > ret) {
333
            // error, or ran out of space
334
0
            break;
335
0
        }
336
0
        next += ret;
337
0
    }
338
0
    return outbuf;
339
0
}
340
341
342
// vim: set expandtab shiftwidth=4