Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 : /*
3 : * lt-script-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 <stdlib.h>
18 : #include <string.h>
19 : #include <libxml/xpath.h>
20 : #include "lt-error.h"
21 : #include "lt-mem.h"
22 : #include "lt-messages.h"
23 : #include "lt-trie.h"
24 : #include "lt-utils.h"
25 : #include "lt-xml.h"
26 : #include "lt-script-private.h"
27 : #include "lt-script-db.h"
28 :
29 :
30 : /**
31 : * SECTION:lt-script-db
32 : * @Short_Description: An interface to access Script Database
33 : * @Title: Database - Script
34 : *
35 : * This class provides an interface to access Script Database. which has been
36 : * registered as ISO 15924.
37 : */
38 : struct _lt_script_db_t {
39 : lt_mem_t parent;
40 : lt_xml_t *xml;
41 : lt_trie_t *script_entries;
42 : };
43 :
44 : /*< private >*/
45 : static lt_bool_t
46 4 : lt_script_db_parse(lt_script_db_t *scriptdb,
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 (scriptdb != NULL, FALSE);
57 :
58 4 : doc = lt_xml_get_subtag_registry(scriptdb->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/script", 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 644 : for (i = 0; i < n; i++) {
75 640 : xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
76 : xmlNodePtr cnode;
77 640 : xmlChar *subtag = NULL, *desc = NULL;
78 640 : lt_script_t *le = NULL;
79 : char *s;
80 :
81 640 : 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 640 : cnode = ent->children;
87 6128 : while (cnode != NULL) {
88 4848 : if (xmlStrcmp(cnode->name, (const xmlChar *)"subtag") == 0) {
89 640 : if (subtag) {
90 0 : lt_warning("Duplicate subtag element in script: previous value was '%s'",
91 : subtag);
92 : } else {
93 640 : subtag = xmlNodeGetContent(cnode);
94 : }
95 7776 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"added") == 0 ||
96 4392 : xmlStrcmp(cnode->name, (const xmlChar *)"text") == 0 ||
97 824 : xmlStrcmp(cnode->name, (const xmlChar *)"comments") == 0) {
98 : /* ignore it */
99 820 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"description") == 0) {
100 : /* wonder if many descriptions helps something. or is it a bug? */
101 820 : if (!desc)
102 640 : desc = xmlNodeGetContent(cnode);
103 : } else {
104 0 : lt_warning("Unknown node under /registry/script: %s", cnode->name);
105 : }
106 4848 : cnode = cnode->next;
107 : }
108 640 : if (!subtag) {
109 0 : lt_warning("No subtag node: description = '%s'",
110 : desc);
111 0 : goto bail1;
112 : }
113 640 : if (!desc) {
114 0 : lt_warning("No description node: subtag = '%s'",
115 : subtag);
116 0 : goto bail1;
117 : }
118 640 : le = lt_script_create();
119 640 : if (!le) {
120 0 : lt_error_set(&err, LT_ERR_OOM,
121 : "Unable to create an instance of lt_script_t.");
122 0 : goto bail1;
123 : }
124 640 : lt_script_set_tag(le, (const char *)subtag);
125 640 : lt_script_set_name(le, (const char *)desc);
126 :
127 640 : s = strdup(lt_script_get_tag(le));
128 640 : lt_trie_replace(scriptdb->script_entries,
129 640 : lt_strlower(s),
130 640 : lt_script_ref(le),
131 : (lt_destroy_func_t)lt_script_unref);
132 640 : free(s);
133 : bail1:
134 640 : if (subtag)
135 640 : xmlFree(subtag);
136 640 : if (desc)
137 640 : xmlFree(desc);
138 640 : lt_script_unref(le);
139 : }
140 : bail:
141 4 : if (lt_error_is_set(err, LT_ERR_ANY)) {
142 0 : if (error)
143 0 : *error = lt_error_ref(err);
144 : else
145 0 : lt_error_print(err, LT_ERR_ANY);
146 0 : lt_error_unref(err);
147 0 : retval = FALSE;
148 : }
149 :
150 4 : if (xobj)
151 4 : xmlXPathFreeObject(xobj);
152 4 : if (xctxt)
153 4 : xmlXPathFreeContext(xctxt);
154 :
155 4 : return retval;
156 : }
157 :
158 : /*< public >*/
159 : /**
160 : * lt_script_db_new:
161 : *
162 : * Create a new instance of a #lt_script_db_t.
163 : *
164 : * Returns: (transfer full): a new instance of #lt_script_db_t.
165 : */
166 : lt_script_db_t *
167 4 : lt_script_db_new(void)
168 : {
169 4 : lt_script_db_t *retval = lt_mem_alloc_object(sizeof (lt_script_db_t));
170 :
171 4 : if (retval) {
172 4 : lt_error_t *err = NULL;
173 : lt_script_t *le;
174 :
175 4 : retval->script_entries = lt_trie_new();
176 4 : lt_mem_add_ref(&retval->parent, retval->script_entries,
177 : (lt_destroy_func_t)lt_trie_unref);
178 :
179 4 : le = lt_script_create();
180 4 : lt_script_set_tag(le, "*");
181 4 : lt_script_set_name(le, "Wildcard entry");
182 4 : lt_trie_replace(retval->script_entries,
183 : lt_script_get_tag(le),
184 : le,
185 : (lt_destroy_func_t)lt_script_unref);
186 4 : le = lt_script_create();
187 4 : lt_script_set_tag(le, "");
188 4 : lt_script_set_name(le, "Empty entry");
189 4 : lt_trie_replace(retval->script_entries,
190 : lt_script_get_tag(le),
191 : le,
192 : (lt_destroy_func_t)lt_script_unref);
193 :
194 4 : retval->xml = lt_xml_new();
195 4 : if (!retval->xml) {
196 0 : lt_script_db_unref(retval);
197 0 : retval = NULL;
198 : goto bail;
199 : }
200 4 : lt_mem_add_ref(&retval->parent, retval->xml,
201 : (lt_destroy_func_t)lt_xml_unref);
202 :
203 4 : lt_script_db_parse(retval, &err);
204 4 : if (lt_error_is_set(err, LT_ERR_ANY)) {
205 0 : lt_error_print(err, LT_ERR_ANY);
206 0 : lt_script_db_unref(retval);
207 0 : retval = NULL;
208 0 : lt_error_unref(err);
209 : }
210 : }
211 : bail:
212 :
213 4 : return retval;
214 : }
215 :
216 : /**
217 : * lt_script_db_ref:
218 : * @scriptdb: a #lt_script_db_t.
219 : *
220 : * Increases the reference count of @scriptdb.
221 : *
222 : * Returns: (transfer none): the same @scriptdb object.
223 : */
224 : lt_script_db_t *
225 4 : lt_script_db_ref(lt_script_db_t *scriptdb)
226 : {
227 4 : lt_return_val_if_fail (scriptdb != NULL, NULL);
228 :
229 4 : return lt_mem_ref(&scriptdb->parent);
230 : }
231 :
232 : /**
233 : * lt_script_db_unref:
234 : * @scriptdb: a #lt_script_db_t.
235 : *
236 : * Decreases the reference count of @scriptdb. when its reference count
237 : * drops to 0, the object is finalized (i.e. its memory is freed).
238 : */
239 : void
240 8 : lt_script_db_unref(lt_script_db_t *scriptdb)
241 : {
242 8 : if (scriptdb)
243 8 : lt_mem_unref(&scriptdb->parent);
244 8 : }
245 :
246 : /**
247 : * lt_script_db_lookup:
248 : * @scriptdb: a #lt_script_db_t.
249 : * @subtag: a subtag name to lookup.
250 : *
251 : * Lookup @lt_script_t if @subtag is valid and registered into the database.
252 : *
253 : * Returns: (transfer full): a #lt_script_t that meets with @subtag.
254 : * otherwise %NULL.
255 : */
256 : lt_script_t *
257 4 : lt_script_db_lookup(lt_script_db_t *scriptdb,
258 : const char *subtag)
259 : {
260 : lt_script_t *retval;
261 : char *s;
262 :
263 4 : lt_return_val_if_fail (scriptdb != NULL, NULL);
264 4 : lt_return_val_if_fail (subtag != NULL, NULL);
265 :
266 4 : s = strdup(subtag);
267 4 : retval = lt_trie_lookup(scriptdb->script_entries,
268 4 : lt_strlower(s));
269 4 : free(s);
270 4 : if (retval)
271 4 : return lt_script_ref(retval);
272 :
273 0 : return NULL;
274 : }
|