Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 : /*
3 : * lt-grandfathered-db.c
4 : * Copyright (C) 2011-2012 Akira TAGOH
5 : *
6 : * Authors:
7 : * Akira TAGOH <akira@tagoh.org>
8 : *
9 : * You may distribute under the terms of either the GNU
10 : * Lesser General Public License or the Mozilla Public
11 : * License, as specified in the README file.
12 : */
13 : #ifdef HAVE_CONFIG_H
14 : #include "config.h"
15 : #endif
16 :
17 : #include <string.h>
18 : #include <libxml/xpath.h>
19 : #include "lt-error.h"
20 : #include "lt-grandfathered.h"
21 : #include "lt-grandfathered-private.h"
22 : #include "lt-mem.h"
23 : #include "lt-messages.h"
24 : #include "lt-trie.h"
25 : #include "lt-utils.h"
26 : #include "lt-xml.h"
27 : #include "lt-grandfathered-db.h"
28 :
29 :
30 : /**
31 : * SECTION: lt-grandfathered-db
32 : * @Short_Description: An interface to access Grandfathered Database
33 : * @Title: Database - Grandfathered
34 : *
35 : * This class provides an interface to access Grandfathered database.
36 : * which has been registered under RFC 3066 and mostly deprecated.
37 : */
38 : struct _lt_grandfathered_db_t {
39 : lt_mem_t parent;
40 : lt_xml_t *xml;
41 : lt_trie_t *grandfathered_entries;
42 : };
43 :
44 : /*< private >*/
45 : static lt_bool_t
46 4 : lt_grandfathered_db_parse(lt_grandfathered_db_t *grandfathereddb,
47 : lt_error_t **error)
48 : {
49 4 : lt_bool_t retval = TRUE;
50 4 : xmlDocPtr doc = NULL;
51 4 : xmlXPathContextPtr xctxt = NULL;
52 4 : xmlXPathObjectPtr xobj = NULL;
53 4 : lt_error_t *err = NULL;
54 : int i, n;
55 :
56 4 : lt_return_val_if_fail (grandfathereddb != NULL, FALSE);
57 :
58 4 : doc = lt_xml_get_subtag_registry(grandfathereddb->xml);
59 4 : xctxt = xmlXPathNewContext(doc);
60 4 : if (!xctxt) {
61 0 : lt_error_set(&err, LT_ERR_OOM,
62 : "Unable to create an instance of xmlXPathContextPtr.");
63 0 : goto bail;
64 : }
65 4 : xobj = xmlXPathEvalExpression((const xmlChar *)"/registry/grandfathered", xctxt);
66 4 : if (!xobj) {
67 0 : lt_error_set(&err, LT_ERR_FAIL_ON_XML,
68 : "No valid elements for %s",
69 : doc->name);
70 0 : goto bail;
71 : }
72 4 : n = xmlXPathNodeSetGetLength(xobj->nodesetval);
73 :
74 108 : for (i = 0; i < n; i++) {
75 104 : xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
76 : xmlNodePtr cnode;
77 104 : xmlChar *tag = NULL, *desc = NULL, *preferred = NULL;
78 104 : lt_grandfathered_t *le = NULL;
79 : char *s;
80 :
81 104 : if (!ent) {
82 0 : lt_error_set(&err, LT_ERR_FAIL_ON_XML,
83 : "Unable to obtain the xml node via XPath.");
84 0 : goto bail;
85 : }
86 104 : cnode = ent->children;
87 1264 : while (cnode != NULL) {
88 1056 : if (xmlStrcmp(cnode->name, (const xmlChar *)"tag") == 0) {
89 104 : if (tag) {
90 0 : lt_warning("Duplicate tag element in grandfathered: previous value was '%s'",
91 : tag);
92 : } else {
93 104 : tag = xmlNodeGetContent(cnode);
94 : }
95 1800 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"added") == 0 ||
96 1116 : xmlStrcmp(cnode->name, (const xmlChar *)"text") == 0 ||
97 268 : xmlStrcmp(cnode->name, (const xmlChar *)"deprecated") == 0) {
98 : /* ignore it */
99 184 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"description") == 0) {
100 : /* wonder if many descriptions helps something. or is it a bug? */
101 104 : if (!desc)
102 104 : desc = xmlNodeGetContent(cnode);
103 80 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"preferred-value") == 0) {
104 80 : if (preferred) {
105 0 : lt_warning("Duplicate preferred-value element in grandfathered: previous value was '%s'",
106 : preferred);
107 : } else {
108 80 : preferred = xmlNodeGetContent(cnode);
109 : }
110 : } else {
111 0 : lt_warning("Unknown node under /registry/grandfathered: %s", cnode->name);
112 : }
113 1056 : cnode = cnode->next;
114 : }
115 104 : if (!tag) {
116 0 : lt_warning("No tag node: description = '%s', preferred-value = '%s'",
117 : desc, preferred);
118 0 : goto bail1;
119 : }
120 104 : if (!desc) {
121 0 : lt_warning("No description node: tag = '%s', preferred-value = '%s'",
122 : tag, preferred);
123 0 : goto bail1;
124 : }
125 104 : le = lt_grandfathered_create();
126 104 : if (!le) {
127 0 : lt_error_set(&err, LT_ERR_OOM,
128 : "Unable to create an instance of lt_grandfathered_t.");
129 0 : goto bail1;
130 : }
131 104 : lt_grandfathered_set_tag(le, (const char *)tag);
132 104 : lt_grandfathered_set_name(le, (const char *)desc);
133 104 : if (preferred)
134 80 : lt_grandfathered_set_preferred_tag(le, (const char *)preferred);
135 :
136 104 : s = strdup(lt_grandfathered_get_tag(le));
137 104 : lt_trie_replace(grandfathereddb->grandfathered_entries,
138 104 : lt_strlower(s),
139 104 : lt_grandfathered_ref(le),
140 : (lt_destroy_func_t)lt_grandfathered_unref);
141 104 : free(s);
142 : bail1:
143 104 : if (tag)
144 104 : xmlFree(tag);
145 104 : if (desc)
146 104 : xmlFree(desc);
147 104 : if (preferred)
148 80 : xmlFree(preferred);
149 104 : lt_grandfathered_unref(le);
150 : }
151 : bail:
152 4 : if (lt_error_is_set(err, LT_ERR_ANY)) {
153 0 : if (error)
154 0 : *error = lt_error_ref(err);
155 : else
156 0 : lt_error_print(err, LT_ERR_ANY);
157 0 : lt_error_unref(err);
158 0 : retval = FALSE;
159 : }
160 :
161 4 : if (xobj)
162 4 : xmlXPathFreeObject(xobj);
163 4 : if (xctxt)
164 4 : xmlXPathFreeContext(xctxt);
165 :
166 4 : return retval;
167 : }
168 :
169 : /*< public >*/
170 : /**
171 : * lt_grandfathered_db_new:
172 : *
173 : * Create a new instance of a #lt_grandfathered_db_t.
174 : *
175 : * Returns: (transfer full): a new instance of #lt_grandfathered_db_t.
176 : */
177 : lt_grandfathered_db_t *
178 4 : lt_grandfathered_db_new(void)
179 : {
180 4 : lt_grandfathered_db_t *retval = lt_mem_alloc_object(sizeof (lt_grandfathered_db_t));
181 :
182 4 : if (retval) {
183 4 : lt_error_t *err = NULL;
184 :
185 4 : retval->grandfathered_entries = lt_trie_new();
186 4 : lt_mem_add_ref(&retval->parent, retval->grandfathered_entries,
187 : (lt_destroy_func_t)lt_trie_unref);
188 :
189 4 : retval->xml = lt_xml_new();
190 4 : if (!retval->xml) {
191 0 : lt_grandfathered_db_unref(retval);
192 0 : retval = NULL;
193 : goto bail;
194 : }
195 4 : lt_mem_add_ref(&retval->parent, retval->xml,
196 : (lt_destroy_func_t)lt_xml_unref);
197 :
198 4 : lt_grandfathered_db_parse(retval, &err);
199 4 : if (lt_error_is_set(err, LT_ERR_ANY)) {
200 0 : lt_error_print(err, LT_ERR_ANY);
201 0 : lt_grandfathered_db_unref(retval);
202 0 : retval = NULL;
203 0 : lt_error_unref(err);
204 : }
205 : }
206 : bail:
207 :
208 4 : return retval;
209 : }
210 :
211 : /**
212 : * lt_grandfathered_db_ref:
213 : * @grandfathereddb: a #lt_grandfathered_db_t.
214 : *
215 : * Increases the reference count of @grandfathereddb.
216 : *
217 : * Returns: (transfer none): the same @grandfathereddb object.
218 : */
219 : lt_grandfathered_db_t *
220 24 : lt_grandfathered_db_ref(lt_grandfathered_db_t *grandfathereddb)
221 : {
222 24 : lt_return_val_if_fail (grandfathereddb != NULL, NULL);
223 :
224 24 : return lt_mem_ref(&grandfathereddb->parent);
225 : }
226 :
227 : /**
228 : * lt_grandfathered_db_unref:
229 : * @grandfathereddb: a #lt_grandfathered_db_t.
230 : *
231 : * Decreases the reference count of @grandfathereddb. when its reference count
232 : * drops to 0, the object is finalized (i.e. its memory is freed).
233 : */
234 : void
235 28 : lt_grandfathered_db_unref(lt_grandfathered_db_t *grandfathereddb)
236 : {
237 28 : if (grandfathereddb)
238 28 : lt_mem_unref(&grandfathereddb->parent);
239 28 : }
240 :
241 : /**
242 : * lt_grandfathered_db_lookup:
243 : * @grandfathereddb: a #lt_grandfathered_db_t.
244 : * @tag: a tag name to lookup.
245 : *
246 : * Lookup @lt_grandfathered_t if @tag is valid and registered into the database.
247 : *
248 : * Returns: (transfer full): a #lt_grandfathered_t that meets with @tag.
249 : * otherwise %NULL.
250 : */
251 : lt_grandfathered_t *
252 24 : lt_grandfathered_db_lookup(lt_grandfathered_db_t *grandfathereddb,
253 : const char *tag)
254 : {
255 : lt_grandfathered_t *retval;
256 : char *s;
257 :
258 24 : lt_return_val_if_fail (grandfathereddb != NULL, NULL);
259 24 : lt_return_val_if_fail (tag != NULL, NULL);
260 :
261 24 : s = strdup(tag);
262 24 : retval = lt_trie_lookup(grandfathereddb->grandfathered_entries,
263 24 : lt_strlower(s));
264 24 : free(s);
265 24 : if (retval)
266 2 : return lt_grandfathered_ref(retval);
267 :
268 22 : return NULL;
269 : }
|