blob: 2db62efa64b1b83338b47d7d19907e8dc4f3a183 [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/* bit vector utility routines */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
Maxa15f05f2016-01-26 10:43:15 +01004 * (C) 2012 Ivan Klyuchnikov
Jacob Erlbeck5f349be2015-12-21 16:04:03 +01005 * (C) 2015 by Sysmocom s.f.m.c. GmbH
Harald Welteec8b4502010-02-20 20:34:29 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
Harald Welteba6988b2011-08-17 12:46:48 +020025/*! \addtogroup bitvec
26 * @{
27 */
28
29/*! \file bitvec.c
30 * \brief Osmocom bit vector abstraction
31 */
Harald Welteec8b4502010-02-20 20:34:29 +010032
33#include <errno.h>
34#include <stdint.h>
Jacob Erlbeck5f349be2015-12-21 16:04:03 +010035#include <string.h>
Maxa15f05f2016-01-26 10:43:15 +010036#include <stdio.h>
Harald Welteec8b4502010-02-20 20:34:29 +010037
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010038#include <osmocom/core/bitvec.h>
Harald Welteec8b4502010-02-20 20:34:29 +010039
40#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
41
42static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
43{
44 unsigned int bytenum = bitnum / 8;
45
46 return bytenum;
47}
48
49/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
50static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
51{
52 int bitval;
53
54 switch (bit) {
55 case ZERO:
56 bitval = (0 << bitnum);
57 break;
58 case ONE:
59 bitval = (1 << bitnum);
60 break;
61 case L:
62 bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
63 break;
64 case H:
65 bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
66 break;
67 default:
68 return 0;
69 }
70 return bitval;
71}
72
Harald Welteba6988b2011-08-17 12:46:48 +020073/*! \brief check if the bit is 0 or 1 for a given position inside a bitvec
74 * \param[in] bv the bit vector on which to check
75 * \param[in] bitnr the bit number inside the bit vector to check
76 * \returns
77 */
Harald Welted9abf012010-03-06 11:28:49 +010078enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
Harald Welteec8b4502010-02-20 20:34:29 +010079{
80 unsigned int bytenum = bytenum_from_bitnum(bitnr);
81 unsigned int bitnum = 7 - (bitnr % 8);
82 uint8_t bitval;
83
84 if (bytenum >= bv->data_len)
85 return -EINVAL;
86
87 bitval = bitval2mask(ONE, bitnum);
88
89 if (bv->data[bytenum] & bitval)
90 return ONE;
91
92 return ZERO;
93}
94
Harald Welteba6988b2011-08-17 12:46:48 +020095/*! \brief check if the bit is L or H for a given position inside a bitvec
96 * \param[in] bv the bit vector on which to check
97 * \param[in] bitnr the bit number inside the bit vector to check
98 */
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +000099enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
100 unsigned int bitnr)
101{
102 unsigned int bytenum = bytenum_from_bitnum(bitnr);
103 unsigned int bitnum = 7 - (bitnr % 8);
104 uint8_t bitval;
105
106 if (bytenum >= bv->data_len)
107 return -EINVAL;
108
109 bitval = bitval2mask(H, bitnum);
110
Andreas.Eversbergdc0ebdf2010-10-24 11:59:33 +0200111 if ((bv->data[bytenum] & (1 << bitnum)) == bitval)
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000112 return H;
113
114 return L;
115}
116
Harald Welteba6988b2011-08-17 12:46:48 +0200117/*! \brief get the Nth set bit inside the bit vector
118 * \param[in] bv the bit vector to use
119 * \param[in] n the bit number to get
120 * \returns the bit number (offset) of the Nth set bit in \a bv
121 */
Harald Welted9abf012010-03-06 11:28:49 +0100122unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
Harald Welteec8b4502010-02-20 20:34:29 +0100123{
124 unsigned int i, k = 0;
125
126 for (i = 0; i < bv->data_len*8; i++) {
127 if (bitvec_get_bit_pos(bv, i) == ONE) {
128 k++;
129 if (k == n)
130 return i;
131 }
132 }
133
134 return 0;
135}
136
Harald Welteba6988b2011-08-17 12:46:48 +0200137/*! \brief set a bit at given position in a bit vector
138 * \param[in] bv bit vector on which to operate
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100139 * \param[in] bitnr number of bit to be set
Harald Welteba6988b2011-08-17 12:46:48 +0200140 * \param[in] bit value to which the bit is to be set
141 */
Harald Welteec8b4502010-02-20 20:34:29 +0100142int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
143 enum bit_value bit)
144{
145 unsigned int bytenum = bytenum_from_bitnum(bitnr);
146 unsigned int bitnum = 7 - (bitnr % 8);
147 uint8_t bitval;
148
149 if (bytenum >= bv->data_len)
150 return -EINVAL;
151
152 /* first clear the bit */
153 bitval = bitval2mask(ONE, bitnum);
154 bv->data[bytenum] &= ~bitval;
155
156 /* then set it to desired value */
157 bitval = bitval2mask(bit, bitnum);
158 bv->data[bytenum] |= bitval;
159
160 return 0;
161}
162
Harald Welteba6988b2011-08-17 12:46:48 +0200163/*! \brief set the next bit inside a bitvec
164 * \param[in] bv bit vector to be used
165 * \param[in] bit value of the bit to be set
166 */
Harald Welteec8b4502010-02-20 20:34:29 +0100167int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
168{
169 int rc;
170
171 rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
172 if (!rc)
173 bv->cur_bit++;
174
175 return rc;
176}
177
Harald Welteba6988b2011-08-17 12:46:48 +0200178/*! \brief get the next bit (low/high) inside a bitvec */
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000179int bitvec_get_bit_high(struct bitvec *bv)
180{
181 int rc;
182
183 rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
184 if (rc >= 0)
185 bv->cur_bit++;
186
187 return rc;
188}
189
Harald Welteba6988b2011-08-17 12:46:48 +0200190/*! \brief set multiple bits (based on array of bitvals) at current pos
191 * \param[in] bv bit vector
192 * \param[in] bits array of \ref bit_value
193 * \param[in] count number of bits to set
194 */
Maxe49af082016-01-22 16:46:56 +0100195int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, unsigned int count)
Harald Welteec8b4502010-02-20 20:34:29 +0100196{
197 int i, rc;
198
199 for (i = 0; i < count; i++) {
200 rc = bitvec_set_bit(bv, bits[i]);
201 if (rc)
202 return rc;
203 }
204
205 return 0;
206}
207
Harald Welteba6988b2011-08-17 12:46:48 +0200208/*! \brief set multiple bits (based on numeric value) at current pos */
Maxe49af082016-01-22 16:46:56 +0100209int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
Harald Welteec8b4502010-02-20 20:34:29 +0100210{
Maxe49af082016-01-22 16:46:56 +0100211 int rc;
212 unsigned i;
Harald Welteec8b4502010-02-20 20:34:29 +0100213 for (i = 0; i < num_bits; i++) {
214 int bit = 0;
215 if (ui & (1 << (num_bits - i - 1)))
216 bit = 1;
217 rc = bitvec_set_bit(bv, bit);
218 if (rc)
219 return rc;
220 }
221
222 return 0;
223}
224
Harald Welteba6988b2011-08-17 12:46:48 +0200225/*! \brief get multiple bits (based on numeric value) from current pos */
Maxe49af082016-01-22 16:46:56 +0100226int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000227{
228 int i;
229 unsigned int ui = 0;
230
231 for (i = 0; i < num_bits; i++) {
232 int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
233 if (bit < 0)
234 return bit;
235 if (bit)
236 ui |= (1 << (num_bits - i - 1));
237 bv->cur_bit++;
238 }
239
240 return ui;
241}
242
Harald Welteba6988b2011-08-17 12:46:48 +0200243/*! \brief pad all remaining bits up to num_bits */
Harald Welteec8b4502010-02-20 20:34:29 +0100244int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
245{
246 unsigned int i;
247
248 for (i = bv->cur_bit; i <= up_to_bit; i++)
249 bitvec_set_bit(bv, L);
250
251 return 0;
252}
Pablo Neira Ayuso36bdf2c2011-03-28 19:24:19 +0200253
Harald Welteba6988b2011-08-17 12:46:48 +0200254/*! \brief find first bit set in bit vector */
Pablo Neira Ayuso36bdf2c2011-03-28 19:24:19 +0200255int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n,
256 enum bit_value val)
257{
258 unsigned int i;
259
260 for (i = n; i < bv->data_len*8; i++) {
261 if (bitvec_get_bit_pos(bv, i) == val)
262 return i;
263 }
264
265 return -1;
266}
Harald Welteba6988b2011-08-17 12:46:48 +0200267
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100268/*! \brief get multiple bytes from current pos
269 * Assumes MSB first encoding.
270 * \param[in] bv bit vector
271 * \param[in] bytes array
272 * \param[in] count number of bytes to copy
273 */
Maxe49af082016-01-22 16:46:56 +0100274int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count)
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100275{
276 int byte_offs = bytenum_from_bitnum(bv->cur_bit);
277 int bit_offs = bv->cur_bit % 8;
278 uint8_t c, last_c;
279 int i;
280 uint8_t *src;
281
282 if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
283 return -EINVAL;
284
285 if (bit_offs == 0) {
286 memcpy(bytes, bv->data + byte_offs, count);
287 } else {
288 src = bv->data + byte_offs;
289 last_c = *(src++);
290 for (i = count; i > 0; i--) {
291 c = *(src++);
292 *(bytes++) =
293 (last_c << bit_offs) |
294 (c >> (8 - bit_offs));
295 last_c = c;
296 }
297 }
298
299 bv->cur_bit += count * 8;
300 return 0;
301}
302
303/*! \brief set multiple bytes at current pos
304 * Assumes MSB first encoding.
305 * \param[in] bv bit vector
306 * \param[in] bytes array
307 * \param[in] count number of bytes to copy
308 */
Maxe49af082016-01-22 16:46:56 +0100309int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count)
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100310{
311 int byte_offs = bytenum_from_bitnum(bv->cur_bit);
312 int bit_offs = bv->cur_bit % 8;
313 uint8_t c, last_c;
314 int i;
315 uint8_t *dst;
316
317 if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
318 return -EINVAL;
319
320 if (bit_offs == 0) {
321 memcpy(bv->data + byte_offs, bytes, count);
322 } else if (count > 0) {
323 dst = bv->data + byte_offs;
324 /* Get lower bits of first dst byte */
325 last_c = *dst >> (8 - bit_offs);
326 for (i = count; i > 0; i--) {
327 c = *(bytes++);
328 *(dst++) =
329 (last_c << (8 - bit_offs)) |
330 (c >> bit_offs);
331 last_c = c;
332 }
333 /* Overwrite lower bits of N+1 dst byte */
334 *dst = (*dst & ((1 << (8 - bit_offs)) - 1)) |
335 (last_c << (8 - bit_offs));
336 }
337
338 bv->cur_bit += count * 8;
339 return 0;
340}
Maxa15f05f2016-01-26 10:43:15 +0100341
342struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *ctx)
343{
344 struct bitvec *bv = talloc_zero(ctx, struct bitvec);
345 if (!bv)
346 return NULL;
347
348 bv->data = talloc_zero_array(bv, uint8_t, size);
349 if (!(bv->data)) {
350 talloc_free(bv);
351 return NULL;
352 }
353
354 bv->data_len = size;
355 bv->cur_bit = 0;
356 return bv;
357}
358
359void bitvec_free(struct bitvec *bv)
360{
361 talloc_free(bv->data);
362 talloc_free(bv);
363}
364
365unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
366{
367 unsigned int i = 0;
368 for (i = 0; i < bv->data_len; i++)
369 buffer[i] = bv->data[i];
370
371 return i;
372}
373
374unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
375{
376 unsigned int i = 0;
377 for (i = 0; i < bv->data_len; i++)
378 bv->data[i] = buffer[i];
379
380 return i;
381}
382
383
384int bitvec_unhex(struct bitvec *bv, const char *src)
385{
Holger Hans Peter Freyther2745b482016-01-27 17:08:02 +0100386 unsigned i;
Maxa15f05f2016-01-26 10:43:15 +0100387 unsigned val;
388 unsigned write_index = 0;
389 unsigned digits = bv->data_len * 2;
Holger Hans Peter Freyther2745b482016-01-27 17:08:02 +0100390
391 for (i = 0; i < digits; i++) {
Maxa15f05f2016-01-26 10:43:15 +0100392 if (sscanf(src + i, "%1x", &val) < 1) {
393 return 1;
394 }
395 bitvec_write_field(bv, write_index,val, 4);
396 }
397 return 0;
398}
399
400uint64_t bitvec_read_field(struct bitvec *bv, unsigned int read_index, unsigned int len)
401{
402 unsigned int i;
403 uint64_t ui = 0;
404 bv->cur_bit = read_index;
405
406 for (i = 0; i < len; i++) {
407 int bit = bitvec_get_bit_pos((const struct bitvec *)bv, bv->cur_bit);
408 if (bit < 0)
409 return bit;
410 if (bit)
411 ui |= ((uint64_t)1 << (len - i - 1));
412 bv->cur_bit++;
413 }
414 read_index += len;
415 return ui;
416}
417
418
419int bitvec_write_field(struct bitvec *bv, unsigned int write_index, uint64_t val, unsigned int len)
420{
421 unsigned int i;
422 int rc;
423 bv->cur_bit = write_index;
424 for (i = 0; i < len; i++) {
425 int bit = 0;
426 if (val & ((uint64_t)1 << (len - i - 1)))
427 bit = 1;
428 rc = bitvec_set_bit(bv, bit);
429 if (rc)
430 return rc;
431 }
432 write_index += len;
433 return 0;
434}
435
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200436/*! @} */