1135446Strhodes/*
2193149Sdougb * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2001  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: bitstring.c,v 1.17 2007/06/19 23:47:17 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <stddef.h>
25135446Strhodes
26135446Strhodes#include <isc/magic.h>
27135446Strhodes#include <isc/bitstring.h>
28135446Strhodes#include <isc/util.h>
29135446Strhodes
30135446Strhodes#define DIV8(x)			((x) >> 3)
31135446Strhodes#define MOD8(x)			((x) & 0x00000007U)
32135446Strhodes#define OCTETS(n)		(((n) + 7) >> 3)
33135446Strhodes#define PADDED(n)		((((n) + 7) >> 3) << 3)
34135446Strhodes#define BITSET(bs, n) 		(((bs)->data[DIV8(n)] & \
35135446Strhodes				 (1 << (7 - MOD8(n)))) != 0)
36135446Strhodes#define SETBIT(bs, n)		(bs)->data[DIV8(n)] |= (1 << (7 - MOD8(n)))
37135446Strhodes#define CLEARBIT(bs, n)		(bs)->data[DIV8(n)] &= ~(1 << (7 - MOD8(n)))
38135446Strhodes
39135446Strhodes#define BITSTRING_MAGIC		ISC_MAGIC('B', 'S', 't', 'r')
40135446Strhodes#define VALID_BITSTRING(b)	ISC_MAGIC_VALID(b, BITSTRING_MAGIC)
41135446Strhodes
42135446Strhodesvoid
43135446Strhodesisc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data,
44135446Strhodes		   unsigned int length, unsigned int size, isc_boolean_t lsb0)
45135446Strhodes{
46135446Strhodes	/*
47135446Strhodes	 * Make 'bitstring' refer to the bitstring of 'size' bits starting
48135446Strhodes	 * at 'data'.  'length' bits of the bitstring are valid.  If 'lsb0'
49135446Strhodes	 * is set then, bit 0 refers to the least significant bit of the
50135446Strhodes	 * bitstring.  Otherwise bit 0 is the most significant bit.
51135446Strhodes	 */
52135446Strhodes
53135446Strhodes	REQUIRE(bitstring != NULL);
54135446Strhodes	REQUIRE(data != NULL);
55135446Strhodes	REQUIRE(length <= size);
56135446Strhodes
57135446Strhodes	bitstring->magic = BITSTRING_MAGIC;
58135446Strhodes	bitstring->data = data;
59135446Strhodes	bitstring->length = length;
60135446Strhodes	bitstring->size = size;
61135446Strhodes	bitstring->lsb0 = lsb0;
62135446Strhodes}
63135446Strhodes
64135446Strhodesvoid
65135446Strhodesisc_bitstring_invalidate(isc_bitstring_t *bitstring) {
66135446Strhodes
67135446Strhodes	/*
68135446Strhodes	 * Invalidate 'bitstring'.
69135446Strhodes	 */
70135446Strhodes
71135446Strhodes	REQUIRE(VALID_BITSTRING(bitstring));
72135446Strhodes
73135446Strhodes	bitstring->magic = 0;
74135446Strhodes	bitstring->data = NULL;
75135446Strhodes	bitstring->length = 0;
76135446Strhodes	bitstring->size = 0;
77135446Strhodes	bitstring->lsb0 = ISC_FALSE;
78135446Strhodes}
79135446Strhodes
80135446Strhodesvoid
81135446Strhodesisc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos,
82135446Strhodes		   isc_bitstring_t *target, unsigned int tbitpos,
83135446Strhodes		   unsigned int n)
84135446Strhodes{
85135446Strhodes	unsigned int tlast;
86135446Strhodes
87135446Strhodes	/*
88135446Strhodes	 * Starting at bit 'sbitpos', copy 'n' bits from 'source' to
89135446Strhodes	 * the 'n' bits of 'target' starting at 'tbitpos'.
90135446Strhodes	 */
91135446Strhodes
92135446Strhodes	REQUIRE(VALID_BITSTRING(source));
93135446Strhodes	REQUIRE(VALID_BITSTRING(target));
94135446Strhodes	REQUIRE(source->lsb0 == target->lsb0);
95135446Strhodes	if (source->lsb0) {
96135446Strhodes		REQUIRE(sbitpos <= source->length);
97135446Strhodes		sbitpos = PADDED(source->size) - sbitpos;
98135446Strhodes		REQUIRE(sbitpos >= n);
99135446Strhodes		sbitpos -= n;
100135446Strhodes	} else
101135446Strhodes		REQUIRE(sbitpos + n <= source->length);
102135446Strhodes	tlast = tbitpos + n;
103135446Strhodes	if (target->lsb0) {
104135446Strhodes		REQUIRE(tbitpos <= target->length);
105135446Strhodes		tbitpos = PADDED(target->size) - tbitpos;
106135446Strhodes		REQUIRE(tbitpos >= n);
107135446Strhodes		tbitpos -= n;
108135446Strhodes	} else
109135446Strhodes		REQUIRE(tlast <= target->size);
110135446Strhodes
111135446Strhodes	if (tlast > target->length)
112135446Strhodes		target->length = tlast;
113135446Strhodes
114135446Strhodes	/*
115135446Strhodes	 * This is far from optimal...
116135446Strhodes	 */
117135446Strhodes
118135446Strhodes	while (n > 0) {
119135446Strhodes		if (BITSET(source, sbitpos))
120135446Strhodes			SETBIT(target, tbitpos);
121135446Strhodes		else
122135446Strhodes			CLEARBIT(target, tbitpos);
123135446Strhodes		sbitpos++;
124135446Strhodes		tbitpos++;
125135446Strhodes		n--;
126135446Strhodes	}
127135446Strhodes}
128