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...
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>
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>
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/2.5/",
180 rdf_license_cc_a,
181 },
183 { N_("CC Attribution-ShareAlike"),
184 "http://creativecommons.org/licenses/by-sa/2.5/",
185 rdf_license_cc_a_sa,
186 },
188 { N_("CC Attribution-NoDerivs"),
189 "http://creativecommons.org/licenses/by-nd/2.5/",
190 rdf_license_cc_a_nd,
191 },
193 { N_("CC Attribution-NonCommercial"),
194 "http://creativecommons.org/licenses/by-nc/2.5/",
195 rdf_license_cc_a_nc,
196 },
198 { N_("CC Attribution-NonCommercial-ShareAlike"),
199 "http://creativecommons.org/licenses/by-nc-sa/2.5/",
200 rdf_license_cc_a_nc_sa,
201 },
203 { N_("CC Attribution-NonCommercial-NoDerivs"),
204 "http://creativecommons.org/licenses/by-nc-nd/2.5/",
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://web.resource.org/cc/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 },
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)
317 {
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;
324 }
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)
339 {
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;
441 }
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 )
454 {
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;
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;
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;
522 }
524 unsigned int
525 rdf_set_repr_text ( Inkscape::XML::Node * repr,
526 struct rdf_work_entity_t * entity,
527 gchar const * text )
528 {
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;
539 switch (entity->datatype) {
540 case RDF_CONTENT:
541 temp = sp_repr_children(parent);
542 if ( temp == NULL ) {
543 temp = sp_repr_new_text( text );
544 g_return_val_if_fail (temp != NULL, 0);
546 parent->appendChild(temp);
547 Inkscape::GC::release(temp);
549 return TRUE;
550 }
551 else {
552 temp->setContent(text);
553 return TRUE;
554 }
556 case RDF_AGENT:
557 temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 );
558 if ( temp == NULL ) {
559 temp = sp_repr_new ( "cc:Agent" );
560 g_return_val_if_fail (temp != NULL, 0);
562 parent->appendChild(temp);
563 Inkscape::GC::release(temp);
564 }
565 parent = temp;
567 temp = sp_repr_lookup_name ( parent, "dc:title", 1 );
568 if ( temp == NULL ) {
569 temp = sp_repr_new ( "dc:title" );
570 g_return_val_if_fail (temp != NULL, 0);
572 parent->appendChild(temp);
573 Inkscape::GC::release(temp);
574 }
575 parent = temp;
577 temp = sp_repr_children(parent);
578 if ( temp == NULL ) {
579 temp = sp_repr_new_text( text );
580 g_return_val_if_fail (temp != NULL, 0);
582 parent->appendChild(temp);
583 Inkscape::GC::release(temp);
585 return TRUE;
586 }
587 else {
588 temp->setContent(text);
589 return TRUE;
590 }
592 case RDF_RESOURCE:
593 parent->setAttribute("rdf:resource", text );
594 return true;
596 case RDF_XML:
597 return 1;
599 case RDF_BAG:
600 /* find/create the rdf:Bag item */
601 temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 );
602 if ( temp == NULL ) {
603 /* backward compatibility: drop the dc:subject contents */
604 while ( (temp = sp_repr_children( parent )) ) {
605 parent->removeChild(temp);
606 }
608 temp = sp_repr_new ( "rdf:Bag" );
609 g_return_val_if_fail (temp != NULL, 0);
611 parent->appendChild(temp);
612 Inkscape::GC::release(temp);
613 }
614 parent = temp;
616 /* toss all the old list items */
617 while ( (temp = sp_repr_children( parent )) ) {
618 parent->removeChild(temp);
619 }
621 /* chop our list up on commas */
622 strlist = g_strsplit( text, ",", 0);
624 for (i = 0; (str = strlist[i]); i++) {
625 temp = sp_repr_new ( "rdf:li" );
626 g_return_val_if_fail (temp != NULL, 0);
628 parent->appendChild(temp);
629 Inkscape::GC::release(temp);
631 child = sp_repr_new_text( g_strstrip(str) );
632 g_return_val_if_fail (child != NULL, 0);
634 temp->appendChild(child);
635 Inkscape::GC::release(child);
636 }
637 g_strfreev( strlist );
639 return 1;
641 default:
642 break;
643 }
644 return 0;
645 }
647 Inkscape::XML::Node *
648 rdf_get_rdf_root_repr ( SPDocument * doc, bool build )
649 {
650 g_return_val_if_fail (doc != NULL, NULL);
651 g_return_val_if_fail (doc->rroot != NULL, NULL);
653 Inkscape::XML::Node * rdf = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_RDF );
655 if (rdf == NULL) {
656 //printf("missing XML '%s'\n",XML_TAG_NAME_RDF);
657 if (!build) return NULL;
659 Inkscape::XML::Node * svg = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_SVG );
660 g_return_val_if_fail ( svg != NULL, NULL );
662 Inkscape::XML::Node * parent = sp_repr_lookup_name ( svg, XML_TAG_NAME_METADATA );
663 if ( parent == NULL ) {
664 parent = sp_repr_new( XML_TAG_NAME_METADATA );
665 g_return_val_if_fail ( parent != NULL, NULL);
667 svg->appendChild(parent);
668 Inkscape::GC::release(parent);
669 }
671 rdf = sp_repr_new( XML_TAG_NAME_RDF );
672 g_return_val_if_fail (rdf != NULL, NULL);
674 parent->appendChild(rdf);
675 Inkscape::GC::release(rdf);
676 }
678 /*
679 * some implementations do not put RDF stuff inside <metadata>,
680 * so we need to check for it and add it if we don't see it
681 */
682 Inkscape::XML::Node * want_metadata = sp_repr_parent ( rdf );
683 g_return_val_if_fail (want_metadata != NULL, NULL);
684 if (strcmp( want_metadata->name(), XML_TAG_NAME_METADATA )) {
685 Inkscape::XML::Node * metadata = sp_repr_new( XML_TAG_NAME_METADATA );
686 g_return_val_if_fail (metadata != NULL, NULL);
688 /* attach the metadata node */
689 want_metadata->appendChild(metadata);
690 Inkscape::GC::release(metadata);
692 /* move the RDF into it */
693 Inkscape::GC::anchor(rdf);
694 sp_repr_unparent ( rdf );
695 metadata->appendChild(rdf);
696 Inkscape::GC::release(rdf);
697 }
699 return rdf;
700 }
702 Inkscape::XML::Node *
703 rdf_get_xml_repr( SPDocument * doc, gchar const * name, bool build )
704 {
705 g_return_val_if_fail (name != NULL, NULL);
706 g_return_val_if_fail (doc != NULL, NULL);
707 g_return_val_if_fail (doc->rroot != NULL, NULL);
709 Inkscape::XML::Node * rdf = rdf_get_rdf_root_repr ( doc, build );
710 if (!rdf) return NULL;
712 Inkscape::XML::Node * xml = sp_repr_lookup_name ( rdf, name );
713 if (xml == NULL) {
714 //printf("missing XML '%s'\n",name);
715 if (!build) return NULL;
717 xml = sp_repr_new( name );
718 g_return_val_if_fail (xml != NULL, NULL);
720 xml->setAttribute("rdf:about", "" );
722 rdf->appendChild(xml);
723 Inkscape::GC::release(xml);
724 }
726 return xml;
727 }
729 Inkscape::XML::Node *
730 rdf_get_work_repr( SPDocument * doc, gchar const * name, bool build )
731 {
732 g_return_val_if_fail (name != NULL, NULL);
733 g_return_val_if_fail (doc != NULL, NULL);
734 g_return_val_if_fail (doc->rroot != NULL, NULL);
736 Inkscape::XML::Node * work = rdf_get_xml_repr ( doc, XML_TAG_NAME_WORK, build );
737 if (!work) return NULL;
739 Inkscape::XML::Node * item = sp_repr_lookup_name ( work, name, 1 );
740 if (item == NULL) {
741 //printf("missing XML '%s'\n",name);
742 if (!build) return NULL;
744 item = sp_repr_new( name );
745 g_return_val_if_fail (item != NULL, NULL);
747 work->appendChild(item);
748 Inkscape::GC::release(item);
749 }
751 return item;
752 }
756 /**
757 * \brief Retrieves a known RDF/Work entity's contents from the document XML by name
758 * \return A pointer to the entity's static contents as a string, or NULL if no entity exists
759 * \param entity The desired RDF/Work entity
760 *
761 */
762 const gchar *
763 rdf_get_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity)
764 {
765 g_return_val_if_fail (doc != NULL, NULL);
766 if ( entity == NULL ) return NULL;
767 //printf("want '%s'\n",entity->title);
769 Inkscape::XML::Node * item;
770 if ( entity->datatype == RDF_XML ) {
771 item = rdf_get_xml_repr ( doc, entity->tag, FALSE );
772 }
773 else {
774 item = rdf_get_work_repr( doc, entity->tag, FALSE );
775 }
776 if ( item == NULL ) return NULL;
778 const gchar * result = rdf_get_repr_text ( item, entity );
779 //printf("found '%s' == '%s'\n", entity->title, result );
780 return result;
781 }
783 /**
784 * \brief Stores a string into a named RDF/Work entity in the document XML
785 * \param entity The desired RDF/Work entity to replace
786 * \param string The string to replace the entity contents with
787 *
788 */
789 unsigned int
790 rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity,
791 const gchar * text)
792 {
793 g_return_val_if_fail ( entity != NULL, 0 );
794 if (text == NULL) {
795 // FIXME: on a "NULL" text, delete the entity. For now, blank it.
796 text="";
797 }
799 /*
800 printf("changing '%s' (%s) to '%s'\n",
801 entity->title,
802 entity->tag,
803 text);
804 */
806 Inkscape::XML::Node * item = rdf_get_work_repr( doc, entity->tag, TRUE );
807 g_return_val_if_fail ( item != NULL, 0 );
809 return rdf_set_repr_text ( item, entity, text );
810 }
812 #undef DEBUG_MATCH
814 bool
815 rdf_match_license ( Inkscape::XML::Node * repr, struct rdf_license_t * license )
816 {
817 g_assert ( repr != NULL );
818 g_assert ( license != NULL );
820 bool result=TRUE;
821 #ifdef DEBUG_MATCH
822 printf("checking against '%s'\n",license->name);
823 #endif
825 int count = 0;
826 for (struct rdf_double_t * details = license->details;
827 details->name; details++ ) {
828 count++;
829 }
830 bool * matched = (bool*)calloc(count,sizeof(bool));
832 for (Inkscape::XML::Node * current = sp_repr_children ( repr );
833 current;
834 current = sp_repr_next ( current ) ) {
836 gchar const * attr = current->attribute("rdf:resource");
837 if ( attr == NULL ) continue;
839 #ifdef DEBUG_MATCH
840 printf("\texamining '%s' => '%s'\n", current->name(), attr);
841 #endif
843 bool found_match=FALSE;
844 for (int i=0; i<count; i++) {
845 // skip already matched items
846 if (matched[i]) continue;
848 #ifdef DEBUG_MATCH
849 printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name);
850 printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource);
851 #endif
853 if (!strcmp( current->name(),
854 license->details[i].name ) &&
855 !strcmp( attr,
856 license->details[i].resource )) {
857 matched[i]=TRUE;
858 found_match=TRUE;
859 #ifdef DEBUG_MATCH
860 printf("\t\tgood!\n");
861 #endif
862 break;
863 }
864 }
865 if (!found_match) {
866 // if we checked each known item of the license
867 // and didn't find it, we must abort
868 result=FALSE;
869 #ifdef DEBUG_MATCH
870 printf("\t\tno '%s' element matched XML (bong)!\n",license->name);
871 #endif
872 break;
873 }
874 }
875 #ifdef DEBUG_MATCH
876 if (result) printf("\t\tall XML found matching elements!\n");
877 #endif
878 for (int i=0; result && i<count; i++) {
879 // scan looking for an unmatched item
880 if (matched[i]==0) {
881 result=FALSE;
882 #ifdef DEBUG_MATCH
883 printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name);
884 #endif
885 }
886 }
888 #ifdef DEBUG_MATCH
889 printf("\t\tall '%s' elements used to match!\n",license->name);
890 #endif
892 free(matched);
894 #ifdef DEBUG_MATCH
895 if (result) printf("matched '%s'\n",license->name);
896 #endif
897 return result;
898 }
900 /**
901 * \brief Attempts to match and retrieve a known RDF/License from the document XML
902 * \return A pointer to the static RDF license structure
903 *
904 */
905 struct rdf_license_t *
906 rdf_get_license(SPDocument * document)
907 {
908 Inkscape::XML::Node * repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE );
909 if (repr) {
910 for (struct rdf_license_t * license = rdf_licenses;
911 license->name; license++ ) {
912 if ( rdf_match_license ( repr, license ) ) return license;
913 }
914 }
915 #ifdef DEBUG_MATCH
916 else {
917 printf("no license XML\n");
918 }
919 #endif
920 return NULL;
921 }
923 /**
924 * \brief Stores an RDF/License XML in the document XML
925 * \param document Which document to update
926 * \param license The desired RDF/License structure to store; NULL drops old license, so can be used for proprietary license.
927 *
928 */
929 void
930 rdf_set_license(SPDocument * document, struct rdf_license_t const * license)
931 {
932 // drop old license section
933 Inkscape::XML::Node * repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE );
934 if (repr) sp_repr_unparent(repr);
936 if (!license) return;
938 // build new license section
939 repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, TRUE );
940 g_assert ( repr );
942 repr->setAttribute("rdf:about", license->uri );
944 for (struct rdf_double_t * detail = license->details;
945 detail->name; detail++) {
946 Inkscape::XML::Node * child = sp_repr_new( detail->name );
947 g_assert ( child != NULL );
949 child->setAttribute("rdf:resource", detail->resource );
950 repr->appendChild(child);
951 Inkscape::GC::release(child);
952 }
953 }
955 struct rdf_entity_default_t {
956 gchar const * name;
957 gchar const * text;
958 };
959 struct rdf_entity_default_t rdf_defaults[] = {
960 { "format", "image/svg+xml", },
961 { "type", "http://purl.org/dc/dcmitype/StillImage", },
962 { NULL, NULL, }
963 };
965 void
966 rdf_set_defaults ( SPDocument * document )
967 {
968 g_assert ( document != NULL );
970 // Create metadata node if it doesn't already exist
971 if (!sp_item_group_get_child_by_name ((SPGroup *) document->root, NULL,
972 XML_TAG_NAME_METADATA)) {
973 // create repr
974 Inkscape::XML::Node * rnew = sp_repr_new (XML_TAG_NAME_METADATA);
975 // insert into the document
976 document->rroot->addChild(rnew, NULL);
977 // clean up
978 Inkscape::GC::release(rnew);
979 }
981 /* install defaults */
982 for ( struct rdf_entity_default_t * rdf_default = rdf_defaults;
983 rdf_default->name;
984 rdf_default++) {
985 struct rdf_work_entity_t * entity = rdf_find_entity ( rdf_default->name );
986 g_assert ( entity != NULL );
988 if ( rdf_get_work_entity ( document, entity ) == NULL ) {
989 rdf_set_work_entity ( document, entity, rdf_default->text );
990 }
991 }
992 }
995 /*
996 Local Variables:
997 mode:c++
998 c-file-style:"stroustrup"
999 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1000 indent-tabs-mode:nil
1001 fill-column:99
1002 End:
1003 */
1004 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :