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