xref: /freebsd/crypto/openssh/bitmap.c (revision 47dd1d1b619cc035b82b49a91a25544309ff95ae)
1*47dd1d1bSDag-Erling Smørgrav /* $OpenBSD: bitmap.c,v 1.9 2017/10/20 01:56:39 djm Exp $ */
2bc5531deSDag-Erling Smørgrav /*
3bc5531deSDag-Erling Smørgrav  * Copyright (c) 2015 Damien Miller <djm@mindrot.org>
4bc5531deSDag-Erling Smørgrav  *
5bc5531deSDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
6bc5531deSDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
7bc5531deSDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
8bc5531deSDag-Erling Smørgrav  *
9bc5531deSDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10bc5531deSDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11bc5531deSDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12bc5531deSDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13bc5531deSDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14bc5531deSDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15bc5531deSDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16bc5531deSDag-Erling Smørgrav  */
17bc5531deSDag-Erling Smørgrav 
18bc5531deSDag-Erling Smørgrav #include "includes.h"
19bc5531deSDag-Erling Smørgrav 
20bc5531deSDag-Erling Smørgrav #include <sys/types.h>
21bc5531deSDag-Erling Smørgrav #include <string.h>
22bc5531deSDag-Erling Smørgrav #include <stdlib.h>
23bc5531deSDag-Erling Smørgrav 
24bc5531deSDag-Erling Smørgrav #include "bitmap.h"
25bc5531deSDag-Erling Smørgrav 
26bc5531deSDag-Erling Smørgrav #define BITMAP_WTYPE	u_int
27bc5531deSDag-Erling Smørgrav #define BITMAP_MAX	(1<<24)
28bc5531deSDag-Erling Smørgrav #define BITMAP_BYTES	(sizeof(BITMAP_WTYPE))
29bc5531deSDag-Erling Smørgrav #define BITMAP_BITS	(sizeof(BITMAP_WTYPE) * 8)
30bc5531deSDag-Erling Smørgrav #define BITMAP_WMASK	((BITMAP_WTYPE)BITMAP_BITS - 1)
31bc5531deSDag-Erling Smørgrav struct bitmap {
32bc5531deSDag-Erling Smørgrav 	BITMAP_WTYPE *d;
33bc5531deSDag-Erling Smørgrav 	size_t len; /* number of words allocated */
34bc5531deSDag-Erling Smørgrav 	size_t top; /* index of top word allocated */
35bc5531deSDag-Erling Smørgrav };
36bc5531deSDag-Erling Smørgrav 
37bc5531deSDag-Erling Smørgrav struct bitmap *
bitmap_new(void)38bc5531deSDag-Erling Smørgrav bitmap_new(void)
39bc5531deSDag-Erling Smørgrav {
40bc5531deSDag-Erling Smørgrav 	struct bitmap *ret;
41bc5531deSDag-Erling Smørgrav 
42bc5531deSDag-Erling Smørgrav 	if ((ret = calloc(1, sizeof(*ret))) == NULL)
43bc5531deSDag-Erling Smørgrav 		return NULL;
44bc5531deSDag-Erling Smørgrav 	if ((ret->d = calloc(1, BITMAP_BYTES)) == NULL) {
45bc5531deSDag-Erling Smørgrav 		free(ret);
46bc5531deSDag-Erling Smørgrav 		return NULL;
47bc5531deSDag-Erling Smørgrav 	}
48bc5531deSDag-Erling Smørgrav 	ret->len = 1;
49bc5531deSDag-Erling Smørgrav 	ret->top = 0;
50bc5531deSDag-Erling Smørgrav 	return ret;
51bc5531deSDag-Erling Smørgrav }
52bc5531deSDag-Erling Smørgrav 
53bc5531deSDag-Erling Smørgrav void
bitmap_free(struct bitmap * b)54bc5531deSDag-Erling Smørgrav bitmap_free(struct bitmap *b)
55bc5531deSDag-Erling Smørgrav {
56bc5531deSDag-Erling Smørgrav 	if (b != NULL && b->d != NULL) {
574f52dfbbSDag-Erling Smørgrav 		bitmap_zero(b);
58bc5531deSDag-Erling Smørgrav 		free(b->d);
594f52dfbbSDag-Erling Smørgrav 		b->d = NULL;
60bc5531deSDag-Erling Smørgrav 	}
61bc5531deSDag-Erling Smørgrav 	free(b);
62bc5531deSDag-Erling Smørgrav }
63bc5531deSDag-Erling Smørgrav 
64bc5531deSDag-Erling Smørgrav void
bitmap_zero(struct bitmap * b)65bc5531deSDag-Erling Smørgrav bitmap_zero(struct bitmap *b)
66bc5531deSDag-Erling Smørgrav {
67bc5531deSDag-Erling Smørgrav 	memset(b->d, 0, b->len * BITMAP_BYTES);
68bc5531deSDag-Erling Smørgrav 	b->top = 0;
69bc5531deSDag-Erling Smørgrav }
70bc5531deSDag-Erling Smørgrav 
71bc5531deSDag-Erling Smørgrav int
bitmap_test_bit(struct bitmap * b,u_int n)72bc5531deSDag-Erling Smørgrav bitmap_test_bit(struct bitmap *b, u_int n)
73bc5531deSDag-Erling Smørgrav {
74bc5531deSDag-Erling Smørgrav 	if (b->top >= b->len)
75bc5531deSDag-Erling Smørgrav 		return 0; /* invalid */
76bc5531deSDag-Erling Smørgrav 	if (b->len == 0 || (n / BITMAP_BITS) > b->top)
77bc5531deSDag-Erling Smørgrav 		return 0;
78bc5531deSDag-Erling Smørgrav 	return (b->d[n / BITMAP_BITS] >> (n & BITMAP_WMASK)) & 1;
79bc5531deSDag-Erling Smørgrav }
80bc5531deSDag-Erling Smørgrav 
81bc5531deSDag-Erling Smørgrav static int
reserve(struct bitmap * b,u_int n)82bc5531deSDag-Erling Smørgrav reserve(struct bitmap *b, u_int n)
83bc5531deSDag-Erling Smørgrav {
84bc5531deSDag-Erling Smørgrav 	BITMAP_WTYPE *tmp;
85bc5531deSDag-Erling Smørgrav 	size_t nlen;
86bc5531deSDag-Erling Smørgrav 
87bc5531deSDag-Erling Smørgrav 	if (b->top >= b->len || n > BITMAP_MAX)
88bc5531deSDag-Erling Smørgrav 		return -1; /* invalid */
89bc5531deSDag-Erling Smørgrav 	nlen = (n / BITMAP_BITS) + 1;
90bc5531deSDag-Erling Smørgrav 	if (b->len < nlen) {
914f52dfbbSDag-Erling Smørgrav 		if ((tmp = recallocarray(b->d, b->len,
924f52dfbbSDag-Erling Smørgrav 		    nlen, BITMAP_BYTES)) == NULL)
93bc5531deSDag-Erling Smørgrav 			return -1;
94bc5531deSDag-Erling Smørgrav 		b->d = tmp;
95bc5531deSDag-Erling Smørgrav 		b->len = nlen;
96bc5531deSDag-Erling Smørgrav 	}
97bc5531deSDag-Erling Smørgrav 	return 0;
98bc5531deSDag-Erling Smørgrav }
99bc5531deSDag-Erling Smørgrav 
100bc5531deSDag-Erling Smørgrav int
bitmap_set_bit(struct bitmap * b,u_int n)101bc5531deSDag-Erling Smørgrav bitmap_set_bit(struct bitmap *b, u_int n)
102bc5531deSDag-Erling Smørgrav {
103bc5531deSDag-Erling Smørgrav 	int r;
104bc5531deSDag-Erling Smørgrav 	size_t offset;
105bc5531deSDag-Erling Smørgrav 
106bc5531deSDag-Erling Smørgrav 	if ((r = reserve(b, n)) != 0)
107bc5531deSDag-Erling Smørgrav 		return r;
108bc5531deSDag-Erling Smørgrav 	offset = n / BITMAP_BITS;
109bc5531deSDag-Erling Smørgrav 	if (offset > b->top)
110bc5531deSDag-Erling Smørgrav 		b->top = offset;
111bc5531deSDag-Erling Smørgrav 	b->d[offset] |= (BITMAP_WTYPE)1 << (n & BITMAP_WMASK);
112bc5531deSDag-Erling Smørgrav 	return 0;
113bc5531deSDag-Erling Smørgrav }
114bc5531deSDag-Erling Smørgrav 
115bc5531deSDag-Erling Smørgrav /* Resets b->top to point to the most significant bit set in b->d */
116bc5531deSDag-Erling Smørgrav static void
retop(struct bitmap * b)117bc5531deSDag-Erling Smørgrav retop(struct bitmap *b)
118bc5531deSDag-Erling Smørgrav {
119bc5531deSDag-Erling Smørgrav 	if (b->top >= b->len)
120bc5531deSDag-Erling Smørgrav 		return;
121bc5531deSDag-Erling Smørgrav 	while (b->top > 0 && b->d[b->top] == 0)
122bc5531deSDag-Erling Smørgrav 		b->top--;
123bc5531deSDag-Erling Smørgrav }
124bc5531deSDag-Erling Smørgrav 
125bc5531deSDag-Erling Smørgrav void
bitmap_clear_bit(struct bitmap * b,u_int n)126bc5531deSDag-Erling Smørgrav bitmap_clear_bit(struct bitmap *b, u_int n)
127bc5531deSDag-Erling Smørgrav {
128bc5531deSDag-Erling Smørgrav 	size_t offset;
129bc5531deSDag-Erling Smørgrav 
130bc5531deSDag-Erling Smørgrav 	if (b->top >= b->len || n > BITMAP_MAX)
131bc5531deSDag-Erling Smørgrav 		return; /* invalid */
132bc5531deSDag-Erling Smørgrav 	offset = n / BITMAP_BITS;
133bc5531deSDag-Erling Smørgrav 	if (offset > b->top)
134bc5531deSDag-Erling Smørgrav 		return;
135bc5531deSDag-Erling Smørgrav 	b->d[offset] &= ~((BITMAP_WTYPE)1 << (n & BITMAP_WMASK));
136bc5531deSDag-Erling Smørgrav 	/* The top may have changed as a result of the clear */
137bc5531deSDag-Erling Smørgrav 	retop(b);
138bc5531deSDag-Erling Smørgrav }
139bc5531deSDag-Erling Smørgrav 
140bc5531deSDag-Erling Smørgrav size_t
bitmap_nbits(struct bitmap * b)141bc5531deSDag-Erling Smørgrav bitmap_nbits(struct bitmap *b)
142bc5531deSDag-Erling Smørgrav {
143bc5531deSDag-Erling Smørgrav 	size_t bits;
144bc5531deSDag-Erling Smørgrav 	BITMAP_WTYPE w;
145bc5531deSDag-Erling Smørgrav 
146bc5531deSDag-Erling Smørgrav 	retop(b);
147bc5531deSDag-Erling Smørgrav 	if (b->top >= b->len)
148bc5531deSDag-Erling Smørgrav 		return 0; /* invalid */
149bc5531deSDag-Erling Smørgrav 	if (b->len == 0 || (b->top == 0 && b->d[0] == 0))
150bc5531deSDag-Erling Smørgrav 		return 0;
151bc5531deSDag-Erling Smørgrav 	/* Find MSB set */
152bc5531deSDag-Erling Smørgrav 	w = b->d[b->top];
153bc5531deSDag-Erling Smørgrav 	bits = (b->top + 1) * BITMAP_BITS;
154bc5531deSDag-Erling Smørgrav 	while (!(w & ((BITMAP_WTYPE)1 << (BITMAP_BITS - 1)))) {
155bc5531deSDag-Erling Smørgrav 		w <<= 1;
156bc5531deSDag-Erling Smørgrav 		bits--;
157bc5531deSDag-Erling Smørgrav 	}
158bc5531deSDag-Erling Smørgrav 	return bits;
159bc5531deSDag-Erling Smørgrav }
160bc5531deSDag-Erling Smørgrav 
161bc5531deSDag-Erling Smørgrav size_t
bitmap_nbytes(struct bitmap * b)162bc5531deSDag-Erling Smørgrav bitmap_nbytes(struct bitmap *b)
163bc5531deSDag-Erling Smørgrav {
164bc5531deSDag-Erling Smørgrav 	return (bitmap_nbits(b) + 7) / 8;
165bc5531deSDag-Erling Smørgrav }
166bc5531deSDag-Erling Smørgrav 
167bc5531deSDag-Erling Smørgrav int
bitmap_to_string(struct bitmap * b,void * p,size_t l)168bc5531deSDag-Erling Smørgrav bitmap_to_string(struct bitmap *b, void *p, size_t l)
169bc5531deSDag-Erling Smørgrav {
170bc5531deSDag-Erling Smørgrav 	u_char *s = (u_char *)p;
171bc5531deSDag-Erling Smørgrav 	size_t i, j, k, need = bitmap_nbytes(b);
172bc5531deSDag-Erling Smørgrav 
173bc5531deSDag-Erling Smørgrav 	if (l < need || b->top >= b->len)
174bc5531deSDag-Erling Smørgrav 		return -1;
175bc5531deSDag-Erling Smørgrav 	if (l > need)
176bc5531deSDag-Erling Smørgrav 		l = need;
177bc5531deSDag-Erling Smørgrav 	/* Put the bytes from LSB backwards */
178bc5531deSDag-Erling Smørgrav 	for (i = k = 0; i < b->top + 1; i++) {
179bc5531deSDag-Erling Smørgrav 		for (j = 0; j < BITMAP_BYTES; j++) {
180bc5531deSDag-Erling Smørgrav 			if (k >= l)
181bc5531deSDag-Erling Smørgrav 				break;
182bc5531deSDag-Erling Smørgrav 			s[need - 1 - k++] = (b->d[i] >> (j * 8)) & 0xff;
183bc5531deSDag-Erling Smørgrav 		}
184bc5531deSDag-Erling Smørgrav 	}
185bc5531deSDag-Erling Smørgrav 	return 0;
186bc5531deSDag-Erling Smørgrav }
187bc5531deSDag-Erling Smørgrav 
188bc5531deSDag-Erling Smørgrav int
bitmap_from_string(struct bitmap * b,const void * p,size_t l)189bc5531deSDag-Erling Smørgrav bitmap_from_string(struct bitmap *b, const void *p, size_t l)
190bc5531deSDag-Erling Smørgrav {
191bc5531deSDag-Erling Smørgrav 	int r;
192bc5531deSDag-Erling Smørgrav 	size_t i, offset, shift;
1934f52dfbbSDag-Erling Smørgrav 	const u_char *s = (const u_char *)p;
194bc5531deSDag-Erling Smørgrav 
195bc5531deSDag-Erling Smørgrav 	if (l > BITMAP_MAX / 8)
196bc5531deSDag-Erling Smørgrav 		return -1;
197bc5531deSDag-Erling Smørgrav 	if ((r = reserve(b, l * 8)) != 0)
198bc5531deSDag-Erling Smørgrav 		return r;
199bc5531deSDag-Erling Smørgrav 	bitmap_zero(b);
200bc5531deSDag-Erling Smørgrav 	if (l == 0)
201bc5531deSDag-Erling Smørgrav 		return 0;
202bc5531deSDag-Erling Smørgrav 	b->top = offset = ((l + (BITMAP_BYTES - 1)) / BITMAP_BYTES) - 1;
203bc5531deSDag-Erling Smørgrav 	shift = ((l + (BITMAP_BYTES - 1)) % BITMAP_BYTES) * 8;
204bc5531deSDag-Erling Smørgrav 	for (i = 0; i < l; i++) {
205bc5531deSDag-Erling Smørgrav 		b->d[offset] |= (BITMAP_WTYPE)s[i] << shift;
206bc5531deSDag-Erling Smørgrav 		if (shift == 0) {
207bc5531deSDag-Erling Smørgrav 			offset--;
208bc5531deSDag-Erling Smørgrav 			shift = BITMAP_BITS - 8;
209bc5531deSDag-Erling Smørgrav 		} else
210bc5531deSDag-Erling Smørgrav 			shift -= 8;
211bc5531deSDag-Erling Smørgrav 	}
212bc5531deSDag-Erling Smørgrav 	retop(b);
213bc5531deSDag-Erling Smørgrav 	return 0;
214bc5531deSDag-Erling Smørgrav }
215