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