From 0ed80c3f6e4373e23e12bec23b11c1e9f209cdbc Mon Sep 17 00:00:00 2001 From: Al Date: Sat, 20 Jun 2015 12:00:15 -0500 Subject: [PATCH] [geonames] Geonames generic serialization/deserialization --- src/geonames.c | 438 ++++++++++++++++++++++++++++++------------------- src/geonames.h | 13 +- 2 files changed, 279 insertions(+), 172 deletions(-) diff --git a/src/geonames.c b/src/geonames.c index 9a205232..49bca37f 100644 --- a/src/geonames.c +++ b/src/geonames.c @@ -17,6 +17,9 @@ #define GEONAMES_POSTAL_ADMIN2_IDS_DEFAULT_LENGTH 20 #define GEONAMES_POSTAL_ADMIN3_IDS_DEFAULT_LENGTH 20 +#define PLACE_NAME_FEATURES_DEFAULT_LENGTH 255 +#define GEO_FEATURES_DEFAULT_LENGTH 243 + /* To save on malloc calls, create just one of these and call geoname_clear * (which does not deallocate) and geoname_deserialize */ @@ -53,32 +56,41 @@ void geoname_destroy(geoname_t *self) { if (!self) return; - if (self->name) + if (self->name) { char_array_destroy(self->name); + } - if (self->canonical) + if (self->canonical) { char_array_destroy(self->canonical); + } - if (self->iso_language) + if (self->iso_language) { char_array_destroy(self->iso_language); + } - if (self->feature_code) + if (self->feature_code) { char_array_destroy(self->feature_code); + } - if (self->country_code) + if (self->country_code) { char_array_destroy(self->country_code); + } - if (self->admin1_code) + if (self->admin1_code) { char_array_destroy(self->admin1_code); + } - if (self->admin2_code) + if (self->admin2_code) { char_array_destroy(self->admin2_code); + } - if (self->admin3_code) + if (self->admin3_code) { char_array_destroy(self->admin3_code); + } - if (self->admin4_code) + if (self->admin4_code) { char_array_destroy(self->admin4_code); + } free(self); } @@ -92,8 +104,9 @@ static char_array *read_string(char_array *str, size_t len, buffer_t *buffer) { static bool bytes_reader(cmp_ctx_t *ctx, void *data, size_t size) { buffer_t *buffer = ctx->buf; - if (buffer->offset + size > char_array_len(buffer->data)) + if (buffer->offset + size > char_array_len(buffer->data)) { return false; + } memcpy(data, buffer->data->a + buffer->offset, size); buffer->offset += size; return true; @@ -109,8 +122,9 @@ static size_t bytes_writer(cmp_ctx_t *ctx, const void *data, size_t count) { bool cmp_read_str_size_or_nil(cmp_ctx_t *ctx, char_array **str, uint32_t *size) { cmp_object_t obj; - if (!cmp_read_object(ctx, &obj)) + if (!cmp_read_object(ctx, &obj)) { return false; + } if (cmp_object_is_str(&obj)) { *size = obj.as.str_size; @@ -133,79 +147,131 @@ bool cmp_write_str_or_nil(cmp_ctx_t *ctx, char_array *str) { bool cmp_write_uint_vector(cmp_ctx_t *ctx, uint32_array *array) { size_t n = array->n; - if (!cmp_write_array(ctx, n)) + if (!cmp_write_array(ctx, n)) { return false; + } for (size_t i = 0; i < n; i++) { - if (!cmp_write_uint(ctx, array->a[i])) + if (!cmp_write_uint(ctx, array->a[i])) { return false; + } } return true; } +bool geoname_deserialize_ctx(geoname_t *self, cmp_ctx_t *ctx) { + + uint32_t len; + + if (!cmp_read_uint(ctx, &self->geonames_id)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->name, &len)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->canonical, &len)) { + return false; + } + + if (!cmp_read_uint(ctx, &self->type)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->iso_language, &len)) { + return false; + } + + if (!cmp_read_bool(ctx, &self->is_preferred_name)) { + return false; + } + + if (!cmp_read_uint(ctx, &self->population)) { + return false; + } + + if (!cmp_read_double(ctx, &self->latitude)) { + return false; + } + + if (!cmp_read_double(ctx, &self->longitude)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->feature_code, &len)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->country_code, &len)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->admin1_code, &len)) { + return false; + } + + if (!cmp_read_uint(ctx, &self->admin1_geonames_id)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->admin2_code, &len)) { + return false; + } + + if (!cmp_read_uint(ctx, &self->admin2_geonames_id)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->admin3_code, &len)) { + return false; + } + + if (!cmp_read_uint(ctx, &self->admin3_geonames_id)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->admin4_code, &len)) { + return false; + } + + if (!cmp_read_uint(ctx, &self->admin4_geonames_id)) { + return false; + } + + return true; +} + bool geoname_deserialize(geoname_t *self, char_array *str) { cmp_ctx_t ctx; buffer_t buffer = (buffer_t){str, 0}; cmp_init(&ctx, &buffer, bytes_reader, bytes_writer); - uint32_t len; + return geoname_deserialize_ctx(self, &ctx); +} - if (!cmp_read_uint(&ctx, &self->geonames_id)) - return false; +bool geoname_serialize_ctx(geoname_t *self, cmp_ctx_t *ctx) { - if (!cmp_read_str_size_or_nil(&ctx, &self->name, &len)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->canonical, &len)) - return false; - - if (!cmp_read_uint(&ctx, &self->type)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->iso_language, &len)) - return false; - - if (!cmp_read_bool(&ctx, &self->is_preferred_name)) - return false; - - if (!cmp_read_uint(&ctx, &self->population)) - return false; - - if (!cmp_read_double(&ctx, &self->latitude)) - return false; - - if (!cmp_read_double(&ctx, &self->longitude)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->feature_code, &len)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->country_code, &len)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->admin1_code, &len)) - return false; - - if (!cmp_read_uint(&ctx, &self->admin1_geonames_id)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->admin2_code, &len)) - return false; - - if (!cmp_read_uint(&ctx, &self->admin2_geonames_id)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->admin3_code, &len)) - return false; - - if (!cmp_read_uint(&ctx, &self->admin3_geonames_id)) - return false; - - if (!cmp_read_str_size_or_nil(&ctx, &self->admin4_code, &len)) - return false; - - if (!cmp_read_uint(&ctx, &self->admin4_geonames_id)) - return false; + if (!cmp_write_uint(ctx, self->geonames_id) || + !cmp_write_str_or_nil(ctx, self->name) || + !cmp_write_str_or_nil(ctx, self->canonical) || + !cmp_write_uint(ctx, self->type) || + !cmp_write_str_or_nil(ctx, self->iso_language) || + !cmp_write_bool(ctx, self->is_preferred_name) || + !cmp_write_uint(ctx, self->population) || + !cmp_write_double(ctx, self->latitude) || + !cmp_write_double(ctx, self->longitude) || + !cmp_write_str_or_nil(ctx, self->feature_code) || + !cmp_write_str_or_nil(ctx, self->country_code) || + !cmp_write_str_or_nil(ctx, self->admin1_code) || + !cmp_write_uint(ctx, self->admin1_geonames_id) || + !cmp_write_str_or_nil(ctx, self->admin2_code) || + !cmp_write_uint(ctx, self->admin2_geonames_id) || + !cmp_write_str_or_nil(ctx, self->admin3_code) || + !cmp_write_uint(ctx, self->admin3_geonames_id) || + !cmp_write_str_or_nil(ctx, self->admin4_code) || + !cmp_write_uint(ctx, self->admin4_geonames_id) + ) { return false; } return true; } @@ -214,29 +280,8 @@ bool geoname_serialize(geoname_t *self, char_array *str) { cmp_ctx_t ctx; buffer_t buffer = (buffer_t){str, 0}; cmp_init(&ctx, &buffer, bytes_reader, bytes_writer); - - if (!cmp_write_uint(&ctx, self->geonames_id) || - !cmp_write_str_or_nil(&ctx, self->name) || - !cmp_write_str_or_nil(&ctx, self->canonical) || - !cmp_write_uint(&ctx, self->type) || - !cmp_write_str_or_nil(&ctx, self->iso_language) || - !cmp_write_bool(&ctx, self->is_preferred_name) || - !cmp_write_uint(&ctx, self->population) || - !cmp_write_double(&ctx, self->latitude) || - !cmp_write_double(&ctx, self->longitude) || - !cmp_write_str_or_nil(&ctx, self->feature_code) || - !cmp_write_str_or_nil(&ctx, self->country_code) || - !cmp_write_str_or_nil(&ctx, self->admin1_code) || - !cmp_write_uint(&ctx, self->admin1_geonames_id) || - !cmp_write_str_or_nil(&ctx, self->admin2_code) || - !cmp_write_uint(&ctx, self->admin2_geonames_id) || - !cmp_write_str_or_nil(&ctx, self->admin3_code) || - !cmp_write_uint(&ctx, self->admin3_geonames_id) || - !cmp_write_str_or_nil(&ctx, self->admin4_code) || - !cmp_write_uint(&ctx, self->admin4_geonames_id) - ) { return false; } - - return true; + + return geoname_serialize_ctx(self, &ctx); } void geoname_print(geoname_t *self) { @@ -287,88 +332,125 @@ void gn_postal_code_destroy(gn_postal_code_t *self) { if (!self) return; - if (self->postal_code) + if (self->postal_code) { char_array_destroy(self->postal_code); + } - if (self->country_code) + if (self->country_code) { char_array_destroy(self->country_code); + } - if (self->containing_geoname) + if (self->containing_geoname) { char_array_destroy(self->containing_geoname); + } - if (self->admin1_ids) + if (self->admin1_ids) { uint32_array_destroy(self->admin1_ids); + } - if (self->admin2_ids) + if (self->admin2_ids) { uint32_array_destroy(self->admin2_ids); + } - if (self->admin3_ids) + if (self->admin3_ids) { uint32_array_destroy(self->admin3_ids); + } free(self); } +bool gn_postal_code_deserialize_ctx(gn_postal_code_t *self, cmp_ctx_t *ctx) { + uint32_t len; + + if (!cmp_read_str_size_or_nil(ctx, &self->postal_code, &len)) { + return false; + } + + if (!cmp_read_str_size_or_nil(ctx, &self->country_code, &len)) { + return false; + } + + if (!cmp_read_bool(ctx, &self->have_containing_geoname)) { + return false; + } + + if (self->have_containing_geoname) { + if (!cmp_read_str_size_or_nil(ctx, &self->containing_geoname, &len)) + return false; + + if (!cmp_read_uint(ctx, &self->containing_geonames_id)) + return false; + } + + uint32_t array_size; + + if (!cmp_read_array(ctx, &array_size)) { + return false; + } + + if (array_size > 0) { + uint32_t admin1_id; + for ( ;array_size; array_size--) { + if (!cmp_read_uint(ctx, &admin1_id)) { + return false; + } + uint32_array_push(self->admin1_ids, admin1_id); + } + } + + if (!cmp_read_array(ctx, &array_size)) { + return false; + } + + if (array_size > 0) { + uint32_t admin2_id; + for (; array_size > 0; array_size--) { + if (!cmp_read_uint(ctx, &admin2_id)) { + return false; + } + uint32_array_push(self->admin2_ids, admin2_id); + } + } + + if (!cmp_read_array(ctx, &array_size)) { + return false; + } + + if (array_size > 0) { + uint32_t admin3_id; + for (; array_size > 0; array_size--) { + if (!cmp_read_uint(ctx, &admin3_id)) { + return false; + } + uint32_array_push(self->admin3_ids, admin3_id); + } + } + + return true; +} + bool gn_postal_code_deserialize(gn_postal_code_t *self, char_array *str) { cmp_ctx_t ctx; buffer_t buffer = (buffer_t){str, 0}; cmp_init(&ctx, &buffer, bytes_reader, bytes_writer); - uint32_t len; + return gn_postal_code_deserialize_ctx(self, &ctx); +} - if (!cmp_read_str_size_or_nil(&ctx, &self->postal_code, &len)) - return false; +static bool gn_postal_code_serialize_ctx(gn_postal_code_t *self, cmp_ctx_t *ctx) { - if (!cmp_read_str_size_or_nil(&ctx, &self->country_code, &len)) - return false; - - if (!cmp_read_bool(&ctx, &self->have_containing_geoname)) - return false; - - if (self->have_containing_geoname) { - if (!cmp_read_str_size_or_nil(&ctx, &self->containing_geoname, &len)) - return false; - - if (!cmp_read_uint(&ctx, &self->containing_geonames_id)) - return false; - } - - uint32_t array_size; - - if (!cmp_read_array(&ctx, &array_size)) - return false; - - if (array_size > 0) { - uint32_t admin1_id; - for ( ;array_size; array_size--) { - if (!cmp_read_uint(&ctx, &admin1_id)) - return false; - uint32_array_push(self->admin1_ids, admin1_id); - } - } - - if (!cmp_read_array(&ctx, &array_size)) - return false; - - if (array_size > 0) { - uint32_t admin2_id; - for (; array_size > 0; array_size--) { - if (!cmp_read_uint(&ctx, &admin2_id)) - return false; - uint32_array_push(self->admin2_ids, admin2_id); - } - } - - if (!cmp_read_array(&ctx, &array_size)) - return false; - - if (array_size > 0) { - uint32_t admin3_id; - for (; array_size > 0; array_size--) { - if (!cmp_read_uint(&ctx, &admin3_id)) - return false; - uint32_array_push(self->admin3_ids, admin3_id); - } - } + if (!cmp_write_str_or_nil(ctx, self->postal_code) || + !cmp_write_str_or_nil(ctx, self->country_code) || + !cmp_write_bool(ctx, self->have_containing_geoname) || + (self->have_containing_geoname && + (!cmp_write_str_or_nil(ctx, self->containing_geoname) || + !cmp_write_uint(ctx, self->containing_geonames_id) + ) + ) || + !cmp_write_uint_vector(ctx, self->admin1_ids) || + !cmp_write_uint_vector(ctx, self->admin2_ids) || + !cmp_write_uint_vector(ctx, self->admin3_ids) + ) { return false; } return true; } @@ -378,20 +460,8 @@ bool gn_postal_code_serialize(gn_postal_code_t *self, char_array *str) { buffer_t buffer = (buffer_t){str, 0}; cmp_init(&ctx, &buffer, bytes_reader, bytes_writer); - if (!cmp_write_str_or_nil(&ctx, self->postal_code) || - !cmp_write_str_or_nil(&ctx, self->country_code) || - !cmp_write_bool(&ctx, self->have_containing_geoname) || - (self->have_containing_geoname && - (!cmp_write_str_or_nil(&ctx, self->containing_geoname) || - !cmp_write_uint(&ctx, self->containing_geonames_id) - ) - ) || - !cmp_write_uint_vector(&ctx, self->admin1_ids) || - !cmp_write_uint_vector(&ctx, self->admin2_ids) || - !cmp_write_uint_vector(&ctx, self->admin3_ids) - ) { return false; } + return gn_postal_code_serialize_ctx(self, &ctx); - return true; } void gn_postal_code_print(gn_postal_code_t *self) { @@ -421,10 +491,44 @@ void gn_postal_code_print(gn_postal_code_t *self) { } -void geonames_generic_serialize(geonames_generic_t gn) { +bool geonames_generic_serialize(geonames_generic_t *gn, char_array *str) { + cmp_ctx_t ctx; + buffer_t buffer = (buffer_t){str, 0}; + cmp_init(&ctx, &buffer, bytes_reader, bytes_writer); + if (!cmp_write_u8(&ctx, (uint8_t)gn->type)) { + return false; + } + + if (gn->type == GEONAMES_NAME) { + return geoname_serialize_ctx(gn->geoname, &ctx); + } else if (gn->type == GEONAMES_POSTAL_CODE) { + return gn_postal_code_serialize_ctx(gn->postal_code, &ctx); + } + + return false; } -geonames_generic_t *geonames_generic_deserialize(geonames_generic_t gn) { +bool geonames_generic_deserialize(gn_type *type, geoname_t *geoname, gn_postal_code_t *postal_code, char_array *str) { + cmp_ctx_t ctx; + buffer_t buffer = (buffer_t){str, 0}; + cmp_init(&ctx, &buffer, bytes_reader, bytes_writer); + + uint8_t geonames_type; + + if (!cmp_read_u8(&ctx, &geonames_type)) { + return false; + } + + *type = geonames_type; + + if (geonames_type == GEONAMES_NAME) { + return geoname_deserialize_ctx(geoname, &ctx); + } else if (geonames_type == GEONAMES_POSTAL_CODE) { + return gn_postal_code_deserialize_ctx(postal_code, &ctx); + } + + + return false; } diff --git a/src/geonames.h b/src/geonames.h index 271aad68..a62f748a 100644 --- a/src/geonames.h +++ b/src/geonames.h @@ -87,20 +87,23 @@ void gn_postal_code_print(gn_postal_code_t *self); void gn_postal_code_clear(gn_postal_code_t *self); void gn_postal_code_destroy(gn_postal_code_t *self); -typedef enum { GEONAME, POSTAL_CODE } gn_type; +typedef enum { + GEONAMES_NAME, + GEONAMES_POSTAL_CODE +} gn_type; typedef struct geonames_generic { gn_type type; union { - geoname_t name; - gn_postal_code_t postal; + geoname_t *geoname; + gn_postal_code_t *postal_code; }; } geonames_generic_t; VECTOR_INIT(gn_generic_array, geonames_generic_t); -void geonames_generic_serialize(geonames_generic_t gn); -geonames_generic_t *geonames_generic_deserialize(geonames_generic_t gn); +bool geonames_generic_serialize(geonames_generic_t *gn, char_array *str); +bool geonames_generic_deserialize(gn_type *type, geoname_t *geoname, gn_postal_code_t *postal_code, char_array *str); #ifdef __cplusplus }