/* 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); }