1 #include "geodb.h"
2
3 static geodb_t *geodb = NULL;
4
get_geodb(void)5 geodb_t *get_geodb(void) {
6 return geodb;
7 }
8
geodb_destroy(geodb_t * self)9 void geodb_destroy(geodb_t *self) {
10 if (self == NULL) return;
11
12 if (self->names != NULL) {
13 trie_destroy(self->names);
14 }
15
16 if (self->features != NULL) {
17 trie_destroy(self->features);
18 }
19
20 if (self->postal_codes != NULL) {
21 cstring_array_destroy(self->postal_codes);
22 }
23
24 if (self->hash_reader != NULL) {
25 sparkey_hash_close(&self->hash_reader);
26 }
27
28 if (self->log_iter != NULL) {
29 sparkey_logiter_close(&self->log_iter);
30 }
31
32 if (self->value_buf != NULL) {
33 char_array_destroy(self->value_buf);
34 }
35
36 if (self->geoname != NULL) {
37 geoname_destroy(self->geoname);
38 }
39
40 if (self->postal_code != NULL) {
41 gn_postal_code_destroy(self->postal_code);
42 }
43
44 free(self);
45 }
46
geodb_init(char * dir)47 geodb_t *geodb_init(char *dir) {
48 if (dir == NULL) return NULL;
49
50 geodb_t *gdb = calloc(1, sizeof(geodb_t));
51
52 if (gdb == NULL) return NULL;
53
54 char_array *path = char_array_new_size(strlen(dir));
55 char_array_cat_joined(path, PATH_SEPARATOR, true, 2, dir, GEODB_NAMES_TRIE_FILENAME);
56
57 char *names_path = char_array_get_string(path);
58
59 gdb->names = trie_load(names_path);
60 if (gdb->names == NULL) {
61 goto exit_geodb_created;
62 }
63
64 char_array_clear(path);
65
66 char_array_cat_joined(path, PATH_SEPARATOR, true, 2, dir, GEODB_FEATURES_TRIE_FILENAME);
67
68 char *features_path = char_array_get_string(path);
69
70 gdb->features = trie_load(features_path);
71 if(gdb->features == NULL) {
72 goto exit_geodb_created;
73 }
74
75 char_array_clear(path);
76
77 char_array_cat_joined(path, PATH_SEPARATOR, true, 2, dir, GEODB_POSTAL_CODES_FILENAME);
78 char *postal_codes_path = char_array_get_string(path);
79
80 FILE *f = fopen(postal_codes_path, "rb");
81
82 uint64_t num_postal_strings = 0;
83 if (!file_read_uint64(f, &num_postal_strings)) {
84 goto exit_geodb_created;
85 }
86
87 uint64_t postal_codes_str_len;
88
89 if (!file_read_uint64(f, &postal_codes_str_len)) {
90 goto exit_geodb_created;
91 }
92
93 char_array *array = char_array_new_size((size_t)postal_codes_str_len);
94
95 if (!file_read_chars(f, array->a, (size_t)postal_codes_str_len)) {
96 goto exit_geodb_created;
97 }
98
99 array->n = (size_t)postal_codes_str_len;
100
101 gdb->postal_codes = cstring_array_from_char_array(array);
102
103 if (cstring_array_num_strings(gdb->postal_codes) != num_postal_strings) {
104 goto exit_geodb_created;
105 }
106
107 fclose(f);
108 char_array_clear(path);
109
110 char_array_cat_joined(path, PATH_SEPARATOR, true, 2, dir, GEODB_HASH_FILENAME);
111
112 char *hash_file_path = strdup(char_array_get_string(path));
113
114 char_array_clear(path);
115
116 char_array_cat_joined(path, PATH_SEPARATOR, true, 2, dir, GEODB_LOG_FILENAME);
117
118 char *log_path = char_array_get_string(path);
119
120 gdb->hash_reader = NULL;
121
122 if ((sparkey_hash_open(&gdb->hash_reader, hash_file_path, log_path)) != SPARKEY_SUCCESS) {
123 free(hash_file_path);
124 char_array_destroy(path);
125 goto exit_geodb_created;
126 }
127
128 free(hash_file_path);
129 char_array_destroy(path);
130
131 gdb->log_iter = NULL;
132
133 if ((sparkey_logiter_create(&gdb->log_iter, sparkey_hash_getreader(gdb->hash_reader))) != SPARKEY_SUCCESS) {
134 goto exit_geodb_created;
135 }
136
137 gdb->value_buf = char_array_new_size(sparkey_logreader_maxvaluelen(sparkey_hash_getreader(gdb->hash_reader)));
138 if (gdb->value_buf == NULL) {
139 goto exit_geodb_created;
140 }
141
142 gdb->geoname = geoname_new();
143 if (gdb->geoname == NULL) {
144 goto exit_geodb_created;
145 }
146
147 gdb->postal_code = gn_postal_code_new();
148 if (gdb->postal_code == NULL) {
149 goto exit_geodb_created;
150 }
151
152 return gdb;
153
154 exit_geodb_created:
155 geodb_destroy(gdb);
156 return NULL;
157 }
158
geodb_load(char * dir)159 bool geodb_load(char *dir) {
160 geodb = geodb_init(dir);
161 return (geodb != NULL);
162 }
163
164
search_geodb_with_phrases(char * str,phrase_array ** phrases)165 bool search_geodb_with_phrases(char *str, phrase_array **phrases) {
166 if (str == NULL) return false;
167
168 return trie_search_with_phrases(geodb->names, str, phrases);
169 }
170
search_geodb(char * str)171 phrase_array *search_geodb(char *str) {
172 phrase_array *phrases = NULL;
173
174 if (!search_geodb_with_phrases(str, &phrases)) {
175 return NULL;
176 }
177
178 return phrases;
179 }
180
181
search_geodb_tokens_with_phrases(char * str,token_array * tokens,phrase_array ** phrases)182 bool search_geodb_tokens_with_phrases(char *str, token_array *tokens, phrase_array **phrases) {
183 if (str == NULL) return false;
184
185 return trie_search_tokens_with_phrases(geodb->names, str, tokens, phrases);
186 }
187
188
search_geodb_tokens(char * str,token_array * tokens)189 phrase_array *search_geodb_tokens(char *str, token_array *tokens) {
190 phrase_array *phrases = NULL;
191
192 if (!search_geodb_tokens_with_phrases(str, tokens, &phrases)) {
193 return NULL;
194 }
195
196 return phrases;
197 }
198
199
geodb_get_len(char * key,size_t len)200 geonames_generic_t *geodb_get_len(char *key, size_t len) {
201 if (geodb == NULL || geodb->hash_reader == NULL || geodb->log_iter == NULL) return NULL;
202 sparkey_returncode ret = sparkey_hash_get(geodb->hash_reader, (uint8_t *)key, len, geodb->log_iter);
203 if (sparkey_logiter_state(geodb->log_iter) == SPARKEY_ITER_ACTIVE) {
204 uint64_t expected_value_len = sparkey_logiter_valuelen(geodb->log_iter);
205 uint64_t actual_value_len;
206 ret = sparkey_logiter_fill_value(geodb->log_iter, sparkey_hash_getreader(geodb->hash_reader), expected_value_len, (uint8_t *)geodb->value_buf->a, &actual_value_len);
207 if (ret == SPARKEY_SUCCESS) {
208 geonames_generic_t *generic = malloc(sizeof(geonames_generic_t));
209 if (geonames_generic_deserialize(&generic->type, geodb->geoname, geodb->postal_code, geodb->value_buf)) {
210 if (generic->type == GEONAMES_PLACE) {
211 generic->geoname = geodb->geoname;
212 } else if (generic->type == GEONAMES_POSTAL_CODE) {
213 generic->postal_code = geodb->postal_code;
214 } else {
215 free(generic);
216 return NULL;
217 }
218 return generic;
219 }
220 }
221 }
222 return NULL;
223 }
224
geodb_get(char * key)225 inline geonames_generic_t *geodb_get(char *key) {
226 return geodb_get_len(key, strlen(key));
227 }
228
229
230
geodb_module_setup(char * dir)231 bool geodb_module_setup(char *dir) {
232 if (geodb == NULL) {
233 return geodb_load(dir == NULL ? LIBPOSTAL_GEODB_DIR : dir);
234 }
235
236 return true;
237 }
238
239
geodb_module_teardown(void)240 void geodb_module_teardown(void) {
241 if (geodb != NULL) {
242 geodb_destroy(geodb);
243 }
244 geodb = NULL;
245 }
246
247