Coverage Report

Created: 2026-09-14 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/libgps/bits.c
Line
Count
Source
1
/* bits.c - bitfield extraction code
2
 *
3
 * This file is Copyright 2010 by the GPSD project
4
 * SPDX-License-Identifier: BSD-2-clause
5
 *
6
 * Bitfield extraction functions.  In each, start is a bit index  - not
7
 * a byte index - and width is a bit width.  The width is bounded above by
8
 * 64 bits.
9
 *
10
 * The sbits() function assumes twos-complement arithmetic. ubits()
11
 * and sbits() assume no padding in integers.
12
 */
13
#include "../include/gpsd_config.h"  // must be before all includes
14
15
#include <assert.h>
16
#include <limits.h>
17
#include <stdbool.h>
18
#include <stdint.h>
19
#include <string.h>
20
21
#include "../include/bits.h"
22
23
/* extract a (zero-origin) bitfield from a buffer) as an
24
 * unsigned uint64_t
25
 * Note: max width 56!
26
 *
27
 * Parameters: buf -- the buffer
28
 *             start -- starting bit of desired bitfield
29
 *             width -- width of desired bitfield (0 to 56)
30
 *             le -- little endian input (swap bytes)
31
 *
32
 * Returns: bitfield as uint64_t
33
 *          zero on errors (56 < width)
34
 */
35
uint64_t ubits(const unsigned char buf[], unsigned int start,
36
               unsigned int width, bool le)
37
199k
{
38
199k
    uint64_t fld = 0;
39
199k
    unsigned int i;
40
199k
    unsigned end;
41
42
199k
    assert(width <= sizeof(uint64_t) * CHAR_BIT);
43
199k
    if (0 == width ||
44
199k
        56 < width) {
45
9
        return 0;
46
9
    }
47
199k
    for (i = start / CHAR_BIT;
48
577k
         i < (start + width + CHAR_BIT - 1) / CHAR_BIT; i++) {
49
377k
        fld <<= CHAR_BIT;
50
377k
        fld |= (uint64_t)buf[i];
51
377k
    }
52
53
199k
    end = (start + width) % CHAR_BIT;
54
199k
    if (0 != end) {
55
153k
        fld >>= (CHAR_BIT - end);
56
153k
    }
57
58
199k
    fld &= ~(~0ULL << width);
59
60
199k
    if (le) {
61
        // extraction as a little-endian requested
62
0
        uint64_t reversed = 0;
63
64
0
        for (i = width; i; --i) {
65
0
            reversed <<= 1;
66
0
            if (1 == (1 & fld)) {
67
0
                reversed |= 1;
68
0
            }
69
0
            fld >>= 1;
70
0
        }
71
0
        fld = reversed;
72
0
    }
73
74
199k
    return fld;
75
199k
}
76
77
// extract a bitfield from the buffer as a signed big-endian long
78
int64_t sbits(const unsigned char buf[], unsigned int start, unsigned int width,
79
              bool le)
80
18.3k
{
81
18.3k
    uint64_t fld = ubits(buf, start, width, le);
82
83
    /* ensure width > 0 as the result of
84
       1ULL << (width - 1)
85
       is undefined for width <= 0 */
86
18.3k
    assert(width > 0);
87
88
18.3k
    if (fld & (1ULL << (width - 1))) {
89
4.51k
        fld |= (~0ULL << (width - 1));
90
4.51k
    }
91
18.3k
    return (int64_t)fld;
92
18.3k
}
93
94
union int_float {
95
    int32_t i;
96
    float f;
97
};
98
99
union long_double {
100
    int64_t l;
101
    double d;
102
};
103
104
float getlef32(const char *buf, int off)
105
4.98k
{
106
4.98k
    union int_float i_f;
107
108
4.98k
    i_f.i = getles32(buf, off);
109
4.98k
    return i_f.f;
110
4.98k
}
111
112
double getled64(const char *buf, int off)
113
6.56k
{
114
6.56k
    union long_double l_d;
115
116
6.56k
    l_d.l = getles64(buf, off);
117
6.56k
    return l_d.d;
118
6.56k
}
119
120
float getbef32(const char *buf, int off)
121
32.8k
{
122
32.8k
    union int_float i_f;
123
124
32.8k
    i_f.i = getbes32(buf, off);
125
32.8k
    return i_f.f;
126
32.8k
}
127
128
double getbed64(const char *buf, int off)
129
5.67k
{
130
5.67k
    union long_double l_d;
131
132
5.67k
    l_d.l = getbes64(buf, off);
133
5.67k
    return l_d.d;
134
5.67k
}
135
136
void putbef32(char *buf, int off, float val)
137
2.97k
{
138
2.97k
    union int_float i_f;
139
140
2.97k
    i_f.f = val;
141
2.97k
    putbe32(buf, off, i_f.i);
142
2.97k
}
143
144
145
void shiftleft(unsigned char *data, int size, unsigned short left)
146
305
{
147
305
    unsigned char *byte;
148
149
305
    if (CHAR_BIT <= left) {
150
305
        size -= left / CHAR_BIT;
151
305
        memmove(data, data + left / CHAR_BIT,
152
305
                (size + CHAR_BIT - 1) / CHAR_BIT);
153
305
        left %= CHAR_BIT;
154
305
    }
155
156
19.7k
    for (byte = data; size--; ++byte ) {
157
19.4k
        unsigned char bits;
158
159
19.4k
        if (size) {
160
19.1k
            bits = byte[1] >> (CHAR_BIT - left);
161
19.1k
        } else {
162
305
            bits = 0;
163
305
        }
164
19.4k
        *byte <<= left;
165
        // Yes, the mask should not be needed, but id avoids a compiler
166
        // bug in gcc-amd64 11.2.1
167
19.4k
        *byte |= 0x0ff & bits;
168
19.4k
    }
169
305
}
170
171
#ifdef __UNUSED__
172
void putbed64(char *buf, int off, double val)
173
{
174
    union long_double l_d;
175
176
    l_d.d = val;
177
    putbe32(buf, (off), (l_d.l) >> 32);
178
    putbe32(buf, (off)+4, (l_d.l));
179
}
180
181
// byte-swap a 16-bit unsigned int
182
u_int16_t swap_u16(u_int16_t i)
183
{
184
    u_int8_t c1, c2;
185
186
    c1 = i & 255;
187
    c2 = (i >> 8) & 255;
188
189
    return (c1 << 8) + c2;
190
}
191
192
// byte-swap a 32-bit unsigned int
193
u_int32_t swap_u32(u_int32_t i)
194
{
195
    u_int8_t c1, c2, c3, c4;
196
197
    c1 = i & 255;
198
    c2 = (i >> 8) & 255;
199
    c3 = (i >> 16) & 255;
200
    c4 = (i >> 24) & 255;
201
202
    return ((u_int32_t)c1 << 24) +
203
            ((u_int32_t)c2 << 16) +
204
            ((u_int32_t)c3 << 8) + c4;
205
}
206
207
// byte-swap a 64-bit unsigned int
208
u_int64_t swap_u64(u_int64_t i)
209
{
210
    u_int8_t c1, c2, c3, c4, c5, c6, c7, c8;
211
212
    c1 = i & 255;
213
    c2 = (i >> 8) & 255;
214
    c3 = (i >> 16) & 255;
215
    c4 = (i >> 24) & 255;
216
    c5 = (i >> 32) & 255;
217
    c6 = (i >> 40) & 255;
218
    c7 = (i >> 48) & 255;
219
    c8 = (i >> 56) & 255;
220
221
    return ((u_int64_t)c1 << 56) +
222
            ((u_int64_t)c2 << 48) +
223
            ((u_int64_t)c3 << 40) +
224
            ((u_int64_t)c4 << 32) +
225
            ((u_int64_t)c5 << 24) +
226
            ((u_int64_t)c6 << 16) +
227
            ((u_int64_t)c7 << 8) +
228
            c8;
229
}
230
#endif  // __UNUSED__
231
// vim: set expandtab shiftwidth=4