#include <NetInfo/dsrecord.h>
#include <NetInfo/dsindex.h>
#include <stdlib.h>
#include <string.h>
void
serialize_32(u_int32_t v, char **p)
{
u_int32_t n;
n = htonl(v);
memmove(*p, &n, 4);
*p += 4;
}
dsdata *
dsrecord_to_dsdata(dsrecord *r)
{
u_int32_t i, len, type, attrx, valx;
dsdata *d;
char *p;
if (r == NULL) return NULL;
len = 0;
len += 4;
len += 4;
len += 4;
len += 4;
len += 4;
len += (4 * r->sub_count);
len += 4;
for (attrx = 0; attrx < r->count; attrx++)
{
len += (4 + 4 + r->attribute[attrx]->key->length);
len += 4;
for (valx = 0; valx < r->attribute[attrx]->count; valx++)
{
len += (4 + 4 + r->attribute[attrx]->value[valx]->length);
}
}
len += 4;
for (attrx = 0; attrx < r->meta_count; attrx++)
{
len += (4 + 4 + r->meta_attribute[attrx]->key->length);
len += 4;
for (valx = 0; valx < r->meta_attribute[attrx]->count; valx++)
{
len += (4 + 4 + r->meta_attribute[attrx]->value[valx]->length);
}
}
d = dsdata_alloc();
d->retain = 1;
d->type = DataTypeDSRecord;
d->length = len;
d->data = malloc(len);
p = d->data;
serialize_32(r->dsid, &p);
serialize_32(r->serial, &p);
serialize_32(r->vers, &p);
serialize_32(r->super, &p);
serialize_32(r->sub_count, &p);
for (i = 0; i < r->sub_count; i++)
{
serialize_32(r->sub[i], &p);
}
serialize_32(r->count, &p);
for (attrx = 0; attrx < r->count; attrx++)
{
type = r->attribute[attrx]->key->type;
serialize_32(type, &p);
len = r->attribute[attrx]->key->length;
serialize_32(len, &p);
memmove(p, r->attribute[attrx]->key->data, len);
p += len;
serialize_32(r->attribute[attrx]->count, &p);
for (valx = 0; valx < r->attribute[attrx]->count; valx++)
{
type = r->attribute[attrx]->value[valx]->type;
serialize_32(type, &p);
len = r->attribute[attrx]->value[valx]->length;
serialize_32(len, &p);
memmove(p, r->attribute[attrx]->value[valx]->data, len);
p += len;
}
}
serialize_32(r->meta_count, &p);
for (attrx = 0; attrx < r->meta_count; attrx++)
{
type = r->meta_attribute[attrx]->key->type;
serialize_32(type, &p);
len = r->meta_attribute[attrx]->key->length;
serialize_32(len, &p);
memmove(p, r->meta_attribute[attrx]->key->data, len);
p += len;
serialize_32(r->meta_attribute[attrx]->count, &p);
for (valx = 0; valx < r->meta_attribute[attrx]->count; valx++)
{
type = r->meta_attribute[attrx]->value[valx]->type;
serialize_32(type, &p);
len = r->meta_attribute[attrx]->value[valx]->length;
serialize_32(len, &p);
memmove(p, r->meta_attribute[attrx]->value[valx]->data, len);
p += len;
}
}
return d;
}
u_int32_t
deserialize_32(char **p)
{
u_int32_t n, t;
memmove(&t, *p, 4);
*p += 4;
n = ntohl(t);
return n;
}
dsdata *
deserialize_dsdata(char **p)
{
dsdata *udata;
udata = dsdata_alloc();
udata->retain = 1;
udata->type = deserialize_32(p);
udata->length = deserialize_32(p);
udata->data = NULL;
if (udata->length > 0)
{
udata->data = malloc(udata->length);
memmove(udata->data, *p, udata->length);
}
*p += udata->length;
return udata;
}
dsrecord *
dsdata_to_dsrecord(dsdata *d)
{
dsrecord *r;
char *p;
u_int32_t i, len, attrx, valx;
if (d == NULL) return NULL;
if (d->type != DataTypeDSRecord) return NULL;
r = (dsrecord *)malloc(sizeof(dsrecord));
r->retain = 1;
p = d->data;
r->dsid = deserialize_32(&p);
r->serial = deserialize_32(&p);
r->vers = deserialize_32(&p);
r->super = deserialize_32(&p);
r->sub_count = deserialize_32(&p);
if (r->sub_count > 0)
r->sub = (u_int32_t *)malloc(r->sub_count * sizeof(u_int32_t));
else
r->sub = NULL;
for (i = 0; i < r->sub_count; i++)
{
r->sub[i] = deserialize_32(&p);
}
r->count = deserialize_32(&p);
if (r->count > 0)
r->attribute = (dsattribute **)malloc(r->count * sizeof(dsattribute *));
else
r->attribute = NULL;
for (attrx = 0; attrx < r->count; attrx++)
{
r->attribute[attrx] = dsattribute_alloc();
r->attribute[attrx]->retain = 1;
r->attribute[attrx]->key = deserialize_dsdata(&p);
len = deserialize_32(&p);
r->attribute[attrx]->count = len;
if (len > 0)
r->attribute[attrx]->value = (dsdata **)malloc(len * sizeof(dsdata *));
else
r->attribute[attrx]->value = NULL;
for (valx = 0; valx < r->attribute[attrx]->count; valx++)
r->attribute[attrx]->value[valx] = deserialize_dsdata(&p);
}
r->meta_count = deserialize_32(&p);
if (r->meta_count > 0)
r->meta_attribute = (dsattribute **)malloc(r->meta_count * sizeof(dsattribute *));
else
r->meta_attribute = NULL;
for (attrx = 0; attrx < r->meta_count; attrx++)
{
r->meta_attribute[attrx] = dsattribute_alloc();
r->meta_attribute[attrx]->retain = 1;
r->meta_attribute[attrx]->key = deserialize_dsdata(&p);
len = deserialize_32(&p);
r->meta_attribute[attrx]->count = len;
if (len > 0)
r->meta_attribute[attrx]->value = (dsdata **)malloc(len * sizeof(dsdata *));
else
r->meta_attribute[attrx]->value = NULL;
for (valx = 0; valx < r->meta_attribute[attrx]->count; valx++)
r->meta_attribute[attrx]->value[valx] = deserialize_dsdata(&p);
}
r->index = NULL;
r->next = NULL;
return r;
}
dsstatus
dsrecord_fstats(FILE *f, u_int32_t *dsid, u_int32_t *vers, u_int32_t *serial, u_int32_t *super)
{
int n;
u_int32_t x;
if (dsid != NULL) *dsid = IndexNull;
if (vers != NULL) *vers = IndexNull;
if (serial != NULL) *serial = IndexNull;
if (super != NULL) *super = IndexNull;
if (f == NULL) return DSStatusInvalidStore;
n = fread(&x, sizeof(u_int32_t), 1, f);
if (n != 1) return DSStatusReadFailed;
n = ntohl(x);
if (n != DataTypeDSRecord) return DSStatusInvalidRecord;
n = fread(&x, sizeof(u_int32_t), 1, f);
if (n != 1) return DSStatusReadFailed;
n = fread(&x, sizeof(u_int32_t), 1, f);
if (n != 1) return DSStatusReadFailed;
if (dsid != NULL) *dsid = ntohl(x);
n = fread(&x, sizeof(u_int32_t), 1, f);
if (n != 1) return DSStatusReadFailed;
if (serial != NULL) *serial = ntohl(x);
n = fread(&x, sizeof(u_int32_t), 1, f);
if (n != 1) return DSStatusReadFailed;
if (vers != NULL) *vers = ntohl(x);
n = fread(&x, sizeof(u_int32_t), 1, f);
if (n != 1) return DSStatusReadFailed;
if (super != NULL) *super = ntohl(x);
return DSStatusOK;
}
dsrecord *
dsrecord_new(void)
{
dsrecord *r;
r = (dsrecord *)malloc(sizeof(dsrecord));
r->retain = 1;
r->dsid = -1;
r->serial = 0;
r->vers = -1;
r->super = -1;
r->sub_count = 0;
r->sub = NULL;
r->count = 0;
r->attribute = NULL;
r->meta_count = 0;
r->meta_attribute = NULL;
r->index = NULL;
r->next = NULL;
return r;
}
dsrecord *
dsrecord_retain(dsrecord *r)
{
if (r == NULL) return NULL;
r->retain++;
return r;
}
void
dsrecord_release(dsrecord *r)
{
u_int32_t i;
if (r == NULL) return;
r->retain--;
if (r->retain > 0) return;
if (r->sub_count > 0) free(r->sub);
for (i = 0; i < r->count; i++)
dsattribute_release(r->attribute[i]);
if (r->count > 0) free(r->attribute);
for (i = 0; i < r->meta_count; i++)
dsattribute_release(r->meta_attribute[i]);
if (r->meta_count > 0) free(r->meta_attribute);
if (r->index != NULL) dsindex_free(r->index);
if (r->next != NULL) dsrecord_release(r->next);
free(r);
}
dsrecord *
dsrecord_read(char *filename)
{
dsdata *d;
dsrecord *r;
d = dsdata_read(filename);
r = dsdata_to_dsrecord(d);
dsdata_release(d);
return r;
}
dsrecord *
dsrecord_fread(FILE *f)
{
dsdata *d;
dsrecord *r;
d = dsdata_fread(f);
r = dsdata_to_dsrecord(d);
dsdata_release(d);
return r;
}
dsstatus
dsrecord_write(dsrecord *r, char *filename)
{
dsdata *d;
dsstatus ds;
d = dsrecord_to_dsdata(r);
ds = dsdata_write(d, filename);
dsdata_release(d);
return ds;
}
dsstatus
dsrecord_fwrite(dsrecord *r, FILE *f)
{
dsdata *d;
dsstatus ds;
d = dsrecord_to_dsdata (r);
ds = dsdata_fwrite(d, f);
dsdata_release(d);
return ds;
}
dsrecord *
dsrecord_copy(dsrecord *r)
{
dsdata *d;
dsrecord *x;
if (r == NULL) return NULL;
d = dsrecord_to_dsdata(r);
if (d == NULL) return NULL;
x = dsdata_to_dsrecord(d);
dsdata_release(d);
x->dsid = -1;
return x;
}
u_int32_t
dsrecord_has_sub(dsrecord *r, u_int32_t c)
{
u_int32_t i, len;
if (r == NULL) return 0;
len = r->sub_count;
for (i = 0; i < len; i++) if (r->sub[i] == c) return 1;
return 0;
}
void
dsrecord_append_sub(dsrecord *r, u_int32_t c)
{
u_int32_t i, len;
if (r == NULL) return;
if (c == 0) return;
if (c == r->dsid) return;
if (c == r->super) return;
len = r->sub_count;
for (i = 0; i < len; i++) if (r->sub[i] == c) return;
r->sub_count++;
if (len == 0)
r->sub = (u_int32_t *)malloc(sizeof(u_int32_t));
else
r->sub = (u_int32_t *)realloc(r->sub, r->sub_count * sizeof(u_int32_t));
r->sub[len] = c;
}
void
dsrecord_remove_sub(dsrecord *r, u_int32_t c)
{
u_int32_t i;
if (r == NULL) return;
for (i = 0; i < r->sub_count; i++) if (r->sub[i] == c) break;
if (i >= r->sub_count) return;
if (r->sub_count == 1)
{
free(r->sub);
r->sub = NULL;
r->sub_count = 0;
return;
}
for (i += 1; i < r->sub_count; i++) r->sub[i - 1] = r->sub[i];
r->sub_count--;
r->sub = (u_int32_t *)realloc(r->sub, r->sub_count * sizeof(u_int32_t));
}
void
dsrecord_merge_attribute(dsrecord *r, dsattribute *a, u_int32_t asel)
{
u_int32_t i, x, len, merge;
dsattribute **attribute;
if (r == NULL) return;
if (a == NULL) return;
attribute = r->attribute;
len = r->count;
if (asel == SELECT_META_ATTRIBUTE)
{
attribute = r->meta_attribute;
len = r->meta_count;
}
merge = 0;
x = 0;
for (i = 0; i < len; i++)
{
if (dsattribute_equal(attribute[i], a)) return;
if (dsdata_equal(attribute[i]->key, a->key))
{
x = i;
merge = 1;
break;
}
}
if (merge == 1)
{
for (i = 0; i < a->count; i++)
dsattribute_merge(attribute[x], a->value[i]);
return;
}
dsrecord_append_attribute(r, a, asel);
}
void
dsrecord_insert_attribute(dsrecord *r, dsattribute *a, u_int32_t where, u_int32_t asel)
{
u_int32_t len, x, i;
if (r == NULL) return;
if (a == NULL) return;
if (asel == SELECT_ATTRIBUTE)
{
len = r->count;
r->count++;
if (len == 0)
r->attribute = (dsattribute **)malloc(sizeof(dsattribute *));
else
r->attribute = (dsattribute **)realloc(r->attribute,
r->count * sizeof(dsattribute *));
x = where;
if (x > len) x = len;
for (i = len; i > x; i--) r->attribute[i] = r->attribute[i-1];
r->attribute[x] = dsattribute_retain(a);
}
else
{
len = r->meta_count;
r->meta_count++;
if (len == 0)
r->meta_attribute = (dsattribute **)malloc(sizeof(dsattribute *));
else
r->meta_attribute = (dsattribute **)realloc(r->meta_attribute,
r->meta_count * sizeof(dsattribute *));
x = where;
if (x > len) x = len;
for (i = len; i > x; i--) r->meta_attribute[i] = r->meta_attribute[i-1];
r->meta_attribute[x] = dsattribute_retain(a);
}
}
void
dsrecord_append_attribute(dsrecord *r, dsattribute *a, u_int32_t asel)
{
u_int32_t len;
if (r == NULL) return;
if (a == NULL) return;
if (asel == SELECT_ATTRIBUTE)
{
len = r->count;
r->count++;
if (len == 0)
r->attribute = (dsattribute **)malloc(sizeof(dsattribute *));
else
r->attribute = (dsattribute **)realloc(r->attribute,
r->count * sizeof(dsattribute *));
r->attribute[len] = dsattribute_retain(a);
}
else
{
len = r->meta_count;
r->meta_count++;
if (len == 0)
r->meta_attribute = (dsattribute **)malloc(sizeof(dsattribute *));
else
r->meta_attribute = (dsattribute **)realloc(r->meta_attribute,
r->meta_count * sizeof(dsattribute *));
r->meta_attribute[len] = dsattribute_retain(a);
}
}
static void
dsrecord_remove_attribute_index(dsrecord *r, u_int32_t x, u_int32_t asel)
{
u_int32_t i, len;
dsattribute **attribute;
if (r == NULL) return;
len = r->count;
attribute = r->attribute;
if (asel == SELECT_META_ATTRIBUTE)
{
len = r->meta_count;
attribute = r->meta_attribute;
}
if (x >= len) return;
if (len == 1)
{
if (asel == SELECT_ATTRIBUTE)
{
free(r->attribute);
r->attribute = NULL;
r->count = 0;
}
else
{
free(r->meta_attribute);
r->meta_attribute = NULL;
r->meta_count = 0;
}
return;
}
for (i = x + 1; i < len; i++) attribute[i - 1] = attribute[i];
if (asel == SELECT_ATTRIBUTE)
{
r->count--;
r->attribute = (dsattribute **)realloc(r->attribute, r->count * sizeof(dsattribute *));
}
else
{
r->meta_count--;
r->meta_attribute = (dsattribute **)realloc(r->meta_attribute, r->meta_count * sizeof(dsattribute *));
}
}
void
dsrecord_remove_attribute(dsrecord *r, dsattribute *a, u_int32_t asel)
{
u_int32_t i, len;
dsattribute **attribute;
if (r == NULL) return;
if (a == NULL) return;
attribute = r->attribute;
len = r->count;
if (asel == SELECT_META_ATTRIBUTE)
{
attribute = r->meta_attribute;
len = r->meta_count;
}
for (i = 0; i < len; i++)
if (dsattribute_equal(attribute[i], a)) break;
if (i >= len) return;
dsrecord_remove_attribute_index(r, i, asel);
}
dsattribute *
dsrecord_attribute(dsrecord *r, dsdata *k, u_int32_t asel)
{
u_int32_t i, len;
dsattribute **attribute;
dsattribute *a;
if (r == NULL) return NULL;
if (k == NULL) return NULL;
attribute = r->attribute;
len = r->count;
if (asel == SELECT_META_ATTRIBUTE)
{
attribute = r->meta_attribute;
len = r->meta_count;
}
for (i = 0; i < len; i++)
{
if (dsdata_equal(attribute[i]->key, k))
{
a = attribute[i];
return dsattribute_retain(a);
}
}
return NULL;
}
void
dsrecord_remove_key(dsrecord *r, dsdata *k, u_int32_t asel)
{
u_int32_t i, len;
dsattribute **attribute;
if (r == NULL) return;
if (k == NULL) return;
attribute = r->attribute;
len = r->count;
if (asel == SELECT_META_ATTRIBUTE)
{
attribute = r->meta_attribute;
len = r->meta_count;
}
for (i = 0; i < len; i++)
{
if (dsdata_equal(attribute[i]->key, k)) break;
}
if (i >= len) return;
dsrecord_remove_attribute_index(r, i, asel);
}
u_int32_t
dsrecord_attribute_index(dsrecord *r, dsdata *key, u_int32_t asel)
{
u_int32_t i;
if (asel == SELECT_ATTRIBUTE)
{
for (i = 0; i < r->count; i++)
if (dsdata_equal(r->attribute[i]->key, key)) return i;
}
else
{
for (i = 0; i < r->meta_count; i++)
if (dsdata_equal(r->meta_attribute[i]->key, key)) return i;
}
return IndexNull;
}
int
dsrecord_match_key_val(dsrecord *r, dsdata *k, dsdata *v, u_int32_t asel)
{
u_int32_t i, len;
dsattribute **attribute;
if (r == NULL) return 0;
if ((k == NULL) && (v == NULL)) return 1;
attribute = r->attribute;
len = r->count;
if (asel == SELECT_META_ATTRIBUTE)
{
attribute = r->meta_attribute;
len = r->meta_count;
}
if (k == NULL)
{
for (i = 0; i < len; i++)
{
if (dsattribute_index(attribute[i], v) != IndexNull) return 1;
}
return 0;
}
i = dsrecord_attribute_index(r, k, asel);
if (i != IndexNull)
{
if (v == NULL) return 1;
if (dsattribute_index(attribute[i], v) != IndexNull) return 1;
}
return 0;
}
int
dsrecord_match(dsrecord *r, dsrecord *pattern)
{
u_int32_t i, x;
dsattribute *pa, *ra;
if (r == pattern) return 1;
if (r == NULL) return 0;
if (pattern == NULL) return 1;
for (i = 0; i < pattern->count; i++)
{
pa = pattern->attribute[i];
x = dsrecord_attribute_index(r, pa->key, SELECT_ATTRIBUTE);
if (x == IndexNull) return 0;
ra = r->attribute[x];
if (dsattribute_match(ra, pa) == 0) return 0;
}
for (i = 0; i < pattern->meta_count; i++)
{
pa = pattern->meta_attribute[i];
x = dsrecord_attribute_index(r, pa->key, SELECT_META_ATTRIBUTE);
if (x == IndexNull) return 0;
ra = r->meta_attribute[x];
if (dsattribute_match(ra, pa) == 0) return 0;
}
return 1;
}
int
dsrecord_equal(dsrecord *a, dsrecord *b)
{
u_int32_t i, x;
dsattribute *aa, *ba;
if (a == b) return 1;
if (a == NULL) return 0;
if (b == NULL) return 0;
if (a->count != b->count) return 0;
for (i = 0; i < a->count; i++)
{
aa = a->attribute[i];
x = dsrecord_attribute_index(b, aa->key, SELECT_ATTRIBUTE);
if (x == IndexNull) return 0;
ba = b->attribute[x];
if (dsattribute_equal(aa, ba) == 0) return 0;
}
for (i = 0; i < a->meta_count; i++)
{
aa = a->meta_attribute[i];
x = dsrecord_attribute_index(b, aa->key, SELECT_META_ATTRIBUTE);
if (x == IndexNull) return 0;
ba = b->meta_attribute[x];
if (dsattribute_equal(aa, ba) == 0) return 0;
}
return 1;
}