#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/lib_vpd.h"
#ifndef MIN
#define MIN(a, b) ((a < b) ? a : b)
#endif
void initContainer(struct PairContainer *container) {
container->first = NULL;
}
struct StringPair *findString(struct PairContainer *container,
const uint8_t *key,
struct StringPair ***prev_next) {
struct StringPair *current;
if (prev_next) {
*prev_next = &container->first;
}
for (current = container->first; current; current = current->next) {
if (!strcmp((char*)key, (char*)current->key)) {
return current;
}
if (prev_next) {
*prev_next = ¤t->next;
}
}
return NULL;
}
static void fillStringPair(struct StringPair *pair,
const uint8_t *key,
const uint8_t *value,
const int pad_len) {
pair->key = malloc(strlen((char*)key) + 1);
assert(pair->key);
strcpy((char*)pair->key, (char*)key);
pair->value = malloc(strlen((char*)value) + 1);
strcpy((char*)pair->value, (char*)value);
pair->pad_len = pad_len;
}
void setString(struct PairContainer *container,
const uint8_t *key,
const uint8_t *value,
const int pad_len) {
struct StringPair *found;
found = findString(container, key, NULL);
if (found) {
free(found->key);
free(found->value);
fillStringPair(found, key, value, pad_len);
} else {
struct StringPair *new_pair = malloc(sizeof(struct StringPair));
assert(new_pair);
memset(new_pair, 0, sizeof(struct StringPair));
fillStringPair(new_pair, key, value, pad_len);
if ((found = container->first)) {
while (found->next) found = found->next;
found->next = new_pair;
} else {
container->first = new_pair;
}
new_pair->next = NULL;
}
}
vpd_err_t deleteKey(struct PairContainer *container,
const uint8_t *key) {
struct StringPair *found, **prev_next;
found = findString(container, key, &prev_next);
if (found) {
free(found->key);
free(found->value);
assert(prev_next);
*prev_next = found->next;
free(found);
return VPD_OK;
} else {
return VPD_FAIL;
}
}
int lenOfContainer(const struct PairContainer *container) {
int count;
struct StringPair *current;
for (count = 0, current = container->first;
current;
count++, current = current->next);
return count;
}
void mergeContainer(struct PairContainer *dst,
const struct PairContainer *src) {
struct StringPair *current;
for (current = src->first; current; current = current->next) {
setString(dst, current->key, current->value, current->pad_len);
}
}
int subtractContainer(struct PairContainer *dst,
const struct PairContainer *src) {
struct StringPair *current;
int count = 0;
for (current = src->first; current; current = current->next) {
if (VPD_OK == deleteKey(dst, current->key))
count++;
}
return count;
}
vpd_err_t encodeContainer(const struct PairContainer *container,
const int max_buf_len,
uint8_t *buf,
int *generated) {
struct StringPair *current;
for (current = container->first; current; current = current->next) {
if (VPD_OK != encodeVpdString(current->key,
current->value,
current->pad_len,
max_buf_len,
buf,
generated)) {
return VPD_FAIL;
}
}
return VPD_OK;
}
static int callbackDecodeToContainer(const uint8_t *key,
uint32_t key_len,
const uint8_t *value,
uint32_t value_len,
void *arg) {
struct PairContainer *container = (struct PairContainer*)arg;
uint8_t *key_string = (uint8_t*)malloc(key_len + 1),
*value_string = (uint8_t*)malloc(value_len + 1);
assert(key_string && value_string);
memcpy(key_string, key, key_len);
memcpy(value_string, value, value_len);
key_string[key_len] = '\0';
value_string[value_len] = '\0';
setString(container, key_string, value_string, value_len);
free(key_string);
free(value_string);
return VPD_DECODE_OK;
}
vpd_err_t decodeToContainer(struct PairContainer *container,
const uint32_t max_len,
const uint8_t *input_buf,
uint32_t *consumed) {
return decodeVpdString(max_len, input_buf, consumed,
callbackDecodeToContainer, (void*)container);
}
vpd_err_t setContainerFilter(struct PairContainer *container,
const uint8_t *filter) {
struct StringPair *str;
for (str = container->first; str; str = str->next) {
if (filter) {
if (strcmp((char*)str->key, (char*)filter)) {
str->filter_out = 1;
}
} else {
str->filter_out = 0;
}
}
return VPD_OK;
}
static vpd_err_t _appendToBuf(const void *buf_to_append,
int len,
const int max_buf_len,
uint8_t *buf,
int *generated) {
if (*generated + len > max_buf_len) return VPD_ERR_OVERFLOW;
memcpy(&buf[*generated], buf_to_append, len);
*generated += len;
return VPD_OK;
}
static int _getStringPairValueLen(const struct StringPair *str) {
int len = strlen((const char*)(str->value));
return VPD_AS_LONG_AS == str->pad_len ? len : MIN(str->pad_len, len);
}
static vpd_err_t _exportStringPairKeyValue(const struct StringPair *str,
const int max_buf_len,
uint8_t *buf,
int *generated) {
const void *strs[5] = {"\"", str->key, "\"=\"", str->value, "\"\n"};
const int lens[5] = {
1, strlen((const char*)str->key), 3, _getStringPairValueLen(str), 2};
int retval;
int i;
for (i = 0; i < sizeof(lens) / sizeof(int); ++i) {
retval = _appendToBuf(strs[i], lens[i], max_buf_len, buf, generated);
if (VPD_OK != retval) {
break;
}
}
return retval;
}
static vpd_err_t _appendToBufWithShellEscape(const char *str_to_export,
const int max_buf_len,
uint8_t *buf,
int *generated) {
int len = strlen(str_to_export);
int i;
int retval;
for (i = 0; i < len; ++i) {
if ('\'' == str_to_export[i]) {
retval = _appendToBuf("'\"'\"'", 5, max_buf_len, buf, generated);
} else {
retval = _appendToBuf(str_to_export + i, 1,
max_buf_len, buf, generated);
}
if (VPD_OK != retval) return retval;
}
return VPD_OK;
}
static vpd_err_t _exportStringPairAsParameter(const struct StringPair *str,
const int max_buf_len,
uint8_t *buf,
int *generated) {
int retval;
{
const char extra_params[] = " -s ";
retval = _appendToBuf(extra_params, strlen(extra_params),
max_buf_len, buf, generated);
if (VPD_OK != retval) return retval;
}
if (*generated + 1 > max_buf_len) return VPD_ERR_OVERFLOW;
buf[(*generated)++] = '\'';
retval = _appendToBufWithShellEscape(
(const char*)str->key, max_buf_len, buf, generated);
if (VPD_OK != retval) return retval;
if (*generated + 1 > max_buf_len) return VPD_ERR_OVERFLOW;
buf[(*generated)++] = '=';
retval = _appendToBufWithShellEscape(
(const char*)str->value, max_buf_len, buf, generated);
if (VPD_OK != retval) return retval;
retval = _appendToBuf("' \\\n", 4, max_buf_len, buf, generated);
return retval;
}
static vpd_err_t _exportStringPairNullTerminate(const struct StringPair *str,
const int max_buf_len,
uint8_t *buf,
int *generated) {
int retval;
retval = _appendToBuf(str->key, strlen((const char*)str->key),
max_buf_len, buf, generated);
if (VPD_OK != retval) return retval;
if (*generated + 1 > max_buf_len) return VPD_ERR_OVERFLOW;
buf[(*generated)++] = '=';
retval = _appendToBuf(str->value, _getStringPairValueLen(str),
max_buf_len, buf, generated);
if (VPD_OK != retval) return retval;
if (*generated + 1 > max_buf_len) return VPD_ERR_OVERFLOW;
buf[(*generated)++] = '\0';
return VPD_OK;
}
vpd_err_t exportStringValue(const struct StringPair *str,
const int max_buf_len,
uint8_t *buf,
int *generated) {
assert(generated);
return _appendToBuf(str->value, _getStringPairValueLen(str),
max_buf_len, buf, generated);
}
vpd_err_t exportContainer(const int export_type,
const struct PairContainer *container,
const int max_buf_len,
uint8_t *buf,
int *generated) {
struct StringPair *str;
int index;
int retval;
assert(generated);
index = *generated;
for (str = container->first; str; str = str->next) {
if (str->filter_out)
continue;
if (VPD_EXPORT_KEY_VALUE == export_type) {
retval = _exportStringPairKeyValue(str, max_buf_len, buf, &index);
} else if (VPD_EXPORT_AS_PARAMETER == export_type) {
retval = _exportStringPairAsParameter(str, max_buf_len, buf, &index);
} else if (VPD_EXPORT_NULL_TERMINATE == export_type) {
retval = _exportStringPairNullTerminate(str, max_buf_len, buf, &index);
} else {
assert(0);
}
if (VPD_OK != retval) return retval;
}
*generated = index;
return VPD_OK;
}
void destroyContainer(struct PairContainer *container) {
struct StringPair *current;
for (current = container->first; current;) {
struct StringPair *next;
if (current->key) free(current->key);
if (current->value) free(current->value);
next = current->next;
free(current);
current = next;
}
}