#include "internal.h" #include #include #include typedef struct { const char *name; size_t offset; } address_field_t; static const address_field_t ADDRESS_FIELDS[] = { {"cep", offsetof(cepis_address_t, cep)}, {"logradouro", offsetof(cepis_address_t, logradouro)}, {"complemento", offsetof(cepis_address_t, complemento)}, {"unidade", offsetof(cepis_address_t, unidade)}, {"bairro", offsetof(cepis_address_t, bairro)}, {"localidade", offsetof(cepis_address_t, localidade)}, {"uf", offsetof(cepis_address_t, uf)}, {"estado", offsetof(cepis_address_t, estado)}, {"regiao", offsetof(cepis_address_t, regiao)}, {"ibge", offsetof(cepis_address_t, ibge)}, {"gia", offsetof(cepis_address_t, gia)}, {"ddd", offsetof(cepis_address_t, ddd)}, {"siafi", offsetof(cepis_address_t, siafi)}, }; #define ADDRESS_FIELD_COUNT (sizeof(ADDRESS_FIELDS) / sizeof(ADDRESS_FIELDS[0])) static char **field_slot(cepis_address_t *address, size_t index) { return (char **)((char *)address + ADDRESS_FIELDS[index].offset); } static cepis_address_t *address_new(void) { cepis_address_t *address = calloc(1, sizeof(*address)); size_t i; if (address == NULL) return NULL; for (i = 0; i < ADDRESS_FIELD_COUNT; i++) { char **slot = field_slot(address, i); *slot = cepis_strdup(""); if (*slot == NULL) { cepis_address_free(address); return NULL; } } return address; } static bool set_field(cepis_address_t *address, size_t index, const char *value) { char **slot = field_slot(address, index); char *copy = cepis_strdup(value); if (copy == NULL) return false; free(*slot); *slot = copy; return true; } void cepis_address_free(cepis_address_t *address) { size_t i; if (address == NULL) return; for (i = 0; i < ADDRESS_FIELD_COUNT; i++) free(*field_slot(address, i)); if (address->geo != NULL) { free(address->geo->precisao); free(address->geo); } free(address->raw); free(address); } void cepis_address_list_free(cepis_address_list_t *list) { size_t i; if (list == NULL) return; for (i = 0; i < list->count; i++) cepis_address_free(list->items[i]); free(list->items); list->items = NULL; list->count = 0; } void cepis_health_free(cepis_health_t *health) { if (health == NULL) return; free(health->status); free(health->dne); free(health->base_gerada_em); free(health); } bool cepis_geo_is_precise(const cepis_geo_t *geo) { return geo != NULL && geo->precisao != NULL && strcmp(geo->precisao, "logradouro") == 0; } bool cepis_health_ok(const cepis_health_t *health) { return health != NULL && health->status != NULL && strcmp(health->status, "ok") == 0; } static cepis_geo_t *geo_from_json(const json_value_t *block) { const char *precisao; cepis_geo_t *geo; double lat; double lon; long long raio; if (block == NULL || block->type != JSON_OBJECT) return NULL; if (!json_as_double(json_object_get(block, "lat"), &lat)) return NULL; if (!json_as_double(json_object_get(block, "lon"), &lon)) return NULL; if (!json_as_llong(json_object_get(block, "raio_m"), &raio)) return NULL; precisao = json_as_string(json_object_get(block, "precisao")); if (precisao == NULL) return NULL; geo = calloc(1, sizeof(*geo)); if (geo == NULL) return NULL; geo->lat = lat; geo->lon = lon; geo->raio_m = (long)raio; geo->precisao = cepis_strdup(precisao); if (geo->precisao == NULL) { free(geo); return NULL; } return geo; } cepis_address_t *cepis_address_from_json(const json_value_t *object, const char *raw, size_t raw_len) { cepis_address_t *address; size_t i; if (object == NULL || object->type != JSON_OBJECT) return NULL; address = address_new(); if (address == NULL) return NULL; for (i = 0; i < ADDRESS_FIELD_COUNT; i++) { const char *value = json_as_string( json_object_get(object, ADDRESS_FIELDS[i].name)); if (value == NULL) continue; if (!set_field(address, i, value)) { cepis_address_free(address); return NULL; } } address->geo = geo_from_json(json_object_get(object, "geo")); if (raw != NULL) { address->raw = malloc(raw_len + 1); if (address->raw == NULL) { cepis_address_free(address); return NULL; } memcpy(address->raw, raw, raw_len); address->raw[raw_len] = '\0'; } return address; } cepis_address_t *cepis_address_from_csv(const csv_row_t *header, const csv_row_t *record) { cepis_address_t *address; size_t column; if (header == NULL || record == NULL) return NULL; address = address_new(); if (address == NULL) return NULL; for (column = 0; column < header->count; column++) { size_t i; if (column >= record->count) break; for (i = 0; i < ADDRESS_FIELD_COUNT; i++) { if (strcmp(header->fields[column], ADDRESS_FIELDS[i].name) != 0) continue; if (!set_field(address, i, record->fields[column])) { cepis_address_free(address); return NULL; } break; } } return address; } cepis_health_t *cepis_health_from_json(const json_value_t *object) { cepis_health_t *health; const char *text; if (object == NULL || object->type != JSON_OBJECT) return NULL; health = calloc(1, sizeof(*health)); if (health == NULL) return NULL; text = json_as_string(json_object_get(object, "status")); health->status = cepis_strdup(text); text = json_as_string(json_object_get(object, "dne")); health->dne = cepis_strdup(text); text = json_as_string(json_object_get(object, "base_gerada_em")); health->base_gerada_em = cepis_strdup(text); if (health->status == NULL || health->dne == NULL || health->base_gerada_em == NULL) { cepis_health_free(health); return NULL; } if (!json_as_llong(json_object_get(object, "ceps"), &health->ceps)) health->ceps = 0; if (!json_as_llong(json_object_get(object, "geo"), &health->geo)) health->geo = 0; return health; }