31 #include "gnc-xml-helper.h" 32 #include "sixtp-utils.h" 33 #include "sixtp-dom-parsers.h" 34 #include <kvp-frame.hpp> 36 static QofLogModule log_module = GNC_MOD_IO;
39 dom_node_to_text (xmlNodePtr node) noexcept
41 if (node && node->children && node->children->type == XML_TEXT_NODE
42 && !node->children->next)
43 return reinterpret_cast<const char*
>(node->children->content);
47 std::optional<GncGUID>
48 dom_tree_to_guid (xmlNodePtr node)
50 auto type = xmlGetProp (node, BAD_CAST
"type");
54 bool ok = !g_strcmp0 ((
char*)type,
"guid") || !g_strcmp0 ((
char*)type,
"new");
61 auto extract_guid = [](
auto str) -> std::optional<GncGUID>
69 return apply_xmlnode_text<std::optional<GncGUID>>(extract_guid, node);
73 dom_tree_to_integer_kvp_value (xmlNodePtr node)
75 auto node_to_int_kvp = [](
auto txt) -> KvpValue*
77 if (gint64 daint; string_to_gint64 (txt, &daint))
78 return new KvpValue{daint};
82 return apply_xmlnode_text<KvpValue*> (node_to_int_kvp, node,
nullptr);
87 dom_tree_to_num (xmlNodePtr node, std::function<
bool(
const char*, T*)>string_to_num, T* num_ptr)
89 return apply_xmlnode_text<T>([&](
auto txt){
return string_to_num (txt, num_ptr);}, node,
false);
93 dom_tree_to_integer (xmlNodePtr node, gint64* daint)
95 return dom_tree_to_num<gint64>(node, string_to_gint64, daint);
99 dom_tree_to_guint16 (xmlNodePtr node, guint16* i)
101 return dom_tree_to_num<guint16>(node, string_to_guint16, i);
105 dom_tree_to_guint (xmlNodePtr node, guint* i)
107 return dom_tree_to_num<guint>(node, string_to_guint, i);
111 dom_tree_to_boolean (xmlNodePtr node, gboolean* b)
113 auto set_bool = [b](
auto text) -> gboolean
115 if (g_ascii_strncasecmp (text,
"true", 4) == 0)
120 else if (g_ascii_strncasecmp (text,
"false", 5) == 0)
131 return apply_xmlnode_text<gboolean> (set_bool, node);
135 dom_tree_to_double_kvp_value (xmlNodePtr node)
137 auto node_to_double_kvp = [](
auto txt) -> KvpValue*
139 if (
double dadoub; string_to_double (txt, &dadoub))
return new KvpValue{dadoub};
142 return apply_xmlnode_text<KvpValue*> (node_to_double_kvp, node,
nullptr);
146 dom_tree_to_numeric_kvp_value (xmlNodePtr node)
148 return new KvpValue {dom_tree_to_gnc_numeric (node)};
152 dom_tree_to_string_kvp_value (xmlNodePtr node)
154 auto node_to_string_kvp = [](
auto txt) -> KvpValue*
156 return new KvpValue {g_strdup (txt)};
158 return apply_xmlnode_text<KvpValue*> (node_to_string_kvp, node,
nullptr);
162 dom_tree_to_guid_kvp_value (xmlNodePtr node)
164 auto daguid = dom_tree_to_guid (node);
165 return daguid ?
new KvpValue {
guid_copy (&*daguid)} :
nullptr;
169 dom_tree_to_time64_kvp_value (xmlNodePtr node)
171 Time64 t{dom_tree_to_time64 (node)};
172 return new KvpValue {t};
176 dom_tree_to_gdate_kvp_value (xmlNodePtr node)
178 auto date = dom_tree_to_gdate (node);
179 if (!date)
return nullptr;
180 auto rv{
new KvpValue {*date}};
186 string_to_binary (
const gchar* str,
void** v, guint64* data_len)
192 g_return_val_if_fail (v != NULL, FALSE);
193 g_return_val_if_fail (data_len != NULL, FALSE);
195 str_len = strlen (str);
200 if ((str_len % 2) != 0)
202 *data_len = str_len / 2;
203 data = g_new0 (guchar, *data_len);
205 for (j = 0, i = 0; i < str_len; i += 2, j++)
211 tmpstr[1] = str[i + 1];
214 converted = strtol (tmpstr, NULL, 16);
216 data[j] = (
unsigned char)converted;
224 static KvpValue* dom_tree_to_kvp_value (xmlNodePtr node);
226 KvpFrame* dom_tree_to_kvp_frame (xmlNodePtr node);
229 dom_tree_to_list_kvp_value (xmlNodePtr node)
233 KvpValue* ret = NULL;
235 for (mark = node->xmlChildrenNode; mark; mark = mark->next)
239 if (g_strcmp0 ((
char*)mark->name,
"text") == 0)
242 new_val = dom_tree_to_kvp_value (mark);
245 list = g_list_prepend (list, (gpointer)new_val);
249 list = g_list_reverse (list);
251 ret =
new KvpValue {list};
257 dom_tree_to_frame_kvp_value (xmlNodePtr node)
259 KvpFrame* frame = dom_tree_to_kvp_frame (node);
260 return frame ?
new KvpValue {frame} :
nullptr;
267 KvpValue* (*converter) (xmlNodePtr node);
274 {
"integer", dom_tree_to_integer_kvp_value },
275 {
"double", dom_tree_to_double_kvp_value },
276 {
"numeric", dom_tree_to_numeric_kvp_value },
277 {
"string", dom_tree_to_string_kvp_value },
278 {
"guid", dom_tree_to_guid_kvp_value },
279 {
"timespec", dom_tree_to_time64_kvp_value },
280 {
"gdate", dom_tree_to_gdate_kvp_value },
281 {
"list", dom_tree_to_list_kvp_value },
282 {
"frame", dom_tree_to_frame_kvp_value },
287 dom_tree_to_kvp_value (xmlNodePtr node)
291 KvpValue* ret = NULL;
293 xml_type = xmlGetProp (node, BAD_CAST
"type");
295 for (mark = val_converters; mark->tag; mark++)
297 if (g_strcmp0 (reinterpret_cast<char*>(xml_type), mark->tag) == 0)
299 ret = (mark->converter) (node);
314 dom_tree_to_kvp_frame_given (xmlNodePtr node, KvpFrame* frame)
318 g_return_val_if_fail (node, FALSE);
319 g_return_val_if_fail (frame, FALSE);
321 for (mark = node->xmlChildrenNode; mark; mark = mark->next)
323 if (g_strcmp0 ((
char*)mark->name,
"slot") == 0)
326 const gchar* key = NULL;
327 std::optional<std::string> maybe_key;
328 KvpValue* val = NULL;
330 for (mark2 = mark->xmlChildrenNode; mark2; mark2 = mark2->next)
332 if (g_strcmp0 ((
char*)mark2->name,
"slot:key") == 0)
334 key = dom_node_to_text (mark2);
337 maybe_key = dom_tree_to_text (mark2);
338 key = maybe_key ? maybe_key->c_str() :
nullptr;
341 else if (g_strcmp0 ((
char*)mark2->name,
"slot:value") == 0)
343 val = dom_tree_to_kvp_value (mark2);
357 delete frame->set ({key}, val);
372 dom_tree_to_kvp_frame (xmlNodePtr node)
374 g_return_val_if_fail (node, NULL);
376 auto ret =
new KvpFrame;
378 if (dom_tree_to_kvp_frame_given (node, ret))
386 dom_tree_create_instance_slots (xmlNodePtr node,
QofInstance* inst)
388 KvpFrame* frame = qof_instance_get_slots (inst);
389 return dom_tree_to_kvp_frame_given (node, frame);
392 std::optional<std::string>
393 dom_tree_to_text (xmlNodePtr tree)
407 g_return_val_if_fail (tree, std::nullopt);
410 if (!tree->xmlChildrenNode)
412 DEBUG (
"No children");
416 temp = (
char*)xmlNodeListGetString (NULL, tree->xmlChildrenNode, TRUE);
419 DEBUG (
"Null string");
423 DEBUG (
"node string [%s]", (temp == NULL ?
"(null)" : temp));
430 dom_tree_to_gnc_numeric (xmlNodePtr node)
432 auto node_to_numeric = [](
auto txt)
437 return apply_xmlnode_text<gnc_numeric> (node_to_numeric, node, gnc_numeric_zero());
442 dom_tree_to_time64 (xmlNodePtr node)
456 gboolean seen = FALSE;
459 for (n = node->xmlChildrenNode; n; n = n->next)
463 case XML_COMMENT_NODE:
466 case XML_ELEMENT_NODE:
467 if (g_strcmp0 (
"ts:date", (
char*)n->name) == 0)
478 PERR (
"unexpected sub-node.");
486 PERR (
"no ts:date node found.");
494 dom_tree_to_gdate (xmlNodePtr node)
505 gboolean seen_date = FALSE;
508 auto try_setting_date = [&ret](
const char *content) ->
bool 510 gint year = 0, month = 0, day = 0;
511 if (sscanf (content,
"%d-%d-%d", &year, &month, &day) != 3)
return false;
512 g_date_set_dmy (&ret, day, static_cast<GDateMonth>(month), year);
513 return (g_date_valid (&ret));
517 g_date_clear (&ret, 1);
519 for (n = node->xmlChildrenNode; n; n = n->next)
523 case XML_COMMENT_NODE:
526 case XML_ELEMENT_NODE:
527 if (g_strcmp0 (
"gdate", (
char*)n->name) == 0)
529 if (seen_date || !apply_xmlnode_text<bool> (try_setting_date, n))
535 PERR (
"unexpected sub-node.");
542 PWARN (
"no gdate node found.");
546 return g_date_copy (&ret);
556 gnc_strstrip (std::string_view sv)
558 while (!sv.empty () && g_ascii_isspace (sv.front())) sv.remove_prefix (1);
559 while (!sv.empty () && g_ascii_isspace (sv.back())) sv.remove_suffix (1);
560 return std::string (sv);
563 static std::optional<CommodityRef>
564 parse_commodity_ref (xmlNodePtr node, QofBook* book)
577 bool space_set{
false};
581 if (!node)
return {};
582 if (!node->xmlChildrenNode)
return {};
584 for (n = node->xmlChildrenNode; n; n = n->next)
588 case XML_COMMENT_NODE:
591 case XML_ELEMENT_NODE:
592 if (g_strcmp0 (
"cmdty:space", (
char*)n->name) == 0)
598 rv.space = apply_xmlnode_text<std::string> (gnc_strstrip, n);
601 else if (g_strcmp0 (
"cmdty:id", (
char*)n->name) == 0)
607 rv.id = apply_xmlnode_text<std::string> (gnc_strstrip, n);
612 PERR (
"unexpected sub-node.");
617 if (space_set && id_set)
624 dom_tree_to_commodity_ref_no_engine (xmlNodePtr node, QofBook* book)
626 auto ref = parse_commodity_ref (node, book);
636 dom_tree_to_commodity_ref (xmlNodePtr node, QofBook* book)
639 gnc_commodity_table*
table;
641 auto ref = parse_commodity_ref (node, book);
648 g_return_val_if_fail (
table != NULL, NULL);
650 ret = gnc_commodity_table_lookup (
table, ref->space.c_str(), ref->id.c_str());
652 g_return_val_if_fail (ret != NULL, NULL);
663 for (; handlers->tag != NULL; handlers++)
665 handlers->gotten = 0;
669 static inline gboolean
673 for (; handlers->tag != NULL; handlers++)
675 if (handlers->required && ! handlers->gotten)
677 PERR (
"Not defined and it should be: %s",
678 handlers->tag ? handlers->tag :
"(null)");
686 static inline gboolean
687 gnc_xml_set_data (
const gchar* tag, xmlNodePtr node, gpointer item,
690 for (; handlers->tag != NULL; handlers++)
692 if (g_strcmp0 (tag, handlers->tag) == 0)
694 (handlers->handler) (node, item);
695 handlers->gotten = TRUE;
702 PERR (
"Unhandled tag: %s",
703 tag ? tag :
"(null)");
715 gboolean successful = TRUE;
717 dom_tree_handlers_reset (handlers);
719 for (achild = node->xmlChildrenNode; achild; achild = achild->next)
722 if (g_strcmp0 ((
char*)achild->name,
"text") == 0)
725 if (!gnc_xml_set_data ((
char*)achild->name, achild, data, handlers))
727 PERR (
"gnc_xml_set_data failed");
733 if (!dom_tree_handlers_all_gotten_p (handlers))
735 PERR (
"didn't find all of the expected tags in the input");
743 dom_tree_valid_time64 (
time64 val,
const xmlChar * name)
745 if (val != INT64_MAX)
747 g_warning (
"Invalid timestamp in data file. Look for a '%s' entry " 748 "with a year outside of the valid range: 1400..10000", name);
time64 gnc_iso8601_to_time64_gmt(const gchar *)
The gnc_iso8601_to_time64_gmt() routine converts an ISO-8601 style date/time string to time64...
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
#define DEBUG(format, args...)
Print a debugging message.
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
#define PERR(format, args...)
Log a serious error.
#define PWARN(format, args...)
Log a warning.
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Create a new commodity.
All type declarations for the whole Gnucash engine.
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
The type used to store guids in C.