2011-03-17 18:05:39 +00:00
|
|
|
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
|
2009-06-15 02:44:05 +00:00
|
|
|
|
2009-06-15 16:31:03 +00:00
|
|
|
#include "r_db.h"
|
2009-06-15 02:44:05 +00:00
|
|
|
|
2009-06-18 13:10:26 +00:00
|
|
|
#if 0
|
2009-07-08 17:14:19 +00:00
|
|
|
Configurable options:
|
2009-06-18 13:10:26 +00:00
|
|
|
- allow dupped nodes? (two times the same pointer?)
|
|
|
|
#endif
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
R_API RDatabase *r_db_new() {
|
|
|
|
RDatabase *db = R_NEW (RDatabase);
|
2010-05-20 15:40:58 +00:00
|
|
|
if (db) {
|
2011-03-17 18:05:39 +00:00
|
|
|
memset (&db->blocks, '\0', sizeof (db->blocks));
|
2010-05-20 15:40:58 +00:00
|
|
|
db->id_min = -1;
|
|
|
|
db->id_max = -1;
|
|
|
|
}
|
2009-06-15 02:44:05 +00:00
|
|
|
return db;
|
|
|
|
}
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
R_API RDatabaseBlock *r_db_block_new() {
|
|
|
|
RDatabaseBlock *ptr = R_NEW (RDatabaseBlock);
|
2009-06-15 02:44:05 +00:00
|
|
|
ptr->data = NULL;
|
2011-03-17 18:05:39 +00:00
|
|
|
memset (&ptr->childs, '\0', sizeof (ptr->childs));
|
2009-06-15 02:44:05 +00:00
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API int r_db_add_id(struct r_db_t *db, int key, int size) {
|
2009-06-15 16:31:03 +00:00
|
|
|
key &= 0xff;
|
|
|
|
if (db->blocks[key])
|
2009-06-15 02:44:05 +00:00
|
|
|
return R_FALSE;
|
|
|
|
if (db->id_min==-1) {
|
2009-06-15 16:31:03 +00:00
|
|
|
db->id_min = key;
|
|
|
|
db->id_max = key;
|
|
|
|
} else if (db->id_max < key)
|
|
|
|
db->id_max = key;
|
|
|
|
if (key < db->id_min)
|
|
|
|
db->id_min = key;
|
2011-03-17 18:05:39 +00:00
|
|
|
db->blocks[key] = r_db_block_new ();
|
2009-06-15 16:31:03 +00:00
|
|
|
db->blocks_sz[key] = size;
|
2009-06-15 02:44:05 +00:00
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
static int _r_db_add_internal(struct r_db_t *db, int key, void *b) {
|
2009-07-21 22:59:34 +00:00
|
|
|
int i, idx, len, size;
|
|
|
|
struct r_db_block_t *block;
|
|
|
|
if (key<0 || key>255)
|
|
|
|
return R_FALSE;
|
|
|
|
size = db->blocks_sz[key];
|
|
|
|
block = db->blocks[key];
|
2009-06-15 02:44:05 +00:00
|
|
|
if (block == NULL) {
|
2011-03-17 18:05:39 +00:00
|
|
|
block = r_db_block_new ();
|
2009-06-15 02:44:05 +00:00
|
|
|
db->blocks[key] = block;
|
|
|
|
}
|
2010-03-01 09:49:04 +00:00
|
|
|
for (i=0;i<size;i++) {
|
2009-07-08 11:49:55 +00:00
|
|
|
idx = (((ut8 *)b)[key+i]) & 0xff;
|
2009-06-15 02:44:05 +00:00
|
|
|
if (block->childs[idx] == NULL)
|
|
|
|
block->childs[idx] = r_db_block_new();
|
|
|
|
block = block->childs[idx];
|
|
|
|
}
|
|
|
|
if (block) {
|
2009-07-21 22:59:34 +00:00
|
|
|
if (block->data == NULL) {
|
2011-01-27 08:31:52 +00:00
|
|
|
// TODO: use slices.. much faster alloc+free
|
2009-06-15 02:44:05 +00:00
|
|
|
block->data = malloc(sizeof(void *)*2);
|
|
|
|
block->data[0] = b;
|
|
|
|
block->data[1] = NULL;
|
|
|
|
} else {
|
|
|
|
for(len=0;block->data[len];len++);
|
2010-06-13 09:59:17 +00:00
|
|
|
block->data = realloc(block->data, sizeof(void *)*(len+1));
|
2009-06-15 02:44:05 +00:00
|
|
|
block->data[len] = b;
|
|
|
|
block->data[len+1] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2009-08-14 00:37:18 +00:00
|
|
|
return (block != NULL);
|
2009-06-15 02:44:05 +00:00
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API int r_db_add(struct r_db_t *db, void *b) {
|
2009-07-21 22:59:34 +00:00
|
|
|
int i, ret = R_FALSE;
|
2010-06-13 09:59:17 +00:00
|
|
|
for (i=db->id_min;i<=db->id_max;i++)
|
2009-06-15 02:44:05 +00:00
|
|
|
if (db->blocks[i])
|
2010-03-01 09:49:04 +00:00
|
|
|
ret += _r_db_add_internal (db, i, b);
|
2009-06-15 02:44:05 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API int r_db_add_unique(struct r_db_t *db, void *b) {
|
2009-07-22 15:30:21 +00:00
|
|
|
int i, ret = R_TRUE;
|
|
|
|
for(i=db->id_min;i<=db->id_max;i++) {
|
2010-06-13 09:59:17 +00:00
|
|
|
if (db->blocks[i] && r_db_get (db, i, b) != NULL) {
|
|
|
|
ret = R_FALSE;
|
|
|
|
break;
|
2009-07-22 15:30:21 +00:00
|
|
|
}
|
|
|
|
}
|
2010-06-13 09:59:17 +00:00
|
|
|
if (ret) ret = r_db_add (db, b);
|
2009-07-22 15:30:21 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API void **r_db_get(struct r_db_t *db, int key, const ut8 *b) {
|
2010-06-13 09:59:17 +00:00
|
|
|
RDatabaseBlock *block;
|
2009-06-15 02:44:05 +00:00
|
|
|
int i, size;
|
|
|
|
if (key == -1) {
|
2010-06-13 09:59:17 +00:00
|
|
|
key = db->id_min;
|
|
|
|
#if 0
|
|
|
|
UNNECESSARY LOOPZ
|
|
|
|
for (i=0;i<R_DB_KEYS;i++) {
|
2009-06-15 02:44:05 +00:00
|
|
|
if (db->blocks[i]) {
|
|
|
|
key = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (key == -1)
|
|
|
|
return NULL;
|
2010-06-13 09:59:17 +00:00
|
|
|
#endif
|
2009-06-15 02:44:05 +00:00
|
|
|
}
|
|
|
|
size = db->blocks_sz[key];
|
|
|
|
block = db->blocks[key];
|
2011-03-17 18:05:39 +00:00
|
|
|
for (i=0; block && i<size; i++)
|
2009-06-15 02:44:05 +00:00
|
|
|
block = block->childs[b[key+i]];
|
|
|
|
if (block)
|
|
|
|
return block->data;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-06-18 13:10:26 +00:00
|
|
|
/* TODO: MOVE AS DEFINE IN r_db.h */
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API void **r_db_get_next(void **ptr) {
|
2009-06-18 13:10:26 +00:00
|
|
|
return ptr+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: MOVE AS DEFINE IN r_db.h */
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API void **r_db_get_cur(void **ptr) {
|
2009-06-18 13:10:26 +00:00
|
|
|
return ptr[0];
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
static int _r_db_delete_internal(struct r_db_t *db, int key, const ut8 *b) {
|
2010-06-13 09:59:17 +00:00
|
|
|
RDatabaseBlock *block;
|
|
|
|
int i, j, size = db->blocks_sz[key];
|
2009-06-18 13:10:26 +00:00
|
|
|
block = db->blocks[key];
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
for (i=0;block&&i<size;i++)
|
2009-06-18 13:10:26 +00:00
|
|
|
block = block->childs[b[key+i]];
|
|
|
|
|
|
|
|
if (block && block->data) {
|
2011-03-17 18:05:39 +00:00
|
|
|
for (i=0;block->data[i]; i++) {
|
2010-06-13 09:59:17 +00:00
|
|
|
if (block->data[i] == b)
|
2011-03-17 18:05:39 +00:00
|
|
|
for (j=i;block->data[j]; j++)
|
2009-06-18 13:10:26 +00:00
|
|
|
block->data[j] = block->data[j+1];
|
|
|
|
}
|
|
|
|
if (block->data[0] == NULL) {
|
2011-03-17 18:05:39 +00:00
|
|
|
free (block->data);
|
2009-06-18 13:10:26 +00:00
|
|
|
block->data = NULL;
|
|
|
|
}
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API int r_db_delete(struct r_db_t *db, const void *ptr) {
|
2010-06-13 09:59:17 +00:00
|
|
|
int i;
|
2011-03-17 18:05:39 +00:00
|
|
|
for (i=db->id_min; i<=db->id_max; i++)
|
2009-06-18 13:10:26 +00:00
|
|
|
if (db->blocks[i])
|
2011-03-17 18:05:39 +00:00
|
|
|
if (!_r_db_delete_internal (db, i, ptr))
|
2010-06-13 09:59:17 +00:00
|
|
|
eprintf ("failed to delete internal pointer\n");
|
2009-06-18 13:10:26 +00:00
|
|
|
/* TODO */
|
2009-06-15 02:44:05 +00:00
|
|
|
if (db->cb_free && ptr)
|
2011-03-17 18:05:39 +00:00
|
|
|
return db->cb_free (db, ptr, db->cb_user);
|
2009-06-15 02:44:05 +00:00
|
|
|
return (ptr != NULL);
|
|
|
|
}
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
static int r_db_iter_find_next(RDatabaseIter *it) {
|
|
|
|
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
2009-06-15 02:44:05 +00:00
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
R_API RDatabaseIter *r_db_iter_new(RDatabase *db, int key) {
|
|
|
|
RDatabaseIter *iter = R_NEW (RDatabaseIter);
|
2009-07-08 17:14:19 +00:00
|
|
|
/* TODO: detect when keys are not valid and return NULL */
|
|
|
|
iter->db = db;
|
|
|
|
iter->key = key;
|
|
|
|
iter->size = db->blocks_sz[key];
|
2011-03-17 18:05:39 +00:00
|
|
|
memset (&iter->path, 0, sizeof (iter->path));
|
2009-07-08 17:14:19 +00:00
|
|
|
/* TODO: detect when no keys are found and return NULL */
|
|
|
|
iter->ptr = 0;
|
|
|
|
iter->cur = NULL;
|
2010-06-13 09:59:17 +00:00
|
|
|
r_db_iter_find_next (iter);
|
2009-07-08 17:14:19 +00:00
|
|
|
/* TODO: first iteration must be done here */
|
|
|
|
return iter;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API void *r_db_iter_cur(struct r_db_iter_t *iter) {
|
2009-07-08 17:14:19 +00:00
|
|
|
return iter->cur;
|
|
|
|
#if 0
|
|
|
|
void *cur = NULL;
|
|
|
|
int i, depth = 0;
|
|
|
|
struct r_db_t *db = iter->db;
|
|
|
|
struct r_db_block_t *b = db->blocks[iter->key];
|
|
|
|
if (iter->ptr == 0) {
|
|
|
|
/* first iteration */
|
|
|
|
} else {
|
|
|
|
for(i=0;i<iter->size;i++) {
|
|
|
|
b = &b[iter->path[i]];
|
|
|
|
if (b == NULL) {
|
|
|
|
fprintf(stderr, "r_db: Internal data corruption\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* TODO: check if null to find next node */
|
|
|
|
return b->data[iter->ptr];
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=0;i<255;i++) {
|
|
|
|
if (b->childs[i]) {
|
|
|
|
/* walk childs until reaching the leafs */
|
|
|
|
b = b->childs[i];
|
|
|
|
i=0;
|
|
|
|
depth++;
|
|
|
|
if (depth == iter->size) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//iter->db
|
|
|
|
return cur;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-06-13 09:59:17 +00:00
|
|
|
// NOTE: required for vala/swig
|
|
|
|
R_API void *r_db_iterator(RDatabase *db) {
|
|
|
|
return r_db_iter_new (db, db->id_min);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 1 if there is a next element */
|
|
|
|
R_API int r_db_iter_next(RDatabaseIter *iter) {
|
2010-08-16 15:48:47 +00:00
|
|
|
//RDatabaseBlock *b, *block;
|
|
|
|
int i;//, j;
|
2010-06-13 09:59:17 +00:00
|
|
|
// TODO: must be implemented for Vala/Swig
|
|
|
|
// if (something) return 1;
|
|
|
|
// depth = iter->size
|
|
|
|
//
|
2011-03-17 18:05:39 +00:00
|
|
|
for (i=iter->ptr; i<iter->size; i++) {
|
2010-06-13 09:59:17 +00:00
|
|
|
//block = block->childs[b[key+i]];
|
|
|
|
}
|
|
|
|
iter->ptr = i; // update pointer
|
|
|
|
iter->cur = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return current iter data and go to next iterable element */
|
|
|
|
R_API void *r_db_iter_get(RDatabaseIter *iter) {
|
|
|
|
void *data = iter->cur;
|
|
|
|
|
|
|
|
// TODO: must be implemented for Vala/Swig
|
|
|
|
return data;
|
2009-06-15 02:44:05 +00:00
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API void *r_db_iter_prev(struct r_db_iter_t *iter) {
|
2009-07-08 17:14:19 +00:00
|
|
|
/* TODO */
|
2009-06-15 02:44:05 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API struct r_db_iter_t *r_db_iter_free(struct r_db_iter_t *iter) {
|
2011-03-17 18:05:39 +00:00
|
|
|
free (iter);
|
2009-06-15 02:44:05 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-01 09:49:04 +00:00
|
|
|
R_API int r_db_free(struct r_db_t *db) {
|
2009-07-08 17:14:19 +00:00
|
|
|
/* TODO : using the iterator logic */
|
2009-09-25 02:04:51 +00:00
|
|
|
// TODO: use r_pool_mem here!
|
2009-06-15 02:44:05 +00:00
|
|
|
#if 0
|
2009-07-08 17:14:19 +00:00
|
|
|
r_db_iter_t *iter = r_db_iter(db, -1);
|
2009-06-15 02:44:05 +00:00
|
|
|
if (db->cb_free) {
|
|
|
|
r_db_delete(db); // XXX
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|