/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "bi-inc/attr_container.h" typedef union jvalue { bool z; int8_t b; uint16_t c; int16_t s; int32_t i; int64_t j; float f; double d; } jvalue; static inline int16_t get_int16(const char *buf) { int16_t ret; bh_memcpy_s(&ret, sizeof(int16_t), buf, sizeof(int16_t)); return ret; } static inline uint16_t get_uint16(const char *buf) { return get_int16(buf); } static inline int32_t get_int32(const char *buf) { int32_t ret; bh_memcpy_s(&ret, sizeof(int32_t), buf, sizeof(int32_t)); return ret; } static inline uint32_t get_uint32(const char *buf) { return get_int32(buf); } static inline int64_t get_int64(const char *buf) { int64_t ret; bh_memcpy_s(&ret, sizeof(int64_t), buf, sizeof(int64_t)); return ret; } static inline uint64_t get_uint64(const char *buf) { return get_int64(buf); } static inline void set_int16(char *buf, int16_t v) { bh_memcpy_s(buf, sizeof(int16_t), &v, sizeof(int16_t)); } static inline void set_uint16(char *buf, uint16_t v) { bh_memcpy_s(buf, sizeof(uint16_t), &v, sizeof(uint16_t)); } static inline void set_int32(char *buf, int32_t v) { bh_memcpy_s(buf, sizeof(int32_t), &v, sizeof(int32_t)); } static inline void set_uint32(char *buf, uint32_t v) { bh_memcpy_s(buf, sizeof(uint32_t), &v, sizeof(uint32_t)); } static inline void set_int64(char *buf, int64_t v) { bh_memcpy_s(buf, sizeof(int64_t), &v, sizeof(int64_t)); } static inline void set_uint64(char *buf, uint64_t v) { bh_memcpy_s(buf, sizeof(uint64_t), &v, sizeof(uint64_t)); } char * attr_container_get_attr_begin(const attr_container_t *attr_cont, uint32_t *p_total_length, uint16_t *p_attr_num) { char *p = (char *)attr_cont->buf; uint16_t str_len, attr_num; uint32_t total_length; /* skip total length */ total_length = get_uint32(p); p += sizeof(uint32_t); if (!total_length) return NULL; /* tag length */ str_len = get_uint16(p); p += sizeof(uint16_t); if (!str_len) return NULL; /* tag content */ p += str_len; if ((uint32_t)(p - attr_cont->buf) >= total_length) return NULL; /* attribute num */ attr_num = get_uint16(p); p += sizeof(uint16_t); if ((uint32_t)(p - attr_cont->buf) >= total_length) return NULL; if (p_total_length) *p_total_length = total_length; if (p_attr_num) *p_attr_num = attr_num; /* first attribute */ return p; } static char * attr_container_get_attr_next(const char *curr_attr) { char *p = (char *)curr_attr; uint8_t type; /* key length and key */ p += sizeof(uint16_t) + get_uint16(p); type = *p++; /* Short type to Boolean type */ if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) { p += 1 << (type & 3); return p; } /* String type */ else if (type == ATTR_TYPE_STRING) { p += sizeof(uint16_t) + get_uint16(p); return p; } /* ByteArray type */ else if (type == ATTR_TYPE_BYTEARRAY) { p += sizeof(uint32_t) + get_uint32(p); return p; } return NULL; } static const char * attr_container_find_attr(const attr_container_t *attr_cont, const char *key) { uint32_t total_length; uint16_t str_len, attr_num, i; const char *p = attr_cont->buf; if (!key) return NULL; if (!(p = attr_container_get_attr_begin(attr_cont, &total_length, &attr_num))) return NULL; for (i = 0; i < attr_num; i++) { /* key length */ if (!(str_len = get_uint16(p))) return NULL; if (str_len == strlen(key) + 1 && memcmp(p + sizeof(uint16_t), key, str_len) == 0) { if ((uint32_t)(p + sizeof(uint16_t) + str_len - attr_cont->buf) >= total_length) return NULL; return p; } if (!(p = attr_container_get_attr_next(p))) return NULL; } return NULL; } char * attr_container_get_attr_end(const attr_container_t *attr_cont) { uint32_t total_length; uint16_t attr_num, i; char *p; if (!(p = attr_container_get_attr_begin(attr_cont, &total_length, &attr_num))) return NULL; for (i = 0; i < attr_num; i++) if (!(p = attr_container_get_attr_next(p))) return NULL; return p; } static char * attr_container_get_msg_end(attr_container_t *attr_cont) { char *p = attr_cont->buf; return p + get_uint32(p); } uint16_t attr_container_get_attr_num(const attr_container_t *attr_cont) { uint16_t str_len; /* skip total length */ const char *p = attr_cont->buf + sizeof(uint32_t); str_len = get_uint16(p); /* skip tag length and tag */ p += sizeof(uint16_t) + str_len; /* attribute num */ return get_uint16(p); } static void attr_container_inc_attr_num(attr_container_t *attr_cont) { uint16_t str_len, attr_num; /* skip total length */ char *p = attr_cont->buf + sizeof(uint32_t); str_len = get_uint16(p); /* skip tag length and tag */ p += sizeof(uint16_t) + str_len; /* attribute num */ attr_num = get_uint16(p) + 1; set_uint16(p, attr_num); } attr_container_t * attr_container_create(const char *tag) { attr_container_t *attr_cont; int length, tag_length; char *p; tag_length = tag ? strlen(tag) + 1 : 1; length = offsetof(attr_container_t, buf) + /* total length + tag length + tag + reserved 100 bytes */ sizeof(uint32_t) + sizeof(uint16_t) + tag_length + 100; if (!(attr_cont = attr_container_malloc(length))) { attr_container_printf( "Create attr_container failed: allocate memory failed.\r\n"); return NULL; } memset(attr_cont, 0, length); p = attr_cont->buf; /* total length */ set_uint32(p, length - offsetof(attr_container_t, buf)); p += 4; /* tag length, tag */ set_uint16(p, tag_length); p += 2; if (tag) bh_memcpy_s(p, tag_length, tag, tag_length); return attr_cont; } void attr_container_destroy(const attr_container_t *attr_cont) { if (attr_cont) attr_container_free((char *)attr_cont); } static bool check_set_attr(attr_container_t **p_attr_cont, const char *key) { uint32_t flags; if (!p_attr_cont || !*p_attr_cont || !key || strlen(key) == 0) { attr_container_printf( "Set attribute failed: invalid input arguments.\r\n"); return false; } flags = get_uint32((char *)*p_attr_cont); if (flags & ATTR_CONT_READONLY_SHIFT) { attr_container_printf( "Set attribute failed: attribute container is readonly.\r\n"); return false; } return true; } bool attr_container_set_attr(attr_container_t **p_attr_cont, const char *key, int type, const void *value, int value_length) { attr_container_t *attr_cont, *attr_cont1; uint16_t str_len; uint32_t total_length, attr_len; char *p, *p1, *attr_end, *msg_end, *attr_buf; if (!check_set_attr(p_attr_cont, key)) { return false; } attr_cont = *p_attr_cont; p = attr_cont->buf; total_length = get_uint32(p); if (!(attr_end = attr_container_get_attr_end(attr_cont))) { attr_container_printf("Set attr failed: get attr end failed.\r\n"); return false; } msg_end = attr_container_get_msg_end(attr_cont); /* key len + key + '\0' + type */ attr_len = sizeof(uint16_t) + strlen(key) + 1 + 1; if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) attr_len += 1 << (type & 3); else if (type == ATTR_TYPE_STRING) attr_len += sizeof(uint16_t) + value_length; else if (type == ATTR_TYPE_BYTEARRAY) attr_len += sizeof(uint32_t) + value_length; if (!(p = attr_buf = attr_container_malloc(attr_len))) { attr_container_printf("Set attr failed: allocate memory failed.\r\n"); return false; } /* Set the attr buf */ str_len = (uint16_t)(strlen(key) + 1); set_uint16(p, str_len); p += sizeof(uint16_t); bh_memcpy_s(p, str_len, key, str_len); p += str_len; *p++ = type; if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) bh_memcpy_s(p, 1 << (type & 3), value, 1 << (type & 3)); else if (type == ATTR_TYPE_STRING) { set_uint16(p, value_length); p += sizeof(uint16_t); bh_memcpy_s(p, value_length, value, value_length); } else if (type == ATTR_TYPE_BYTEARRAY) { set_uint32(p, value_length); p += sizeof(uint32_t); bh_memcpy_s(p, value_length, value, value_length); } if ((p = (char *)attr_container_find_attr(attr_cont, key))) { /* key found */ p1 = attr_container_get_attr_next(p); if (p1 - p == attr_len) { bh_memcpy_s(p, attr_len, attr_buf, attr_len); attr_container_free(attr_buf); return true; } if ((uint32_t)(p1 - p + msg_end - attr_end) >= attr_len) { memmove(p, p1, attr_end - p1); bh_memcpy_s(p + (attr_end - p1), attr_len, attr_buf, attr_len); attr_container_free(attr_buf); return true; } total_length += attr_len + 100; if (!(attr_cont1 = attr_container_malloc(offsetof(attr_container_t, buf) + total_length))) { attr_container_printf( "Set attr failed: allocate memory failed.\r\n"); attr_container_free(attr_buf); return false; } bh_memcpy_s(attr_cont1, p - (char *)attr_cont, attr_cont, p - (char *)attr_cont); bh_memcpy_s((char *)attr_cont1 + (unsigned)(p - (char *)attr_cont), attr_end - p1, p1, attr_end - p1); bh_memcpy_s((char *)attr_cont1 + (unsigned)(p - (char *)attr_cont) + (unsigned)(attr_end - p1), attr_len, attr_buf, attr_len); p = attr_cont1->buf; set_uint32(p, total_length); *p_attr_cont = attr_cont1; /* Free original buffer */ attr_container_free(attr_cont); attr_container_free(attr_buf); return true; } else { /* key not found */ if ((uint32_t)(msg_end - attr_end) >= attr_len) { bh_memcpy_s(attr_end, msg_end - attr_end, attr_buf, attr_len); attr_container_inc_attr_num(attr_cont); attr_container_free(attr_buf); return true; } total_length += attr_len + 100; if (!(attr_cont1 = attr_container_malloc(offsetof(attr_container_t, buf) + total_length))) { attr_container_printf( "Set attr failed: allocate memory failed.\r\n"); attr_container_free(attr_buf); return false; } bh_memcpy_s(attr_cont1, attr_end - (char *)attr_cont, attr_cont, attr_end - (char *)attr_cont); bh_memcpy_s((char *)attr_cont1 + (unsigned)(attr_end - (char *)attr_cont), attr_len, attr_buf, attr_len); attr_container_inc_attr_num(attr_cont1); p = attr_cont1->buf; set_uint32(p, total_length); *p_attr_cont = attr_cont1; /* Free original buffer */ attr_container_free(attr_cont); attr_container_free(attr_buf); return true; } return false; } bool attr_container_set_short(attr_container_t **p_attr_cont, const char *key, short value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_SHORT, &value, 2); } bool attr_container_set_int(attr_container_t **p_attr_cont, const char *key, int value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT, &value, 4); } bool attr_container_set_int64(attr_container_t **p_attr_cont, const char *key, int64_t value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT64, &value, 8); } bool attr_container_set_byte(attr_container_t **p_attr_cont, const char *key, int8_t value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_BYTE, &value, 1); } bool attr_container_set_uint16(attr_container_t **p_attr_cont, const char *key, uint16_t value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT16, &value, 2); } bool attr_container_set_float(attr_container_t **p_attr_cont, const char *key, float value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_FLOAT, &value, 4); } bool attr_container_set_double(attr_container_t **p_attr_cont, const char *key, double value) { return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_DOUBLE, &value, 8); } bool attr_container_set_bool(attr_container_t **p_attr_cont, const char *key, bool value) { int8_t value1 = value ? 1 : 0; return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_BOOLEAN, &value1, 1); } bool attr_container_set_string(attr_container_t **p_attr_cont, const char *key, const char *value) { if (!value) { attr_container_printf("Set attr failed: invald input arguments.\r\n"); return false; } return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_STRING, value, strlen(value) + 1); } bool attr_container_set_bytearray(attr_container_t **p_attr_cont, const char *key, const int8_t *value, unsigned length) { if (!value) { attr_container_printf("Set attr failed: invald input arguments.\r\n"); return false; } return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_BYTEARRAY, value, length); } static const char * attr_container_get_attr(const attr_container_t *attr_cont, const char *key) { const char *attr_addr; if (!attr_cont || !key) { attr_container_printf( "Get attribute failed: invalid input arguments.\r\n"); return NULL; } if (!(attr_addr = attr_container_find_attr(attr_cont, key))) { attr_container_printf("Get attribute failed: lookup key failed.\r\n"); return false; } /* key len + key + '\0' */ return attr_addr + 2 + strlen(key) + 1; } #define TEMPLATE_ATTR_BUF_TO_VALUE(attr, key, var_name) \ do { \ jvalue val; \ const char *addr = attr_container_get_attr(attr, key); \ uint8_t type; \ if (!addr) \ return 0; \ val.j = 0; \ type = *(uint8_t *)addr++; \ switch (type) { \ case ATTR_TYPE_SHORT: \ case ATTR_TYPE_INT: \ case ATTR_TYPE_INT64: \ case ATTR_TYPE_BYTE: \ case ATTR_TYPE_UINT16: \ case ATTR_TYPE_FLOAT: \ case ATTR_TYPE_DOUBLE: \ case ATTR_TYPE_BOOLEAN: \ bh_memcpy_s(&val, sizeof(val.var_name), addr, \ 1 << (type & 3)); \ break; \ case ATTR_TYPE_STRING: \ { \ unsigned len = get_uint16(addr); \ addr += 2; \ if (len > sizeof(val.var_name)) \ len = sizeof(val.var_name); \ bh_memcpy_s(&val.var_name, sizeof(val.var_name), addr, len); \ break; \ } \ case ATTR_TYPE_BYTEARRAY: \ { \ unsigned len = get_uint32(addr); \ addr += 4; \ if (len > sizeof(val.var_name)) \ len = sizeof(val.var_name); \ bh_memcpy_s(&val.var_name, sizeof(val.var_name), addr, len); \ break; \ } \ default: \ bh_assert(0); \ break; \ } \ return val.var_name; \ } while (0) short attr_container_get_as_short(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s); } int attr_container_get_as_int(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i); } int64_t attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, j); } int8_t attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, b); } uint16_t attr_container_get_as_uint16(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s); } float attr_container_get_as_float(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, f); } double attr_container_get_as_double(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, d); } bool attr_container_get_as_bool(const attr_container_t *attr_cont, const char *key) { TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, z); } const int8_t * attr_container_get_as_bytearray(const attr_container_t *attr_cont, const char *key, unsigned *array_length) { const char *addr = attr_container_get_attr(attr_cont, key); uint8_t type; uint32_t length; if (!addr) return NULL; if (!array_length) { attr_container_printf("Get attribute failed: invalid input arguments."); return NULL; } type = *(uint8_t *)addr++; switch (type) { case ATTR_TYPE_SHORT: case ATTR_TYPE_INT: case ATTR_TYPE_INT64: case ATTR_TYPE_BYTE: case ATTR_TYPE_UINT16: case ATTR_TYPE_FLOAT: case ATTR_TYPE_DOUBLE: case ATTR_TYPE_BOOLEAN: length = 1 << (type & 3); break; case ATTR_TYPE_STRING: length = get_uint16(addr); addr += 2; break; case ATTR_TYPE_BYTEARRAY: length = get_uint32(addr); addr += 4; break; default: return NULL; } *array_length = length; return (const int8_t *)addr; } char * attr_container_get_as_string(const attr_container_t *attr_cont, const char *key) { unsigned array_length; return (char *)attr_container_get_as_bytearray(attr_cont, key, &array_length); } const char * attr_container_get_tag(const attr_container_t *attr_cont) { return attr_cont ? attr_cont->buf + sizeof(uint32_t) + sizeof(uint16_t) : NULL; } bool attr_container_contain_key(const attr_container_t *attr_cont, const char *key) { if (!attr_cont || !key || !strlen(key)) { attr_container_printf( "Check contain key failed: invalid input arguments.\r\n"); return false; } return attr_container_find_attr(attr_cont, key) ? true : false; } unsigned int attr_container_get_serialize_length(const attr_container_t *attr_cont) { const char *p; if (!attr_cont) { attr_container_printf("Get container serialize length failed: invalid " "input arguments.\r\n"); return 0; } p = attr_cont->buf; return sizeof(uint16_t) + get_uint32(p); } bool attr_container_serialize(char *buf, const attr_container_t *attr_cont) { const char *p; uint16_t flags; uint32_t length; if (!buf || !attr_cont) { attr_container_printf( "Container serialize failed: invalid input arguments.\r\n"); return false; } p = attr_cont->buf; length = sizeof(uint16_t) + get_uint32(p); bh_memcpy_s(buf, length, attr_cont, length); /* Set readonly */ flags = get_uint16((const char *)attr_cont); set_uint16(buf, flags | (1 << ATTR_CONT_READONLY_SHIFT)); return true; } bool attr_container_is_constant(const attr_container_t *attr_cont) { uint16_t flags; if (!attr_cont) { attr_container_printf( "Container check const: invalid input arguments.\r\n"); return false; } flags = get_uint16((const char *)attr_cont); return (flags & (1 << ATTR_CONT_READONLY_SHIFT)) ? true : false; } void attr_container_dump(const attr_container_t *attr_cont) { uint32_t total_length; uint16_t attr_num, i, type; const char *p, *tag, *key; jvalue value; if (!attr_cont) return; tag = attr_container_get_tag(attr_cont); if (!tag) return; attr_container_printf("Attribute container dump:\n"); attr_container_printf("Tag: %s\n", tag); p = attr_container_get_attr_begin(attr_cont, &total_length, &attr_num); if (!p) return; attr_container_printf("Attribute list:\n"); for (i = 0; i < attr_num; i++) { key = p + 2; /* Skip key len and key */ p += 2 + get_uint16(p); type = *p++; attr_container_printf(" key: %s", key); switch (type) { case ATTR_TYPE_SHORT: bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t)); attr_container_printf(", type: short, value: 0x%x\n", value.s & 0xFFFF); p += 2; break; case ATTR_TYPE_INT: bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t)); attr_container_printf(", type: int, value: 0x%x\n", value.i); p += 4; break; case ATTR_TYPE_INT64: bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t)); attr_container_printf(", type: int64, value: 0x%llx\n", (long long unsigned int)(value.j)); p += 8; break; case ATTR_TYPE_BYTE: bh_memcpy_s(&value.b, 1, p, 1); attr_container_printf(", type: byte, value: 0x%x\n", value.b & 0xFF); p++; break; case ATTR_TYPE_UINT16: bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t)); attr_container_printf(", type: uint16, value: 0x%x\n", value.c); p += 2; break; case ATTR_TYPE_FLOAT: bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float)); attr_container_printf(", type: float, value: %f\n", value.f); p += 4; break; case ATTR_TYPE_DOUBLE: bh_memcpy_s(&value.d, sizeof(double), p, sizeof(double)); attr_container_printf(", type: double, value: %f\n", value.d); p += 8; break; case ATTR_TYPE_BOOLEAN: bh_memcpy_s(&value.z, 1, p, 1); attr_container_printf(", type: bool, value: 0x%x\n", value.z); p++; break; case ATTR_TYPE_STRING: attr_container_printf(", type: string, value: %s\n", p + sizeof(uint16_t)); p += sizeof(uint16_t) + get_uint16(p); break; case ATTR_TYPE_BYTEARRAY: attr_container_printf(", type: byte array, length: %d\n", get_uint32(p)); p += sizeof(uint32_t) + get_uint32(p); break; default: bh_assert(0); break; } } attr_container_printf("\n"); }