|
|
|
/*
|
|
|
|
* LibHTP (http://www.libhtp.org)
|
|
|
|
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
|
|
|
|
*
|
|
|
|
* LibHTP is an open source product, released under terms of the General Public Licence
|
|
|
|
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
|
|
|
|
* of the license.
|
|
|
|
*
|
|
|
|
* In addition, there is a special exception that allows LibHTP to be freely
|
|
|
|
* used with any OSI-approved open source licence. Please refer to the file
|
|
|
|
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "dslib.h"
|
|
|
|
|
|
|
|
|
|
|
|
// -- Queue List --
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add element to list.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @param element
|
|
|
|
* @return 1 on success, -1 on error (memory allocation failure)
|
|
|
|
*/
|
|
|
|
static int list_linked_push(list_t *_q, void *element) {
|
|
|
|
list_linked_t *q = (list_linked_t *) _q;
|
|
|
|
list_linked_element_t *qe = calloc(1, sizeof (list_linked_element_t));
|
|
|
|
if (qe == NULL) return -1;
|
|
|
|
|
|
|
|
// Rememeber the element
|
|
|
|
qe->data = element;
|
|
|
|
|
|
|
|
// If the queue is empty, make this element first
|
|
|
|
if (!q->first) {
|
|
|
|
q->first = qe;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q->last) {
|
|
|
|
q->last->next = qe;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->last = qe;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove one element from the beginning of the list.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @return a pointer to the removed element, or NULL if the list is empty.
|
|
|
|
*/
|
|
|
|
static void *list_linked_pop(list_t *_q) {
|
|
|
|
list_linked_t *q = (list_linked_t *) _q;
|
|
|
|
void *r = NULL;
|
|
|
|
|
|
|
|
if (!q->first) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_linked_element_t *qe = q->first;
|
|
|
|
q->first = qe->next;
|
|
|
|
r = qe->data;
|
|
|
|
|
|
|
|
if (!q->first) {
|
|
|
|
q->last = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(qe);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is the list empty?
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @return 1 if the list is empty, 0 if it is not
|
|
|
|
*/
|
|
|
|
static int list_linked_empty(list_t *_q) {
|
|
|
|
list_linked_t *q = (list_linked_t *) _q;
|
|
|
|
|
|
|
|
if (!q->first) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy list. This function will not destroy any of the
|
|
|
|
* data stored in it. You'll have to do that manually beforehand.
|
|
|
|
*
|
|
|
|
* @param l
|
|
|
|
*/
|
|
|
|
void list_linked_destroy(list_linked_t *l) {
|
|
|
|
// Free the list structures
|
|
|
|
list_linked_element_t *temp = l->first;
|
|
|
|
list_linked_element_t *prev = NULL;
|
|
|
|
while (temp != NULL) {
|
|
|
|
free(temp->data);
|
|
|
|
prev = temp;
|
|
|
|
temp = temp->next;
|
|
|
|
free(prev);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free the list itself
|
|
|
|
free(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new linked list.
|
|
|
|
*
|
|
|
|
* @return a pointer to the newly creted list (list_t), or NULL on memory allocation failure
|
|
|
|
*/
|
|
|
|
list_t *list_linked_create(void) {
|
|
|
|
list_linked_t *q = calloc(1, sizeof (list_linked_t));
|
|
|
|
if (q == NULL) return NULL;
|
|
|
|
|
|
|
|
q->push = list_linked_push;
|
|
|
|
q->pop = list_linked_pop;
|
|
|
|
q->empty = list_linked_empty;
|
|
|
|
q->destroy = (void (*)(list_t *))list_linked_destroy;
|
|
|
|
|
|
|
|
return (list_t *) q;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- Queue Array --
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add new element to the end of the list, expanding the list
|
|
|
|
* as necessary.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @param element
|
|
|
|
*
|
|
|
|
* @return 1 on success or -1 on failure (memory allocation)
|
|
|
|
*/
|
|
|
|
static int list_array_push(list_t *_q, void *element) {
|
|
|
|
list_array_t *q = (list_array_t *) _q;
|
|
|
|
|
|
|
|
// Check if we're full
|
|
|
|
if (q->current_size >= q->max_size) {
|
|
|
|
int new_size = q->max_size * 2;
|
|
|
|
void *newblock = NULL;
|
|
|
|
|
|
|
|
if (q->first == 0) {
|
|
|
|
// The simple case of expansion is when the first
|
|
|
|
// element in the list resides in the first slot. In
|
|
|
|
// that case we just add some new space to the end,
|
|
|
|
// adjust the max_size and that's that.
|
|
|
|
newblock = realloc(q->elements, new_size * sizeof (void *));
|
|
|
|
if (newblock == NULL) return -1;
|
|
|
|
} else {
|
|
|
|
// When the first element is not in the first
|
|
|
|
// memory slot, we need to rearrange the order
|
|
|
|
// of the elements in order to expand the storage area.
|
|
|
|
newblock = malloc(new_size * sizeof (void *));
|
|
|
|
if (newblock == NULL) return -1;
|
|
|
|
|
|
|
|
// Copy the beginning of the list to the beginning of the new memory block
|
|
|
|
memcpy(newblock, (char *)q->elements + q->first * sizeof (void *), (q->max_size - q->first) * sizeof (void *));
|
|
|
|
// Append the second part of the list to the end
|
|
|
|
memcpy((char *)newblock + (q->max_size - q->first) * sizeof (void *), q->elements, q->first * sizeof (void *));
|
|
|
|
|
|
|
|
free(q->elements);
|
|
|
|
}
|
|
|
|
|
|
|
|
q->first = 0;
|
|
|
|
q->last = q->current_size;
|
|
|
|
q->max_size = new_size;
|
|
|
|
q->elements = newblock;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->elements[q->last] = element;
|
|
|
|
q->current_size++;
|
|
|
|
|
|
|
|
q->last++;
|
|
|
|
if (q->last == q->max_size) {
|
|
|
|
q->last = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove one element from the beginning of the list.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @return the removed element, or NULL if the list is empty
|
|
|
|
*/
|
|
|
|
static void *list_array_pop(list_t *_q) {
|
|
|
|
list_array_t *q = (list_array_t *) _q;
|
|
|
|
void *r = NULL;
|
|
|
|
|
|
|
|
if (q->current_size == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = q->elements[q->first];
|
|
|
|
q->first++;
|
|
|
|
if (q->first == q->max_size) {
|
|
|
|
q->first = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->current_size--;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the size of the list.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
*/
|
|
|
|
static size_t list_array_size(list_t *_l) {
|
|
|
|
return ((list_array_t *) _l)->current_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the element at the given index.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @param index
|
|
|
|
* @return the desired element, or NULL if the list is too small, or
|
|
|
|
* if the element at that position carries a NULL
|
|
|
|
*/
|
|
|
|
static void *list_array_get(list_t *_l, size_t idx) {
|
|
|
|
list_array_t *l = (list_array_t *) _l;
|
|
|
|
void *r = NULL;
|
|
|
|
|
|
|
|
if (idx + 1 > l->current_size) return NULL;
|
|
|
|
|
|
|
|
size_t i = l->first;
|
|
|
|
r = l->elements[l->first];
|
|
|
|
|
|
|
|
while (idx--) {
|
|
|
|
if (++i == l->max_size) {
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = l->elements[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replace the element at the given index with the provided element.
|
|
|
|
*
|
|
|
|
* @param list
|
|
|
|
* @param index
|
|
|
|
* @param element
|
|
|
|
*
|
|
|
|
* @return 1 if the element was replaced, or 0 if the list is too small
|
|
|
|
*/
|
|
|
|
static int list_array_replace(list_t *_l, size_t idx, void *element) {
|
|
|
|
list_array_t *l = (list_array_t *) _l;
|
|
|
|
|
|
|
|
if (idx + 1 > l->current_size) return 0;
|
|
|
|
|
|
|
|
size_t i = l->first;
|
|
|
|
|
|
|
|
while (idx--) {
|
|
|
|
if (++i == l->max_size) {
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
l->elements[i] = element;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset the list iterator.
|
|
|
|
*
|
|
|
|
* @param l
|
|
|
|
*/
|
|
|
|
void list_array_iterator_reset(list_array_t *l) {
|
|
|
|
l->iterator_index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Advance to the next list value.
|
|
|
|
*
|
|
|
|
* @param l
|
|
|
|
* @return the next list value, or NULL if there aren't more elements
|
|
|
|
* left to iterate over or if the element itself is NULL
|
|
|
|
*/
|
|
|
|
void *list_array_iterator_next(list_array_t *l) {
|
|
|
|
void *r = NULL;
|
|
|
|
|
|
|
|
if (l->iterator_index < l->current_size) {
|
|
|
|
r = list_get(l, l->iterator_index);
|
|
|
|
l->iterator_index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free the memory occupied by this list. This function assumes
|
|
|
|
* the data elements were freed beforehand.
|
|
|
|
*
|
|
|
|
* @param l
|
|
|
|
*/
|
|
|
|
void list_array_destroy(list_array_t *l) {
|
|
|
|
free(l->elements);
|
|
|
|
free(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create new array-based list.
|
|
|
|
*
|
|
|
|
* @param size
|
|
|
|
* @return newly allocated list (list_t)
|
|
|
|
*/
|
|
|
|
list_t *list_array_create(size_t size) {
|
|
|
|
// Allocate the list structure
|
|
|
|
list_array_t *q = calloc(1, sizeof (list_array_t));
|
|
|
|
if (q == NULL) return NULL;
|
|
|
|
|
|
|
|
// Allocate the initial batch of elements
|
|
|
|
q->elements = malloc(size * sizeof (void *));
|
|
|
|
if (q->elements == NULL) {
|
|
|
|
free(q);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialise structure
|
|
|
|
q->first = 0;
|
|
|
|
q->last = 0;
|
|
|
|
q->max_size = size;
|
|
|
|
q->push = list_array_push;
|
|
|
|
q->pop = list_array_pop;
|
|
|
|
q->get = list_array_get;
|
|
|
|
q->replace = list_array_replace;
|
|
|
|
q->size = list_array_size;
|
|
|
|
q->iterator_reset = (void (*)(list_t *))list_array_iterator_reset;
|
|
|
|
q->iterator_next = (void *(*)(list_t *))list_array_iterator_next;
|
|
|
|
q->destroy = (void (*)(list_t *))list_array_destroy;
|
|
|
|
|
|
|
|
return (list_t *) q;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- Table --
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new table structure.
|
|
|
|
*
|
|
|
|
* @param size
|
|
|
|
* @return newly created table_t
|
|
|
|
*/
|
|
|
|
table_t *table_create(size_t size) {
|
|
|
|
table_t *t = calloc(1, sizeof (table_t));
|
|
|
|
if (t == NULL) return NULL;
|
|
|
|
|
|
|
|
// Use a list behind the scenes
|
|
|
|
t->list = list_array_create(size * 2);
|
|
|
|
if (t->list == NULL) {
|
|
|
|
free(t);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy a table.
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
*/
|
|
|
|
void table_destroy(table_t * table) {
|
|
|
|
// Free keys only
|
|
|
|
int counter = 0;
|
|
|
|
void *data = NULL;
|
|
|
|
|
|
|
|
list_iterator_reset(table->list);
|
|
|
|
|
|
|
|
while ((data = list_iterator_next(table->list)) != NULL) {
|
|
|
|
// Free key
|
|
|
|
if ((counter % 2) == 0) {
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_destroy(table->list);
|
|
|
|
|
|
|
|
free(table);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a new table element. This function currently makes a copy of
|
|
|
|
* the key, which is inefficient.
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
* @param key
|
|
|
|
* @param element
|
|
|
|
*/
|
|
|
|
int table_add(table_t *table, bstr *key, void *element) {
|
|
|
|
// Lowercase key
|
|
|
|
bstr *lkey = bstr_dup_lower(key);
|
|
|
|
if (lkey == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add key
|
|
|
|
if (list_add(table->list, lkey) != 1) {
|
|
|
|
free(lkey);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add element
|
|
|
|
if (list_add(table->list, element) != 1) {
|
|
|
|
list_pop(table->list);
|
|
|
|
free(lkey);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param table
|
|
|
|
* @param key
|
|
|
|
*/
|
|
|
|
static void *table_get_internal(table_t *table, bstr *key) {
|
|
|
|
// Iterate through the list, comparing
|
|
|
|
// keys with the parameter, return data if found.
|
|
|
|
bstr *ts = NULL;
|
|
|
|
list_iterator_reset(table->list);
|
|
|
|
while ((ts = list_iterator_next(table->list)) != NULL) {
|
|
|
|
void *data = list_iterator_next(table->list);
|
|
|
|
if (bstr_cmp(ts, key) == 0) {
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the first element in the table with the given
|
|
|
|
* key (as a NUL-terminated string).
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
* @param cstr
|
|
|
|
* @return table element, or NULL if not found
|
|
|
|
*/
|
|
|
|
void *table_getc(table_t *table, char *cstr) {
|
|
|
|
// TODO This is very inefficient
|
|
|
|
bstr *key = bstr_cstrdup(cstr);
|
|
|
|
if (key == NULL)
|
|
|
|
return NULL;
|
|
|
|
bstr_tolowercase(key);
|
|
|
|
void *data = table_get_internal(table, key);
|
|
|
|
free(key);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the first element in the table with the given key.
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
* @param key
|
|
|
|
* @return table element, or NULL if not found
|
|
|
|
*/
|
|
|
|
void *table_get(table_t *table, bstr *key) {
|
|
|
|
if (table == NULL)
|
|
|
|
return NULL;
|
|
|
|
// TODO This is very inefficient
|
|
|
|
bstr *lkey = bstr_dup_lower(key);
|
|
|
|
if (lkey == NULL)
|
|
|
|
return NULL;
|
|
|
|
void *data = table_get_internal(table, lkey);
|
|
|
|
free(lkey);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset the table iterator.
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
*/
|
|
|
|
void table_iterator_reset(table_t *table) {
|
|
|
|
list_iterator_reset(table->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Advance to the next table element.
|
|
|
|
*
|
|
|
|
* @param t
|
|
|
|
* @param data
|
|
|
|
* @return pointer to the key and the element if there is a next element, NULL otherwise
|
|
|
|
*/
|
|
|
|
bstr *table_iterator_next(table_t *t, void **data) {
|
|
|
|
bstr *s = list_iterator_next(t->list);
|
|
|
|
if (s != NULL) {
|
|
|
|
*data = list_iterator_next(t->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the size of the table.
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
* @return table size
|
|
|
|
*/
|
|
|
|
size_t table_size(table_t *table) {
|
|
|
|
return list_size(table->list) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all elements from the table.
|
|
|
|
*
|
|
|
|
* @param table
|
|
|
|
*/
|
|
|
|
void table_clear(table_t *table) {
|
|
|
|
// TODO Clear table by removing the existing elements
|
|
|
|
|
|
|
|
size_t size = list_size(table->list);
|
|
|
|
|
|
|
|
list_destroy(table->list);
|
|
|
|
|
|
|
|
// Use a list behind the scenes
|
|
|
|
table->list = list_array_create(size == 0 ? 10 : size);
|
|
|
|
if (table->list == NULL) {
|
|
|
|
free(table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
list_t *q = list_linked_create();
|
|
|
|
|
|
|
|
list_push(q, "1");
|
|
|
|
list_push(q, "2");
|
|
|
|
list_push(q, "3");
|
|
|
|
list_push(q, "4");
|
|
|
|
|
|
|
|
char *s = NULL;
|
|
|
|
while ((s = (char *) list_pop(q)) != NULL) {
|
|
|
|
printf("Got: %s\n", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(q);
|
|
|
|
}
|
|
|
|
#endif
|