]> git.ipfire.org Git - location/libloc.git/blame - src/country.c
country: Fix segmentation fault when continent code is not set
[location/libloc.git] / src / country.c
CommitLineData
ec684c1a
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2019 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <loc/libloc.h>
22#include <loc/country.h>
23#include <loc/private.h>
24
25struct loc_country {
26 struct loc_ctx* ctx;
27 int refcount;
28
29 char* code;
30 char* continent_code;
31
32 char* name;
33};
34
35LOC_EXPORT int loc_country_new(struct loc_ctx* ctx, struct loc_country** country, const char* country_code) {
36 struct loc_country* c = calloc(1, sizeof(*c));
37 if (!c)
38 return -ENOMEM;
39
40 c->ctx = loc_ref(ctx);
41 c->refcount = 1;
42
43 c->code = strdup(country_code);
44
45 DEBUG(c->ctx, "Country %s allocated at %p\n", c->code, c);
46 *country = c;
47
48 return 0;
49}
50
51LOC_EXPORT struct loc_country* loc_country_ref(struct loc_country* country) {
52 country->refcount++;
53
54 return country;
55}
56
57static void loc_country_free(struct loc_country* country) {
58 DEBUG(country->ctx, "Releasing country %s %p\n", country->code, country);
59
60 if (country->code)
61 free(country->code);
62
63 if (country->continent_code)
64 free(country->continent_code);
65
66 if (country->name)
67 free(country->name);
68
69 loc_unref(country->ctx);
70 free(country);
71}
72
73LOC_EXPORT struct loc_country* loc_country_unref(struct loc_country* country) {
74 if (--country->refcount > 0)
75 return NULL;
76
77 loc_country_free(country);
78
79 return NULL;
80}
81
82LOC_EXPORT const char* loc_country_get_code(struct loc_country* country) {
83 return country->code;
84}
85
86LOC_EXPORT const char* loc_country_get_continent_code(struct loc_country* country) {
87 return country->continent_code;
88}
89
90LOC_EXPORT int loc_country_set_continent_code(struct loc_country* country, const char* continent_code) {
91 // XXX validate input
92
93 // Free previous value
94 if (country->continent_code)
95 free(country->continent_code);
96
97 country->continent_code = strdup(continent_code);
98
99 return 0;
100}
101
102LOC_EXPORT const char* loc_country_get_name(struct loc_country* country) {
103 return country->name;
104}
105
106LOC_EXPORT int loc_country_set_name(struct loc_country* country, const char* name) {
107 if (country->name)
108 free(country->name);
109
110 if (name)
111 country->name = strdup(name);
112
113 return 0;
114}
115
116int loc_country_cmp(struct loc_country* country1, struct loc_country* country2) {
117 return strcmp(country1->code, country2->code);
118}
119
120int loc_country_new_from_database_v0(struct loc_ctx* ctx, struct loc_stringpool* pool,
121 struct loc_country** country, const struct loc_database_country_v0* dbobj) {
122 char buffer[3];
123
124 // Read country code
a7a3d958 125 loc_country_code_copy(buffer, dbobj->code);
ec684c1a
MT
126
127 // Create a new country object
128 int r = loc_country_new(ctx, country, buffer);
129 if (r)
130 return r;
131
132 // Continent Code
a7a3d958 133 loc_country_code_copy(buffer, dbobj->continent_code);
ec684c1a
MT
134
135 r = loc_country_set_continent_code(*country, buffer);
136 if (r)
137 goto FAIL;
138
139 // Set name
ec684c1a
MT
140 const char* name = loc_stringpool_get(pool, be32toh(dbobj->name));
141 if (name) {
142 r = loc_country_set_name(*country, name);
143 if (r)
144 goto FAIL;
145 }
ec684c1a
MT
146
147 return 0;
148
149FAIL:
150 loc_country_unref(*country);
151 return r;
152}
153
154int loc_country_to_database_v0(struct loc_country* country,
155 struct loc_stringpool* pool, struct loc_database_country_v0* dbobj) {
156 // Add country code
157 for (unsigned int i = 0; i < 2; i++) {
158 dbobj->code[i] = country->code[i] ? country->code[i] : '\0';
159 }
160
161 // Add continent code
d7c9d57b
MT
162 if (country->continent_code) {
163 for (unsigned int i = 0; i < 2; i++) {
164 dbobj->continent_code[i] = country->continent_code[i] ? country->continent_code[i] : '\0';
165 }
ec684c1a
MT
166 }
167
168 // Save the name string in the string pool
169 off_t name = loc_stringpool_add(pool, country->name ? country->name : "");
170 dbobj->name = htobe32(name);
171
172 return 0;
173}