Branch data Line data Source code
1 : : /********************************************************************
2 : : * sixtp-dom-parsers.c *
3 : : * Copyright 2001 Gnumatic, Inc. *
4 : : * *
5 : : * This program is free software; you can redistribute it and/or *
6 : : * modify it under the terms of the GNU General Public License as *
7 : : * published by the Free Software Foundation; either version 2 of *
8 : : * the License, or (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, contact: *
17 : : * *
18 : : * Free Software Foundation Voice: +1-617-542-5942 *
19 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
21 : : * *
22 : : ********************************************************************/
23 : : #include <glib.h>
24 : :
25 : : #include <config.h>
26 : :
27 : : #include <string.h>
28 : :
29 : : #include <gnc-engine.h>
30 : :
31 : : #include "gnc-xml-helper.h"
32 : : #include "sixtp-utils.h"
33 : : #include "sixtp-dom-parsers.h"
34 : : #include <kvp-frame.hpp>
35 : :
36 : : static QofLogModule log_module = GNC_MOD_IO;
37 : :
38 : : GncGUID*
39 : 8479 : dom_tree_to_guid (xmlNodePtr node)
40 : : {
41 : 8479 : if (!node->properties)
42 : : {
43 : 0 : return NULL;
44 : : }
45 : :
46 : 8479 : if (strcmp ((char*) node->properties->name, "type") != 0)
47 : : {
48 : 0 : PERR ("Unknown attribute for id tag: %s",
49 : : node->properties->name ?
50 : : (char*) node->properties->name : "(null)");
51 : 0 : return NULL;
52 : : }
53 : :
54 : : {
55 : : char* type;
56 : :
57 : 8479 : type = (char*)xmlNodeGetContent (node->properties->xmlAttrPropertyValue);
58 : :
59 : : /* handle new and guid the same for the moment */
60 : 8479 : if ((g_strcmp0 ("guid", type) == 0) || (g_strcmp0 ("new", type) == 0))
61 : : {
62 : 8479 : auto gid = guid_new ();
63 : : char* guid_str;
64 : :
65 : 8479 : guid_str = (char*)xmlNodeGetContent (node->xmlChildrenNode);
66 : 8479 : string_to_guid (guid_str, gid);
67 : 8479 : xmlFree (guid_str);
68 : 8479 : xmlFree (type);
69 : 8479 : return gid;
70 : : }
71 : : else
72 : : {
73 : 0 : PERR ("Unknown type %s for attribute type for tag %s",
74 : : type ? type : "(null)",
75 : : node->properties->name ?
76 : : (char*) node->properties->name : "(null)");
77 : 0 : xmlFree (type);
78 : 0 : return NULL;
79 : : }
80 : : }
81 : : }
82 : :
83 : : static KvpValue*
84 : 1237 : dom_tree_to_integer_kvp_value (xmlNodePtr node)
85 : : {
86 : : gchar* text;
87 : : gint64 daint;
88 : 1237 : KvpValue* ret = NULL;
89 : :
90 : 1237 : text = dom_tree_to_text (node);
91 : :
92 : 1237 : if (string_to_gint64 (text, &daint))
93 : : {
94 : 1237 : ret = new KvpValue {daint};
95 : : }
96 : 1237 : g_free (text);
97 : :
98 : 1237 : return ret;
99 : : }
100 : :
101 : : template <typename T>
102 : : static bool
103 : 710 : dom_tree_to_num (xmlNodePtr node, std::function<bool(const char*, T*)>string_to_num, T* num_ptr)
104 : : {
105 : 710 : auto text = dom_tree_to_text (node);
106 : 710 : auto ret = string_to_num (text, num_ptr);
107 : 710 : g_free (text);
108 : 710 : return ret;
109 : : }
110 : :
111 : : gboolean
112 : 703 : dom_tree_to_integer (xmlNodePtr node, gint64* daint)
113 : : {
114 : 703 : return dom_tree_to_num<gint64>(node, string_to_gint64, daint);
115 : : }
116 : :
117 : : gboolean
118 : 6 : dom_tree_to_guint16 (xmlNodePtr node, guint16* i)
119 : : {
120 : 6 : return dom_tree_to_num<guint16>(node, string_to_guint16, i);
121 : : }
122 : :
123 : : gboolean
124 : 1 : dom_tree_to_guint (xmlNodePtr node, guint* i)
125 : : {
126 : 1 : return dom_tree_to_num<guint>(node, string_to_guint, i);
127 : : }
128 : :
129 : : gboolean
130 : 0 : dom_tree_to_boolean (xmlNodePtr node, gboolean* b)
131 : : {
132 : : gchar* text;
133 : :
134 : 0 : text = dom_tree_to_text (node);
135 : 0 : if (g_ascii_strncasecmp (text, "true", 4) == 0)
136 : : {
137 : 0 : *b = TRUE;
138 : 0 : g_free (text);
139 : 0 : return TRUE;
140 : : }
141 : 0 : else if (g_ascii_strncasecmp (text, "false", 5) == 0)
142 : : {
143 : 0 : *b = FALSE;
144 : 0 : g_free (text);
145 : 0 : return TRUE;
146 : : }
147 : : else
148 : : {
149 : 0 : *b = FALSE;
150 : 0 : g_free (text);
151 : 0 : return FALSE;
152 : : }
153 : : }
154 : :
155 : : static KvpValue*
156 : 0 : dom_tree_to_double_kvp_value (xmlNodePtr node)
157 : : {
158 : : gchar* text;
159 : : double dadoub;
160 : 0 : KvpValue* ret = NULL;
161 : :
162 : 0 : text = dom_tree_to_text (node);
163 : :
164 : 0 : if (string_to_double (text, &dadoub))
165 : : {
166 : 0 : ret = new KvpValue {dadoub};
167 : : }
168 : :
169 : 0 : g_free (text);
170 : :
171 : 0 : return ret;
172 : : }
173 : :
174 : : static KvpValue*
175 : 591 : dom_tree_to_numeric_kvp_value (xmlNodePtr node)
176 : : {
177 : 591 : return new KvpValue {dom_tree_to_gnc_numeric (node)};
178 : : }
179 : :
180 : : static KvpValue*
181 : 904 : dom_tree_to_string_kvp_value (xmlNodePtr node)
182 : : {
183 : : const gchar* datext;
184 : 904 : KvpValue* ret = NULL;
185 : :
186 : 904 : datext = dom_tree_to_text (node);
187 : 904 : if (datext)
188 : : {
189 : 904 : ret = new KvpValue {datext};
190 : : }
191 : :
192 : 904 : return ret;
193 : : }
194 : :
195 : : static KvpValue*
196 : 616 : dom_tree_to_guid_kvp_value (xmlNodePtr node)
197 : : {
198 : : GncGUID* daguid;
199 : 616 : KvpValue* ret = NULL;
200 : :
201 : 616 : daguid = dom_tree_to_guid (node);
202 : 616 : if (daguid)
203 : : {
204 : 616 : ret = new KvpValue {daguid};
205 : : }
206 : :
207 : 616 : return ret;
208 : : }
209 : :
210 : : static KvpValue*
211 : 4 : dom_tree_to_time64_kvp_value (xmlNodePtr node)
212 : : {
213 : 4 : Time64 t{dom_tree_to_time64 (node)};
214 : 8 : return new KvpValue {t};
215 : : }
216 : :
217 : : static KvpValue*
218 : 2 : dom_tree_to_gdate_kvp_value (xmlNodePtr node)
219 : : {
220 : : GDate* date;
221 : 2 : KvpValue* ret = NULL;
222 : :
223 : 2 : date = dom_tree_to_gdate (node);
224 : :
225 : 2 : if (date)
226 : : {
227 : 2 : ret = new KvpValue {*date};
228 : : }
229 : :
230 : 2 : g_free (date);
231 : :
232 : 2 : return ret;
233 : : }
234 : :
235 : : gboolean
236 : 0 : string_to_binary (const gchar* str, void** v, guint64* data_len)
237 : : {
238 : : guint64 str_len;
239 : : guchar* data;
240 : : unsigned int i, j;
241 : :
242 : 0 : g_return_val_if_fail (v != NULL, FALSE);
243 : 0 : g_return_val_if_fail (data_len != NULL, FALSE);
244 : :
245 : 0 : str_len = strlen (str);
246 : :
247 : : /* Since no whitespace is allowed and hex encoding is 2 text chars
248 : : per binary char, the result must be half the input size and the
249 : : input size must be even. */
250 : 0 : if ((str_len % 2) != 0)
251 : 0 : return (FALSE);
252 : 0 : *data_len = str_len / 2;
253 : 0 : data = g_new0 (guchar, *data_len);
254 : :
255 : 0 : for (j = 0, i = 0; i < str_len; i += 2, j++)
256 : : {
257 : : gchar tmpstr[3];
258 : : long int converted;
259 : :
260 : 0 : tmpstr[0] = str[i];
261 : 0 : tmpstr[1] = str[i + 1];
262 : 0 : tmpstr[2] = '\0';
263 : :
264 : 0 : converted = strtol (tmpstr, NULL, 16);
265 : :
266 : 0 : data[j] = (unsigned char)converted;
267 : : }
268 : :
269 : 0 : *v = data;
270 : :
271 : 0 : return (TRUE);
272 : : }
273 : :
274 : : static KvpValue* dom_tree_to_kvp_value (xmlNodePtr node);
275 : : //needed for test access as well as internal use.
276 : : KvpFrame* dom_tree_to_kvp_frame (xmlNodePtr node);
277 : :
278 : : static KvpValue*
279 : 356 : dom_tree_to_list_kvp_value (xmlNodePtr node)
280 : : {
281 : 356 : GList* list = NULL;
282 : : xmlNodePtr mark;
283 : 356 : KvpValue* ret = NULL;
284 : :
285 : 2355 : for (mark = node->xmlChildrenNode; mark; mark = mark->next)
286 : : {
287 : : KvpValue* new_val;
288 : :
289 : 1999 : if (g_strcmp0 ((char*)mark->name, "text") == 0)
290 : 925 : continue;
291 : :
292 : 1074 : new_val = dom_tree_to_kvp_value (mark);
293 : 1074 : if (new_val)
294 : : {
295 : 1074 : list = g_list_prepend (list, (gpointer)new_val);
296 : : }
297 : : }
298 : :
299 : 356 : list = g_list_reverse (list);
300 : :
301 : 356 : ret = new KvpValue {list};
302 : :
303 : 356 : return ret;
304 : : }
305 : :
306 : : static KvpValue*
307 : 359 : dom_tree_to_frame_kvp_value (xmlNodePtr node)
308 : : {
309 : : KvpFrame* frame;
310 : 359 : KvpValue* ret = NULL;
311 : :
312 : 359 : frame = dom_tree_to_kvp_frame (node);
313 : :
314 : 359 : if (frame)
315 : : {
316 : 359 : ret = new KvpValue {frame};
317 : : }
318 : :
319 : 359 : return ret;
320 : : }
321 : :
322 : :
323 : : struct kvp_val_converter
324 : : {
325 : : const gchar* tag;
326 : : KvpValue* (*converter) (xmlNodePtr node);
327 : : };
328 : : /* Note: The type attribute must remain 'timespec' to maintain compatibility.
329 : : */
330 : :
331 : : struct kvp_val_converter val_converters[] =
332 : : {
333 : : { "integer", dom_tree_to_integer_kvp_value },
334 : : { "double", dom_tree_to_double_kvp_value },
335 : : { "numeric", dom_tree_to_numeric_kvp_value },
336 : : { "string", dom_tree_to_string_kvp_value },
337 : : { "guid", dom_tree_to_guid_kvp_value },
338 : : { "timespec", dom_tree_to_time64_kvp_value },
339 : : { "gdate", dom_tree_to_gdate_kvp_value },
340 : : { "list", dom_tree_to_list_kvp_value },
341 : : { "frame", dom_tree_to_frame_kvp_value },
342 : : { 0, 0 },
343 : : };
344 : :
345 : : static KvpValue*
346 : 4069 : dom_tree_to_kvp_value (xmlNodePtr node)
347 : : {
348 : : xmlChar* xml_type;
349 : : gchar* type;
350 : : struct kvp_val_converter* mark;
351 : 4069 : KvpValue* ret = NULL;
352 : :
353 : 4069 : xml_type = xmlGetProp (node, BAD_CAST "type");
354 : 4069 : if (xml_type)
355 : : {
356 : 4069 : type = g_strdup ((char*) xml_type);
357 : 4069 : xmlFree (xml_type);
358 : : }
359 : : else
360 : 0 : type = NULL;
361 : :
362 : 40690 : for (mark = val_converters; mark->tag; mark++)
363 : : {
364 : 36621 : if (g_strcmp0 (type, mark->tag) == 0)
365 : : {
366 : 4069 : ret = (mark->converter) (node);
367 : : }
368 : : }
369 : :
370 : 4069 : if (!mark->tag)
371 : : {
372 : : /* FIXME: deal with unknown type tag here */
373 : : }
374 : :
375 : 4069 : g_free (type);
376 : :
377 : 4069 : return ret;
378 : : }
379 : :
380 : : static gboolean
381 : 879 : dom_tree_to_kvp_frame_given (xmlNodePtr node, KvpFrame* frame)
382 : : {
383 : : xmlNodePtr mark;
384 : :
385 : 879 : g_return_val_if_fail (node, FALSE);
386 : 879 : g_return_val_if_fail (frame, FALSE);
387 : :
388 : 6621 : for (mark = node->xmlChildrenNode; mark; mark = mark->next)
389 : : {
390 : 5742 : if (g_strcmp0 ((char*)mark->name, "slot") == 0)
391 : : {
392 : : xmlNodePtr mark2;
393 : 2995 : gchar* key = NULL;
394 : 2995 : KvpValue* val = NULL;
395 : :
396 : 15207 : for (mark2 = mark->xmlChildrenNode; mark2; mark2 = mark2->next)
397 : : {
398 : 12212 : if (g_strcmp0 ((char*)mark2->name, "slot:key") == 0)
399 : : {
400 : 2995 : key = dom_tree_to_text (mark2);
401 : : }
402 : 9217 : else if (g_strcmp0 ((char*)mark2->name, "slot:value") == 0)
403 : : {
404 : 2995 : val = dom_tree_to_kvp_value (mark2);
405 : : }
406 : : else
407 : : {
408 : : /* FIXME: should put some error here.
409 : : * But ignore text type! */
410 : : }
411 : : }
412 : :
413 : 2995 : if (key)
414 : : {
415 : 2995 : if (val)
416 : : {
417 : : //We're deleting the old KvpValue returned by replace_nc().
418 : 8985 : delete frame->set ({key}, val);
419 : : }
420 : : else
421 : : {
422 : : /* FIXME: should put some error here */
423 : : }
424 : 2995 : g_free (key);
425 : : }
426 : : }
427 : : }
428 : :
429 : 879 : return TRUE;
430 : 8985 : }
431 : :
432 : :
433 : : KvpFrame*
434 : 450 : dom_tree_to_kvp_frame (xmlNodePtr node)
435 : : {
436 : 450 : g_return_val_if_fail (node, NULL);
437 : :
438 : 450 : auto ret = new KvpFrame;
439 : :
440 : 450 : if (dom_tree_to_kvp_frame_given (node, ret))
441 : 450 : return ret;
442 : :
443 : 0 : delete ret;
444 : 0 : return NULL;
445 : : }
446 : :
447 : : gboolean
448 : 429 : dom_tree_create_instance_slots (xmlNodePtr node, QofInstance* inst)
449 : : {
450 : 429 : KvpFrame* frame = qof_instance_get_slots (inst);
451 : 429 : return dom_tree_to_kvp_frame_given (node, frame);
452 : : }
453 : :
454 : : gchar*
455 : 28880 : dom_tree_to_text (xmlNodePtr tree)
456 : : {
457 : : /* Expect *only* text and comment sibling nodes in the given tree --
458 : : which actually may only be a "list". i.e. if you're trying to
459 : : extract bar from <foo>bar</foo>, pass in <foo>->xmlChildrenNode
460 : : to this function. This expectation is different from the rest of
461 : : the dom_tree_to_* converters...
462 : :
463 : : Ignores comment nodes and collapse text nodes into one string.
464 : : Returns NULL if expectations are unsatisfied.
465 : : */
466 : : gchar* result;
467 : : gchar* temp;
468 : :
469 : 28880 : g_return_val_if_fail (tree, NULL);
470 : :
471 : : /* no nodes means it's an empty string text */
472 : 28880 : if (!tree->xmlChildrenNode)
473 : : {
474 : 574 : DEBUG ("No children");
475 : 574 : return g_strdup ("");
476 : : }
477 : :
478 : 28306 : temp = (char*)xmlNodeListGetString (NULL, tree->xmlChildrenNode, TRUE);
479 : 28306 : if (!temp)
480 : : {
481 : 0 : DEBUG ("Null string");
482 : 0 : return NULL;
483 : : }
484 : :
485 : 28306 : DEBUG ("node string [%s]", (temp == NULL ? "(null)" : temp));
486 : 28306 : result = g_strdup (temp);
487 : 28306 : xmlFree (temp);
488 : 28306 : return result;
489 : : }
490 : :
491 : : gnc_numeric
492 : 5129 : dom_tree_to_gnc_numeric (xmlNodePtr node)
493 : : {
494 : 5129 : gchar* content = dom_tree_to_text (node);
495 : 5129 : if (!content)
496 : 0 : return gnc_numeric_zero ();
497 : :
498 : 5129 : gnc_numeric num = gnc_numeric_from_string (content);
499 : 5129 : if (gnc_numeric_check (num))
500 : 0 : num = gnc_numeric_zero ();
501 : :
502 : 5129 : g_free (content);
503 : 5129 : return num;
504 : : }
505 : :
506 : :
507 : : time64
508 : 2644 : dom_tree_to_time64 (xmlNodePtr node)
509 : : {
510 : : /* Turn something like this
511 : :
512 : : <date-posted>
513 : : <ts:date>Mon, 05 Jun 2000 23:16:19 -0500</ts:date>
514 : : </date-posted>
515 : :
516 : : into a time64, returning INT64_MAX that we're using to flag an erroneous
517 : : date if there's a problem. Only one ts:date element is permitted for any
518 : : date attribute.
519 : : */
520 : :
521 : 2644 : time64 ret {INT64_MAX};
522 : 2644 : gboolean seen = FALSE;
523 : : xmlNodePtr n;
524 : :
525 : 11784 : for (n = node->xmlChildrenNode; n; n = n->next)
526 : : {
527 : 9140 : switch (n->type)
528 : : {
529 : 5772 : case XML_COMMENT_NODE:
530 : : case XML_TEXT_NODE:
531 : 5772 : break;
532 : 3368 : case XML_ELEMENT_NODE:
533 : 3368 : if (g_strcmp0 ("ts:date", (char*)n->name) == 0)
534 : : {
535 : 2644 : if (seen)
536 : : {
537 : 0 : return INT64_MAX;
538 : : }
539 : : else
540 : : {
541 : 2644 : gchar* content = dom_tree_to_text (n);
542 : 2644 : if (!content)
543 : : {
544 : 0 : return INT64_MAX;
545 : : }
546 : :
547 : 2644 : ret = gnc_iso8601_to_time64_gmt (content);
548 : 2644 : g_free (content);
549 : 2644 : seen = TRUE;
550 : : }
551 : : }
552 : 3368 : break;
553 : 0 : default:
554 : 0 : PERR ("unexpected sub-node.");
555 : 0 : return INT64_MAX;
556 : : break;
557 : : }
558 : : }
559 : :
560 : 2644 : if (!seen)
561 : : {
562 : 0 : PERR ("no ts:date node found.");
563 : 0 : return INT64_MAX;
564 : : }
565 : :
566 : 2644 : return ret;
567 : : }
568 : :
569 : : GDate*
570 : 16 : dom_tree_to_gdate (xmlNodePtr node)
571 : : {
572 : : /* Turn something like this
573 : :
574 : : <sx:startdate>
575 : : <gdate>2001-04-03</gdate>
576 : : </sx:startdate>
577 : :
578 : : into a GDate. If the xml is invalid, returns NULL. */
579 : :
580 : : GDate* ret;
581 : 16 : gboolean seen_date = FALSE;
582 : : xmlNodePtr n;
583 : :
584 : : /* creates an invalid date */
585 : 16 : ret = g_date_new ();
586 : :
587 : 64 : for (n = node->xmlChildrenNode; n; n = n->next)
588 : : {
589 : 48 : switch (n->type)
590 : : {
591 : 32 : case XML_COMMENT_NODE:
592 : : case XML_TEXT_NODE:
593 : 32 : break;
594 : 16 : case XML_ELEMENT_NODE:
595 : 16 : if (g_strcmp0 ("gdate", (char*)n->name) == 0)
596 : : {
597 : 16 : if (seen_date)
598 : : {
599 : 0 : goto failure;
600 : : }
601 : : else
602 : : {
603 : 16 : gchar* content = dom_tree_to_text (n);
604 : : gint year, month, day;
605 : 16 : if (!content)
606 : : {
607 : 0 : goto failure;
608 : : }
609 : :
610 : 16 : if (sscanf (content, "%d-%d-%d", &year, &month, &day) != 3)
611 : : {
612 : 0 : g_free (content);
613 : 0 : goto failure;
614 : : }
615 : 16 : g_free (content);
616 : 16 : seen_date = TRUE;
617 : 16 : g_date_set_dmy (ret, day, static_cast<GDateMonth> (month),
618 : : year);
619 : 16 : if (!g_date_valid (ret))
620 : : {
621 : 0 : PWARN ("invalid date");
622 : 0 : goto failure;
623 : : }
624 : : }
625 : : }
626 : 16 : break;
627 : 0 : default:
628 : 0 : PERR ("unexpected sub-node.");
629 : 0 : goto failure;
630 : : }
631 : : }
632 : :
633 : 16 : if (!seen_date)
634 : : {
635 : 0 : PWARN ("no gdate node found.");
636 : 0 : goto failure;
637 : : }
638 : :
639 : 16 : return ret;
640 : 0 : failure:
641 : 0 : g_date_free (ret);
642 : 0 : return NULL;
643 : : }
644 : :
645 : :
646 : : gnc_commodity*
647 : 3513 : dom_tree_to_commodity_ref_no_engine (xmlNodePtr node, QofBook* book)
648 : : {
649 : : /* Turn something like this
650 : :
651 : : <currency>
652 : : <cmdty:space>NASDAQ</cmdty:space>
653 : : <cmdty:id>LNUX</cmdty:space>
654 : : </currency>
655 : :
656 : : into a gnc_commodity*, returning NULL on failure. Both sub-nodes
657 : : are required, though for now, order is irrelevant. */
658 : :
659 : 3513 : gnc_commodity* c = NULL;
660 : 3513 : gchar* space_str = NULL;
661 : 3513 : gchar* id_str = NULL;
662 : : xmlNodePtr n;
663 : :
664 : 3513 : if (!node) return NULL;
665 : 3513 : if (!node->xmlChildrenNode) return NULL;
666 : :
667 : 20955 : for (n = node->xmlChildrenNode; n; n = n->next)
668 : : {
669 : 17442 : switch (n->type)
670 : : {
671 : 10416 : case XML_COMMENT_NODE:
672 : : case XML_TEXT_NODE:
673 : 10416 : break;
674 : 7026 : case XML_ELEMENT_NODE:
675 : 7026 : if (g_strcmp0 ("cmdty:space", (char*)n->name) == 0)
676 : : {
677 : 3513 : if (space_str)
678 : : {
679 : 0 : return NULL;
680 : : }
681 : : else
682 : : {
683 : 3513 : gchar* content = dom_tree_to_text (n);
684 : 3513 : if (!content) return NULL;
685 : 3513 : space_str = content;
686 : : }
687 : : }
688 : 3513 : else if (g_strcmp0 ("cmdty:id", (char*)n->name) == 0)
689 : : {
690 : 3513 : if (id_str)
691 : : {
692 : 0 : return NULL;
693 : : }
694 : : else
695 : : {
696 : 3513 : gchar* content = dom_tree_to_text (n);
697 : 3513 : if (!content) return NULL;
698 : 3513 : id_str = content;
699 : : }
700 : : }
701 : 7026 : break;
702 : 0 : default:
703 : 0 : PERR ("unexpected sub-node.");
704 : 0 : return NULL;
705 : : break;
706 : : }
707 : : }
708 : 3513 : if (! (space_str && id_str))
709 : : {
710 : 0 : c = NULL;
711 : : }
712 : : else
713 : : {
714 : 3513 : g_strstrip (space_str);
715 : 3513 : g_strstrip (id_str);
716 : 3513 : c = gnc_commodity_new (book, NULL, space_str, id_str, NULL, 0);
717 : : }
718 : :
719 : 3513 : g_free (space_str);
720 : 3513 : g_free (id_str);
721 : :
722 : 3513 : return c;
723 : : }
724 : :
725 : : gnc_commodity*
726 : 3472 : dom_tree_to_commodity_ref (xmlNodePtr node, QofBook* book)
727 : : {
728 : : gnc_commodity* daref;
729 : : gnc_commodity* ret;
730 : : gnc_commodity_table* table;
731 : :
732 : 3472 : daref = dom_tree_to_commodity_ref_no_engine (node, book);
733 : :
734 : 3472 : table = gnc_commodity_table_get_table (book);
735 : :
736 : 3472 : g_return_val_if_fail (table != NULL, NULL);
737 : :
738 : 3472 : ret = gnc_commodity_table_lookup (table,
739 : : gnc_commodity_get_namespace (daref),
740 : : gnc_commodity_get_mnemonic (daref));
741 : :
742 : 3472 : gnc_commodity_destroy (daref);
743 : :
744 : 3472 : g_return_val_if_fail (ret != NULL, NULL);
745 : :
746 : 3472 : return ret;
747 : : }
748 : :
749 : : /***********************************************************************/
750 : : /* generic parser */
751 : :
752 : : static inline void
753 : 3776 : dom_tree_handlers_reset (struct dom_tree_handler* handlers)
754 : : {
755 : 48276 : for (; handlers->tag != NULL; handlers++)
756 : : {
757 : 44500 : handlers->gotten = 0;
758 : : }
759 : 3776 : }
760 : :
761 : : static inline gboolean
762 : 3776 : dom_tree_handlers_all_gotten_p (struct dom_tree_handler* handlers)
763 : : {
764 : 3776 : gboolean ret = TRUE;
765 : 48276 : for (; handlers->tag != NULL; handlers++)
766 : : {
767 : 44500 : if (handlers->required && ! handlers->gotten)
768 : : {
769 : 0 : PERR ("Not defined and it should be: %s",
770 : : handlers->tag ? handlers->tag : "(null)");
771 : 0 : ret = FALSE;
772 : : }
773 : : }
774 : 3776 : return ret;
775 : : }
776 : :
777 : :
778 : : static inline gboolean
779 : 22626 : gnc_xml_set_data (const gchar* tag, xmlNodePtr node, gpointer item,
780 : : struct dom_tree_handler* handlers)
781 : : {
782 : 108198 : for (; handlers->tag != NULL; handlers++)
783 : : {
784 : 108198 : if (g_strcmp0 (tag, handlers->tag) == 0)
785 : : {
786 : 22626 : (handlers->handler) (node, item);
787 : 22626 : handlers->gotten = TRUE;
788 : 22626 : break;
789 : : }
790 : : }
791 : :
792 : 22626 : if (!handlers->tag)
793 : : {
794 : 0 : PERR ("Unhandled tag: %s",
795 : : tag ? tag : "(null)");
796 : 0 : return FALSE;
797 : : }
798 : :
799 : 22626 : return TRUE;
800 : : }
801 : :
802 : : gboolean
803 : 3776 : dom_tree_generic_parse (xmlNodePtr node, struct dom_tree_handler* handlers,
804 : : gpointer data)
805 : : {
806 : : xmlNodePtr achild;
807 : 3776 : gboolean successful = TRUE;
808 : :
809 : 3776 : dom_tree_handlers_reset (handlers);
810 : :
811 : 52804 : for (achild = node->xmlChildrenNode; achild; achild = achild->next)
812 : : {
813 : : /* ignore stray text nodes */
814 : 49028 : if (g_strcmp0 ((char*)achild->name, "text") == 0)
815 : 26402 : continue;
816 : :
817 : 22626 : if (!gnc_xml_set_data ((char*)achild->name, achild, data, handlers))
818 : : {
819 : 0 : PERR ("gnc_xml_set_data failed");
820 : 0 : successful = FALSE;
821 : 0 : continue;
822 : : }
823 : : }
824 : :
825 : 3776 : if (!dom_tree_handlers_all_gotten_p (handlers))
826 : : {
827 : 0 : PERR ("didn't find all of the expected tags in the input");
828 : 0 : successful = FALSE;
829 : : }
830 : :
831 : 3776 : return successful;
832 : : }
833 : :
834 : : gboolean
835 : 2540 : dom_tree_valid_time64 (time64 val, const xmlChar * name)
836 : : {
837 : 2540 : if (val != INT64_MAX)
838 : 2540 : return TRUE;
839 : 0 : g_warning ("Invalid timestamp in data file. Look for a '%s' entry "
840 : : "with a year outside of the valid range: 1400..10000", name);
841 : 0 : return FALSE;
842 : : }
|