/** * Convert string into a bitset. Inverse of bitset_to_str(). * */ bitset *str_to_bitset(char *str, char **end) { int nbits = 0; int bytes; int n; int pos; int b; int len; bitset *bp; char dst[1024]; if (!str) return NULL; /* hex string has 0x prefix */ if (str[0] == '0' && str[1] == 'x') str = str + 2; len = strlen(str); if (len % 2) { nbits = (len + 1) << 2; bytes = NUM_BYTES(nbits); pos = (bytes << 3) - 5; } else { nbits = len << 2; bytes = NUM_BYTES(nbits); pos = (bytes << 3) - 1; } if (0) hex2binary(str, dst); bp = bitset_new(nbits); for (; *str != '\0' && isxdigit(*str) && pos >= 0; str++) { b = digittoint(*str); for (n = 3; n >= 0; n--, pos--) { if (b & (1 << n)) { bitset_set(bp, pos); } } } if (end != NULL) *end = str - 1; return bp; }
/** * Return a string representation of a bitset. We use hex to compress * the string somewhat and drop leading zeros. * * Format is "NN:HHHHHH..." where "NN" is the actual number of bits in hex, * and "HHHHH...." is a hex representation of the bits in the set. The number * of characters in the bit string is always rounded to the nearest byte. * * e.g. "111" -> "3:07" * "11011010101011101" -> "11:01b55d" */ char *bitset_to_str(bitset *b) { int bytes; int pbit; int bit; char *str; char *s; unsigned char val; int found = 0; if (!b) return strdup("00"); /* * Find out how many bytes needed (rounded up) */ bytes = NUM_BYTES(b->bs_nbits); str = (char *)calloc(bytes * 2 + 1, 1); s = str; for (pbit = (bytes << 3) - 1; pbit > 0; ) { for (val = 0, bit = 3; bit >= 0; bit--, pbit--) { if (pbit < (int)b->bs_nbits && bitset_test(b, pbit)) { val |= (1 << bit); found = 1; } } if (found) *s++ = tohex[val & 0x0f]; } if (b->bs_nbits == 0) { *s++ = '0'; } *s = '\0'; return str; }
int structs_fixedarray_decode(const struct structs_type *type, const u_char *code, size_t cmax, void *data, char *ebuf, size_t emax) { const struct structs_type *const etype = type->args[0].v; const u_int length = type->args[2].i; const u_int bitslen = NUM_BYTES(length); const u_char *bits; int clen = 0; u_int i; /* Make sure it's really a fixedarray type */ if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) { errno = EINVAL; return (-1); } /* Get bits array */ if (cmax < bitslen) { strlcpy(ebuf, "encoded array is truncated", emax); errno = EINVAL; return (-1); } bits = code; code += bitslen; cmax -= bitslen; clen += bitslen; /* Decode elements */ for (i = 0; i < length; i++) { void *const edata = (char *)data + (i * etype->size); int eclen; /* If element not present, assign it the default value */ if ((bits[i / 8] & (1 << (i % 8))) == 0) { if (structs_init(etype, NULL, edata) == -1) goto fail; continue; } /* Decode element */ if ((eclen = (*etype->decode)(etype, code, cmax, edata, ebuf, emax)) == -1) goto fail; /* Go to next encoded element */ code += eclen; cmax -= eclen; clen += eclen; continue; /* Un-do work done so far */ fail: while (i-- > 0) { structs_free(etype, NULL, (char *)data + (i * etype->size)); } return (-1); } /* Done */ return (clen); }
int structs_fixedarray_encode(const struct structs_type *type, const char *mtype, struct structs_data *code, const void *data) { const struct structs_type *const etype = type->args[0].v; const u_int length = type->args[2].i; const u_int bitslen = NUM_BYTES(length); struct structs_data *ecodes; u_char *bits; void *delem; u_int tlen; int r = -1; u_int i; /* Make sure it's really a fixedarray type */ if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) { errno = EINVAL; return (-1); } /* Get the default value for an element */ if ((delem = MALLOC(TYPED_MEM_TEMP, etype->size)) == NULL) return (-1); if (structs_init(etype, NULL, delem) == -1) goto fail1; /* Create bit array. Each bit indicates an element that is present. */ if ((bits = MALLOC(TYPED_MEM_TEMP, bitslen)) == NULL) goto fail2; memset(bits, 0, bitslen); tlen = bitslen; /* Create array of individual encodings, one per element */ if ((ecodes = MALLOC(TYPED_MEM_TEMP, length * sizeof(*ecodes))) == NULL) goto fail3; for (i = 0; i < length; i++) { const void *const elem = (char *)data + (i * etype->size); struct structs_data *const ecode = &ecodes[i]; /* Check for default value, leave out if same as */ if ((*etype->equal)(etype, elem, delem) == 1) { memset(ecode, 0, sizeof(*ecode)); continue; } bits[i / 8] |= (1 << (i % 8)); /* Encode element */ if ((*etype->encode)(etype, TYPED_MEM_TEMP, ecode, elem) == -1) goto fail4; tlen += ecode->length; } /* Allocate final encoded region */ if ((code->data = MALLOC(mtype, tlen)) == NULL) goto fail4; /* Copy bits array */ memcpy(code->data, bits, bitslen); code->length = bitslen; /* Copy encoded elements */ for (i = 0; i < length; i++) { struct structs_data *const ecode = &ecodes[i]; memcpy(code->data + code->length, ecode->data, ecode->length); code->length += ecode->length; } /* OK */ r = 0; /* Clean up and exit */ fail4: while (i-- > 0) FREE(TYPED_MEM_TEMP, ecodes[i].data); FREE(TYPED_MEM_TEMP, ecodes); fail3: FREE(TYPED_MEM_TEMP, bits); fail2: structs_free(etype, NULL, delem); fail1: FREE(TYPED_MEM_TEMP, delem); return (r); }
int structs_array_decode(const struct structs_type *type, const u_char *code, size_t cmax, void *data, char *ebuf, size_t emax) { const struct structs_type *const etype = type->args[0].v; const char *const mtype = type->args[1].v; struct structs_array *const ary = data; const u_char *bits; u_int32_t elength; u_int bitslen; int clen; u_int i; /* Make sure it's really an array type */ if (type->tclass != STRUCTS_TYPE_ARRAY) { errno = EINVAL; return (-1); } /* Get number of elements */ if (cmax < 4) goto truncated; memcpy(&elength, code, 4); ary->length = ntohl(elength); code += 4; cmax -= 4; clen = 4; /* Get bits array */ bitslen = NUM_BYTES(ary->length); if (cmax < bitslen) { truncated: strlcpy(ebuf, "encoded array is truncated", emax); errno = EINVAL; return (-1); } bits = code; code += bitslen; cmax -= bitslen; clen += bitslen; /* Allocate array elements */ if ((ary->elems = MALLOC(mtype, ary->length * etype->size)) == NULL) return (-1); /* Decode elements */ for (i = 0; i < ary->length; i++) { void *const edata = (char *)ary->elems + (i * etype->size); int eclen; /* If element not present, assign it the default value */ if ((bits[i / 8] & (1 << (i % 8))) == 0) { if (structs_init(etype, NULL, edata) == -1) goto fail; continue; } /* Decode element */ if ((eclen = (*etype->decode)(etype, code, cmax, edata, ebuf, emax)) == -1) goto fail; /* Go to next encoded element */ code += eclen; cmax -= eclen; clen += eclen; continue; /* Un-do work done so far */ fail: while (i-- > 0) { structs_free(etype, NULL, (char *)ary->elems + (i * etype->size)); } FREE(mtype, ary->elems); return (-1); } /* Done */ return (clen); }