1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * metadata-editor.c
5 * Copyright (C) 2016, 2017 Ben Touchette
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <gexiv2/gexiv2.h>
24
25 #include <libgimp/gimp.h>
26 #include <libgimp/gimpui.h>
27
28 #include "libgimp/stdplugins-intl.h"
29
30 #include "metadata-misc.h"
31 #include "metadata-xml.h"
32 #include "metadata-tags.h"
33
34 extern gboolean gimpmetadata;
35 extern gboolean force_write;
36
37 gboolean xmptag;
38 gboolean iptctag;
39 gboolean tagvalue;
40 gboolean taglistvalue;
41 gboolean tagname;
42 gboolean tagmode;
43 gboolean listelement;
44 gboolean element;
45 gchar *str_tag_value;
46 gchar *str_tag_name;
47 gchar *str_tag_mode;
48 gchar *str_element;
49 gchar *list_tag_data[256][256];
50 gint row_count = 0;
51 gint item_count = 0;
52
53
54 static void get_list_elements (GString *xmldata,
55 int element_count,
56 gchar **rowtagdata);
57
58
59 void
xml_parser_start_element(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)60 xml_parser_start_element (GMarkupParseContext *context,
61 const gchar *element_name,
62 const gchar **attribute_names,
63 const gchar **attribute_values,
64 gpointer user_data,
65 GError **error)
66 {
67 if (strcmp (element_name, "gimp-metadata") == 0)
68 {
69 gimpmetadata = TRUE;
70 }
71 else if (strcmp (element_name, "iptc-tag") == 0)
72 {
73 item_count = 0;
74 row_count = 0;
75 iptctag = TRUE;
76 }
77 else if (strcmp (element_name, "xmp-tag") == 0)
78 {
79 item_count = 0;
80 row_count = 0;
81 xmptag = TRUE;
82 }
83 else if (strcmp (element_name, "tag-value") == 0)
84 {
85 tagvalue = TRUE;
86 }
87 else if (strcmp (element_name, "tag-list-value") == 0)
88 {
89 taglistvalue = TRUE;
90 }
91 else if (strcmp (element_name, "tag-name") == 0)
92 {
93 tagname = TRUE;
94 }
95 else if (strcmp (element_name, "tag-mode") == 0)
96 {
97 tagmode = TRUE;
98 }
99 else if (strcmp (element_name, "list-element") == 0)
100 {
101 listelement = TRUE;
102 row_count += 1;
103 }
104 else if (strcmp (element_name, "element") == 0)
105 {
106 element = TRUE;
107 item_count += 1;
108 }
109 }
110
111 void
xml_parser_data(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)112 xml_parser_data (GMarkupParseContext *context,
113 const gchar *text,
114 gsize text_len,
115 gpointer user_data,
116 GError **error)
117 {
118 if (tagvalue)
119 {
120 if (str_tag_value)
121 g_free(str_tag_value);
122
123 if (text)
124 str_tag_value = g_strdup(text);
125 else
126 str_tag_value = g_strconcat("", NULL);
127 }
128 else if (tagname)
129 {
130 if (str_tag_name)
131 g_free(str_tag_name);
132
133 if (text)
134 str_tag_name = g_strdup(text);
135 else
136 str_tag_name = g_strconcat("", NULL);
137 }
138 else if (tagmode)
139 {
140 if (str_tag_mode)
141 g_free(str_tag_mode);
142
143 if (text)
144 str_tag_mode = g_strdup(text);
145 else
146 str_tag_mode = g_strconcat("", NULL);
147 }
148 else if (element)
149 {
150 if (str_element)
151 g_free(str_element);
152
153 if (text)
154 str_element = g_strdup(text);
155 else
156 str_element = g_strconcat("", NULL);
157 }
158 }
159
160 void
set_tag_ui(metadata_editor * args,gint index,gchar * name,gchar * value,gchar * mode)161 set_tag_ui (metadata_editor *args,
162 gint index,
163 gchar *name,
164 gchar *value,
165 gchar* mode)
166 {
167 GtkWidget *widget;
168
169 widget = GTK_WIDGET (gtk_builder_get_object (args->builder, str_tag_name));
170
171 if (!strcmp ("single", mode))
172 {
173 GtkEntry *entry_widget;
174 gchar *value_utf;
175
176 value_utf = g_locale_to_utf8 (str_tag_value, -1, NULL, NULL, NULL);
177 entry_widget = GTK_ENTRY (widget);
178 gtk_entry_set_text (entry_widget, value_utf);
179 g_free (value_utf);
180 }
181 else if (!strcmp ("multi", mode))
182 {
183 GtkTextView *text_view;
184 GtkTextBuffer *buffer;
185 gchar *value_utf;
186
187 value_utf = g_locale_to_utf8 (str_tag_value, -1, NULL, NULL, NULL);
188 text_view = GTK_TEXT_VIEW (widget);
189 buffer = gtk_text_view_get_buffer (text_view);
190 gtk_text_buffer_set_text (buffer, value_utf, -1);
191 g_free (value_utf);
192 }
193 else if (!strcmp ("combo", mode))
194 {
195 gint32 value;
196 gchar *value_utf;
197
198 value_utf = g_locale_to_utf8 (str_tag_value, -1, NULL, NULL, NULL);
199 value = atoi(value_utf);
200 gtk_combo_box_set_active (GTK_COMBO_BOX(widget), value);
201 g_free (value_utf);
202 }
203 else if (!strcmp ("list", mode))
204 {
205 GtkTreeModel *treemodel;
206 GtkListStore *liststore;
207 GtkTreeIter iter;
208 gint number_of_rows;
209 gint row;
210 gint item;
211
212 liststore = GTK_LIST_STORE(gtk_tree_view_get_model((GtkTreeView *)widget));
213 treemodel = GTK_TREE_MODEL (liststore);
214 number_of_rows =
215 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore), NULL);
216
217 /* Clear all current values */
218 for (row = number_of_rows; row > -1; row--)
219 {
220 if (gtk_tree_model_iter_nth_child(treemodel, &iter, NULL, row))
221 {
222 gtk_list_store_remove(liststore, &iter);
223 }
224 }
225 /* Add new values values */
226 if (!strcmp (LICENSOR_HEADER, name))
227 {
228 for (row = 1; row < row_count+1; row++)
229 {
230 gtk_list_store_append (liststore, &iter);
231 gtk_list_store_set (liststore, &iter,
232 COL_LICENSOR_NAME, list_tag_data[row][1],
233 COL_LICENSOR_ID, list_tag_data[row][2],
234 COL_LICENSOR_PHONE1, list_tag_data[row][3],
235 COL_LICENSOR_PHONE_TYPE1, list_tag_data[row][4],
236 COL_LICENSOR_PHONE2, list_tag_data[row][5],
237 COL_LICENSOR_PHONE_TYPE2, list_tag_data[row][6],
238 COL_LICENSOR_EMAIL, list_tag_data[row][7],
239 COL_LICENSOR_WEB, list_tag_data[row][8],
240 -1);
241 for (item = 1; item < n_licensor + 1; item++)
242 {
243 if (list_tag_data[row][item])
244 {
245 if (list_tag_data[row][item])
246 g_free(list_tag_data[row][item]);
247 }
248 }
249 }
250
251 if (row_count < 2)
252 {
253 for (row = 0; row < 2 - row_count; row++)
254 {
255 gtk_list_store_append (liststore, &iter);
256 gtk_list_store_set (liststore, &iter,
257 COL_LICENSOR_NAME, NULL,
258 COL_LICENSOR_ID, NULL,
259 COL_LICENSOR_PHONE1, NULL,
260 COL_LICENSOR_PHONE_TYPE1, NULL,
261 COL_LICENSOR_PHONE2, NULL,
262 COL_LICENSOR_PHONE_TYPE2, NULL,
263 COL_LICENSOR_EMAIL, NULL,
264 COL_LICENSOR_WEB, NULL,
265 -1);
266 }
267 }
268 }
269 else if (!strcmp (IMAGECREATOR_HEADER, name))
270 {
271 for (row = 1; row < row_count+1; row++)
272 {
273 gtk_list_store_append (liststore, &iter);
274 gtk_list_store_set (liststore, &iter,
275 COL_IMG_CR8_NAME, list_tag_data[row][1],
276 COL_IMG_CR8_ID, list_tag_data[row][2],
277 -1);
278 for (item = 1; item < n_imagecreator + 1; item++)
279 {
280 if (list_tag_data[row][item])
281 {
282 if (list_tag_data[row][item])
283 g_free(list_tag_data[row][item]);
284 }
285 }
286 }
287
288 if (row_count < 2)
289 {
290 for (row = 0; row < 2 - row_count; row++)
291 {
292 gtk_list_store_append (liststore, &iter);
293 gtk_list_store_set (liststore, &iter,
294 COL_IMG_CR8_NAME, NULL,
295 COL_IMG_CR8_ID, NULL,
296 -1);
297 }
298 }
299 }
300 else if (!strcmp (ARTWORKOROBJECT_HEADER, name))
301 {
302 for (row = 1; row < row_count+1; row++)
303 {
304 gtk_list_store_append (liststore, &iter);
305 gtk_list_store_set (liststore, &iter,
306 COL_AOO_TITLE, list_tag_data[row][1],
307 COL_AOO_DATE_CREAT, list_tag_data[row][2],
308 COL_AOO_CREATOR, list_tag_data[row][3],
309 COL_AOO_SOURCE, list_tag_data[row][4],
310 COL_AOO_SRC_INV_ID, list_tag_data[row][5],
311 COL_AOO_CR_NOT, list_tag_data[row][6],
312 -1);
313 for (item = 1; item < n_artworkorobject + 1; item++)
314 {
315 if (list_tag_data[row][item])
316 {
317 if (list_tag_data[row][item])
318 g_free(list_tag_data[row][item]);
319 }
320 }
321 }
322
323 if (row_count < 2)
324 {
325 for (row = 0; row < 2 - row_count; row++)
326 {
327 gtk_list_store_append (liststore, &iter);
328 gtk_list_store_set (liststore, &iter,
329 COL_AOO_TITLE, NULL,
330 COL_AOO_DATE_CREAT, NULL,
331 COL_AOO_CREATOR, NULL,
332 COL_AOO_SOURCE, NULL,
333 COL_AOO_SRC_INV_ID, NULL,
334 COL_AOO_CR_NOT, NULL,
335 -1);
336 }
337 }
338 }
339 else if (!strcmp (REGISTRYID_HEADER, name))
340 {
341 for (row = 1; row < row_count+1; row++)
342 {
343 gtk_list_store_append (liststore, &iter);
344 gtk_list_store_set (liststore, &iter,
345 COL_REGISTRY_ORG_ID, list_tag_data[row][1],
346 COL_REGISTRY_ITEM_ID, list_tag_data[row][2],
347 -1);
348 for (item = 1; item < n_registryid + 1; item++)
349 {
350 if (list_tag_data[row][item])
351 {
352 if (list_tag_data[row][item])
353 g_free(list_tag_data[row][item]);
354 }
355 }
356 }
357
358 if (row_count < 2)
359 {
360 for (row = 0; row < 2 - row_count; row++)
361 {
362 gtk_list_store_append (liststore, &iter);
363 gtk_list_store_set (liststore, &iter,
364 COL_REGISTRY_ORG_ID, NULL,
365 COL_REGISTRY_ITEM_ID, NULL,
366 -1);
367 }
368 }
369 }
370 else if (!strcmp (COPYRIGHTOWNER_HEADER, name))
371 {
372 if (row_count > 0)
373 {
374 for (row = 1; row < row_count+1; row++)
375 {
376 gtk_list_store_append (liststore, &iter);
377 gtk_list_store_set (liststore, &iter,
378 COL_CR_OWNER_NAME, list_tag_data[row][1],
379 COL_CR_OWNER_ID, list_tag_data[row][2],
380 -1);
381 for (item = 1; item < n_copyrightowner + 1; item++)
382 {
383 if (list_tag_data[row][item])
384 {
385 if (list_tag_data[row][item])
386 g_free(list_tag_data[row][item]);
387 }
388 }
389 }
390 }
391
392 if (row_count < 2)
393 {
394 for (row = 0; row < 2 - row_count; row++)
395 {
396 gtk_list_store_append (liststore, &iter);
397 gtk_list_store_set (liststore, &iter,
398 COL_CR_OWNER_NAME, NULL,
399 COL_CR_OWNER_ID, NULL,
400 -1);
401 }
402 }
403 }
404 else if (!strcmp (LOCATIONSHOWN_HEADER, name))
405 {
406 for (row = 1; row < row_count+1; row++)
407 {
408 gtk_list_store_append (liststore, &iter);
409 gtk_list_store_set (liststore, &iter,
410 COL_LOC_SHO_SUB_LOC, list_tag_data[row][1],
411 COL_LOC_SHO_CITY, list_tag_data[row][2],
412 COL_LOC_SHO_STATE_PROV, list_tag_data[row][3],
413 COL_LOC_SHO_CNTRY, list_tag_data[row][4],
414 COL_LOC_SHO_CNTRY_ISO, list_tag_data[row][5],
415 COL_LOC_SHO_CNTRY_WRLD_REG, list_tag_data[row][6],
416 -1);
417 for (item = 1; item < n_locationshown + 1; item++)
418 {
419 if (list_tag_data[row][item])
420 {
421 if (list_tag_data[row][item])
422 g_free(list_tag_data[row][item]);
423 }
424 }
425 }
426
427 if (row_count < 2)
428 {
429 for (row = 0; row < 2 - row_count; row++)
430 {
431 gtk_list_store_append (liststore, &iter);
432 gtk_list_store_set (liststore, &iter,
433 COL_LOC_SHO_SUB_LOC, NULL,
434 COL_LOC_SHO_CITY, NULL,
435 COL_LOC_SHO_STATE_PROV, NULL,
436 COL_LOC_SHO_CNTRY, NULL,
437 COL_LOC_SHO_CNTRY_ISO, NULL,
438 COL_LOC_SHO_CNTRY_WRLD_REG, NULL,
439 -1);
440 }
441 }
442 }
443 else if (!strcmp ("Xmp.iptcExt.OrganisationInImageName", name))
444 {
445 for (row = 1; row < row_count+1; row++)
446 {
447 gtk_list_store_append (liststore, &iter);
448 gtk_list_store_set (liststore, &iter,
449 COL_ORG_IMG_NAME, list_tag_data[row][1],
450 -1);
451 if (list_tag_data[row][1])
452 {
453 if (list_tag_data[row][1])
454 g_free(list_tag_data[row][1]);
455 }
456 }
457
458 if (row_count < 2)
459 {
460 for (row = 0; row < 2 - row_count; row++)
461 {
462 gtk_list_store_append (liststore, &iter);
463 gtk_list_store_set (liststore, &iter,
464 COL_ORG_IMG_NAME, NULL,
465 -1);
466 }
467 }
468 }
469 else if (!strcmp ("Xmp.iptcExt.OrganisationInImageCode", name))
470 {
471 for (row = 1; row < row_count+1; row++)
472 {
473 gtk_list_store_append (liststore, &iter);
474 gtk_list_store_set (liststore, &iter,
475 COL_ORG_IMG_CODE, list_tag_data[row][1],
476 -1);
477 if (list_tag_data[row][1])
478 {
479 if (list_tag_data[row][1])
480 g_free(list_tag_data[row][1]);
481 }
482 }
483
484 if (row_count < 2)
485 {
486 for (row = 0; row < 2 - row_count; row++)
487 {
488 gtk_list_store_append (liststore, &iter);
489 gtk_list_store_set (liststore, &iter,
490 COL_ORG_IMG_CODE, NULL,
491 -1);
492 }
493 }
494 }
495 else if (!strcmp ("Xmp.plus.PropertyReleaseID", name))
496 {
497 for (row = 1; row < row_count+1; row++)
498 {
499 gtk_list_store_append (liststore, &iter);
500 gtk_list_store_set (liststore, &iter,
501 COL_PROP_REL_ID, list_tag_data[row][1],
502 -1);
503 if (list_tag_data[row][1])
504 {
505 if (list_tag_data[row][1])
506 g_free(list_tag_data[row][1]);
507 }
508 }
509
510 if (row_count < 2)
511 {
512 for (row = 0; row < 2 - row_count; row++)
513 {
514 gtk_list_store_append (liststore, &iter);
515 gtk_list_store_set (liststore, &iter,
516 COL_PROP_REL_ID, NULL,
517 -1);
518 }
519 }
520 }
521 else if (!strcmp ("Xmp.plus.ModelReleaseID", name))
522 {
523 for (row = 1; row < row_count+1; row++)
524 {
525 gtk_list_store_append (liststore, &iter);
526 gtk_list_store_set (liststore, &iter,
527 COL_MOD_REL_ID, list_tag_data[row][1],
528 -1);
529 if (list_tag_data[row][1])
530 {
531 if (list_tag_data[row][1])
532 g_free(list_tag_data[row][1]);
533 }
534 }
535
536 if (row_count < 2)
537 {
538 for (row = 0; row < 2 - row_count; row++)
539 {
540 gtk_list_store_append (liststore, &iter);
541 gtk_list_store_set (liststore, &iter,
542 COL_MOD_REL_ID, NULL,
543 -1);
544 }
545 }
546 }
547 }
548 }
549
550 const gchar *
get_tag_ui_text(metadata_editor * args,gchar * name,gchar * mode)551 get_tag_ui_text (metadata_editor *args,
552 gchar *name,
553 gchar *mode)
554 {
555 GObject *object;
556
557 object = gtk_builder_get_object (args->builder, name);
558
559 if (! strcmp ("single", mode))
560 {
561 GtkEntry *entry = GTK_ENTRY (object);
562 return gtk_entry_get_text (entry);
563 }
564 else if (!strcmp ("multi", mode))
565 {
566 GtkTextView *text_view = GTK_TEXT_VIEW (object);
567 GtkTextBuffer *buffer;
568 GtkTextIter start;
569 GtkTextIter end;
570
571 buffer = gtk_text_view_get_buffer (text_view);
572 gtk_text_buffer_get_start_iter (buffer, &start);
573 gtk_text_buffer_get_end_iter (buffer, &end);
574
575 return gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
576 }
577
578 return NULL;
579 }
580
581 static void
get_list_elements(GString * xmldata,int element_count,gchar ** rowtagdata)582 get_list_elements (GString *xmldata, int element_count, gchar **rowtagdata)
583 {
584 gint list_idx;
585
586 g_string_append (xmldata, "\t\t\t<list-element>\n");
587
588 for (list_idx = 0; list_idx < element_count; list_idx++)
589 {
590 g_string_append (xmldata, "\t\t\t\t<element>");
591
592 if (rowtagdata && rowtagdata[list_idx] && strlen(rowtagdata[list_idx]) > 0)
593 {
594 g_string_append (xmldata, rowtagdata[list_idx]);
595 }
596
597 g_string_append (xmldata, "</element>\n");
598 }
599 g_string_append (xmldata, "\t\t\t</list-element>\n");
600 }
601
602 gchar *
get_tag_ui_list(metadata_editor * args,gchar * name,gchar * mode)603 get_tag_ui_list (metadata_editor *args, gchar *name, gchar *mode)
604 {
605 GObject *object;
606 GtkWidget *widget;
607 GtkTreeModel *treemodel;
608 GtkListStore *liststore;
609 GtkTreeIter iter;
610 GString *xmldata;
611 gint number_of_rows;
612 gint row;
613 gint has_data;
614 gchar *tagdata[256][256];
615
616 has_data = FALSE;
617 xmldata = g_string_new ("");
618
619 object = gtk_builder_get_object (args->builder, name);
620 widget = GTK_WIDGET(object);
621
622 liststore = GTK_LIST_STORE(gtk_tree_view_get_model((GtkTreeView *)widget));
623 treemodel = GTK_TREE_MODEL (liststore);
624 number_of_rows =
625 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore), NULL);
626
627 for (row = 0; row < number_of_rows; row++)
628 {
629 if (gtk_tree_model_iter_nth_child(treemodel, &iter, NULL, row))
630 {
631 if (!strcmp (LICENSOR_HEADER, name))
632 {
633 gtk_tree_model_get (treemodel, &iter,
634 COL_LICENSOR_NAME, &tagdata[row][0],
635 COL_LICENSOR_ID, &tagdata[row][1],
636 COL_LICENSOR_PHONE1, &tagdata[row][2],
637 COL_LICENSOR_PHONE_TYPE1, &tagdata[row][3],
638 COL_LICENSOR_PHONE2, &tagdata[row][4],
639 COL_LICENSOR_PHONE_TYPE2, &tagdata[row][5],
640 COL_LICENSOR_EMAIL, &tagdata[row][6],
641 COL_LICENSOR_WEB, &tagdata[row][7],
642 -1);
643
644 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0) ||
645 (tagdata[row][1] != NULL && strlen(tagdata[row][1]) > 0) ||
646 (tagdata[row][2] != NULL && strlen(tagdata[row][2]) > 0) ||
647 (tagdata[row][3] != NULL && strlen(tagdata[row][3]) > 0) ||
648 (tagdata[row][4] != NULL && strlen(tagdata[row][4]) > 0) ||
649 (tagdata[row][5] != NULL && strlen(tagdata[row][5]) > 0) ||
650 (tagdata[row][6] != NULL && strlen(tagdata[row][6]) > 0) ||
651 (tagdata[row][7] != NULL && strlen(tagdata[row][7]) > 0))
652 {
653
654 has_data = TRUE;
655
656 get_list_elements (xmldata, 8, tagdata[row]);
657 }
658 }
659 else if (!strcmp (COPYRIGHTOWNER_HEADER, name))
660 {
661 gtk_tree_model_get (treemodel, &iter,
662 COL_CR_OWNER_NAME, &tagdata[row][0],
663 COL_CR_OWNER_ID, &tagdata[row][1],
664 -1);
665
666 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0) ||
667 (tagdata[row][1] != NULL && strlen(tagdata[row][1]) > 0))
668 {
669 has_data = TRUE;
670
671 g_string_append (xmldata, "\t\t\t<list-element>\n");
672 g_string_append (xmldata, "\t\t\t\t<element>");
673 g_string_append (xmldata, tagdata[row][0]);
674 g_string_append (xmldata, "</element>\n");
675 g_string_append (xmldata, "\t\t\t\t<element>");
676 g_string_append (xmldata, tagdata[row][1]);
677 g_string_append (xmldata, "</element>\n");
678 g_string_append (xmldata, "\t\t\t</list-element>\n");
679 }
680 }
681 else if (!strcmp (IMAGECREATOR_HEADER, name))
682 {
683 gtk_tree_model_get (treemodel, &iter,
684 COL_IMG_CR8_NAME, &tagdata[row][0],
685 COL_IMG_CR8_ID, &tagdata[row][1],
686 -1);
687
688 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0) ||
689 (tagdata[row][1] != NULL && strlen(tagdata[row][1]) > 0))
690 {
691 has_data = TRUE;
692
693 get_list_elements (xmldata, 2, tagdata[row]);
694 }
695 }
696 else if (!strcmp (ARTWORKOROBJECT_HEADER, name))
697 {
698 gtk_tree_model_get (treemodel, &iter,
699 COL_AOO_TITLE, &tagdata[row][0],
700 COL_AOO_DATE_CREAT, &tagdata[row][1],
701 COL_AOO_CREATOR, &tagdata[row][2],
702 COL_AOO_SOURCE, &tagdata[row][3],
703 COL_AOO_SRC_INV_ID, &tagdata[row][4],
704 COL_AOO_CR_NOT, &tagdata[row][5],
705 -1);
706
707 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0) ||
708 (tagdata[row][1] != NULL && strlen(tagdata[row][1]) > 0) ||
709 (tagdata[row][2] != NULL && strlen(tagdata[row][2]) > 0) ||
710 (tagdata[row][3] != NULL && strlen(tagdata[row][3]) > 0) ||
711 (tagdata[row][4] != NULL && strlen(tagdata[row][4]) > 0) ||
712 (tagdata[row][5] != NULL && strlen(tagdata[row][5]) > 0))
713 {
714 has_data = TRUE;
715
716 get_list_elements (xmldata, 6, tagdata[row]);
717 }
718 }
719 else if (!strcmp (REGISTRYID_HEADER, name))
720 {
721 gtk_tree_model_get (treemodel, &iter,
722 COL_REGISTRY_ORG_ID, &tagdata[row][0],
723 COL_REGISTRY_ITEM_ID, &tagdata[row][1],
724 -1);
725
726 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0) ||
727 (tagdata[row][1] != NULL && strlen(tagdata[row][1]) > 0))
728 {
729 has_data = TRUE;
730
731 get_list_elements (xmldata, 2, tagdata[row]);
732 }
733 }
734 else if (!strcmp (LOCATIONSHOWN_HEADER, name))
735 {
736 gtk_tree_model_get (treemodel, &iter,
737 COL_LOC_SHO_SUB_LOC, &tagdata[row][0],
738 COL_LOC_SHO_CITY, &tagdata[row][1],
739 COL_LOC_SHO_STATE_PROV, &tagdata[row][2],
740 COL_LOC_SHO_CNTRY, &tagdata[row][3],
741 COL_LOC_SHO_CNTRY_ISO, &tagdata[row][4],
742 COL_LOC_SHO_CNTRY_WRLD_REG, &tagdata[row][5],
743 -1);
744
745 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0) ||
746 (tagdata[row][1] != NULL && strlen(tagdata[row][1]) > 0) ||
747 (tagdata[row][2] != NULL && strlen(tagdata[row][2]) > 0) ||
748 (tagdata[row][3] != NULL && strlen(tagdata[row][3]) > 0) ||
749 (tagdata[row][4] != NULL && strlen(tagdata[row][4]) > 0) ||
750 (tagdata[row][5] != NULL && strlen(tagdata[row][5]) > 0))
751 {
752 has_data = TRUE;
753
754 get_list_elements (xmldata, 6, tagdata[row]);
755 }
756 }
757 else if (!strcmp ("Xmp.iptcExt.OrganisationInImageName", name))
758 {
759 gtk_tree_model_get (treemodel, &iter,
760 COL_ORG_IMG_NAME, &tagdata[row][0],
761 -1);
762
763 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0))
764 {
765 has_data = TRUE;
766
767 get_list_elements (xmldata, 1, tagdata[row]);
768 }
769 }
770 else if (!strcmp ("Xmp.iptcExt.OrganisationInImageCode", name))
771 {
772 gtk_tree_model_get (treemodel, &iter,
773 COL_ORG_IMG_CODE, &tagdata[row][0],
774 -1);
775
776 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0))
777 {
778 has_data = TRUE;
779
780 get_list_elements (xmldata, 1, tagdata[row]);
781 }
782 }
783 else if (!strcmp ("Xmp.plus.PropertyReleaseID", name))
784 {
785 gtk_tree_model_get (treemodel, &iter,
786 COL_PROP_REL_ID, &tagdata[row][0],
787 -1);
788
789 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0))
790 {
791 has_data = TRUE;
792
793 get_list_elements (xmldata, 1, tagdata[row]);
794 }
795 }
796 else if (!strcmp ("Xmp.plus.ModelReleaseID", name))
797 {
798 gtk_tree_model_get (treemodel, &iter,
799 COL_MOD_REL_ID, &tagdata[row][0],
800 -1);
801
802 if ((tagdata[row][0] != NULL && strlen(tagdata[row][0]) > 0))
803 {
804 has_data = TRUE;
805
806 get_list_elements (xmldata, 1, tagdata[row]);
807 }
808 }
809 }
810 }
811
812 if (has_data == TRUE)
813 {
814 gchar *xml;
815
816 xml = g_strdup (xmldata->str);
817 g_string_free(xmldata, TRUE);
818 return xml;
819 }
820
821 g_string_free(xmldata, TRUE);
822
823 return NULL;
824 }
825
826 gint
get_tag_ui_combo(metadata_editor * args,gchar * name,gchar * mode)827 get_tag_ui_combo (metadata_editor *args, gchar *name, gchar *mode)
828 {
829 GObject *object;
830 GtkComboBoxText *combo;
831 gint value;
832
833 object = gtk_builder_get_object (args->builder, name);
834
835 combo = GTK_COMBO_BOX_TEXT (object);
836 value = gtk_combo_box_get_active (GTK_COMBO_BOX(combo));
837
838 return value;
839 }
840
841 void
xml_parser_end_element(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)842 xml_parser_end_element (GMarkupParseContext *context,
843 const gchar *element_name,
844 gpointer user_data,
845 GError **error)
846 {
847 metadata_editor *args;
848 int i;
849
850 args = user_data;
851
852 if (strcmp (element_name, "gimp-metadata") == 0)
853 {
854 gimpmetadata = FALSE;
855 }
856 else if (strcmp (element_name, "iptc-tag") == 0)
857 {
858 iptctag = FALSE;
859 #ifdef _ENABLE_IPTC_TAG_
860 if (str_tag_name && str_tag_value)
861 {
862 /* make sure to only allow supported tags */
863 for (i = 0; i < n_equivalent_metadata_tags; i++)
864 {
865 if (strcmp(equivalent_metadata_tags[i].tag, str_tag_name) == 0)
866 {
867 #ifdef _SET_IPTC_TAG_
868 set_tag_ui (args, i, str_tag_name, str_tag_value,
869 equivalent_metadata_tags[i].mode);
870 #endif
871 if (force_write == TRUE)
872 gexiv2_metadata_set_tag_string (args->metadata,
873 str_tag_name,
874 str_tag_value);
875 break;
876 }
877 }
878 }
879 #endif
880 }
881 else if (strcmp (element_name, "xmp-tag") == 0)
882 {
883 xmptag = FALSE;
884 if (strcmp (str_tag_mode, "list") != 0)
885 {
886 if (str_tag_name && str_tag_value)
887 {
888 /* make sure to only allow supported tags */
889 for (i = 0; i < n_default_metadata_tags; i++)
890 {
891 if (strcmp(default_metadata_tags[i].tag, str_tag_name) == 0)
892 {
893 set_tag_ui (args, i, str_tag_name, str_tag_value,
894 default_metadata_tags[i].mode);
895 #ifdef _ENABLE_FORCE_WRITE_
896 if (force_write == TRUE)
897 gexiv2_metadata_set_tag_string (args->metadata,
898 str_tag_name,
899 str_tag_value);
900 #endif
901 break;
902 }
903 }
904 }
905
906 }
907 else if (strcmp (str_tag_mode, "list") == 0)
908 {
909 if (row_count > 0)
910 {
911 /* make sure to only allow supported tags */
912 for (i = 0; i < n_default_metadata_tags; i++)
913 {
914 if (strcmp(default_metadata_tags[i].tag, str_tag_name) == 0)
915 {
916 set_tag_ui (args, i, str_tag_name, str_tag_value,
917 default_metadata_tags[i].mode);
918 #ifdef _ENABLE_FORCE_WRITE_
919 if (force_write == TRUE)
920 gexiv2_metadata_set_tag_string (args->metadata,
921 str_tag_name,
922 str_tag_value);
923 #endif
924 break;
925 }
926 }
927 }
928 row_count = 0;
929 item_count = 0;
930 }
931 }
932 else if (strcmp (element_name, "tag-value") == 0)
933 {
934 tagvalue = FALSE;
935 }
936 else if (strcmp (element_name, "tag-list-value") == 0)
937 {
938 taglistvalue = FALSE;
939 }
940 else if (strcmp (element_name, "tag-name") == 0)
941 {
942 tagname = FALSE;
943 }
944 else if (strcmp (element_name, "tag-mode") == 0)
945 {
946 tagmode = FALSE;
947 }
948 else if (strcmp (element_name, "list-element") == 0)
949 {
950 listelement = FALSE;
951 item_count = 0;
952 }
953 else if (strcmp (element_name, "element") == 0)
954 {
955 element = FALSE;
956 list_tag_data[row_count][item_count] = g_strdup(str_element);
957 }
958 }
959
960 gboolean
xml_parser_parse_file(GimpXmlParser * parser,const gchar * filename,GError ** error)961 xml_parser_parse_file (GimpXmlParser *parser,
962 const gchar *filename,
963 GError **error)
964 {
965 GIOChannel *io;
966 gboolean success;
967
968 g_return_val_if_fail (parser != NULL, FALSE);
969 g_return_val_if_fail (filename != NULL, FALSE);
970 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
971
972 io = g_io_channel_new_file (filename, "r", error);
973 if (!io)
974 return FALSE;
975
976 success = xml_parser_parse_io_channel (parser, io, error);
977
978 g_io_channel_unref (io);
979
980 return success;
981 }
982
983 GimpXmlParser *
xml_parser_new(const GMarkupParser * markup_parser,gpointer user_data)984 xml_parser_new (const GMarkupParser *markup_parser,
985 gpointer user_data)
986 {
987 GimpXmlParser *parser;
988
989 g_return_val_if_fail (markup_parser != NULL, NULL);
990
991 parser = g_slice_new (GimpXmlParser);
992
993 parser->context = g_markup_parse_context_new (markup_parser,
994 0, user_data, NULL);
995
996 return parser;
997 }
998
999 void
xml_parser_free(GimpXmlParser * parser)1000 xml_parser_free (GimpXmlParser *parser)
1001 {
1002 g_return_if_fail (parser != NULL);
1003
1004 g_markup_parse_context_free (parser->context);
1005 g_slice_free (GimpXmlParser, parser);
1006 }
1007
1008 gboolean
parse_encoding(const gchar * text,gint text_len,gchar ** encoding)1009 parse_encoding (const gchar *text,
1010 gint text_len,
1011 gchar **encoding)
1012 {
1013 const gchar *start;
1014 const gchar *end;
1015 gint i;
1016
1017 g_return_val_if_fail (text, FALSE);
1018
1019 if (text_len < 20)
1020 return FALSE;
1021
1022 start = g_strstr_len (text, text_len, "<?xml");
1023 if (!start)
1024 return FALSE;
1025
1026 end = g_strstr_len (start, text_len - (start - text), "?>");
1027 if (!end)
1028 return FALSE;
1029
1030 *encoding = NULL;
1031
1032 text_len = end - start;
1033 if (text_len < 12)
1034 return TRUE;
1035
1036 start = g_strstr_len (start + 1, text_len - 1, "encoding");
1037 if (!start)
1038 return TRUE;
1039
1040 start += 8;
1041
1042 while (start < end && *start == ' ')
1043 start++;
1044
1045 if (*start != '=')
1046 return TRUE;
1047
1048 start++;
1049
1050 while (start < end && *start == ' ')
1051 start++;
1052
1053 if (*start != '\"' && *start != '\'')
1054 return TRUE;
1055
1056 text_len = end - start;
1057 if (text_len < 1)
1058 return TRUE;
1059
1060 for (i = 1; i < text_len; i++)
1061 if (start[i] == start[0])
1062 break;
1063
1064 if (i == text_len || i < 3)
1065 return TRUE;
1066
1067 *encoding = g_strndup (start + 1, i - 1);
1068
1069 return TRUE;
1070 }
1071
1072 gboolean
xml_parser_parse_io_channel(GimpXmlParser * parser,GIOChannel * io,GError ** error)1073 xml_parser_parse_io_channel (GimpXmlParser *parser,
1074 GIOChannel *io,
1075 GError **error)
1076 {
1077 GIOStatus status;
1078 gchar buffer[4096];
1079 gsize len = 0;
1080 gsize bytes;
1081 const gchar *io_encoding;
1082 gchar *encoding = NULL;
1083
1084 g_return_val_if_fail (parser != NULL, FALSE);
1085 g_return_val_if_fail (io != NULL, FALSE);
1086 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1087
1088 io_encoding = g_io_channel_get_encoding (io);
1089 if (g_strcmp0 (io_encoding, "UTF-8"))
1090 {
1091 g_warning ("xml_parser_parse_io_channel():\n"
1092 "The encoding has already been set on this GIOChannel!");
1093 return FALSE;
1094 }
1095
1096 /* try to determine the encoding */
1097
1098 g_io_channel_set_encoding (io, NULL, NULL);
1099
1100 while (len < sizeof (buffer))
1101 {
1102 status = g_io_channel_read_chars (io, buffer + len, 1, &bytes, error);
1103 len += bytes;
1104
1105 if (status == G_IO_STATUS_ERROR)
1106 return FALSE;
1107 if (status == G_IO_STATUS_EOF)
1108 break;
1109
1110 if (parse_encoding (buffer, len, &encoding))
1111 break;
1112 }
1113
1114 if (encoding)
1115 {
1116 if (! g_io_channel_set_encoding (io, encoding, error))
1117 return FALSE;
1118
1119 if (encoding)
1120 g_free (encoding);
1121 }
1122 else
1123 {
1124 g_io_channel_set_encoding (io, "UTF-8", NULL);
1125 }
1126
1127 while (TRUE)
1128 {
1129 if (!g_markup_parse_context_parse (parser->context, buffer, len, error))
1130 return FALSE;
1131
1132 status = g_io_channel_read_chars (io,
1133 buffer, sizeof (buffer), &len, error);
1134
1135 switch (status)
1136 {
1137 case G_IO_STATUS_ERROR:
1138 return FALSE;
1139 case G_IO_STATUS_EOF:
1140 return g_markup_parse_context_end_parse (parser->context, error);
1141 case G_IO_STATUS_NORMAL:
1142 case G_IO_STATUS_AGAIN:
1143 break;
1144 }
1145 }
1146 }
1147
1148