Branch data Line data Source code
1 : : /********************************************************************
2 : : * sixtp-dom-generators.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 : : #define __EXTENSIONS__
26 : :
27 : : #include <config.h>
28 : :
29 : : #include <gnc-date.h>
30 : : #include <cstdint>
31 : :
32 : : #include "gnc-xml-helper.h"
33 : : #include "sixtp-dom-generators.h"
34 : : #include "sixtp-utils.h"
35 : :
36 : : #include <kvp-frame.hpp>
37 : : #include <gnc-datetime.hpp>
38 : :
39 : : static QofLogModule log_module = GNC_MOD_IO;
40 : :
41 : : xmlNodePtr
42 : 0 : boolean_to_dom_tree (const char* tag, gboolean val)
43 : : {
44 : 0 : return text_to_dom_tree (tag, val ? "TRUE" : "FALSE");
45 : : }
46 : :
47 : : xmlNodePtr
48 : 2041 : text_to_dom_tree (const char* tag, const char* str)
49 : : {
50 : 2041 : g_return_val_if_fail (tag, NULL);
51 : 2041 : g_return_val_if_fail (str, NULL);
52 : :
53 : 2041 : xmlNodePtr result = xmlNewNode (NULL, BAD_CAST tag);
54 : 2041 : g_return_val_if_fail (result, NULL);
55 : :
56 : 2041 : gchar* newstr = g_strdup (str);
57 : 2041 : xmlNodeAddContent (result, checked_char_cast (newstr));
58 : 2041 : g_free (newstr);
59 : :
60 : 2041 : return result;
61 : : }
62 : :
63 : : xmlNodePtr
64 : 293 : int_to_dom_tree (const char* tag, gint64 val)
65 : : {
66 : : gchar* text;
67 : : xmlNodePtr result;
68 : :
69 : 293 : text = g_strdup_printf ("%" G_GINT64_FORMAT, val);
70 : 293 : g_return_val_if_fail (text, NULL);
71 : 293 : result = text_to_dom_tree (tag, text);
72 : 293 : g_free (text);
73 : 293 : return result;
74 : : }
75 : :
76 : : xmlNodePtr
77 : 2 : guint_to_dom_tree (const char* tag, guint an_int)
78 : : {
79 : : gchar* text;
80 : : xmlNodePtr result;
81 : :
82 : 2 : text = g_strdup_printf ("%u", an_int);
83 : 2 : g_return_val_if_fail (text, NULL);
84 : 2 : result = text_to_dom_tree (tag, text);
85 : 2 : g_free (text);
86 : 2 : return result;
87 : : }
88 : :
89 : :
90 : : xmlNodePtr
91 : 1258 : guid_to_dom_tree (const char* tag, const GncGUID* gid)
92 : : {
93 : : char guid_str[GUID_ENCODING_LENGTH + 1];
94 : : xmlNodePtr ret;
95 : :
96 : 1258 : ret = xmlNewNode (NULL, BAD_CAST tag);
97 : :
98 : 1258 : xmlSetProp (ret, BAD_CAST "type", BAD_CAST "guid");
99 : :
100 : 1258 : if (!guid_to_string_buff (gid, guid_str))
101 : : {
102 : 0 : PERR ("guid_to_string_buff failed\n");
103 : 0 : return NULL;
104 : : }
105 : :
106 : 1258 : xmlNodeAddContent (ret, BAD_CAST guid_str);
107 : :
108 : 1258 : return ret;
109 : : }
110 : :
111 : : xmlNodePtr
112 : 1169 : commodity_ref_to_dom_tree (const char* tag, const gnc_commodity* c)
113 : : {
114 : : xmlNodePtr ret;
115 : : gchar* name_space, *mnemonic;
116 : :
117 : 1169 : g_return_val_if_fail (c, NULL);
118 : :
119 : 1169 : ret = xmlNewNode (NULL, BAD_CAST tag);
120 : :
121 : 1169 : if (!gnc_commodity_get_namespace (c) || !gnc_commodity_get_mnemonic (c))
122 : : {
123 : 0 : return NULL;
124 : : }
125 : 1169 : name_space = g_strdup (gnc_commodity_get_namespace (c));
126 : 1169 : mnemonic = g_strdup (gnc_commodity_get_mnemonic (c));
127 : 1169 : xmlNewTextChild (ret, NULL, BAD_CAST "cmdty:space",
128 : 1169 : checked_char_cast (name_space));
129 : 1169 : xmlNewTextChild (ret, NULL, BAD_CAST "cmdty:id",
130 : 1169 : checked_char_cast (mnemonic));
131 : 1169 : g_free (name_space);
132 : 1169 : g_free (mnemonic);
133 : 1169 : return ret;
134 : : }
135 : :
136 : : xmlNodePtr
137 : 664 : time64_to_dom_tree (const char* tag, const time64 time)
138 : : {
139 : : xmlNodePtr ret;
140 : 664 : g_return_val_if_fail (time != INT64_MAX, NULL);
141 : 664 : auto date_str = GncDateTime(time).format_iso8601();
142 : 664 : if (date_str.empty())
143 : 0 : return NULL;
144 : 664 : date_str += " +0000"; //Tack on a UTC offset to mollify GnuCash for Android
145 : 664 : ret = xmlNewNode (NULL, BAD_CAST tag);
146 : 664 : xmlNewTextChild (ret, NULL, BAD_CAST "ts:date",
147 : 664 : checked_char_cast (const_cast<char*>(date_str.c_str())));
148 : 664 : return ret;
149 : 664 : }
150 : :
151 : : xmlNodePtr
152 : 8 : gdate_to_dom_tree (const char* tag, const GDate* date)
153 : : {
154 : : xmlNodePtr ret;
155 : 8 : gchar* date_str = NULL;
156 : :
157 : 8 : g_return_val_if_fail (date, NULL);
158 : 8 : date_str = g_new (gchar, 512);
159 : :
160 : 8 : g_date_strftime (date_str, 512, "%Y-%m-%d", date);
161 : :
162 : 8 : ret = xmlNewNode (NULL, BAD_CAST tag);
163 : :
164 : 8 : xmlNewTextChild (ret, NULL, BAD_CAST "gdate", checked_char_cast (date_str));
165 : :
166 : 8 : g_free (date_str);
167 : :
168 : 8 : return ret;
169 : : }
170 : :
171 : : xmlNodePtr
172 : 675 : gnc_numeric_to_dom_tree (const char* tag, const gnc_numeric* num)
173 : : {
174 : : xmlNodePtr ret;
175 : : gchar* numstr;
176 : :
177 : 675 : g_return_val_if_fail (num, NULL);
178 : :
179 : 675 : numstr = gnc_numeric_to_string (*num);
180 : 675 : g_return_val_if_fail (numstr, NULL);
181 : :
182 : 675 : ret = xmlNewNode (NULL, BAD_CAST tag);
183 : :
184 : 675 : xmlNodeAddContent (ret, checked_char_cast (numstr));
185 : :
186 : 675 : g_free (numstr);
187 : :
188 : 675 : return ret;
189 : : }
190 : :
191 : : gchar*
192 : 0 : double_to_string (double value)
193 : : {
194 : : gchar* numstr;
195 : 0 : numstr = g_strdup_printf ("%24.18g", value);
196 : :
197 : 0 : if (!numstr)
198 : : {
199 : 0 : return NULL;
200 : :
201 : : }
202 : : else
203 : : {
204 : 0 : return g_strstrip (numstr);
205 : : }
206 : : }
207 : :
208 : : static void
209 : 1749 : add_text_to_node (xmlNodePtr node, const gchar* type, gchar* val)
210 : : {
211 : 1749 : xmlSetProp (node, BAD_CAST "type", BAD_CAST type);
212 : 1749 : xmlNodeSetContent (node, checked_char_cast (val));
213 : 1749 : }
214 : :
215 : : static void add_kvp_slot (const char* key, KvpValue* value, void* data);
216 : :
217 : : static void
218 : 2744 : add_kvp_value_node (xmlNodePtr node, const gchar* tag, KvpValue* val)
219 : : {
220 : : xmlNodePtr val_node;
221 : :
222 : 2744 : switch (val->get_type ())
223 : : {
224 : 482 : case KvpValue::Type::STRING:
225 : : {
226 : 482 : auto newstr = g_strdup (val->get<const char*> ());
227 : 964 : val_node = xmlNewTextChild (node, NULL, BAD_CAST tag,
228 : 482 : checked_char_cast (newstr));
229 : 482 : g_free (newstr);
230 : 482 : break;
231 : : }
232 : 2 : case KvpValue::Type::TIME64:
233 : 2 : val_node = NULL;
234 : 2 : break;
235 : 2 : case KvpValue::Type::GDATE:
236 : : {
237 : 2 : auto d = val->get<GDate> ();
238 : 2 : val_node = gdate_to_dom_tree (tag, &d);
239 : 2 : xmlAddChild (node, val_node);
240 : 2 : break;
241 : : }
242 : 2258 : default:
243 : 2258 : val_node = xmlNewTextChild (node, NULL, BAD_CAST tag, NULL);
244 : 2258 : break;
245 : : }
246 : :
247 : 2744 : switch (val->get_type ())
248 : : {
249 : 862 : case KvpValue::Type::INT64:
250 : : {
251 : 862 : char *int_str = g_strdup_printf ("%" G_GINT64_FORMAT, val->get<int64_t> ());
252 : 862 : add_text_to_node (val_node, "integer", int_str);
253 : 862 : g_free (int_str);
254 : 862 : break;
255 : : }
256 : 0 : case KvpValue::Type::DOUBLE:
257 : : {
258 : 0 : char *dbl_str = double_to_string (val->get<double> ());
259 : 0 : add_text_to_node (val_node, "double", dbl_str);
260 : 0 : g_free (dbl_str);
261 : 0 : break;
262 : : }
263 : 446 : case KvpValue::Type::NUMERIC:
264 : : {
265 : 446 : char *num_str = gnc_numeric_to_string (val->get<gnc_numeric> ());
266 : 446 : add_text_to_node (val_node, "numeric", num_str);
267 : 446 : g_free (num_str);
268 : 446 : break;
269 : : }
270 : 482 : case KvpValue::Type::STRING:
271 : 482 : xmlSetProp (val_node, BAD_CAST "type", BAD_CAST "string");
272 : 482 : break;
273 : 441 : case KvpValue::Type::GUID:
274 : : {
275 : : gchar guidstr[GUID_ENCODING_LENGTH + 1];
276 : 441 : guid_to_string_buff (val->get<GncGUID*> (), guidstr);
277 : 441 : add_text_to_node (val_node, "guid", guidstr);
278 : 441 : break;
279 : : }
280 : : /* Note: The type attribute must remain 'timespec' to maintain
281 : : * compatibility.
282 : : */
283 : 2 : case KvpValue::Type::TIME64:
284 : : {
285 : 2 : auto t = val->get<Time64> ();
286 : 2 : val_node = time64_to_dom_tree (tag, t.t);
287 : 2 : xmlSetProp (val_node, BAD_CAST "type", BAD_CAST "timespec");
288 : 2 : xmlAddChild (node, val_node);
289 : 2 : break;
290 : : }
291 : 2 : case KvpValue::Type::GDATE:
292 : 2 : xmlSetProp (val_node, BAD_CAST "type", BAD_CAST "gdate");
293 : 2 : break;
294 : 254 : case KvpValue::Type::GLIST:
295 : 254 : xmlSetProp (val_node, BAD_CAST "type", BAD_CAST "list");
296 : 1014 : for (auto cursor = val->get<GList*> (); cursor; cursor = cursor->next)
297 : : {
298 : 760 : auto val = static_cast<KvpValue*> (cursor->data);
299 : 760 : add_kvp_value_node (val_node, "slot:value", val);
300 : : }
301 : 254 : break;
302 : 255 : case KvpValue::Type::FRAME:
303 : : {
304 : 255 : xmlSetProp (val_node, BAD_CAST "type", BAD_CAST "frame");
305 : :
306 : 255 : auto frame = val->get<KvpFrame*> ();
307 : 255 : if (!frame)
308 : 0 : break;
309 : 255 : frame->for_each_slot_temp (&add_kvp_slot, val_node);
310 : 255 : break;
311 : : }
312 : 0 : default:
313 : 0 : break;
314 : : }
315 : 2744 : }
316 : :
317 : : static void
318 : 1984 : add_kvp_slot (const char* key, KvpValue* value, void* data)
319 : : {
320 : 1984 : auto newkey = g_strdup ((gchar*)key);
321 : 1984 : auto node = static_cast<xmlNodePtr> (data);
322 : 1984 : auto slot_node = xmlNewChild (node, NULL, BAD_CAST "slot", NULL);
323 : :
324 : 1984 : xmlNewTextChild (slot_node, NULL, BAD_CAST "slot:key",
325 : 1984 : checked_char_cast (newkey));
326 : 1984 : g_free (newkey);
327 : 1984 : add_kvp_value_node (slot_node, "slot:value", value);
328 : 1984 : }
329 : :
330 : : xmlNodePtr
331 : 1395 : qof_instance_slots_to_dom_tree (const char* tag, const QofInstance* inst)
332 : : {
333 : : xmlNodePtr ret;
334 : 1395 : KvpFrame* frame = qof_instance_get_slots (inst);
335 : 1395 : if (!frame || frame->empty())
336 : 1160 : return nullptr;
337 : :
338 : 235 : ret = xmlNewNode (nullptr, BAD_CAST tag);
339 : 235 : frame->for_each_slot_temp (&add_kvp_slot, ret);
340 : 235 : return ret;
341 : : }
|