1 #include "geonames.h"
2 #include "msgpack_utils.h"
3
4 #define DEFAULT_BUFFER_SIZE 4096
5
6 #define GEONAMES_NAME_DEFAULT_LENGTH 255
7 #define GEONAMES_ISO_LANGUAGE_DEFAULT_LENGTH 10
8 #define GEONAMES_FEATURE_CODE_DEFAULT_LENGTH 5
9 #define GEONAMES_COUNTRY_CODE_DEFAULT_LENGTH 3
10 #define GEONAMES_ADMIN1_CODE_DEFAULT_LENGTH 32
11 #define GEONAMES_ADMIN2_CODE_DEFAULT_LENGTH 64
12 #define GEONAMES_ADMIN3_CODE_DEFAULT_LENGTH 32
13 #define GEONAMES_ADMIN4_CODE_DEFAULT_LENGTH 32
14 #define GEONAMES_POSTAL_CODE_DEFAULT_LENGTH 64
15
16
17 #define GEONAMES_POSTAL_ADMIN1_IDS_DEFAULT_LENGTH 10
18 #define GEONAMES_POSTAL_ADMIN2_IDS_DEFAULT_LENGTH 20
19 #define GEONAMES_POSTAL_ADMIN3_IDS_DEFAULT_LENGTH 20
20
21 /* To save on malloc calls, create just one of these and call geoname_clear
22 * (which does not deallocate) and geoname_deserialize
23 */
geoname_new(void)24 geoname_t *geoname_new(void) {
25 geoname_t *self = malloc(sizeof(geoname_t));
26 if (self == NULL) {
27 return NULL;
28 }
29
30 self->name = char_array_new_size(GEONAMES_NAME_DEFAULT_LENGTH);
31 self->canonical = char_array_new_size(GEONAMES_NAME_DEFAULT_LENGTH);
32
33 self->iso_language = char_array_new_size(GEONAMES_ISO_LANGUAGE_DEFAULT_LENGTH);
34
35 self->feature_code = char_array_new_size(GEONAMES_FEATURE_CODE_DEFAULT_LENGTH);
36 self->country_code = char_array_new_size(GEONAMES_COUNTRY_CODE_DEFAULT_LENGTH);
37
38 self->admin1_code = char_array_new_size(GEONAMES_ADMIN1_CODE_DEFAULT_LENGTH);
39 self->admin2_code = char_array_new_size(GEONAMES_ADMIN2_CODE_DEFAULT_LENGTH);
40 self->admin3_code = char_array_new_size(GEONAMES_ADMIN3_CODE_DEFAULT_LENGTH);
41 self->admin4_code = char_array_new_size(GEONAMES_ADMIN4_CODE_DEFAULT_LENGTH);
42
43 if (!(self->name && self->canonical && self->iso_language
44 && self->feature_code && self->country_code
45 && self->admin1_code && self->admin2_code
46 && self->admin3_code && self->admin4_code)) {
47 geoname_destroy(self);
48 return NULL;
49 }
50
51 return self;
52 }
53
geoname_clear(geoname_t * self)54 void geoname_clear(geoname_t *self) {
55 char_array_clear(self->name);
56 char_array_clear(self->canonical);
57 char_array_clear(self->iso_language);
58 char_array_clear(self->feature_code);
59 char_array_clear(self->country_code);
60 char_array_clear(self->admin1_code);
61 char_array_clear(self->admin2_code);
62 char_array_clear(self->admin3_code);
63 char_array_clear(self->admin4_code);
64 }
65
geoname_destroy(geoname_t * self)66 void geoname_destroy(geoname_t *self) {
67 if (!self)
68 return;
69
70 if (self->name) {
71 char_array_destroy(self->name);
72 }
73
74 if (self->canonical) {
75 char_array_destroy(self->canonical);
76 }
77
78 if (self->iso_language) {
79 char_array_destroy(self->iso_language);
80 }
81
82 if (self->feature_code) {
83 char_array_destroy(self->feature_code);
84 }
85
86 if (self->country_code) {
87 char_array_destroy(self->country_code);
88 }
89
90 if (self->admin1_code) {
91 char_array_destroy(self->admin1_code);
92 }
93
94 if (self->admin2_code) {
95 char_array_destroy(self->admin2_code);
96 }
97
98 if (self->admin3_code) {
99 char_array_destroy(self->admin3_code);
100 }
101
102 if (self->admin4_code) {
103 char_array_destroy(self->admin4_code);
104 }
105
106 free(self);
107 }
108
geoname_deserialize_ctx(geoname_t * self,cmp_ctx_t * ctx)109 bool geoname_deserialize_ctx(geoname_t *self, cmp_ctx_t *ctx) {
110
111 uint32_t len;
112
113 if (!cmp_read_uint(ctx, &self->geonames_id)) {
114 return false;
115 }
116
117 if (!cmp_read_str_size_or_nil(ctx, &self->name, &len)) {
118 return false;
119 }
120
121 if (!cmp_read_str_size_or_nil(ctx, &self->canonical, &len)) {
122 return false;
123 }
124
125 if (!cmp_read_uint(ctx, &self->type)) {
126 return false;
127 }
128
129 if (!cmp_read_str_size_or_nil(ctx, &self->iso_language, &len)) {
130 return false;
131 }
132
133 if (!cmp_read_bool(ctx, &self->has_wikipedia_entry)) {
134 return false;
135 }
136
137 if (!cmp_read_bool(ctx, &self->is_preferred_name)) {
138 return false;
139 }
140
141 if (!cmp_read_bool(ctx, &self->is_short_name)) {
142 return false;
143 }
144
145 if (!cmp_read_bool(ctx, &self->is_colloquial)) {
146 return false;
147 }
148
149 if (!cmp_read_bool(ctx, &self->is_historical)) {
150 return false;
151 }
152
153 if (!cmp_read_uint(ctx, &self->population)) {
154 return false;
155 }
156
157 if (!cmp_read_double(ctx, &self->latitude)) {
158 return false;
159 }
160
161 if (!cmp_read_double(ctx, &self->longitude)) {
162 return false;
163 }
164
165 if (!cmp_read_str_size_or_nil(ctx, &self->feature_code, &len)) {
166 return false;
167 }
168
169 if (!cmp_read_str_size_or_nil(ctx, &self->country_code, &len)) {
170 return false;
171 }
172
173 if (!cmp_read_uint(ctx, &self->country_geonames_id)) {
174 return false;
175 }
176
177 if (!cmp_read_str_size_or_nil(ctx, &self->admin1_code, &len)) {
178 return false;
179 }
180
181 if (!cmp_read_uint(ctx, &self->admin1_geonames_id)) {
182 return false;
183 }
184
185 if (!cmp_read_str_size_or_nil(ctx, &self->admin2_code, &len)) {
186 return false;
187 }
188
189 if (!cmp_read_uint(ctx, &self->admin2_geonames_id)) {
190 return false;
191 }
192
193 if (!cmp_read_str_size_or_nil(ctx, &self->admin3_code, &len)) {
194 return false;
195 }
196
197 if (!cmp_read_uint(ctx, &self->admin3_geonames_id)) {
198 return false;
199 }
200
201 if (!cmp_read_str_size_or_nil(ctx, &self->admin4_code, &len)) {
202 return false;
203 }
204
205 if (!cmp_read_uint(ctx, &self->admin4_geonames_id)) {
206 return false;
207 }
208
209 return true;
210 }
211
geoname_deserialize(geoname_t * self,char_array * str)212 bool geoname_deserialize(geoname_t *self, char_array *str) {
213 cmp_ctx_t ctx;
214 msgpack_buffer_t buffer = (msgpack_buffer_t){str, 0};
215 cmp_init(&ctx, &buffer, msgpack_bytes_reader, msgpack_bytes_writer);
216
217 return geoname_deserialize_ctx(self, &ctx);
218 }
219
geoname_serialize_ctx(geoname_t * self,cmp_ctx_t * ctx)220 bool geoname_serialize_ctx(geoname_t *self, cmp_ctx_t *ctx) {
221
222 if (!cmp_write_uint(ctx, self->geonames_id) ||
223 !cmp_write_str_or_nil(ctx, self->name) ||
224 !cmp_write_str_or_nil(ctx, self->canonical) ||
225 !cmp_write_uint(ctx, self->type) ||
226 !cmp_write_str_or_nil(ctx, self->iso_language) ||
227 !cmp_write_bool(ctx, self->has_wikipedia_entry) ||
228 !cmp_write_bool(ctx, self->is_preferred_name) ||
229 !cmp_write_bool(ctx, self->is_short_name) ||
230 !cmp_write_bool(ctx, self->is_colloquial) ||
231 !cmp_write_bool(ctx, self->is_historical) ||
232 !cmp_write_uint(ctx, self->population) ||
233 !cmp_write_double(ctx, self->latitude) ||
234 !cmp_write_double(ctx, self->longitude) ||
235 !cmp_write_str_or_nil(ctx, self->feature_code) ||
236 !cmp_write_str_or_nil(ctx, self->country_code) ||
237 !cmp_write_uint(ctx, self->country_geonames_id) ||
238 !cmp_write_str_or_nil(ctx, self->admin1_code) ||
239 !cmp_write_uint(ctx, self->admin1_geonames_id) ||
240 !cmp_write_str_or_nil(ctx, self->admin2_code) ||
241 !cmp_write_uint(ctx, self->admin2_geonames_id) ||
242 !cmp_write_str_or_nil(ctx, self->admin3_code) ||
243 !cmp_write_uint(ctx, self->admin3_geonames_id) ||
244 !cmp_write_str_or_nil(ctx, self->admin4_code) ||
245 !cmp_write_uint(ctx, self->admin4_geonames_id)
246 ) { return false; }
247
248 return true;
249 }
250
geoname_serialize(geoname_t * self,char_array * str)251 bool geoname_serialize(geoname_t *self, char_array *str) {
252 cmp_ctx_t ctx;
253 msgpack_buffer_t buffer = (msgpack_buffer_t){str, 0};
254 cmp_init(&ctx, &buffer, msgpack_bytes_reader, msgpack_bytes_writer);
255
256 return geoname_serialize_ctx(self, &ctx);
257 }
258
geoname_print(geoname_t * self)259 void geoname_print(geoname_t *self) {
260 printf("geonames_id: %d\n", self->geonames_id);
261 printf("name: %s\n", char_array_get_string(self->name));
262 printf("canonical: %s\n", char_array_get_string(self->canonical));
263 printf("type: %d\n", self->type);
264 printf("iso_language: %s\n", char_array_get_string(self->iso_language));
265 printf("has_wikipedia_entry: %d\n", self->has_wikipedia_entry);
266 printf("is_preferred: %d\n", self->is_preferred_name);
267 printf("is_short_name: %d\n", self->is_short_name);
268 printf("is_colloquial: %d\n", self->is_colloquial);
269 printf("is_historical: %d\n", self->is_historical);
270 printf("population: %d\n", self->population);
271 printf("latitude: %f\n", self->latitude);
272 printf("longitude: %f\n", self->longitude);
273 printf("feature_code: %s\n", char_array_get_string(self->feature_code));
274 printf("country_code: %s\n", char_array_get_string(self->country_code));
275 printf("country_geonames_id: %d\n", self->country_geonames_id);
276 printf("admin1_code: %s\n", char_array_get_string(self->admin1_code));
277 printf("admin1_geonames_id: %d\n", self->admin1_geonames_id);
278 printf("admin2_code: %s\n", char_array_get_string(self->admin2_code));
279 printf("admin2_geonames_id: %d\n", self->admin2_geonames_id);
280 printf("admin3_code: %s\n", char_array_get_string(self->admin3_code));
281 printf("admin3_geonames_id: %d\n", self->admin3_geonames_id);
282 printf("admin4_code: %s\n", char_array_get_string(self->admin4_code));
283 printf("admin4_geonames_id: %d\n", self->admin4_geonames_id);
284 }
285
gn_postal_code_new(void)286 gn_postal_code_t *gn_postal_code_new(void) {
287 gn_postal_code_t *self = malloc(sizeof(gn_postal_code_t));
288 if (self == NULL) {
289 return NULL;
290 }
291
292 self->postal_code = char_array_new_size(GEONAMES_POSTAL_CODE_DEFAULT_LENGTH);
293 self->country_code = char_array_new_size(GEONAMES_COUNTRY_CODE_DEFAULT_LENGTH);
294 self->containing_geoname = char_array_new_size(GEONAMES_NAME_DEFAULT_LENGTH);
295
296 self->have_lat_lon = false;
297 self->have_containing_geoname = false;
298
299 self->admin1_ids = uint32_array_new_size(GEONAMES_POSTAL_ADMIN1_IDS_DEFAULT_LENGTH);
300 self->admin2_ids = uint32_array_new_size(GEONAMES_POSTAL_ADMIN2_IDS_DEFAULT_LENGTH);
301 self->admin3_ids = uint32_array_new_size(GEONAMES_POSTAL_ADMIN3_IDS_DEFAULT_LENGTH);
302
303 if (!(self->postal_code && self->country_code && self->containing_geoname
304 && self->admin1_ids && self->admin2_ids && self->admin3_ids)) {
305 gn_postal_code_destroy(self);
306 return NULL;
307 }
308
309 return self;
310 }
311
gn_postal_code_clear(gn_postal_code_t * self)312 void gn_postal_code_clear(gn_postal_code_t *self) {
313 char_array_clear(self->postal_code);
314 char_array_clear(self->country_code);
315 char_array_clear(self->containing_geoname);
316 uint32_array_clear(self->admin1_ids);
317 uint32_array_clear(self->admin2_ids);
318 uint32_array_clear(self->admin3_ids);
319 }
320
gn_postal_code_destroy(gn_postal_code_t * self)321 void gn_postal_code_destroy(gn_postal_code_t *self) {
322 if (!self)
323 return;
324
325 if (self->postal_code) {
326 char_array_destroy(self->postal_code);
327 }
328
329 if (self->country_code) {
330 char_array_destroy(self->country_code);
331 }
332
333 if (self->containing_geoname) {
334 char_array_destroy(self->containing_geoname);
335 }
336
337 if (self->admin1_ids) {
338 uint32_array_destroy(self->admin1_ids);
339 }
340
341 if (self->admin2_ids) {
342 uint32_array_destroy(self->admin2_ids);
343 }
344
345 if (self->admin3_ids) {
346 uint32_array_destroy(self->admin3_ids);
347 }
348
349 free(self);
350 }
351
gn_postal_code_deserialize_ctx(gn_postal_code_t * self,cmp_ctx_t * ctx)352 bool gn_postal_code_deserialize_ctx(gn_postal_code_t *self, cmp_ctx_t *ctx) {
353 uint32_t len;
354
355 if (!cmp_read_str_size_or_nil(ctx, &self->postal_code, &len)) {
356 return false;
357 }
358
359 if (!cmp_read_str_size_or_nil(ctx, &self->country_code, &len)) {
360 return false;
361 }
362
363 if (!cmp_read_uint(ctx, &self->country_geonames_id)) {
364 return false;
365 }
366
367 if (!cmp_read_bool(ctx, &self->have_containing_geoname)) {
368 return false;
369 }
370
371 if (self->have_containing_geoname) {
372 if (!cmp_read_str_size_or_nil(ctx, &self->containing_geoname, &len))
373 return false;
374
375 if (!cmp_read_uint(ctx, &self->containing_geonames_id))
376 return false;
377 }
378
379 uint32_t array_size;
380
381 if (!cmp_read_array(ctx, &array_size)) {
382 return false;
383 }
384
385 if (array_size > 0) {
386 uint32_t admin1_id;
387 for ( ;array_size; array_size--) {
388 if (!cmp_read_uint(ctx, &admin1_id)) {
389 return false;
390 }
391 uint32_array_push(self->admin1_ids, admin1_id);
392 }
393 }
394
395 if (!cmp_read_array(ctx, &array_size)) {
396 return false;
397 }
398
399 if (array_size > 0) {
400 uint32_t admin2_id;
401 for (; array_size > 0; array_size--) {
402 if (!cmp_read_uint(ctx, &admin2_id)) {
403 return false;
404 }
405 uint32_array_push(self->admin2_ids, admin2_id);
406 }
407 }
408
409 if (!cmp_read_array(ctx, &array_size)) {
410 return false;
411 }
412
413 if (array_size > 0) {
414 uint32_t admin3_id;
415 for (; array_size > 0; array_size--) {
416 if (!cmp_read_uint(ctx, &admin3_id)) {
417 return false;
418 }
419 uint32_array_push(self->admin3_ids, admin3_id);
420 }
421 }
422
423 return true;
424 }
425
gn_postal_code_deserialize(gn_postal_code_t * self,char_array * str)426 bool gn_postal_code_deserialize(gn_postal_code_t *self, char_array *str) {
427 cmp_ctx_t ctx;
428 msgpack_buffer_t buffer = (msgpack_buffer_t){str, 0};
429 cmp_init(&ctx, &buffer, msgpack_bytes_reader, msgpack_bytes_writer);
430
431 return gn_postal_code_deserialize_ctx(self, &ctx);
432 }
433
gn_postal_code_serialize_ctx(gn_postal_code_t * self,cmp_ctx_t * ctx)434 static bool gn_postal_code_serialize_ctx(gn_postal_code_t *self, cmp_ctx_t *ctx) {
435
436 if (!cmp_write_str_or_nil(ctx, self->postal_code) ||
437 !cmp_write_str_or_nil(ctx, self->country_code) ||
438 !cmp_write_uint(ctx, self->country_geonames_id) ||
439 !cmp_write_bool(ctx, self->have_containing_geoname) ||
440 (self->have_containing_geoname &&
441 (!cmp_write_str_or_nil(ctx, self->containing_geoname) ||
442 !cmp_write_uint(ctx, self->containing_geonames_id)
443 )
444 ) ||
445 !cmp_write_uint_vector(ctx, self->admin1_ids) ||
446 !cmp_write_uint_vector(ctx, self->admin2_ids) ||
447 !cmp_write_uint_vector(ctx, self->admin3_ids)
448 ) { return false; }
449
450 return true;
451 }
452
gn_postal_code_serialize(gn_postal_code_t * self,char_array * str)453 bool gn_postal_code_serialize(gn_postal_code_t *self, char_array *str) {
454 cmp_ctx_t ctx;
455 msgpack_buffer_t buffer = (msgpack_buffer_t){str, 0};
456 cmp_init(&ctx, &buffer, msgpack_bytes_reader, msgpack_bytes_writer);
457
458 return gn_postal_code_serialize_ctx(self, &ctx);
459
460 }
461
gn_postal_code_print(gn_postal_code_t * self)462 void gn_postal_code_print(gn_postal_code_t *self) {
463 int i;
464 printf("postal_code: %s\n", char_array_get_string(self->postal_code));
465 printf("country_code: %s\n", char_array_get_string(self->country_code));
466 printf("have_containing_geoname: %d\n", self->have_containing_geoname);
467 if (self->have_containing_geoname) {
468 printf("containing_geoname: %s\n", char_array_get_string(self->containing_geoname));
469 printf("containing_geonames_id: %d\n", self->containing_geonames_id);
470 }
471 printf("admin1_ids: [ ");
472 for (i = 0; i < self->admin1_ids->n; i++) {
473 printf("%d ", self->admin1_ids->a[i]);
474 }
475 printf("]\n");
476 printf("admin2_ids: [ ");
477 for (i = 0; i < self->admin2_ids->n; i++) {
478 printf("%d ", self->admin2_ids->a[i]);
479 }
480 printf("]\n");
481 printf("admin3_ids: [ ");
482 for (i = 0; i < self->admin3_ids->n; i++) {
483 printf("%d ", self->admin3_ids->a[i]);
484 }
485 printf("]\n");
486 }
487
488
geonames_generic_serialize(geonames_generic_t * gn,char_array * str)489 bool geonames_generic_serialize(geonames_generic_t *gn, char_array *str) {
490 cmp_ctx_t ctx;
491 msgpack_buffer_t buffer = (msgpack_buffer_t){str, 0};
492 cmp_init(&ctx, &buffer, msgpack_bytes_reader, msgpack_bytes_writer);
493
494 if (!cmp_write_u8(&ctx, (uint8_t)gn->type)) {
495 return false;
496 }
497
498 if (gn->type == GEONAMES_PLACE) {
499 return geoname_serialize_ctx(gn->geoname, &ctx);
500 } else if (gn->type == GEONAMES_POSTAL_CODE) {
501 return gn_postal_code_serialize_ctx(gn->postal_code, &ctx);
502 }
503
504 return false;
505 }
506
geonames_generic_deserialize(gn_type * type,geoname_t * geoname,gn_postal_code_t * postal_code,char_array * str)507 bool geonames_generic_deserialize(gn_type *type, geoname_t *geoname, gn_postal_code_t *postal_code, char_array *str) {
508 cmp_ctx_t ctx;
509 msgpack_buffer_t buffer = (msgpack_buffer_t){str, 0};
510 cmp_init(&ctx, &buffer, msgpack_bytes_reader, msgpack_bytes_writer);
511
512 uint8_t geonames_type;
513
514 if (!cmp_read_u8(&ctx, &geonames_type)) {
515 return false;
516 }
517
518 *type = geonames_type;
519
520 if (geonames_type == GEONAMES_PLACE) {
521 return geoname_deserialize_ctx(geoname, &ctx);
522 } else if (geonames_type == GEONAMES_POSTAL_CODE) {
523 return gn_postal_code_deserialize_ctx(postal_code, &ctx);
524 }
525
526
527 return false;
528
529 }
530