Code

Applying fixes for gcc 4.3 build issues (closes LP: #169115)
[inkscape.git] / src / dialogs / rdf.cpp
1 /**
2  * \brief  RDF manipulation functions
3  *
4  * FIXME: move these to xml/ instead of dialogs/
5  *
6  * Authors:
7  *   Kees Cook <kees@outflux.net>
8  *   Jon Phillips <jon@rejon.org>
9  *
10  * Copyright (C) 2004 Kees Cook <kees@outflux.net>
11  * Copyright (C) 2006 Jon Phillips <jon@rejon.org>
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  *
15  */
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
23 #include "xml/repr.h"
24 #include "rdf.h"
25 #include "sp-item-group.h"
27 /*
29    Example RDF XML from various places...
30  
31 <rdf:RDF xmlns="http://creativecommons.org/ns#"
32     xmlns:dc="http://purl.org/dc/elements/1.1/"
33     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
34 <Work rdf:about="">
35    <dc:title>title of work</dc:title>
36    <dc:date>year</dc:date>
37    <dc:description>description of work</dc:description>
38    <dc:creator><Agent>
39       <dc:title>creator</dc:title>
40    </Agent></dc:creator>
41    <dc:rights><Agent>
42       <dc:title>holder</dc:title>
43    </Agent></dc:rights>
44    <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
45    <dc:source rdf:resource="source"/>
46    <license rdf:resource="http://creativecommons.org/licenses/by/2.0/" 
47 />
48 </Work>
51   <rdf:RDF xmlns="http://creativecommons.org/ns#"
52       xmlns:dc="http://purl.org/dc/elements/1.1/"
53       xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
54   <Work rdf:about="">
55      <dc:title>SVG Road Signs</dc:title>
56      <dc:rights><Agent>
57         <dc:title>John Cliff</dc:title>
58      </Agent></dc:rights>
59      <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
60      <license rdf:resource="http://creativecommons.org/ns#PublicDomain" />
61   </Work>
62   
63   <License rdf:about="http://creativecommons.org/ns#PublicDomain">
64      <permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
65      <permits rdf:resource="http://creativecommons.org/ns#Distribution" />
66      <permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
67   </License>
68   
69 </rdf:RDF>
72 Bag example:
74 <dc:subject>
75 <rdf:Bag>
76 <rdf:li>open clip art logo</rdf:li>
77 <rdf:li>images</rdf:li>
78 <rdf:li>logo</rdf:li>
79 <rdf:li>clip art</rdf:li>
80 <rdf:li>ocal</rdf:li>
81 <rdf:li>logotype</rdf:li>
82 <rdf:li>filetype</rdf:li>
83 </rdf:Bag>
84 </dc:subject>
87 */
89 struct rdf_double_t rdf_license_empty [] = {
90     { NULL, NULL }
91 };
93 struct rdf_double_t rdf_license_cc_a [] = {
94     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
95     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
96     { "cc:requires", "http://creativecommons.org/ns#Notice", },
97     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
98     { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
99     { NULL, NULL }
100 };
102 struct rdf_double_t rdf_license_cc_a_sa [] = {
103     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
104     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
105     { "cc:requires", "http://creativecommons.org/ns#Notice", },
106     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
107     { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
108     { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
109     { NULL, NULL }
110 };
112 struct rdf_double_t rdf_license_cc_a_nd [] = {
113     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
114     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
115     { "cc:requires", "http://creativecommons.org/ns#Notice", },
116     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
117     { NULL, NULL }
118 };
120 struct rdf_double_t rdf_license_cc_a_nc [] = {
121     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
122     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
123     { "cc:requires", "http://creativecommons.org/ns#Notice", },
124     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
125     { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
126     { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
127     { NULL, NULL }
128 };
130 struct rdf_double_t rdf_license_cc_a_nc_sa [] = {
131     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
132     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
133     { "cc:requires", "http://creativecommons.org/ns#Notice", },
134     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
135     { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
136     { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
137     { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
138     { NULL, NULL }
139 };
141 struct rdf_double_t rdf_license_cc_a_nc_nd [] = {
142     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
143     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
144     { "cc:requires", "http://creativecommons.org/ns#Notice", },
145     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
146     { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
147     { NULL, NULL }
148 };
150 struct rdf_double_t rdf_license_pd [] = {
151     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
152     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
153     { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
154     { NULL, NULL }
155 };
157 struct rdf_double_t rdf_license_freeart [] = {
158     { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
159     { "cc:permits", "http://creativecommons.org/ns#Distribution", },
160     { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
161     { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
162     { "cc:requires", "http://creativecommons.org/ns#Notice", },
163     { "cc:requires", "http://creativecommons.org/ns#Attribution", },
164     { NULL, NULL }
165 };
167 struct rdf_double_t rdf_license_ofl [] = {
168     { "cc:permits", "http://scripts.sil.org/pub/OFL/Reproduction", },
169     { "cc:permits", "http://scripts.sil.org/pub/OFL/Distribution", },
170     { "cc:permits", "http://scripts.sil.org/pub/OFL/Embedding", },
171     { "cc:permits", "http://scripts.sil.org/pub/OFL/DerivativeWorks", },
172     { "cc:requires", "http://scripts.sil.org/pub/OFL/Notice", },
173     { "cc:requires", "http://scripts.sil.org/pub/OFL/Attribution", },
174     { "cc:requires", "http://scripts.sil.org/pub/OFL/ShareAlike", },
175     { "cc:requires", "http://scripts.sil.org/pub/OFL/DerivativeRenaming", },
176     { "cc:requires", "http://scripts.sil.org/pub/OFL/BundlingWhenSelling", },
177     { NULL, NULL }
178 };
180 struct rdf_license_t rdf_licenses [] = {
181     { N_("CC Attribution"), 
182       "http://creativecommons.org/licenses/by/3.0/",
183       rdf_license_cc_a,
184     },
186     { N_("CC Attribution-ShareAlike"), 
187       "http://creativecommons.org/licenses/by-sa/3.0/",
188       rdf_license_cc_a_sa,
189     },
191     { N_("CC Attribution-NoDerivs"), 
192       "http://creativecommons.org/licenses/by-nd/3.0/",
193       rdf_license_cc_a_nd,
194     },
196     { N_("CC Attribution-NonCommercial"), 
197       "http://creativecommons.org/licenses/by-nc/3.0/",
198       rdf_license_cc_a_nc,
199     },
201     { N_("CC Attribution-NonCommercial-ShareAlike"), 
202       "http://creativecommons.org/licenses/by-nc-sa/3.0/",
203       rdf_license_cc_a_nc_sa,
204     },
206     { N_("CC Attribution-NonCommercial-NoDerivs"), 
207       "http://creativecommons.org/licenses/by-nc-nd/3.0/",
208       rdf_license_cc_a_nc_nd,
209     },
211     { N_("Public Domain"),
212       "http://creativecommons.org/licenses/publicdomain/",
213       rdf_license_pd,
214     },
216     { N_("FreeArt"),
217       "http://artlibre.org/licence.php/lalgb.html",
218       rdf_license_freeart,
219     },
221     { N_("Open Font License"),
222       "http://scripts.sil.org/OFL",
223       rdf_license_ofl,
224     },
226     { NULL, NULL, rdf_license_empty, }
227 };
229 #define XML_TAG_NAME_SVG      "svg:svg"
230 #define XML_TAG_NAME_METADATA "svg:metadata"
231 #define XML_TAG_NAME_RDF      "rdf:RDF"
232 #define XML_TAG_NAME_WORK     "cc:Work"
233 #define XML_TAG_NAME_LICENSE  "cc:License"
235 // Remember when using the "title" and "tip" elements to pass them through
236 // the localization functions when you use them!
237 struct rdf_work_entity_t rdf_work_entities [] = {
238     { "title", N_("Title"), "dc:title", RDF_CONTENT,
239       N_("Name by which this document is formally known."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
240     },
241     { "date", N_("Date"), "dc:date", RDF_CONTENT,
242       N_("Date associated with the creation of this document (YYYY-MM-DD)."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
243     },
244     { "format", N_("Format"), "dc:format", RDF_CONTENT,
245       N_("The physical or digital manifestation of this document (MIME type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
246     },
247     { "type", N_("Type"), "dc:type", RDF_RESOURCE,
248       N_("Type of document (DCMI Type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
249     },
251     { "creator", N_("Creator"), "dc:creator", RDF_AGENT,
252       N_("Name of entity primarily responsible for making the content of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
253     },
254     { "rights", N_("Rights"), "dc:rights", RDF_AGENT,
255       N_("Name of entity with rights to the Intellectual Property of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
256     },
257     { "publisher", N_("Publisher"), "dc:publisher", RDF_AGENT,
258       N_("Name of entity responsible for making this document available."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
259     },
261     { "identifier", N_("Identifier"), "dc:identifier", RDF_CONTENT,
262       N_("Unique URI to reference this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
263     },
264     { "source", N_("Source"), "dc:source", RDF_CONTENT,
265       N_("Unique URI to reference the source of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
266     },
267     { "relation", N_("Relation"), "dc:relation", RDF_CONTENT,
268       N_("Unique URI to a related document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
269     },
270     { "language", N_("Language"), "dc:language", RDF_CONTENT,
271       N_("Two-letter language tag with optional subtags for the language of this document.  (e.g. 'en-GB')"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
272     },
273     { "subject", N_("Keywords"), "dc:subject", RDF_BAG,
274       N_("The topic of this document as comma-separated key words, phrases, or classifications."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
275     },
276     // TRANSLATORS: "Coverage": the spatial or temporal characteristics of the content.
277     // For info, see Appendix D of http://www.w3.org/TR/1998/WD-rdf-schema-19980409/
278     { "coverage", N_("Coverage"), "dc:coverage", RDF_CONTENT,
279       N_("Extent or scope of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
280     },
282     { "description", N_("Description"), "dc:description", RDF_CONTENT,
283       N_("A short account of the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
284     },
286     // FIXME: need to handle 1 agent per line of input
287     { "contributor", N_("Contributors"), "dc:contributor", RDF_AGENT,
288       N_("Names of entities responsible for making contributions to the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
289     },
291     // TRANSLATORS: URL to a page that defines the license for the document
292     { "license_uri", N_("URI"), "cc:license", RDF_RESOURCE,
293       // TRANSLATORS: this is where you put a URL to a page that defines the license
294       N_("URI to this document's license's namespace definition."), RDF_FORMAT_LINE, RDF_EDIT_SPECIAL,
295     },
297       // TRANSLATORS: fragment of XML representing the license of the document
298     { "license_fragment", N_("Fragment"), "License", RDF_XML,
299       N_("XML fragment for the RDF 'License' section."), RDF_FORMAT_MULTILINE, RDF_EDIT_SPECIAL,
300     },
301     
302     { NULL, NULL, NULL, RDF_CONTENT,
303       NULL, RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
304     }
305 };
307 /**
308  *  \brief   Retrieves a known RDF/Work entity by name
309  *  \return  A pointer to an RDF/Work entity
310  *  \param   name  The desired RDF/Work entity
311  *  
312  */
313 struct rdf_work_entity_t *
314 rdf_find_entity(gchar const * name)
316     struct rdf_work_entity_t *entity;
317     for (entity=rdf_work_entities; entity->name; entity++) {
318         if (strcmp(entity->name,name)==0) break;
319     }
320     if (entity->name) return entity;
321     return NULL;
324 /*
325  * Takes the inkscape rdf struct and spits out a static RDF, which is only
326  * useful for testing.  We must merge the rdf struct into the XML DOM for
327  * changes to be saved.
328  */
329 /*
331    Since g_markup_printf_escaped doesn't exist for most people's glib
332    right now, this function will remain commented out since it's only
333    for generic debug anyway.  --Kees
335 gchar *
336 rdf_string(struct rdf_t * rdf)
338     gulong overall=0;
339     gchar *string=NULL;
341     gchar *rdf_head="\
342 <rdf:RDF xmlns=\"http://creativecommons.org/ns#\"\
343     xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\
344     xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\
345 ";
346     gchar *work_head="\
347 <Work rdf:about=\"\">\
348    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\
349 ";
350     gchar *work_title=NULL;
351     gchar *work_date=NULL;
352     gchar *work_description=NULL;
353     gchar *work_creator=NULL;
354     gchar *work_owner=NULL;
355     gchar *work_source=NULL;
356     gchar *work_license=NULL;
357     gchar *license_head=NULL;
358     gchar *license=NULL;
359     gchar *license_end="</License>\n";
360     gchar *work_end="</Work>\n";
361     gchar *rdf_end="</rdf:RDF>\n";
363     if (rdf && rdf->work_title && rdf->work_title[0]) {
364         work_title=g_markup_printf_escaped("   <dc:title>%s</dc:title>\n",
365             rdf->work_title);
366     overall+=strlen(work_title);
367     }
368     if (rdf && rdf->work_date && rdf->work_date[0]) {
369         work_date=g_markup_printf_escaped("   <dc:date>%s</dc:date>\n",
370             rdf->work_date);
371     overall+=strlen(work_date);
372     }
373     if (rdf && rdf->work_description && rdf->work_description[0]) {
374         work_description=g_markup_printf_escaped("   <dc:description>%s</dc:description>\n",
375             rdf->work_description);
376     overall+=strlen(work_description);
377     }
378     if (rdf && rdf->work_creator && rdf->work_creator[0]) {
379         work_creator=g_markup_printf_escaped("   <dc:creator><Agent>\
380       <dc:title>%s</dc:title>\
381    </Agent></dc:creator>\n",
382             rdf->work_creator);
383     overall+=strlen(work_creator);
384     }
385     if (rdf && rdf->work_owner && rdf->work_owner[0]) {
386         work_owner=g_markup_printf_escaped("   <dc:rights><Agent>\
387       <dc:title>%s</dc:title>\
388    </Agent></dc:rights>\n",
389             rdf->work_owner);
390     overall+=strlen(work_owner);
391     }
392     if (rdf && rdf->work_source && rdf->work_source[0]) {
393         work_source=g_markup_printf_escaped("   <dc:source rdf:resource=\"%s\" />\n",
394             rdf->work_source);
395     overall+=strlen(work_source);
396     }
397     if (rdf && rdf->license && rdf->license->work_rdf && rdf->license->work_rdf[0]) {
398         work_license=g_markup_printf_escaped("   <license rdf:resource=\"%s\" />\n",
399             rdf->license->work_rdf);
400     overall+=strlen(work_license);
402     license_head=g_markup_printf_escaped("<License rdf:about=\"%s\">\n",
403             rdf->license->work_rdf);
404     overall+=strlen(license_head);
405     overall+=strlen(rdf->license->license_rdf);
406     overall+=strlen(license_end);
407     }
409     overall+=strlen(rdf_head)+strlen(rdf_end);
410     overall+=strlen(work_head)+strlen(work_end);
412     overall++; // NULL term
414     if (!(string=(gchar*)g_malloc(overall))) {
415         return NULL;
416     }
418     string[0]='\0';
419     strcat(string,rdf_head);
420     strcat(string,work_head);
422     if (work_title)       strcat(string,work_title);
423     if (work_date)        strcat(string,work_date);
424     if (work_description) strcat(string,work_description);
425     if (work_creator)     strcat(string,work_creator);
426     if (work_owner)       strcat(string,work_owner);
427     if (work_source)      strcat(string,work_source);
428     if (work_license)     strcat(string,work_license);
430     strcat(string,work_end);
431     if (license_head) {
432         strcat(string,license_head);
433     strcat(string,rdf->license->license_rdf);
434     strcat(string,license_end);
435     }
436     strcat(string,rdf_end);
438     return string;
440 */
443 /**
444  *  \brief   Pull the text out of an RDF entity, depends on how it's stored
445  *  \return  A pointer to the entity's static contents as a string
446  *  \param   repr    The XML element to extract from
447  *  \param   entity  The desired RDF/Work entity
448  *  
449  */
450 const gchar *
451 rdf_get_repr_text ( Inkscape::XML::Node * repr, struct rdf_work_entity_t * entity )
453     g_return_val_if_fail (repr != NULL, NULL);
454     g_return_val_if_fail (entity != NULL, NULL);
455     static gchar * bag = NULL;
456     gchar * holder = NULL;
458     Inkscape::XML::Node * temp=NULL;
459     switch (entity->datatype) {
460         case RDF_CONTENT:
461             temp = sp_repr_children(repr);
462             if ( temp == NULL ) return NULL;
463             
464             return temp->content();
466         case RDF_AGENT:
467             temp = sp_repr_lookup_name ( repr, "cc:Agent", 1 );
468             if ( temp == NULL ) return NULL;
470             temp = sp_repr_lookup_name ( temp, "dc:title", 1 );
471             if ( temp == NULL ) return NULL;
473             temp = sp_repr_children(temp);
474             if ( temp == NULL ) return NULL;
476             return temp->content();
478         case RDF_RESOURCE:
479             return repr->attribute("rdf:resource");
481         case RDF_XML:
482             return "xml goes here";
484         case RDF_BAG:
485             /* clear the static string.  yucky. */
486             if (bag) g_free(bag);
487             bag = NULL;
489             temp = sp_repr_lookup_name ( repr, "rdf:Bag", 1 );
490             if ( temp == NULL ) {
491                 /* backwards compatible: read contents */
492                 temp = sp_repr_children(repr);
493                 if ( temp == NULL ) return NULL;
494             
495                 return temp->content();
496             }
498             for ( temp = sp_repr_children(temp) ;
499                   temp ;
500                   temp = sp_repr_next(temp) ) {
501                 if (!strcmp(temp->name(),"rdf:li") &&
502                     temp->firstChild()) {
503                     const gchar * str = temp->firstChild()->content();
504                     if (bag) {
505                         holder = bag;
506                         bag = g_strconcat(holder, ", ", str, NULL);
507                         g_free(holder);
508                     }
509                     else {
510                         bag = g_strdup(str);
511                     }
512                 }
513             }
514             return bag;
516         default:
517             break;
518     }
519     return NULL;
522 unsigned int
523 rdf_set_repr_text ( Inkscape::XML::Node * repr,
524                     struct rdf_work_entity_t * entity,
525                     gchar const * text )
527     g_return_val_if_fail ( repr != NULL, 0);
528     g_return_val_if_fail ( entity != NULL, 0);
529     g_return_val_if_fail ( text != NULL, 0);
530     gchar * str = NULL;
531     gchar** strlist = NULL;
532     int i;
534     Inkscape::XML::Node * temp=NULL;
535     Inkscape::XML::Node * child=NULL;
536     Inkscape::XML::Node * parent=repr;
538     Inkscape::XML::Document * xmldoc = parent->document();
539     g_return_val_if_fail (xmldoc != NULL, FALSE);
541     switch (entity->datatype) {
542         case RDF_CONTENT:
543             temp = sp_repr_children(parent);
544             if ( temp == NULL ) {
545                 temp = xmldoc->createTextNode( text );
546                 g_return_val_if_fail (temp != NULL, FALSE);
548                 parent->appendChild(temp);
549                 Inkscape::GC::release(temp);
551                 return TRUE;
552             }
553             else {
554                 temp->setContent(text);
555                 return TRUE;
556             }
558         case RDF_AGENT:
559             temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 );
560             if ( temp == NULL ) {
561                 temp = xmldoc->createElement ( "cc:Agent" );
562                 g_return_val_if_fail (temp != NULL, FALSE);
564                 parent->appendChild(temp);
565                 Inkscape::GC::release(temp);
566             }
567             parent = temp;
569             temp = sp_repr_lookup_name ( parent, "dc:title", 1 );
570             if ( temp == NULL ) {
571                 temp = xmldoc->createElement ( "dc:title" );
572                 g_return_val_if_fail (temp != NULL, FALSE);
574                 parent->appendChild(temp);
575                 Inkscape::GC::release(temp);
576             }
577             parent = temp;
579             temp = sp_repr_children(parent);
580             if ( temp == NULL ) {
581                 temp = xmldoc->createTextNode( text );
582                 g_return_val_if_fail (temp != NULL, FALSE);
584                 parent->appendChild(temp);
585                 Inkscape::GC::release(temp);
587                 return TRUE;
588             }
589             else {
590                 temp->setContent(text);
591                                 return TRUE;
592             }
594         case RDF_RESOURCE:
595             parent->setAttribute("rdf:resource", text );
596             return true;
598         case RDF_XML:
599             return 1;
601         case RDF_BAG:
602             /* find/create the rdf:Bag item */
603             temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 );
604             if ( temp == NULL ) {
605                 /* backward compatibility: drop the dc:subject contents */
606                 while ( (temp = sp_repr_children( parent )) ) {
607                     parent->removeChild(temp);
608                 }
610                 temp = xmldoc->createElement ( "rdf:Bag" );
611                 g_return_val_if_fail (temp != NULL, FALSE);
613                 parent->appendChild(temp);
614                 Inkscape::GC::release(temp);
615             }
616             parent = temp;
618             /* toss all the old list items */
619             while ( (temp = sp_repr_children( parent )) ) {
620                 parent->removeChild(temp);
621             }
623             /* chop our list up on commas */
624             strlist = g_strsplit( text, ",", 0);
626             for (i = 0; (str = strlist[i]); i++) {
627                 temp = xmldoc->createElement ( "rdf:li" );
628                 g_return_val_if_fail (temp != NULL, 0);
630                 parent->appendChild(temp);
631                 Inkscape::GC::release(temp);
633                 child = xmldoc->createTextNode( g_strstrip(str) );
634                 g_return_val_if_fail (child != NULL, 0);
636                 temp->appendChild(child);
637                 Inkscape::GC::release(child);
638             }
639             g_strfreev( strlist );
641             return 1;
643         default:
644             break;
645     }
646     return 0;
649 Inkscape::XML::Node *
650 rdf_get_rdf_root_repr ( SPDocument * doc, bool build )
652     g_return_val_if_fail (doc        != NULL, NULL);
653     g_return_val_if_fail (doc->rroot != NULL, NULL);
655     Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
656     g_return_val_if_fail (xmldoc != NULL, NULL);
658     Inkscape::XML::Node * rdf = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_RDF );
660     if (rdf == NULL) {
661         //printf("missing XML '%s'\n",XML_TAG_NAME_RDF);
662         if (!build) return NULL;
664         Inkscape::XML::Node * svg = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_SVG );
665         g_return_val_if_fail ( svg != NULL, NULL );
667         Inkscape::XML::Node * parent = sp_repr_lookup_name ( svg, XML_TAG_NAME_METADATA );
668         if ( parent == NULL ) {
669             parent = xmldoc->createElement( XML_TAG_NAME_METADATA );
670             g_return_val_if_fail ( parent != NULL, NULL);
672             svg->appendChild(parent);
673             Inkscape::GC::release(parent);
674         }
676         Inkscape::XML::Document * xmldoc = parent->document();
677         g_return_val_if_fail (xmldoc != NULL, FALSE);
679         rdf = xmldoc->createElement( XML_TAG_NAME_RDF );
680         g_return_val_if_fail (rdf != NULL, NULL);
682         parent->appendChild(rdf);
683         Inkscape::GC::release(rdf);
684     }
686     /*
687      * some implementations do not put RDF stuff inside <metadata>,
688      * so we need to check for it and add it if we don't see it
689      */
690     Inkscape::XML::Node * want_metadata = sp_repr_parent ( rdf );
691     g_return_val_if_fail (want_metadata != NULL, NULL);
692     if (strcmp( want_metadata->name(), XML_TAG_NAME_METADATA )) {
693             Inkscape::XML::Node * metadata = xmldoc->createElement( XML_TAG_NAME_METADATA );
694             g_return_val_if_fail (metadata != NULL, NULL);
696             /* attach the metadata node */
697             want_metadata->appendChild(metadata);
698             Inkscape::GC::release(metadata);
700             /* move the RDF into it */
701             Inkscape::GC::anchor(rdf);
702             sp_repr_unparent ( rdf );
703             metadata->appendChild(rdf);
704             Inkscape::GC::release(rdf);
705     }
706     
707     return rdf;
710 Inkscape::XML::Node *
711 rdf_get_xml_repr( SPDocument * doc, gchar const * name, bool build )
713     g_return_val_if_fail (name       != NULL, NULL);
714     g_return_val_if_fail (doc        != NULL, NULL);
715     g_return_val_if_fail (doc->rroot != NULL, NULL);
717     Inkscape::XML::Node * rdf = rdf_get_rdf_root_repr ( doc, build );
718     if (!rdf) return NULL;
720     Inkscape::XML::Node * xml = sp_repr_lookup_name ( rdf, name );
721     if (xml == NULL) {
722         //printf("missing XML '%s'\n",name);
723         if (!build) return NULL;
725         Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
726         g_return_val_if_fail (xmldoc != NULL, NULL);
728         xml = xmldoc->createElement( name );
729         g_return_val_if_fail (xml != NULL, NULL);
731         xml->setAttribute("rdf:about", "" );
733         rdf->appendChild(xml);
734         Inkscape::GC::release(xml);
735     }
737     return xml;
740 Inkscape::XML::Node *
741 rdf_get_work_repr( SPDocument * doc, gchar const * name, bool build )
743     g_return_val_if_fail (name       != NULL, NULL);
744     g_return_val_if_fail (doc        != NULL, NULL);
745     g_return_val_if_fail (doc->rroot != NULL, NULL);
747     Inkscape::XML::Node * work = rdf_get_xml_repr ( doc, XML_TAG_NAME_WORK, build );
748     if (!work) return NULL;
750     Inkscape::XML::Node * item = sp_repr_lookup_name ( work, name, 1 );
751     if (item == NULL) {
752         //printf("missing XML '%s'\n",name);
753         if (!build) return NULL;
755         Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
756         g_return_val_if_fail (xmldoc != NULL, NULL);
758         item = xmldoc->createElement( name );
759         g_return_val_if_fail (item != NULL, NULL);
761         work->appendChild(item);
762         Inkscape::GC::release(item);
763     }
765     return item;
770 /**
771  *  \brief   Retrieves a known RDF/Work entity's contents from the document XML by name
772  *  \return  A pointer to the entity's static contents as a string, or NULL if no entity exists
773  *  \param   entity  The desired RDF/Work entity
774  *  
775  */
776 const gchar *
777 rdf_get_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity)
779     g_return_val_if_fail (doc    != NULL, NULL);
780     if ( entity == NULL ) return NULL;
781     //printf("want '%s'\n",entity->title);
783     Inkscape::XML::Node * item;
784     if ( entity->datatype == RDF_XML ) {
785         item = rdf_get_xml_repr ( doc, entity->tag, FALSE );
786     }
787     else {
788         item = rdf_get_work_repr( doc, entity->tag, FALSE );
789     }
790     if ( item == NULL ) return NULL;
792     const gchar * result = rdf_get_repr_text ( item, entity );
793     //printf("found '%s' == '%s'\n", entity->title, result );
794     return result;
797 /**
798  *  \brief   Stores a string into a named RDF/Work entity in the document XML
799  *  \param   entity The desired RDF/Work entity to replace
800  *  \param   string The string to replace the entity contents with
801  *  
802  */
803 unsigned int
804 rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity,
805                     const gchar * text)
807     g_return_val_if_fail ( entity != NULL, 0 );
808     if (text == NULL) {
809         // FIXME: on a "NULL" text, delete the entity.  For now, blank it.
810         text="";
811     }
813     /*
814     printf("changing '%s' (%s) to '%s'\n",
815         entity->title,
816         entity->tag,
817         text);
818     */
820     Inkscape::XML::Node * item = rdf_get_work_repr( doc, entity->tag, TRUE );
821     g_return_val_if_fail ( item != NULL, 0 );
823     return rdf_set_repr_text ( item, entity, text );
826 #undef DEBUG_MATCH
828 static bool
829 rdf_match_license(Inkscape::XML::Node const *repr, struct rdf_license_t const *license)
831     g_assert ( repr != NULL );
832     g_assert ( license != NULL );
834     bool result=TRUE;
835 #ifdef DEBUG_MATCH
836     printf("checking against '%s'\n",license->name);
837 #endif
839     int count = 0;
840     for (struct rdf_double_t const *details = license->details;
841          details->name; details++ ) {
842         count++;
843     }
844     bool * matched = (bool*)calloc(count,sizeof(bool));
846     for (Inkscape::XML::Node const *current = sp_repr_children(repr);
847          current;
848          current = sp_repr_next ( current ) ) {
850         gchar const * attr = current->attribute("rdf:resource");
851         if ( attr == NULL ) continue;
853 #ifdef DEBUG_MATCH
854         printf("\texamining '%s' => '%s'\n", current->name(), attr);
855 #endif
857         bool found_match=FALSE;
858         for (int i=0; i<count; i++) {
859             // skip already matched items
860             if (matched[i]) continue;
862 #ifdef DEBUG_MATCH
863             printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name);
864             printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource);
865 #endif
867             if (!strcmp( current->name(),
868                          license->details[i].name ) &&
869                 !strcmp( attr,
870                          license->details[i].resource )) {
871                 matched[i]=TRUE;
872                 found_match=TRUE;
873 #ifdef DEBUG_MATCH
874                 printf("\t\tgood!\n");
875 #endif
876                 break;
877             }
878         }
879         if (!found_match) {
880             // if we checked each known item of the license
881             // and didn't find it, we must abort
882             result=FALSE;
883 #ifdef DEBUG_MATCH
884             printf("\t\tno '%s' element matched XML (bong)!\n",license->name);
885 #endif
886             break;
887         }
888     }
889 #ifdef DEBUG_MATCH
890     if (result) printf("\t\tall XML found matching elements!\n");
891 #endif
892     for (int i=0; result && i<count; i++) {
893         // scan looking for an unmatched item
894         if (matched[i]==0) {
895             result=FALSE;
896 #ifdef DEBUG_MATCH
897             printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name);
898 #endif
899         }
900     }
902 #ifdef DEBUG_MATCH
903     printf("\t\tall '%s' elements used to match!\n",license->name);
904 #endif
906     free(matched);
908 #ifdef DEBUG_MATCH
909     if (result) printf("matched '%s'\n",license->name);
910 #endif
911     return result;
914 /**
915  *  \brief   Attempts to match and retrieve a known RDF/License from the document XML
916  *  \return  A pointer to the static RDF license structure
917  *  
918  */
919 struct rdf_license_t *
920 rdf_get_license(SPDocument * document)
922     Inkscape::XML::Node const *repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE );
923     if (repr) {
924         for (struct rdf_license_t * license = rdf_licenses;
925              license->name; license++ ) {
926             if ( rdf_match_license ( repr, license ) ) return license;
927         }
928     }
929 #ifdef DEBUG_MATCH
930     else {
931         printf("no license XML\n");
932     }
933 #endif
934     return NULL;
937 /**
938  *  \brief   Stores an RDF/License XML in the document XML
939  *  \param   document  Which document to update
940  *  \param   license   The desired RDF/License structure to store; NULL drops old license, so can be used for proprietary license. 
941  *  
942  */
943 void
944 rdf_set_license(SPDocument * doc, struct rdf_license_t const * license)
946     // drop old license section
947     Inkscape::XML::Node * repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, FALSE );
948     if (repr) sp_repr_unparent(repr);
950     if (!license) return;
952     // build new license section
953     repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, TRUE );
954     g_assert ( repr );
956     repr->setAttribute("rdf:about", license->uri );
958     Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
959     g_return_if_fail (xmldoc != NULL);
961     for (struct rdf_double_t const * detail = license->details;
962          detail->name; detail++) {
963         Inkscape::XML::Node * child = xmldoc->createElement( detail->name );
964         g_assert ( child != NULL );
966         child->setAttribute("rdf:resource", detail->resource );
967         repr->appendChild(child);
968         Inkscape::GC::release(child);
969     }
972 struct rdf_entity_default_t {
973     gchar const * name;
974     gchar const * text;
975 };
976 struct rdf_entity_default_t rdf_defaults[] = {
977     { "format",      "image/svg+xml", },
978     { "type",        "http://purl.org/dc/dcmitype/StillImage", },
979     { NULL,          NULL, }
980 };
982 void
983 rdf_set_defaults ( SPDocument * doc )
985     g_assert ( doc != NULL );
987     // Create metadata node if it doesn't already exist
988     if (!sp_item_group_get_child_by_name ((SPGroup *) doc->root, NULL,
989                                           XML_TAG_NAME_METADATA)) {
990         // create repr
991         Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
992         g_return_if_fail (xmldoc != NULL);
993         Inkscape::XML::Node * rnew = xmldoc->createElement (XML_TAG_NAME_METADATA);
994         // insert into the document
995         doc->rroot->addChild(rnew, NULL);
996         // clean up
997         Inkscape::GC::release(rnew);
998     }
1000     /* install defaults */
1001     for ( struct rdf_entity_default_t * rdf_default = rdf_defaults;
1002           rdf_default->name;
1003           rdf_default++) {
1004         struct rdf_work_entity_t * entity = rdf_find_entity ( rdf_default->name );
1005         g_assert ( entity != NULL );
1007         if ( rdf_get_work_entity ( doc, entity ) == NULL ) {
1008             rdf_set_work_entity ( doc, entity, rdf_default->text );
1009         }
1010     }
1014 /*
1015   Local Variables:
1016   mode:c++
1017   c-file-style:"stroustrup"
1018   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1019   indent-tabs-mode:nil
1020   fill-column:99
1021   End:
1022 */
1023 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :