blob: b5d2c243d7a5961486a09ed82e2bf3a99d824e7a [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
Max912bc6f2016-01-28 12:07:12 +0100141 * \returns 0 on success, negative value on error
Harald Welteba6988b2011-08-17 12:46:48 +0200142 */
Harald Welteec8b4502010-02-20 20:34:29 +0100143int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
144 enum bit_value bit)
145{
146 unsigned int bytenum = bytenum_from_bitnum(bitnr);
147 unsigned int bitnum = 7 - (bitnr % 8);
148 uint8_t bitval;
149
150 if (bytenum >= bv->data_len)
151 return -EINVAL;
152
153 /* first clear the bit */
154 bitval = bitval2mask(ONE, bitnum);
155 bv->data[bytenum] &= ~bitval;
156
157 /* then set it to desired value */
158 bitval = bitval2mask(bit, bitnum);
159 bv->data[bytenum] |= bitval;
160
161 return 0;
162}
163
Harald Welteba6988b2011-08-17 12:46:48 +0200164/*! \brief set the next bit inside a bitvec
165 * \param[in] bv bit vector to be used
166 * \param[in] bit value of the bit to be set
Max912bc6f2016-01-28 12:07:12 +0100167 * \returns 0 on success, negative value on error
Harald Welteba6988b2011-08-17 12:46:48 +0200168 */
Harald Welteec8b4502010-02-20 20:34:29 +0100169int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
170{
171 int rc;
172
173 rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
174 if (!rc)
175 bv->cur_bit++;
176
177 return rc;
178}
179
Harald Welteba6988b2011-08-17 12:46:48 +0200180/*! \brief get the next bit (low/high) inside a bitvec */
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000181int bitvec_get_bit_high(struct bitvec *bv)
182{
183 int rc;
184
185 rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
186 if (rc >= 0)
187 bv->cur_bit++;
188
189 return rc;
190}
191
Harald Welteba6988b2011-08-17 12:46:48 +0200192/*! \brief set multiple bits (based on array of bitvals) at current pos
193 * \param[in] bv bit vector
194 * \param[in] bits array of \ref bit_value
195 * \param[in] count number of bits to set
196 */
Maxe49af082016-01-22 16:46:56 +0100197int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, unsigned int count)
Harald Welteec8b4502010-02-20 20:34:29 +0100198{
199 int i, rc;
200
201 for (i = 0; i < count; i++) {
202 rc = bitvec_set_bit(bv, bits[i]);
203 if (rc)
204 return rc;
205 }
206
207 return 0;
208}
209
Harald Welteba6988b2011-08-17 12:46:48 +0200210/*! \brief set multiple bits (based on numeric value) at current pos */
Maxe49af082016-01-22 16:46:56 +0100211int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
Harald Welteec8b4502010-02-20 20:34:29 +0100212{
Maxe49af082016-01-22 16:46:56 +0100213 int rc;
214 unsigned i;
Harald Welteec8b4502010-02-20 20:34:29 +0100215 for (i = 0; i < num_bits; i++) {
216 int bit = 0;
217 if (ui & (1 << (num_bits - i - 1)))
218 bit = 1;
219 rc = bitvec_set_bit(bv, bit);
220 if (rc)
221 return rc;
222 }
223
224 return 0;
225}
226
Harald Welteba6988b2011-08-17 12:46:48 +0200227/*! \brief get multiple bits (based on numeric value) from current pos */
Maxe49af082016-01-22 16:46:56 +0100228int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000229{
230 int i;
231 unsigned int ui = 0;
232
233 for (i = 0; i < num_bits; i++) {
234 int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
235 if (bit < 0)
236 return bit;
237 if (bit)
238 ui |= (1 << (num_bits - i - 1));
239 bv->cur_bit++;
240 }
241
242 return ui;
243}
244
Harald Welteba6988b2011-08-17 12:46:48 +0200245/*! \brief pad all remaining bits up to num_bits */
Harald Welteec8b4502010-02-20 20:34:29 +0100246int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
247{
248 unsigned int i;
249
250 for (i = bv->cur_bit; i <= up_to_bit; i++)
251 bitvec_set_bit(bv, L);
252
253 return 0;
254}
Pablo Neira Ayuso36bdf2c2011-03-28 19:24:19 +0200255
Harald Welteba6988b2011-08-17 12:46:48 +0200256/*! \brief find first bit set in bit vector */
Pablo Neira Ayuso36bdf2c2011-03-28 19:24:19 +0200257int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n,
258 enum bit_value val)
259{
260 unsigned int i;
261
262 for (i = n; i < bv->data_len*8; i++) {
263 if (bitvec_get_bit_pos(bv, i) == val)
264 return i;
265 }
266
267 return -1;
268}
Harald Welteba6988b2011-08-17 12:46:48 +0200269
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100270/*! \brief get multiple bytes from current pos
271 * Assumes MSB first encoding.
272 * \param[in] bv bit vector
273 * \param[in] bytes array
274 * \param[in] count number of bytes to copy
275 */
Maxe49af082016-01-22 16:46:56 +0100276int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count)
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100277{
278 int byte_offs = bytenum_from_bitnum(bv->cur_bit);
279 int bit_offs = bv->cur_bit % 8;
280 uint8_t c, last_c;
281 int i;
282 uint8_t *src;
283
284 if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
285 return -EINVAL;
286
287 if (bit_offs == 0) {
288 memcpy(bytes, bv->data + byte_offs, count);
289 } else {
290 src = bv->data + byte_offs;
291 last_c = *(src++);
292 for (i = count; i > 0; i--) {
293 c = *(src++);
294 *(bytes++) =
295 (last_c << bit_offs) |
296 (c >> (8 - bit_offs));
297 last_c = c;
298 }
299 }
300
301 bv->cur_bit += count * 8;
302 return 0;
303}
304
305/*! \brief set multiple bytes at current pos
306 * Assumes MSB first encoding.
307 * \param[in] bv bit vector
308 * \param[in] bytes array
309 * \param[in] count number of bytes to copy
310 */
Maxe49af082016-01-22 16:46:56 +0100311int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count)
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100312{
313 int byte_offs = bytenum_from_bitnum(bv->cur_bit);
314 int bit_offs = bv->cur_bit % 8;
315 uint8_t c, last_c;
316 int i;
317 uint8_t *dst;
318
319 if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
320 return -EINVAL;
321
322 if (bit_offs == 0) {
323 memcpy(bv->data + byte_offs, bytes, count);
324 } else if (count > 0) {
325 dst = bv->data + byte_offs;
326 /* Get lower bits of first dst byte */
327 last_c = *dst >> (8 - bit_offs);
328 for (i = count; i > 0; i--) {
329 c = *(bytes++);
330 *(dst++) =
331 (last_c << (8 - bit_offs)) |
332 (c >> bit_offs);
333 last_c = c;
334 }
335 /* Overwrite lower bits of N+1 dst byte */
336 *dst = (*dst & ((1 << (8 - bit_offs)) - 1)) |
337 (last_c << (8 - bit_offs));
338 }
339
340 bv->cur_bit += count * 8;
341 return 0;
342}
Maxa15f05f2016-01-26 10:43:15 +0100343
344struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *ctx)
345{
346 struct bitvec *bv = talloc_zero(ctx, struct bitvec);
347 if (!bv)
348 return NULL;
349
350 bv->data = talloc_zero_array(bv, uint8_t, size);
351 if (!(bv->data)) {
352 talloc_free(bv);
353 return NULL;
354 }
355
356 bv->data_len = size;
357 bv->cur_bit = 0;
358 return bv;
359}
360
361void bitvec_free(struct bitvec *bv)
362{
363 talloc_free(bv->data);
364 talloc_free(bv);
365}
366
367unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
368{
369 unsigned int i = 0;
370 for (i = 0; i < bv->data_len; i++)
371 buffer[i] = bv->data[i];
372
373 return i;
374}
375
376unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
377{
378 unsigned int i = 0;
379 for (i = 0; i < bv->data_len; i++)
380 bv->data[i] = buffer[i];
381
382 return i;
383}
384
385
386int bitvec_unhex(struct bitvec *bv, const char *src)
387{
Holger Hans Peter Freyther2745b482016-01-27 17:08:02 +0100388 unsigned i;
Maxa15f05f2016-01-26 10:43:15 +0100389 unsigned val;
390 unsigned write_index = 0;
391 unsigned digits = bv->data_len * 2;
Holger Hans Peter Freyther2745b482016-01-27 17:08:02 +0100392
393 for (i = 0; i < digits; i++) {
Maxa15f05f2016-01-26 10:43:15 +0100394 if (sscanf(src + i, "%1x", &val) < 1) {
395 return 1;
396 }
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100397 bitvec_write_field(bv, &write_index, val, 4);
Maxa15f05f2016-01-26 10:43:15 +0100398 }
399 return 0;
400}
401
Max912bc6f2016-01-28 12:07:12 +0100402/*! \brief read part of the vector
403 * \param[in] bv The boolean vector to work on
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100404 * \param[in,out] read_index Where reading supposed to start in the vector
Max912bc6f2016-01-28 12:07:12 +0100405 * \param[in] len How many bits to read from vector
406 * \returns read bits or negative value on error
407 */
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100408uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len)
Maxa15f05f2016-01-26 10:43:15 +0100409{
410 unsigned int i;
411 uint64_t ui = 0;
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100412 bv->cur_bit = *read_index;
Maxa15f05f2016-01-26 10:43:15 +0100413
414 for (i = 0; i < len; i++) {
415 int bit = bitvec_get_bit_pos((const struct bitvec *)bv, bv->cur_bit);
416 if (bit < 0)
417 return bit;
418 if (bit)
419 ui |= ((uint64_t)1 << (len - i - 1));
420 bv->cur_bit++;
421 }
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100422 *read_index += len;
Maxa15f05f2016-01-26 10:43:15 +0100423 return ui;
424}
425
Max912bc6f2016-01-28 12:07:12 +0100426/*! \brief write into the vector
427 * \param[in] bv The boolean vector to work on
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100428 * \param[in,out] write_index Where writing supposed to start in the vector
Max912bc6f2016-01-28 12:07:12 +0100429 * \param[in] len How many bits to write
430 * \returns next write index or negative value on error
431 */
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100432int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len)
Maxa15f05f2016-01-26 10:43:15 +0100433{
434 unsigned int i;
435 int rc;
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100436 bv->cur_bit = *write_index;
Maxa15f05f2016-01-26 10:43:15 +0100437 for (i = 0; i < len; i++) {
438 int bit = 0;
439 if (val & ((uint64_t)1 << (len - i - 1)))
440 bit = 1;
441 rc = bitvec_set_bit(bv, bit);
442 if (rc)
443 return rc;
444 }
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100445 *write_index += len;
Maxa15f05f2016-01-26 10:43:15 +0100446 return 0;
447}
448
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200449/*! @} */