diff options
Diffstat (limited to 'src/doveadm/dsync/dsync-deserializer.c')
-rw-r--r-- | src/doveadm/dsync/dsync-deserializer.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/doveadm/dsync/dsync-deserializer.c b/src/doveadm/dsync/dsync-deserializer.c new file mode 100644 index 0000000..2a90c47 --- /dev/null +++ b/src/doveadm/dsync/dsync-deserializer.c @@ -0,0 +1,193 @@ +/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "strescape.h" +#include "dsync-serializer.h" +#include "dsync-deserializer.h" + +struct dsync_deserializer { + pool_t pool; + const char *name; + const char *const *required_fields; + const char *const *keys; + unsigned int *required_field_indexes; + unsigned int required_field_count; +}; + +struct dsync_deserializer_decoder { + pool_t pool; + struct dsync_deserializer *deserializer; + const char *const *values; + unsigned int values_count; +}; + +static bool field_find(const char *const *names, const char *name, + unsigned int *idx_r) +{ + unsigned int i; + + for (i = 0; names[i] != NULL; i++) { + if (strcmp(names[i], name) == 0) { + *idx_r = i; + return TRUE; + } + } + return FALSE; +} + +int dsync_deserializer_init(const char *name, const char *const *required_fields, + const char *header_line, + struct dsync_deserializer **deserializer_r, + const char **error_r) +{ + struct dsync_deserializer *deserializer; + const char **dup_required_fields; + unsigned int i, required_count; + pool_t pool; + + *deserializer_r = NULL; + + pool = pool_alloconly_create("dsync deserializer", 1024); + deserializer = p_new(pool, struct dsync_deserializer, 1); + deserializer->pool = pool; + deserializer->name = p_strdup(pool, name); + deserializer->keys = (void *)p_strsplit_tabescaped(pool, header_line); + + deserializer->required_field_count = required_count = + required_fields == NULL ? 0 : + str_array_length(required_fields); + dup_required_fields = p_new(pool, const char *, required_count + 1); + deserializer->required_field_indexes = + p_new(pool, unsigned int, required_count + 1); + for (i = 0; i < required_count; i++) { + dup_required_fields[i] = + p_strdup(pool, required_fields[i]); + if (!field_find(deserializer->keys, required_fields[i], + &deserializer->required_field_indexes[i])) { + *error_r = t_strdup_printf( + "Header missing required field %s", + required_fields[i]); + pool_unref(&pool); + return -1; + } + } + deserializer->required_fields = dup_required_fields; + + *deserializer_r = deserializer; + return 0; +} + +void dsync_deserializer_deinit(struct dsync_deserializer **_deserializer) +{ + struct dsync_deserializer *deserializer = *_deserializer; + + *_deserializer = NULL; + + pool_unref(&deserializer->pool); +} + +int dsync_deserializer_decode_begin(struct dsync_deserializer *deserializer, + const char *input, + struct dsync_deserializer_decoder **decoder_r, + const char **error_r) +{ + struct dsync_deserializer_decoder *decoder; + unsigned int i; + char **values; + pool_t pool; + + *decoder_r = NULL; + + pool = pool_alloconly_create("dsync deserializer decode", 1024); + decoder = p_new(pool, struct dsync_deserializer_decoder, 1); + decoder->pool = pool; + decoder->deserializer = deserializer; + values = p_strsplit_tabescaped(pool, input); + + /* fix NULLs */ + for (i = 0; values[i] != NULL; i++) { + if (values[i][0] == NULL_CHR) { + /* NULL? */ + if (values[i][1] == '\0') + values[i] = NULL; + else + values[i] += 1; + } + } + decoder->values_count = i; + + /* see if all required fields exist */ + for (i = 0; i < deserializer->required_field_count; i++) { + unsigned int ridx = deserializer->required_field_indexes[i]; + + if (ridx >= decoder->values_count || values[ridx] == NULL) { + *error_r = t_strdup_printf("Missing required field %s", + deserializer->required_fields[i]); + pool_unref(&pool); + return -1; + } + } + decoder->values = (void *)values; + + *decoder_r = decoder; + return 0; +} + +static bool +dsync_deserializer_find_field(struct dsync_deserializer *deserializer, + const char *key, unsigned int *idx_r) +{ + unsigned int i; + + for (i = 0; deserializer->keys[i] != NULL; i++) { + if (strcmp(deserializer->keys[i], key) == 0) { + *idx_r = i; + return TRUE; + } + } + return FALSE; +} + +bool dsync_deserializer_decode_try(struct dsync_deserializer_decoder *decoder, + const char *key, const char **value_r) +{ + unsigned int idx; + + if (!dsync_deserializer_find_field(decoder->deserializer, key, &idx) || + idx >= decoder->values_count) { + *value_r = NULL; + return FALSE; + } else { + *value_r = decoder->values[idx]; + return *value_r != NULL; + } +} + +const char * +dsync_deserializer_decode_get(struct dsync_deserializer_decoder *decoder, + const char *key) +{ + const char *value; + + if (!dsync_deserializer_decode_try(decoder, key, &value)) { + i_panic("dsync_deserializer_decode_get() " + "used for non-required key %s", key); + } + return value; +} + +const char * +dsync_deserializer_decoder_get_name(struct dsync_deserializer_decoder *decoder) +{ + return decoder->deserializer->name; +} + +void dsync_deserializer_decode_finish(struct dsync_deserializer_decoder **_decoder) +{ + struct dsync_deserializer_decoder *decoder = *_decoder; + + *_decoder = NULL; + + pool_unref(&decoder->pool); +} |