mirror of
https://github.com/vale981/libblobpack
synced 2025-03-05 09:51:42 -05:00
419 lines
11 KiB
C
419 lines
11 KiB
C
#include "blob.h"
|
|
#include "blob_field.h"
|
|
|
|
|
|
static const int blob_type_minlen[BLOB_FIELD_LAST] = {
|
|
[BLOB_FIELD_STRING] = 1,
|
|
[BLOB_FIELD_INT8] = sizeof(uint8_t),
|
|
[BLOB_FIELD_INT16] = sizeof(uint16_t),
|
|
[BLOB_FIELD_INT32] = sizeof(uint32_t),
|
|
[BLOB_FIELD_INT64] = sizeof(uint64_t),
|
|
};
|
|
|
|
/*const char *blob_field_name(struct blob_field *attr){
|
|
if(!blob_field_has_name(attr)) return "";
|
|
struct blob_name_hdr *hdr = (struct blob_name_hdr*)attr->data;
|
|
return (char*)hdr->name;
|
|
}*/
|
|
|
|
void blob_field_fill_pad(struct blob_field *attr) {
|
|
assert(attr);
|
|
char *buf = (char *) attr;
|
|
int len = blob_field_raw_pad_len(attr);
|
|
int delta = len - blob_field_raw_len(attr);
|
|
|
|
if (delta > 0)
|
|
memset(buf + len - delta, 0, delta);
|
|
}
|
|
|
|
void blob_field_set_raw_len(struct blob_field *attr, unsigned int len){
|
|
assert(attr);
|
|
if(len < sizeof(struct blob_field)) len = sizeof(struct blob_field);
|
|
len &= BLOB_FIELD_LEN_MASK;
|
|
attr->id_len &= ~cpu_to_be32(BLOB_FIELD_LEN_MASK);
|
|
attr->id_len |= cpu_to_be32(len);
|
|
}
|
|
|
|
|
|
bool blob_field_check_type(const void *ptr, unsigned int len, int type){
|
|
const char *data = ptr;
|
|
|
|
if (type >= BLOB_FIELD_LAST)
|
|
return false;
|
|
|
|
if (type >= BLOB_FIELD_INT8 && type <= BLOB_FIELD_INT64) {
|
|
if (len != blob_type_minlen[type])
|
|
return false;
|
|
} else {
|
|
if (len < blob_type_minlen[type])
|
|
return false;
|
|
}
|
|
|
|
if (type == BLOB_FIELD_STRING && data[len - 1] != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
blob_field_equal(const struct blob_field *a1, const struct blob_field *a2)
|
|
{
|
|
if (!a1 && !a2)
|
|
return true;
|
|
|
|
if (!a1 || !a2)
|
|
return false;
|
|
|
|
if (blob_field_raw_pad_len(a1) != blob_field_raw_pad_len(a2))
|
|
return false;
|
|
|
|
return !memcmp(a1, a2, blob_field_raw_pad_len(a1));
|
|
}
|
|
|
|
//! returns the data of the attribute
|
|
void *blob_field_data(const struct blob_field *attr){
|
|
if(!attr) return NULL;
|
|
return (void *) attr->data;
|
|
}
|
|
|
|
|
|
struct blob_field *blob_field_copy(struct blob_field *attr){
|
|
struct blob_field *ret;
|
|
int size = blob_field_raw_pad_len(attr);
|
|
|
|
ret = malloc(size);
|
|
if (!ret)
|
|
return NULL;
|
|
|
|
memcpy(ret, attr, size);
|
|
return ret;
|
|
}
|
|
|
|
uint8_t
|
|
blob_field_get_u8(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return *((uint8_t *) attr->data);
|
|
}
|
|
|
|
void blob_field_set_u8(const struct blob_field *attr, uint8_t val){
|
|
if(!attr) return;
|
|
*((uint8_t *) attr->data) = val;
|
|
}
|
|
|
|
uint16_t
|
|
blob_field_get_u16(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
uint16_t *tmp = (uint16_t*)attr->data;
|
|
return be16_to_cpu(*tmp);
|
|
}
|
|
|
|
void
|
|
blob_field_set_u16(const struct blob_field *attr, uint16_t val){
|
|
if(!attr) return;
|
|
uint16_t *tmp = (uint16_t*)attr->data;
|
|
*tmp = cpu_to_be16(val);
|
|
}
|
|
|
|
uint32_t
|
|
blob_field_get_u32(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
uint32_t *tmp = (uint32_t*)attr->data;
|
|
return be32_to_cpu(*tmp);
|
|
}
|
|
|
|
void
|
|
blob_field_set_u32(const struct blob_field *attr, uint32_t val){
|
|
if(!attr) return;
|
|
uint32_t *tmp = (uint32_t*)attr->data;
|
|
*tmp = cpu_to_be32(val);
|
|
}
|
|
|
|
uint64_t
|
|
blob_field_get_u64(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
uint32_t *ptr = (uint32_t *) blob_field_data(attr);
|
|
uint64_t tmp = ((uint64_t) be32_to_cpu(ptr[0])) << 32;
|
|
tmp |= be32_to_cpu(ptr[1]);
|
|
return tmp;
|
|
}
|
|
|
|
int8_t
|
|
blob_field_get_i8(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return blob_field_get_u8(attr);
|
|
}
|
|
|
|
void
|
|
blob_field_set_i8(const struct blob_field *attr, int8_t val){
|
|
if(!attr) return;
|
|
blob_field_set_u8(attr, val);
|
|
}
|
|
|
|
int16_t
|
|
blob_field_get_i16(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return blob_field_get_u16(attr);
|
|
}
|
|
|
|
void
|
|
blob_field_set_i16(const struct blob_field *attr, int16_t val){
|
|
if(!attr) return;
|
|
blob_field_set_u16(attr, val);
|
|
}
|
|
|
|
int32_t
|
|
blob_field_get_i32(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return blob_field_get_u32(attr);
|
|
}
|
|
|
|
void
|
|
blob_field_set_i32(const struct blob_field *attr, int32_t val){
|
|
if(!attr) return;
|
|
blob_field_set_u32(attr, val);
|
|
}
|
|
|
|
int64_t
|
|
blob_field_get_i64(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return blob_field_get_u64(attr);
|
|
}
|
|
|
|
float blob_field_get_f32(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return unpack754_32(blob_field_get_u32(attr));
|
|
}
|
|
|
|
double blob_field_get_f64(const struct blob_field *attr){
|
|
if(!attr) return 0;
|
|
return unpack754_64(blob_field_get_u64(attr));
|
|
}
|
|
|
|
|
|
long long blob_field_get_int(const struct blob_field *self){
|
|
assert(self);
|
|
int type = blob_field_type(self);
|
|
switch(type){
|
|
case BLOB_FIELD_INT8: return blob_field_get_i8(self);
|
|
case BLOB_FIELD_INT16: return blob_field_get_i16(self);
|
|
case BLOB_FIELD_INT32: return blob_field_get_i32(self);
|
|
case BLOB_FIELD_FLOAT32: return blob_field_get_f32(self);
|
|
case BLOB_FIELD_FLOAT64: return blob_field_get_f64(self);
|
|
case BLOB_FIELD_STRING: {
|
|
long long val;
|
|
sscanf(self->data, "%lli", &val);
|
|
return val;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
double blob_field_get_real(const struct blob_field *self){
|
|
assert(self);
|
|
int type = blob_field_type(self);
|
|
switch(type){
|
|
case BLOB_FIELD_INT8: return blob_field_get_i8(self);
|
|
case BLOB_FIELD_INT16: return blob_field_get_i16(self);
|
|
case BLOB_FIELD_INT32: return blob_field_get_i32(self);
|
|
case BLOB_FIELD_FLOAT32: return blob_field_get_f32(self);
|
|
case BLOB_FIELD_FLOAT64: return blob_field_get_f64(self);
|
|
case BLOB_FIELD_STRING: {
|
|
double val;
|
|
sscanf(self->data, "%lf", &val);
|
|
return val;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool blob_field_get_bool(const struct blob_field *self){
|
|
assert(self);
|
|
return !!blob_field_get_int(self);
|
|
}
|
|
|
|
const char *
|
|
blob_field_get_string(const struct blob_field *attr){
|
|
if(!attr) return NULL;
|
|
return attr->data;
|
|
}
|
|
|
|
void
|
|
blob_field_get_raw(const struct blob_field *attr, uint8_t *data, size_t data_size){
|
|
assert(attr);
|
|
memcpy(data, attr->data, data_size);
|
|
}
|
|
|
|
//! returns the type of the attribute
|
|
unsigned int blob_field_type(const struct blob_field *attr){
|
|
if(!attr) return BLOB_FIELD_INVALID;
|
|
int id = (be32_to_cpu(attr->id_len) & BLOB_FIELD_ID_MASK) >> BLOB_FIELD_ID_SHIFT;
|
|
return id;
|
|
}
|
|
|
|
void blob_field_set_type(struct blob_field *self, int type){
|
|
int id_len = be32_to_cpu(self->id_len);
|
|
id_len = (id_len & ~BLOB_FIELD_ID_MASK) | (type << BLOB_FIELD_ID_SHIFT);
|
|
self->id_len = cpu_to_be32(id_len);
|
|
}
|
|
|
|
//! returns full length of attribute
|
|
unsigned int
|
|
blob_field_raw_len(const struct blob_field *attr){
|
|
assert(attr);
|
|
return (be32_to_cpu(attr->id_len) & BLOB_FIELD_LEN_MASK);
|
|
}
|
|
|
|
//! includes length of data of the attribute
|
|
unsigned int
|
|
blob_field_data_len(const struct blob_field *attr){
|
|
assert(attr);
|
|
return blob_field_raw_len(attr) - sizeof(struct blob_field);
|
|
}
|
|
|
|
//! returns padded length of full attribute
|
|
uint32_t
|
|
blob_field_raw_pad_len(const struct blob_field *attr){
|
|
assert(attr);
|
|
uint32_t len = blob_field_raw_len(attr);
|
|
len = (len + BLOB_FIELD_ALIGN - 1) & ~(BLOB_FIELD_ALIGN - 1);
|
|
return len;
|
|
}
|
|
|
|
struct blob_field *blob_field_first_child(const struct blob_field *self){
|
|
assert(self);
|
|
if(blob_field_raw_len(self) <= sizeof(struct blob_field)) return NULL;
|
|
return (struct blob_field*)blob_field_data(self);
|
|
}
|
|
|
|
struct blob_field *blob_field_next_child(const struct blob_field *self, const struct blob_field *child){
|
|
if(!child) return NULL;
|
|
struct blob_field *ret = (struct blob_field *) ((char *) child + blob_field_raw_pad_len(child));
|
|
// check if we are still within bounds
|
|
size_t offset = (char*)ret - (char*)self;
|
|
if(offset >= blob_field_raw_pad_len(self)) return NULL;
|
|
return ret;
|
|
}
|
|
bool _blob_field_validate(struct blob_field *attr, const char *signature, const char **nk){
|
|
const char *k = signature;
|
|
//printf("validating %s\n", signature);
|
|
struct blob_field *field = blob_field_first_child(attr);
|
|
if(!field) return false; // correctly handle empty message!
|
|
while(*k && field){
|
|
//printf("KEY: %c\n", *k);
|
|
switch(*k){
|
|
case '{':
|
|
if(blob_field_type(field) != BLOB_FIELD_TABLE) return false;
|
|
if(!_blob_field_validate(field, k + 1, &k)) return false;
|
|
//printf("continuing at %s\n", k);
|
|
break;
|
|
case '}':
|
|
//printf("closing\n");
|
|
if(!field) {
|
|
printf("exiting level\n");
|
|
if(nk) *nk = k ;
|
|
return true;
|
|
}
|
|
k = signature;
|
|
continue;
|
|
break;
|
|
case '[':
|
|
//printf("parsing array!\n");
|
|
if(blob_field_type(field) != BLOB_FIELD_ARRAY) return false;
|
|
if(!_blob_field_validate(field, k + 1, &k)) return false;
|
|
break;
|
|
case ']':
|
|
//printf("closing array\n");
|
|
if(!field) return true;
|
|
k = signature;
|
|
continue;
|
|
break;
|
|
case 'i':
|
|
switch(blob_field_type(field)){
|
|
case BLOB_FIELD_INT8:
|
|
case BLOB_FIELD_INT16:
|
|
case BLOB_FIELD_INT32:
|
|
case BLOB_FIELD_INT64:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
case 'f':
|
|
switch(blob_field_type(field)){
|
|
case BLOB_FIELD_FLOAT32:
|
|
case BLOB_FIELD_FLOAT64:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
case 's':
|
|
if(blob_field_type(field) != BLOB_FIELD_STRING) return false;
|
|
break;
|
|
case 't':
|
|
if(blob_field_type(field) != BLOB_FIELD_TABLE) return false;
|
|
break;
|
|
case 'a':
|
|
if(blob_field_type(field) != BLOB_FIELD_ARRAY) return false;
|
|
break;
|
|
case 'v':
|
|
break;
|
|
}
|
|
k++;
|
|
field = blob_field_next_child(attr, field);
|
|
//printf("next field %s %d\n", k, blob_field_type(field));
|
|
}
|
|
//printf("exiting at %s\n", k);
|
|
if(nk) *nk = k;
|
|
return true;
|
|
}
|
|
|
|
bool blob_field_validate(struct blob_field *attr, const char *signature){
|
|
assert(attr);
|
|
return _blob_field_validate(attr, signature, NULL);
|
|
}
|
|
|
|
bool blob_field_parse(struct blob_field *attr, const char *signature, struct blob_field **out, int out_size){
|
|
assert(attr);
|
|
memset(out, 0, sizeof(struct blob_field*) * out_size);
|
|
if(!blob_field_validate(attr, signature)) return false;
|
|
for(struct blob_field *a = blob_field_first_child(attr); a && out_size; a = blob_field_next_child(attr, a)){
|
|
*out = a;
|
|
out++;
|
|
out_size--;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool blob_field_parse_values(struct blob_field *attr, struct blob_policy *policy, int policy_size){
|
|
assert(attr);
|
|
bool valid = true;
|
|
if(blob_field_type(attr) == BLOB_FIELD_TABLE){
|
|
struct blob_field *key, *value;
|
|
int processed = 0;
|
|
blob_field_for_each_kv(attr, key, value){
|
|
if(processed == policy_size) return false;
|
|
for(int c = 0; c < policy_size; c++){
|
|
if(strcmp(blob_field_get_string(key), policy[c].name) == 0){
|
|
if(policy[c].type == BLOB_FIELD_ANY || blob_field_type(value) == policy[c].type) {
|
|
policy[c].value = value;
|
|
} else { policy[c].value = NULL; valid = false; }
|
|
processed++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else if(blob_field_type(attr) == BLOB_FIELD_ARRAY){
|
|
struct blob_field *child;
|
|
int pidx = 0;
|
|
blob_field_for_each_child(attr, child){
|
|
if(!policy_size) return false;
|
|
if(policy[pidx].type == BLOB_FIELD_ANY || blob_field_type(child) == policy[pidx].type) {
|
|
policy[pidx].value = child;
|
|
} else { policy[pidx].value = NULL; valid = false; }
|
|
pidx++;
|
|
policy_size--;
|
|
}
|
|
}
|
|
return valid;
|
|
}
|