/*
* ndpi_binary_bitmap.c
*
* Copyright (C) 2011-23 - ntop.org and contributors
*
* nDPI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* nDPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with nDPI. If not, see .
*
*/
#include
#include
#include
#include
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN
#include "ndpi_config.h"
#include "ndpi_api.h"
#define NDPI_BINARY_BITMAP_REALLOC_SIZE 4096
// #define PRINT_DUPLICATED_HASHS
/* ********************************************************** */
ndpi_binary_bitmap* ndpi_binary_bitmap_alloc() {
ndpi_binary_bitmap *rc = (ndpi_binary_bitmap*)ndpi_malloc(sizeof(ndpi_binary_bitmap));
if(!rc) return(rc);
rc->num_allocated_entries = NDPI_BINARY_BITMAP_REALLOC_SIZE, rc->num_used_entries = 0;
if((rc->entries = (struct ndpi_binary_bitmap_entry*)ndpi_calloc(rc->num_allocated_entries,
sizeof(struct ndpi_binary_bitmap_entry))) == NULL) {
ndpi_free(rc);
return(NULL);
}
rc->is_compressed = false;
return(rc);
}
/* ********************************************************** */
bool ndpi_binary_bitmap_set(ndpi_binary_bitmap *b, u_int64_t value, u_int8_t category) {
if(b->num_used_entries >= b->num_allocated_entries) {
struct ndpi_binary_bitmap_entry *rc;
u_int32_t new_len = b->num_allocated_entries + NDPI_BINARY_BITMAP_REALLOC_SIZE;
rc = (struct ndpi_binary_bitmap_entry*)ndpi_realloc(b->entries,
sizeof(struct ndpi_binary_bitmap_entry)*b->num_allocated_entries,
sizeof(struct ndpi_binary_bitmap_entry)*new_len);
if(rc == NULL) return(false);
b->entries = rc, b->num_allocated_entries = new_len;
}
#ifdef PRINT_DUPLICATED_HASHS
if(value == 0)
printf("[add] ZERO hash !!!\n");
#endif
b->entries[b->num_used_entries].value = value,
b->entries[b->num_used_entries].category = category;
b->num_used_entries++, b->is_compressed = false;
return(true);
}
/* ********************************************************** */
static int ndpi_binary_bitmap_entry_compare(const void *_a, const void *_b) {
struct ndpi_binary_bitmap_entry *a = (struct ndpi_binary_bitmap_entry*)_a;
struct ndpi_binary_bitmap_entry *b = (struct ndpi_binary_bitmap_entry*)_b;
// return(a->value > b->value) - (a->value < b->value);
if (a->value < b->value) return -1;
else if (a->value > b->value) return 1;
else return 0;
}
/* ********************************************************** */
/* Sort and compact memory before searching */
bool ndpi_binary_bitmap_compress(ndpi_binary_bitmap *b) {
u_int32_t i;
if(b->num_used_entries > 0) {
if(b->num_used_entries > 1)
qsort(b->entries, b->num_used_entries,
sizeof(struct ndpi_binary_bitmap_entry),
ndpi_binary_bitmap_entry_compare);
/* Now remove duplicates */
u_int64_t old_value = b->entries[0].value, new_len = 1;
for(i=1; inum_used_entries; i++) {
if(b->entries[i].value != old_value) {
if(new_len != i)
memcpy(&b->entries[new_len], &b->entries[i], sizeof(struct ndpi_binary_bitmap_entry));
old_value = b->entries[i].value;
new_len++;
} else {
#ifdef PRINT_DUPLICATED_HASHS
printf("Skipping duplicate hash %lluu [id: %u/%u]\n",
b->entries[i].value, i, b->num_used_entries);
#endif
}
// printf("Shrinking %u -> %u\n", b->num_used_entries, new_len);
}
b->entries = (struct ndpi_binary_bitmap_entry*)
ndpi_realloc(b->entries,
sizeof(struct ndpi_binary_bitmap_entry)*b->num_allocated_entries,
sizeof(struct ndpi_binary_bitmap_entry)*new_len);
b->num_used_entries = b->num_allocated_entries = new_len;
}
b->is_compressed = true;
return(true);
}
/* ********************************************************** */
bool ndpi_binary_bitmap_isset(ndpi_binary_bitmap *b, u_int64_t value, u_int8_t *out_category) {
if(!b->is_compressed) ndpi_binary_bitmap_compress(b);
if(b->num_used_entries > 0) {
struct ndpi_binary_bitmap_entry *rc;
struct ndpi_binary_bitmap_entry tofind;
tofind.value = value;
rc = (struct ndpi_binary_bitmap_entry*)bsearch(&tofind, b->entries,
b->num_used_entries,
sizeof(struct ndpi_binary_bitmap_entry),
ndpi_binary_bitmap_entry_compare);
if(rc != NULL)
*out_category = rc->category;
return(rc == NULL ? false : true);
} else
return(false);
}
/* ********************************************************** */
void ndpi_binary_bitmap_free(ndpi_binary_bitmap *b) {
ndpi_free(b->entries);
ndpi_free(b);
}
/* ********************************************************** */
u_int32_t ndpi_binary_bitmap_size(ndpi_binary_bitmap *b) {
if(!b->is_compressed) ndpi_binary_bitmap_compress(b);
return(sizeof(ndpi_binary_bitmap) + b->num_used_entries * sizeof(struct ndpi_binary_bitmap_entry));
}
/* ********************************************************** */
u_int32_t ndpi_binary_bitmap_cardinality(ndpi_binary_bitmap *b) {
return(b->num_used_entries);
}