Code

fix range, make integer, remove unnecessary document_done, fix 1635388
[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://web.resource.org/cc/"
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://web.resource.org/cc/"
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://web.resource.org/cc/PublicDomain" />
61   </Work>
62   
63   <License rdf:about="http://web.resource.org/cc/PublicDomain">
64      <permits rdf:resource="http://web.resource.org/cc/Reproduction" />
65      <permits rdf:resource="http://web.resource.org/cc/Distribution" />
66      <permits rdf:resource="http://web.resource.org/cc/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://web.resource.org/cc/Reproduction", },
95     { "cc:permits", "http://web.resource.org/cc/Distribution", },
96     { "cc:requires", "http://web.resource.org/cc/Notice", },
97     { "cc:requires", "http://web.resource.org/cc/Attribution", },
98     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
99     { NULL, NULL }
100 };
102 struct rdf_double_t rdf_license_cc_a_sa [] = {
103     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
104     { "cc:permits", "http://web.resource.org/cc/Distribution", },
105     { "cc:requires", "http://web.resource.org/cc/Notice", },
106     { "cc:requires", "http://web.resource.org/cc/Attribution", },
107     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
108     { "cc:requires", "http://web.resource.org/cc/ShareAlike", },
109     { NULL, NULL }
110 };
112 struct rdf_double_t rdf_license_cc_a_nd [] = {
113     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
114     { "cc:permits", "http://web.resource.org/cc/Distribution", },
115     { "cc:requires", "http://web.resource.org/cc/Notice", },
116     { "cc:requires", "http://web.resource.org/cc/Attribution", },
117     { NULL, NULL }
118 };
120 struct rdf_double_t rdf_license_cc_a_nc [] = {
121     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
122     { "cc:permits", "http://web.resource.org/cc/Distribution", },
123     { "cc:requires", "http://web.resource.org/cc/Notice", },
124     { "cc:requires", "http://web.resource.org/cc/Attribution", },
125     { "cc:prohibits", "http://web.resource.org/cc/CommercialUse", },
126     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
127     { NULL, NULL }
128 };
130 struct rdf_double_t rdf_license_cc_a_nc_sa [] = {
131     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
132     { "cc:permits", "http://web.resource.org/cc/Distribution", },
133     { "cc:requires", "http://web.resource.org/cc/Notice", },
134     { "cc:requires", "http://web.resource.org/cc/Attribution", },
135     { "cc:prohibits", "http://web.resource.org/cc/CommercialUse", },
136     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
137     { "cc:requires", "http://web.resource.org/cc/ShareAlike", },
138     { NULL, NULL }
139 };
141 struct rdf_double_t rdf_license_cc_a_nc_nd [] = {
142     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
143     { "cc:permits", "http://web.resource.org/cc/Distribution", },
144     { "cc:requires", "http://web.resource.org/cc/Notice", },
145     { "cc:requires", "http://web.resource.org/cc/Attribution", },
146     { "cc:prohibits", "http://web.resource.org/cc/CommercialUse", },
147     { NULL, NULL }
148 };
150 struct rdf_double_t rdf_license_gpl [] = {
151     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
152     { "cc:permits", "http://web.resource.org/cc/Distribution", },
153     { "cc:requires", "http://web.resource.org/cc/Notice", },
154     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
155     { "cc:requires", "http://web.resource.org/cc/ShareAlike", },
156     { "cc:requires", "http://web.resource.org/cc/SourceCode", },
157     { NULL, NULL }
158 };
160 struct rdf_double_t rdf_license_pd [] = {
161     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
162     { "cc:permits", "http://web.resource.org/cc/Distribution", },
163     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
164     { NULL, NULL }
165 };
167 struct rdf_double_t rdf_license_freeart [] = {
168     { "cc:permits", "http://web.resource.org/cc/Reproduction", },
169     { "cc:permits", "http://web.resource.org/cc/Distribution", },
170     { "cc:permits", "http://web.resource.org/cc/DerivativeWorks", },
171     { "cc:requires", "http://web.resource.org/cc/ShareAlike", },
172     { "cc:requires", "http://web.resource.org/cc/Notice", },
173     { "cc:requires", "http://web.resource.org/cc/Attribution", },
174     { NULL, NULL }
175 };
177 struct rdf_license_t rdf_licenses [] = {
178     { N_("CC Attribution"), 
179       "http://creativecommons.org/licenses/by/3.0/",
180       rdf_license_cc_a,
181     },
183     { N_("CC Attribution-ShareAlike"), 
184       "http://creativecommons.org/licenses/by-sa/3.0/",
185       rdf_license_cc_a_sa,
186     },
188     { N_("CC Attribution-NoDerivs"), 
189       "http://creativecommons.org/licenses/by-nd/3.0/",
190       rdf_license_cc_a_nd,
191     },
193     { N_("CC Attribution-NonCommercial"), 
194       "http://creativecommons.org/licenses/by-nc/3.0/",
195       rdf_license_cc_a_nc,
196     },
198     { N_("CC Attribution-NonCommercial-ShareAlike"), 
199       "http://creativecommons.org/licenses/by-nc-sa/3.0/",
200       rdf_license_cc_a_nc_sa,
201     },
203     { N_("CC Attribution-NonCommercial-NoDerivs"), 
204       "http://creativecommons.org/licenses/by-nc-nd/3.0/",
205       rdf_license_cc_a_nc_nd,
206     },
208     { N_("GNU General Public License"), 
209       "http://creativecommons.org/licenses/GPL/2.0/",
210       rdf_license_gpl,
211     },
213     { N_("GNU Lesser General Public License"), 
214       "http://creativecommons.org/licenses/LGPL/2.1/",
215       rdf_license_gpl,
216     },
218     { N_("Public Domain"),
219       "http://creativecommons.org/licenses/publicdomain/",
220       rdf_license_pd,
221     },
223     { N_("FreeArt"),
224       "http://artlibre.org/licence.php/lalgb.html",
225       rdf_license_freeart,
226     },
228     { NULL, NULL, rdf_license_empty, }
229 };
231 #define XML_TAG_NAME_SVG      "svg:svg"
232 #define XML_TAG_NAME_METADATA "svg:metadata"
233 #define XML_TAG_NAME_RDF      "rdf:RDF"
234 #define XML_TAG_NAME_WORK     "cc:Work"
235 #define XML_TAG_NAME_LICENSE  "cc:License"
237 // Remember when using the "title" and "tip" elements to pass them through
238 // the localization functions when you use them!
239 struct rdf_work_entity_t rdf_work_entities [] = {
240     { "title", N_("Title"), "dc:title", RDF_CONTENT,
241       N_("Name by which this document is formally known."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
242     },
243     { "date", N_("Date"), "dc:date", RDF_CONTENT,
244       N_("Date associated with the creation of this document (YYYY-MM-DD)."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
245     },
246     { "format", N_("Format"), "dc:format", RDF_CONTENT,
247       N_("The physical or digital manifestation of this document (MIME type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
248     },
249     { "type", N_("Type"), "dc:type", RDF_RESOURCE,
250       N_("Type of document (DCMI Type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
251     },
253     { "creator", N_("Creator"), "dc:creator", RDF_AGENT,
254       N_("Name of entity primarily responsible for making the content of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
255     },
256     { "rights", N_("Rights"), "dc:rights", RDF_AGENT,
257       N_("Name of entity with rights to the Intellectual Property of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
258     },
259     { "publisher", N_("Publisher"), "dc:publisher", RDF_AGENT,
260       N_("Name of entity responsible for making this document available."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
261     },
263     { "identifier", N_("Identifier"), "dc:identifier", RDF_CONTENT,
264       N_("Unique URI to reference this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
265     },
266     { "source", N_("Source"), "dc:source", RDF_CONTENT,
267       N_("Unique URI to reference the source of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
268     },
269     { "relation", N_("Relation"), "dc:relation", RDF_CONTENT,
270       N_("Unique URI to a related document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
271     },
272     { "language", N_("Language"), "dc:language", RDF_CONTENT,
273       N_("Two-letter language tag with optional subtags for the language of this document.  (e.g. 'en-GB')"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
274     },
275     { "subject", N_("Keywords"), "dc:subject", RDF_BAG,
276       N_("The topic of this document as comma-separated key words, phrases, or classifications."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
277     },
278     // TRANSLATORS: "Coverage": the spatial or temporal characteristics of the content.
279     // For info, see Appendix D of http://www.w3.org/TR/1998/WD-rdf-schema-19980409/
280     { "coverage", N_("Coverage"), "dc:coverage", RDF_CONTENT,
281       N_("Extent or scope of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
282     },
284     { "description", N_("Description"), "dc:description", RDF_CONTENT,
285       N_("A short account of the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
286     },
288     // FIXME: need to handle 1 agent per line of input
289     { "contributor", N_("Contributors"), "dc:contributor", RDF_AGENT,
290       N_("Names of entities responsible for making contributions to the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
291     },
293     // TRANSLATORS: URL to a page that defines the license for the document
294     { "license_uri", N_("URI"), "cc:license", RDF_RESOURCE,
295       // TRANSLATORS: this is where you put a URL to a page that defines the license
296       N_("URI to this document's license's namespace definition."), RDF_FORMAT_LINE, RDF_EDIT_SPECIAL,
297     },
299       // TRANSLATORS: fragment of XML representing the license of the document
300     { "license_fragment", N_("Fragment"), "License", RDF_XML,
301       N_("XML fragment for the RDF 'License' section."), RDF_FORMAT_MULTILINE, RDF_EDIT_SPECIAL,
302     },
303     
304     { NULL, NULL, NULL, RDF_CONTENT,
305       NULL, RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
306     }
307 };
309 /**
310  *  \brief   Retrieves a known RDF/Work entity by name
311  *  \return  A pointer to an RDF/Work entity
312  *  \param   name  The desired RDF/Work entity
313  *  
314  */
315 struct rdf_work_entity_t *
316 rdf_find_entity(gchar const * name)
318     struct rdf_work_entity_t *entity;
319     for (entity=rdf_work_entities; entity->name; entity++) {
320         if (strcmp(entity->name,name)==0) break;
321     }
322     if (entity->name) return entity;
323     return NULL;
326 /*
327  * Takes the inkscape rdf struct and spits out a static RDF, which is only
328  * useful for testing.  We must merge the rdf struct into the XML DOM for
329  * changes to be saved.
330  */
331 /*
333    Since g_markup_printf_escaped doesn't exist for most people's glib
334    right now, this function will remain commented out since it's only
335    for generic debug anyway.  --Kees
337 gchar *
338 rdf_string(struct rdf_t * rdf)
340     gulong overall=0;
341     gchar *string=NULL;
343     gchar *rdf_head="\
344 <rdf:RDF xmlns=\"http://web.resource.org/cc/\"\
345     xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\
346     xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\
347 ";
348     gchar *work_head="\
349 <Work rdf:about=\"\">\
350    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\
351 ";
352     gchar *work_title=NULL;
353     gchar *work_date=NULL;
354     gchar *work_description=NULL;
355     gchar *work_creator=NULL;
356     gchar *work_owner=NULL;
357     gchar *work_source=NULL;
358     gchar *work_license=NULL;
359     gchar *license_head=NULL;
360     gchar *license=NULL;
361     gchar *license_end="</License>\n";
362     gchar *work_end="</Work>\n";
363     gchar *rdf_end="</rdf:RDF>\n";
365     if (rdf && rdf->work_title && rdf->work_title[0]) {
366         work_title=g_markup_printf_escaped("   <dc:title>%s</dc:title>\n",
367             rdf->work_title);
368     overall+=strlen(work_title);
369     }
370     if (rdf && rdf->work_date && rdf->work_date[0]) {
371         work_date=g_markup_printf_escaped("   <dc:date>%s</dc:date>\n",
372             rdf->work_date);
373     overall+=strlen(work_date);
374     }
375     if (rdf && rdf->work_description && rdf->work_description[0]) {
376         work_description=g_markup_printf_escaped("   <dc:description>%s</dc:description>\n",
377             rdf->work_description);
378     overall+=strlen(work_description);
379     }
380     if (rdf && rdf->work_creator && rdf->work_creator[0]) {
381         work_creator=g_markup_printf_escaped("   <dc:creator><Agent>\
382       <dc:title>%s</dc:title>\
383    </Agent></dc:creator>\n",
384             rdf->work_creator);
385     overall+=strlen(work_creator);
386     }
387     if (rdf && rdf->work_owner && rdf->work_owner[0]) {
388         work_owner=g_markup_printf_escaped("   <dc:rights><Agent>\
389       <dc:title>%s</dc:title>\
390    </Agent></dc:rights>\n",
391             rdf->work_owner);
392     overall+=strlen(work_owner);
393     }
394     if (rdf && rdf->work_source && rdf->work_source[0]) {
395         work_source=g_markup_printf_escaped("   <dc:source rdf:resource=\"%s\" />\n",
396             rdf->work_source);
397     overall+=strlen(work_source);
398     }
399     if (rdf && rdf->license && rdf->license->work_rdf && rdf->license->work_rdf[0]) {
400         work_license=g_markup_printf_escaped("   <license rdf:resource=\"%s\" />\n",
401             rdf->license->work_rdf);
402     overall+=strlen(work_license);
404     license_head=g_markup_printf_escaped("<License rdf:about=\"%s\">\n",
405             rdf->license->work_rdf);
406     overall+=strlen(license_head);
407     overall+=strlen(rdf->license->license_rdf);
408     overall+=strlen(license_end);
409     }
411     overall+=strlen(rdf_head)+strlen(rdf_end);
412     overall+=strlen(work_head)+strlen(work_end);
414     overall++; // NULL term
416     if (!(string=(gchar*)g_malloc(overall))) {
417         return NULL;
418     }
420     string[0]='\0';
421     strcat(string,rdf_head);
422     strcat(string,work_head);
424     if (work_title)       strcat(string,work_title);
425     if (work_date)        strcat(string,work_date);
426     if (work_description) strcat(string,work_description);
427     if (work_creator)     strcat(string,work_creator);
428     if (work_owner)       strcat(string,work_owner);
429     if (work_source)      strcat(string,work_source);
430     if (work_license)     strcat(string,work_license);
432     strcat(string,work_end);
433     if (license_head) {
434         strcat(string,license_head);
435     strcat(string,rdf->license->license_rdf);
436     strcat(string,license_end);
437     }
438     strcat(string,rdf_end);
440     return string;
442 */
445 /**
446  *  \brief   Pull the text out of an RDF entity, depends on how it's stored
447  *  \return  A pointer to the entity's static contents as a string
448  *  \param   repr    The XML element to extract from
449  *  \param   entity  The desired RDF/Work entity
450  *  
451  */
452 const gchar *
453 rdf_get_repr_text ( Inkscape::XML::Node * repr, struct rdf_work_entity_t * entity )
455     g_return_val_if_fail (repr != NULL, NULL);
456     g_return_val_if_fail (entity != NULL, NULL);
457     static gchar * bag = NULL;
458     gchar * holder = NULL;
460     Inkscape::XML::Node * temp=NULL;
461     switch (entity->datatype) {
462         case RDF_CONTENT:
463             temp = sp_repr_children(repr);
464             if ( temp == NULL ) return NULL;
465             
466             return temp->content();
468         case RDF_AGENT:
469             temp = sp_repr_lookup_name ( repr, "cc:Agent", 1 );
470             if ( temp == NULL ) return NULL;
472             temp = sp_repr_lookup_name ( temp, "dc:title", 1 );
473             if ( temp == NULL ) return NULL;
475             temp = sp_repr_children(temp);
476             if ( temp == NULL ) return NULL;
478             return temp->content();
480         case RDF_RESOURCE:
481             return repr->attribute("rdf:resource");
483         case RDF_XML:
484             return "xml goes here";
486         case RDF_BAG:
487             /* clear the static string.  yucky. */
488             if (bag) g_free(bag);
489             bag = NULL;
491             temp = sp_repr_lookup_name ( repr, "rdf:Bag", 1 );
492             if ( temp == NULL ) {
493                 /* backwards compatible: read contents */
494                 temp = sp_repr_children(repr);
495                 if ( temp == NULL ) return NULL;
496             
497                 return temp->content();
498             }
500             for ( temp = sp_repr_children(temp) ;
501                   temp ;
502                   temp = sp_repr_next(temp) ) {
503                 if (!strcmp(temp->name(),"rdf:li") &&
504                     temp->firstChild()) {
505                     const gchar * str = temp->firstChild()->content();
506                     if (bag) {
507                         holder = bag;
508                         bag = g_strconcat(holder, ", ", str, NULL);
509                         g_free(holder);
510                     }
511                     else {
512                         bag = g_strdup(str);
513                     }
514                 }
515             }
516             return bag;
518         default:
519             break;
520     }
521     return NULL;
524 unsigned int
525 rdf_set_repr_text ( Inkscape::XML::Node * repr,
526                     struct rdf_work_entity_t * entity,
527                     gchar const * text )
529     g_return_val_if_fail ( repr != NULL, 0);
530     g_return_val_if_fail ( entity != NULL, 0);
531     g_return_val_if_fail ( text != NULL, 0);
532     gchar * str = NULL;
533     gchar** strlist = NULL;
534     int i;
536     Inkscape::XML::Node * temp=NULL;
537     Inkscape::XML::Node * child=NULL;
538     Inkscape::XML::Node * parent=repr;
540     Inkscape::XML::Document * xmldoc = parent->document();
541     g_return_val_if_fail (xmldoc != NULL, FALSE);
543     switch (entity->datatype) {
544         case RDF_CONTENT:
545             temp = sp_repr_children(parent);
546             if ( temp == NULL ) {
547                 temp = xmldoc->createTextNode( text );
548                 g_return_val_if_fail (temp != NULL, FALSE);
550                 parent->appendChild(temp);
551                 Inkscape::GC::release(temp);
553                 return TRUE;
554             }
555             else {
556                 temp->setContent(text);
557                 return TRUE;
558             }
560         case RDF_AGENT:
561             temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 );
562             if ( temp == NULL ) {
563                 temp = xmldoc->createElement ( "cc:Agent" );
564                 g_return_val_if_fail (temp != NULL, FALSE);
566                 parent->appendChild(temp);
567                 Inkscape::GC::release(temp);
568             }
569             parent = temp;
571             temp = sp_repr_lookup_name ( parent, "dc:title", 1 );
572             if ( temp == NULL ) {
573                 temp = xmldoc->createElement ( "dc:title" );
574                 g_return_val_if_fail (temp != NULL, FALSE);
576                 parent->appendChild(temp);
577                 Inkscape::GC::release(temp);
578             }
579             parent = temp;
581             temp = sp_repr_children(parent);
582             if ( temp == NULL ) {
583                 temp = xmldoc->createTextNode( text );
584                 g_return_val_if_fail (temp != NULL, FALSE);
586                 parent->appendChild(temp);
587                 Inkscape::GC::release(temp);
589                 return TRUE;
590             }
591             else {
592                 temp->setContent(text);
593                                 return TRUE;
594             }
596         case RDF_RESOURCE:
597             parent->setAttribute("rdf:resource", text );
598             return true;
600         case RDF_XML:
601             return 1;
603         case RDF_BAG:
604             /* find/create the rdf:Bag item */
605             temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 );
606             if ( temp == NULL ) {
607                 /* backward compatibility: drop the dc:subject contents */
608                 while ( (temp = sp_repr_children( parent )) ) {
609                     parent->removeChild(temp);
610                 }
612                 temp = xmldoc->createElement ( "rdf:Bag" );
613                 g_return_val_if_fail (temp != NULL, FALSE);
615                 parent->appendChild(temp);
616                 Inkscape::GC::release(temp);
617             }
618             parent = temp;
620             /* toss all the old list items */
621             while ( (temp = sp_repr_children( parent )) ) {
622                 parent->removeChild(temp);
623             }
625             /* chop our list up on commas */
626             strlist = g_strsplit( text, ",", 0);
628             for (i = 0; (str = strlist[i]); i++) {
629                 temp = xmldoc->createElement ( "rdf:li" );
630                 g_return_val_if_fail (temp != NULL, 0);
632                 parent->appendChild(temp);
633                 Inkscape::GC::release(temp);
635                 child = xmldoc->createTextNode( g_strstrip(str) );
636                 g_return_val_if_fail (child != NULL, 0);
638                 temp->appendChild(child);
639                 Inkscape::GC::release(child);
640             }
641             g_strfreev( strlist );
643             return 1;
645         default:
646             break;
647     }
648     return 0;
651 Inkscape::XML::Node *
652 rdf_get_rdf_root_repr ( SPDocument * doc, bool build )
654     g_return_val_if_fail (doc        != NULL, NULL);
655     g_return_val_if_fail (doc->rroot != NULL, NULL);
657     Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
658     g_return_val_if_fail (xmldoc != NULL, NULL);
660     Inkscape::XML::Node * rdf = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_RDF );
662     if (rdf == NULL) {
663         //printf("missing XML '%s'\n",XML_TAG_NAME_RDF);
664         if (!build) return NULL;
666         Inkscape::XML::Node * svg = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_SVG );
667         g_return_val_if_fail ( svg != NULL, NULL );
669         Inkscape::XML::Node * parent = sp_repr_lookup_name ( svg, XML_TAG_NAME_METADATA );
670         if ( parent == NULL ) {
671             parent = xmldoc->createElement( XML_TAG_NAME_METADATA );
672             g_return_val_if_fail ( parent != NULL, NULL);
674             svg->appendChild(parent);
675             Inkscape::GC::release(parent);
676         }
678         Inkscape::XML::Document * xmldoc = parent->document();
679         g_return_val_if_fail (xmldoc != NULL, FALSE);
681         rdf = xmldoc->createElement( XML_TAG_NAME_RDF );
682         g_return_val_if_fail (rdf != NULL, NULL);
684         parent->appendChild(rdf);
685         Inkscape::GC::release(rdf);
686     }
688     /*
689      * some implementations do not put RDF stuff inside <metadata>,
690      * so we need to check for it and add it if we don't see it
691      */
692     Inkscape::XML::Node * want_metadata = sp_repr_parent ( rdf );
693     g_return_val_if_fail (want_metadata != NULL, NULL);
694     if (strcmp( want_metadata->name(), XML_TAG_NAME_METADATA )) {
695             Inkscape::XML::Node * metadata = xmldoc->createElement( XML_TAG_NAME_METADATA );
696             g_return_val_if_fail (metadata != NULL, NULL);
698             /* attach the metadata node */
699             want_metadata->appendChild(metadata);
700             Inkscape::GC::release(metadata);
702             /* move the RDF into it */
703             Inkscape::GC::anchor(rdf);
704             sp_repr_unparent ( rdf );
705             metadata->appendChild(rdf);
706             Inkscape::GC::release(rdf);
707     }
708     
709     return rdf;
712 Inkscape::XML::Node *
713 rdf_get_xml_repr( SPDocument * doc, gchar const * name, bool build )
715     g_return_val_if_fail (name       != NULL, NULL);
716     g_return_val_if_fail (doc        != NULL, NULL);
717     g_return_val_if_fail (doc->rroot != NULL, NULL);
719     Inkscape::XML::Node * rdf = rdf_get_rdf_root_repr ( doc, build );
720     if (!rdf) return NULL;
722     Inkscape::XML::Node * xml = sp_repr_lookup_name ( rdf, name );
723     if (xml == NULL) {
724         //printf("missing XML '%s'\n",name);
725         if (!build) return NULL;
727         Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
728         g_return_val_if_fail (xmldoc != NULL, NULL);
730         xml = xmldoc->createElement( name );
731         g_return_val_if_fail (xml != NULL, NULL);
733         xml->setAttribute("rdf:about", "" );
735         rdf->appendChild(xml);
736         Inkscape::GC::release(xml);
737     }
739     return xml;
742 Inkscape::XML::Node *
743 rdf_get_work_repr( SPDocument * doc, gchar const * name, bool build )
745     g_return_val_if_fail (name       != NULL, NULL);
746     g_return_val_if_fail (doc        != NULL, NULL);
747     g_return_val_if_fail (doc->rroot != NULL, NULL);
749     Inkscape::XML::Node * work = rdf_get_xml_repr ( doc, XML_TAG_NAME_WORK, build );
750     if (!work) return NULL;
752     Inkscape::XML::Node * item = sp_repr_lookup_name ( work, name, 1 );
753     if (item == NULL) {
754         //printf("missing XML '%s'\n",name);
755         if (!build) return NULL;
757         Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
758         g_return_val_if_fail (xmldoc != NULL, NULL);
760         item = xmldoc->createElement( name );
761         g_return_val_if_fail (item != NULL, NULL);
763         work->appendChild(item);
764         Inkscape::GC::release(item);
765     }
767     return item;
772 /**
773  *  \brief   Retrieves a known RDF/Work entity's contents from the document XML by name
774  *  \return  A pointer to the entity's static contents as a string, or NULL if no entity exists
775  *  \param   entity  The desired RDF/Work entity
776  *  
777  */
778 const gchar *
779 rdf_get_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity)
781     g_return_val_if_fail (doc    != NULL, NULL);
782     if ( entity == NULL ) return NULL;
783     //printf("want '%s'\n",entity->title);
785     Inkscape::XML::Node * item;
786     if ( entity->datatype == RDF_XML ) {
787         item = rdf_get_xml_repr ( doc, entity->tag, FALSE );
788     }
789     else {
790         item = rdf_get_work_repr( doc, entity->tag, FALSE );
791     }
792     if ( item == NULL ) return NULL;
794     const gchar * result = rdf_get_repr_text ( item, entity );
795     //printf("found '%s' == '%s'\n", entity->title, result );
796     return result;
799 /**
800  *  \brief   Stores a string into a named RDF/Work entity in the document XML
801  *  \param   entity The desired RDF/Work entity to replace
802  *  \param   string The string to replace the entity contents with
803  *  
804  */
805 unsigned int
806 rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity,
807                     const gchar * text)
809     g_return_val_if_fail ( entity != NULL, 0 );
810     if (text == NULL) {
811         // FIXME: on a "NULL" text, delete the entity.  For now, blank it.
812         text="";
813     }
815     /*
816     printf("changing '%s' (%s) to '%s'\n",
817         entity->title,
818         entity->tag,
819         text);
820     */
822     Inkscape::XML::Node * item = rdf_get_work_repr( doc, entity->tag, TRUE );
823     g_return_val_if_fail ( item != NULL, 0 );
825     return rdf_set_repr_text ( item, entity, text );
828 #undef DEBUG_MATCH
830 bool
831 rdf_match_license ( Inkscape::XML::Node * repr, struct rdf_license_t * license )
833     g_assert ( repr != NULL );
834     g_assert ( license != NULL );
836     bool result=TRUE;
837 #ifdef DEBUG_MATCH
838     printf("checking against '%s'\n",license->name);
839 #endif
841     int count = 0;
842     for (struct rdf_double_t * details = license->details;
843          details->name; details++ ) {
844         count++;
845     }
846     bool * matched = (bool*)calloc(count,sizeof(bool));
848     for (Inkscape::XML::Node * current = sp_repr_children ( repr );
849          current;
850          current = sp_repr_next ( current ) ) {
852         gchar const * attr = current->attribute("rdf:resource");
853         if ( attr == NULL ) continue;
855 #ifdef DEBUG_MATCH
856         printf("\texamining '%s' => '%s'\n", current->name(), attr);
857 #endif
859         bool found_match=FALSE;
860         for (int i=0; i<count; i++) {
861             // skip already matched items
862             if (matched[i]) continue;
864 #ifdef DEBUG_MATCH
865             printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name);
866             printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource);
867 #endif
869             if (!strcmp( current->name(),
870                          license->details[i].name ) &&
871                 !strcmp( attr,
872                          license->details[i].resource )) {
873                 matched[i]=TRUE;
874                 found_match=TRUE;
875 #ifdef DEBUG_MATCH
876                 printf("\t\tgood!\n");
877 #endif
878                 break;
879             }
880         }
881         if (!found_match) {
882             // if we checked each known item of the license
883             // and didn't find it, we must abort
884             result=FALSE;
885 #ifdef DEBUG_MATCH
886             printf("\t\tno '%s' element matched XML (bong)!\n",license->name);
887 #endif
888             break;
889         }
890     }
891 #ifdef DEBUG_MATCH
892     if (result) printf("\t\tall XML found matching elements!\n");
893 #endif
894     for (int i=0; result && i<count; i++) {
895         // scan looking for an unmatched item
896         if (matched[i]==0) {
897             result=FALSE;
898 #ifdef DEBUG_MATCH
899             printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name);
900 #endif
901         }
902     }
904 #ifdef DEBUG_MATCH
905     printf("\t\tall '%s' elements used to match!\n",license->name);
906 #endif
908     free(matched);
910 #ifdef DEBUG_MATCH
911     if (result) printf("matched '%s'\n",license->name);
912 #endif
913     return result;
916 /**
917  *  \brief   Attempts to match and retrieve a known RDF/License from the document XML
918  *  \return  A pointer to the static RDF license structure
919  *  
920  */
921 struct rdf_license_t *
922 rdf_get_license(SPDocument * document)
924     Inkscape::XML::Node * repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE );
925     if (repr) {
926         for (struct rdf_license_t * license = rdf_licenses;
927              license->name; license++ ) {
928             if ( rdf_match_license ( repr, license ) ) return license;
929         }
930     }
931 #ifdef DEBUG_MATCH
932     else {
933         printf("no license XML\n");
934     }
935 #endif
936     return NULL;
939 /**
940  *  \brief   Stores an RDF/License XML in the document XML
941  *  \param   document  Which document to update
942  *  \param   license   The desired RDF/License structure to store; NULL drops old license, so can be used for proprietary license. 
943  *  
944  */
945 void
946 rdf_set_license(SPDocument * doc, struct rdf_license_t const * license)
948     // drop old license section
949     Inkscape::XML::Node * repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, FALSE );
950     if (repr) sp_repr_unparent(repr);
952     if (!license) return;
954     // build new license section
955     repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, TRUE );
956     g_assert ( repr );
958     repr->setAttribute("rdf:about", license->uri );
960     Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
961     g_return_if_fail (xmldoc != NULL);
963     for (struct rdf_double_t * detail = license->details;
964          detail->name; detail++) {
965         Inkscape::XML::Node * child = xmldoc->createElement( detail->name );
966         g_assert ( child != NULL );
968         child->setAttribute("rdf:resource", detail->resource );
969         repr->appendChild(child);
970         Inkscape::GC::release(child);
971     }
974 struct rdf_entity_default_t {
975     gchar const * name;
976     gchar const * text;
977 };
978 struct rdf_entity_default_t rdf_defaults[] = {
979     { "format",      "image/svg+xml", },
980     { "type",        "http://purl.org/dc/dcmitype/StillImage", },
981     { NULL,          NULL, }
982 };
984 void
985 rdf_set_defaults ( SPDocument * doc )
987     g_assert ( doc != NULL );
989     // Create metadata node if it doesn't already exist
990     if (!sp_item_group_get_child_by_name ((SPGroup *) doc->root, NULL,
991                                           XML_TAG_NAME_METADATA)) {
992         // create repr
993         Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
994         g_return_if_fail (xmldoc != NULL);
995         Inkscape::XML::Node * rnew = xmldoc->createElement (XML_TAG_NAME_METADATA);
996         // insert into the document
997         doc->rroot->addChild(rnew, NULL);
998         // clean up
999         Inkscape::GC::release(rnew);
1000     }
1002     /* install defaults */
1003     for ( struct rdf_entity_default_t * rdf_default = rdf_defaults;
1004           rdf_default->name;
1005           rdf_default++) {
1006         struct rdf_work_entity_t * entity = rdf_find_entity ( rdf_default->name );
1007         g_assert ( entity != NULL );
1009         if ( rdf_get_work_entity ( doc, entity ) == NULL ) {
1010             rdf_set_work_entity ( doc, entity, rdf_default->text );
1011         }
1012     }
1016 /*
1017   Local Variables:
1018   mode:c++
1019   c-file-style:"stroustrup"
1020   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1021   indent-tabs-mode:nil
1022   fill-column:99
1023   End:
1024 */
1025 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :