1 /* assetml - assetml.c
2 *
3 * Copyright (C) 2003 Bruno Coudoin
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "assetml.h"
21 #include <config.h>
22
23 /* libxml includes */
24 #include <libxml/tree.h>
25 #include <libxml/parser.h>
26
27 #include <locale.h>
28 #include <dirent.h>
29 #include <string.h>
30
31 #define FILE_EXT ".assetml"
32
33 gchar *assetml_get_locale(void);
34 gchar *reactivate_newline(gchar *str);
35 void dump_asset(AssetML *assetml);
36 int selectAssetML(const struct dirent *d);
37 void assetml_read_xml_file(GList **gl_result, char *fname,
38 gchar *dataset, gchar* categories, gchar* mimetype, gchar *locale, gchar* file);
39 void assetml_load_xml(GList **gl_result, gchar *dataset, gchar* categories, gchar* mimetype,
40 gchar* locale, gchar* file);
41 void free_asset(AssetML *assetml);
42
43 /*
44 * This returns the locale for which text must be displayed
45 *
46 */
assetml_get_locale()47 gchar *assetml_get_locale()
48 {
49 char *locale;
50
51 locale = getenv("LC_ALL");
52 if(locale == NULL)
53 locale = getenv("LANG");
54
55 if(locale!=NULL)
56 return(locale);
57
58 return("en_US.UTF-8");
59 }
60
61 /*
62 * Return a copy of the given string in which it has
63 * changes '\''n' to '\n'.
64 * The recognized sequences are \b
65 * \f \n \r \t \\ \" and the octal format.
66 *
67 */
reactivate_newline(gchar * str)68 gchar *reactivate_newline(gchar *str)
69 {
70 gchar *newstr;
71
72 if(str==NULL)
73 return NULL;
74
75 newstr = g_strcompress(str);
76
77 g_free(str);
78
79 return newstr;
80 }
81
dump_asset(AssetML * assetml)82 void dump_asset(AssetML *assetml)
83 {
84
85 printf("Dump Asset\n");
86
87 if(assetml==NULL)
88 return;
89
90 printf(" dataset = %s\n",assetml->dataset);
91 printf(" file = %s\n",assetml->file);
92 printf(" locale = %s\n",assetml->locale);
93 printf(" description = %s\n",assetml->description);
94 printf(" categories = %s\n",assetml->categories);
95 printf(" mimetype = %s\n",assetml->mimetype);
96 printf(" credits = %s\n",assetml->credits);
97
98 }
99
100 /*
101 * Thanks for George Lebl <jirka@5z.com> for his Genealogy example
102 * for all the XML stuff there
103 */
104
assetml_add_xml_to_data(xmlDocPtr doc,xmlNodePtr xmlnode,gchar * rootdir,GNode * child)105 static AssetML *assetml_add_xml_to_data(xmlDocPtr doc,
106 xmlNodePtr xmlnode,
107 gchar *rootdir,
108 GNode * child)
109 {
110 AssetML *assetml = NULL;
111 gchar *tmpstr;
112
113 if(/* if the node has no name */
114 !xmlnode->name ||
115 /* or if the name is not "Asset" */
116 (g_strcasecmp(xmlnode->name,"Asset")!=0)
117 )
118 return NULL;
119
120 assetml = g_malloc0 (sizeof (AssetML));
121
122 /* get the specific values */
123 tmpstr = xmlGetProp(xmlnode,"file");
124 if(tmpstr && strlen(tmpstr)>0)
125 if(rootdir[0]!='/')
126 /* This is a relative path, add ASSETML_DIR and rootdir prefix */
127 assetml->file = g_build_filename(ASSETML_DIR, rootdir, tmpstr, NULL);
128 else
129 assetml->file = g_build_filename(rootdir, tmpstr, NULL);
130 else
131 assetml->file = NULL;
132 xmlFree(tmpstr);
133
134 tmpstr = xmlGetProp(xmlnode,"mimetype");
135 if(tmpstr && strlen(tmpstr)>0)
136 assetml->mimetype = g_strdup(tmpstr);
137 else
138 assetml->mimetype = NULL;
139 xmlFree(tmpstr);
140
141 xmlnode = xmlnode->xmlChildrenNode;
142 while (xmlnode != NULL) {
143 gchar *lang = xmlGetProp(xmlnode,"lang");
144
145 /* get the description of the asset */
146 if (!strcmp(xmlnode->name, "Description")
147 && (lang==NULL ||
148 !strcmp(lang, assetml_get_locale())
149 || !strncmp(lang, assetml_get_locale(), 2)))
150 {
151 assetml->description = reactivate_newline(xmlNodeListGetString(doc,
152 xmlnode->xmlChildrenNode, 1));
153 }
154
155 /* get the description of the Credits */
156 if (!strcmp(xmlnode->name, "Credits")
157 && (lang==NULL ||
158 !strcmp(lang, assetml_get_locale())
159 || !strncmp(lang, assetml_get_locale(), 2)))
160 {
161 assetml->credits = reactivate_newline(xmlNodeListGetString(doc,
162 xmlnode->xmlChildrenNode, 1));
163 }
164
165
166 /* get the description of the Categories */
167 if (!strcmp(xmlnode->name, "Categories")
168 && (lang==NULL ||
169 !strcmp(lang, assetml_get_locale())
170 || !strncmp(lang, assetml_get_locale(), 2)))
171 {
172 assetml->categories = reactivate_newline(xmlNodeListGetString(doc,
173 xmlnode->xmlChildrenNode, 1));
174 }
175
176 xmlnode = xmlnode->next;
177 }
178
179 return(assetml);
180 }
181
182 /*
183 * Given the assetml and the dataset, categories, name
184 * return true if the assetml matches the requirements
185 */
matching(AssetML * assetml,gchar * mydataset,gchar * dataset,gchar * categories,gchar * mimetype,gchar * mylocale,gchar * locale,gchar * file)186 static gboolean matching(AssetML *assetml, gchar *mydataset,
187 gchar *dataset, gchar* categories, gchar* mimetype,
188 gchar* mylocale, gchar* locale, gchar* file)
189 {
190 g_assert(assetml);
191
192 assetml->dataset = g_strdup(mydataset);
193 if(assetml->dataset && dataset)
194 if(g_ascii_strcasecmp(assetml->dataset, dataset))
195 return FALSE;
196
197 /* Check the leading locale definition matches the leading user request so that
198 * File Requested Status
199 * fr fr_FR.UTF8 OK
200 * pt pt_BR OK
201 * pt_BR pt NO
202 */
203 assetml->locale = g_strdup(mylocale);
204 if(assetml->locale && locale)
205 if(g_ascii_strncasecmp(assetml->locale, locale, strlen(assetml->locale)))
206 return FALSE;
207
208 if(assetml->mimetype && mimetype)
209 if(g_ascii_strcasecmp(assetml->mimetype, mimetype))
210 return FALSE;
211
212 if(assetml->file && file)
213 {
214 gchar *str1;
215 gchar *str2;
216 gboolean nomatch;
217 /* We test only the basename of the file so that caller do not need to specify a full path */
218 str1 = g_path_get_basename(assetml->file);
219 str2 = g_path_get_basename(file);
220
221 nomatch = g_ascii_strcasecmp(str1, str2);
222
223 g_free(str1);
224 g_free(str2);
225
226 if(nomatch)
227 return FALSE;
228 }
229
230 if(assetml->categories && categories)
231 {
232 guint i;
233 for(i=0; i<strlen(assetml->categories)-strlen(categories)+1; i++)
234 {
235 if(!g_ascii_strncasecmp(assetml->categories+i, categories, strlen(categories)))
236 {
237 return TRUE;
238 }
239 }
240 return FALSE;
241 }
242
243 return TRUE;
244 }
245
246 /* parse the doc, add it to our internal structures and to the clist */
247 static void
parse_doc(GList ** gl_result,xmlDocPtr doc,gchar * mydataset,gchar * rootdir,gchar * mylocale,gchar * dataset,gchar * categories,gchar * mimetype,gchar * locale,gchar * file)248 parse_doc(GList **gl_result, xmlDocPtr doc,
249 gchar *mydataset, gchar *rootdir, gchar* mylocale,
250 gchar *dataset, gchar* categories, gchar* mimetype, gchar* locale, gchar* file)
251 {
252 xmlNodePtr node;
253
254 /* find <Asset> nodes and add them to the list, this just
255 loops through all the children of the root of the document */
256 for(node = doc->children->children; node != NULL; node = node->next) {
257 /* add the board to the list, there are no children so
258 we pass NULL as the node of the child */
259 AssetML *assetml = assetml_add_xml_to_data(doc, node, rootdir, NULL);
260
261 if(assetml && matching(assetml, mydataset, dataset, categories, mimetype, mylocale, locale, file))
262 *gl_result = g_list_append (*gl_result, assetml);
263
264 }
265 }
266
267
268
269 /* read an xml file into our memory structures and update our view,
270 dump any old data we have in memory if we can load a new set
271 Fill the gl_result list with all matching asseml items
272 */
assetml_read_xml_file(GList ** gl_result,char * assetmlfile,gchar * dataset,gchar * categories,gchar * mimetype,gchar * locale,gchar * file)273 void assetml_read_xml_file(GList **gl_result, char *assetmlfile,
274 gchar *dataset, gchar* categories, gchar* mimetype, gchar *locale, gchar* file)
275 {
276 /* pointer to the new doc */
277 xmlDocPtr doc;
278 gchar *rootdir;
279 gchar *mylocale;
280 gchar *mydataset;
281
282 g_return_if_fail(assetmlfile!=NULL);
283
284 /* parse the new file and put the result into newdoc */
285 doc = xmlParseFile(assetmlfile);
286
287 /* in case something went wrong */
288 if(!doc) {
289 g_warning("Oups, the parsing of %s failed", assetmlfile);
290 return;
291 }
292
293 if(/* if there is no root element */
294 !doc->children ||
295 /* if it doesn't have a name */
296 !doc->children->name ||
297 /* if it isn't a Assetml node */
298 g_strcasecmp(doc->children->name,"AssetML")!=0)
299 {
300 xmlFreeDoc(doc);
301 g_warning("Oups, the file %s is not of the assetml type", assetmlfile);
302 return;
303 }
304
305 rootdir = xmlGetProp(doc->children,"rootdir");
306 mydataset = xmlGetProp(doc->children,"dataset");
307 mylocale = xmlGetProp(doc->children,"locale");
308
309 /* parse our document and replace old data */
310 parse_doc(gl_result, doc, mydataset, rootdir, mylocale, dataset, categories, mimetype, locale, file);
311
312 xmlFree(rootdir);
313 xmlFree(mydataset);
314
315 xmlFreeDoc(doc);
316 }
317
318
319 /*
320 * Select only files with FILE_EXT
321 */
selectAssetML(const struct dirent * d)322 int selectAssetML(const struct dirent *d)
323 {
324 gchar *file = ((struct dirent *)d)->d_name;
325 guint ext_length = strlen(FILE_EXT);
326
327 if(strlen(file)<ext_length)
328 return 0;
329
330 return (strncmp (&file[strlen(file)-ext_length], FILE_EXT, ext_length) == 0);
331 }
332
333 /* load all the xml files in the assetml path
334 * into our memory structures.
335 */
assetml_load_xml(GList ** gl_result,gchar * dataset,gchar * categories,gchar * mimetype,gchar * locale,gchar * name)336 void assetml_load_xml(GList **gl_result, gchar *dataset, gchar* categories, gchar* mimetype, gchar *locale,
337 gchar* name)
338 {
339 struct dirent **namelist;
340 int n;
341
342 n = scandir(ASSETML_DIR, &namelist, &selectAssetML, 0);
343
344 if (n <= 0)
345 g_warning("scandir returns no files with extension %s in directory %s", FILE_EXT, ASSETML_DIR);
346 else {
347 while(n--) {
348 gchar *assetmlfile = g_strdup_printf("%s/%s", ASSETML_DIR, namelist[n]->d_name);
349
350 assetml_read_xml_file(gl_result, assetmlfile,
351 dataset, categories, mimetype, locale, name);
352
353 g_free(assetmlfile);
354 free (namelist [n]);
355 }
356 free (namelist);
357 }
358 }
359
360
361
free_asset(AssetML * assetml)362 void free_asset(AssetML *assetml)
363 {
364
365 xmlFree(assetml->locale);
366 xmlFree(assetml->dataset);
367 xmlFree(assetml->description);
368 xmlFree(assetml->categories);
369 xmlFree(assetml->file);
370 xmlFree(assetml->mimetype);
371 xmlFree(assetml->credits);
372
373 g_free(assetml);
374 }
375
assetml_free_assetlist(GList * assetlist)376 void assetml_free_assetlist(GList *assetlist)
377 {
378 g_list_foreach (assetlist, (GFunc) free_asset, NULL);
379 g_list_free(assetlist);
380
381
382 }
383
assetml_get_asset(gchar * dataset,gchar * categories,gchar * mimetype,gchar * locale,gchar * file)384 GList* assetml_get_asset(gchar *dataset, gchar* categories, gchar* mimetype, gchar *locale, gchar* file)
385 {
386 GList *gl_result = NULL;
387
388 assetml_load_xml(&gl_result, dataset, categories, mimetype, locale, file);
389
390 if(g_list_length(gl_result)==0)
391 {
392 g_list_free(gl_result);
393 return NULL;
394 }
395 else
396 {
397 #ifdef DEBUG
398 printf("Dumping return value of assetml_get_asset\n");
399 g_list_foreach (gl_result, (GFunc) dump_asset, NULL);
400 #endif
401 return gl_result;
402 }
403 }
404