1 /** \file
2 * Code for handling XSLT extensions.
3 */
4 /*
5 * Authors:
6 * Ted Gould <ted@gould.cx>
7 *
8 * Copyright (C) 2006-2007 Authors
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif
17 #include "xslt.h"
18 #include "../extension.h"
19 #include "../output.h"
21 #include "xml/repr.h"
22 #include "io/sys.h"
23 #include "file.h"
24 #include <unistd.h>
25 #include <cstring>
26 #include "document.h"
28 #include <libxml/parser.h>
29 #include <libxslt/transform.h>
31 Inkscape::XML::Document * sp_repr_do_read (xmlDocPtr doc, const gchar * default_ns);
33 /* Namespaces */
34 namespace Inkscape {
35 namespace Extension {
36 namespace Implementation {
38 /* Real functions */
39 /**
40 \return A XSLT object
41 \brief This function creates a XSLT object and sets up the
42 variables.
44 */
45 XSLT::XSLT(void) :
46 Implementation(),
47 _filename(""),
48 _parsedDoc(NULL),
49 _stylesheet(NULL)
50 {
51 }
53 Glib::ustring
54 XSLT::solve_reldir(Inkscape::XML::Node *reprin) {
56 gchar const *s = reprin->attribute("reldir");
58 if (!s) {
59 Glib::ustring str = sp_repr_children(reprin)->content();
60 return str;
61 }
63 Glib::ustring reldir = s;
65 if (reldir == "extensions") {
67 for (unsigned int i=0;
68 i < Inkscape::Extension::Extension::search_path.size();
69 i++) {
71 gchar * fname = g_build_filename(
72 Inkscape::Extension::Extension::search_path[i],
73 sp_repr_children(reprin)->content(),
74 NULL);
75 Glib::ustring filename = fname;
76 g_free(fname);
78 if ( Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS) )
79 return filename;
81 }
82 } else {
83 Glib::ustring str = sp_repr_children(reprin)->content();
84 return str;
85 }
87 return "";
88 }
90 bool
91 XSLT::check(Inkscape::Extension::Extension *module)
92 {
93 if (load(module)) {
94 unload(module);
95 return true;
96 } else {
97 return false;
98 }
99 }
101 bool
102 XSLT::load(Inkscape::Extension::Extension *module)
103 {
104 if (module->loaded()) { return true; }
106 Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
107 while (child_repr != NULL) {
108 if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "xslt")) {
109 child_repr = sp_repr_children(child_repr);
110 while (child_repr != NULL) {
111 if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "file")) {
112 _filename = solve_reldir(child_repr);
113 }
114 child_repr = sp_repr_next(child_repr);
115 }
117 break;
118 }
119 child_repr = sp_repr_next(child_repr);
120 }
122 _parsedDoc = xmlParseFile(_filename.c_str());
123 if (_parsedDoc == NULL) { return false; }
125 _stylesheet = xsltParseStylesheetDoc(_parsedDoc);
127 return true;
128 }
130 void
131 XSLT::unload(Inkscape::Extension::Extension *module)
132 {
133 if (!module->loaded()) { return; }
134 xsltFreeStylesheet(_stylesheet);
135 xmlFreeDoc(_parsedDoc);
136 return;
137 }
139 SPDocument *
140 XSLT::open(Inkscape::Extension::Input */*module*/, gchar const *filename)
141 {
142 xmlDocPtr filein = xmlParseFile(filename);
143 if (filein == NULL) { return NULL; }
145 const char * params[1];
146 params[0] = NULL;
148 xmlDocPtr result = xsltApplyStylesheet(_stylesheet, filein, params);
149 xmlFreeDoc(filein);
151 Inkscape::XML::Document * rdoc = sp_repr_do_read( result, SP_SVG_NS_URI);
152 xmlFreeDoc(result);
154 if (rdoc == NULL) {
155 return NULL;
156 }
158 if (strcmp(rdoc->root()->name(), "svg:svg") != 0) {
159 return NULL;
160 }
162 gchar * base = NULL;
163 gchar * name = NULL;
164 gchar * s = NULL, * p = NULL;
165 s = g_strdup(filename);
166 p = strrchr(s, '/');
167 if (p) {
168 name = g_strdup(p + 1);
169 p[1] = '\0';
170 base = g_strdup(s);
171 } else {
172 base = NULL;
173 name = g_strdup(filename);
174 }
175 g_free(s);
177 SPDocument * doc = sp_document_create(rdoc, filename, base, name, true);
179 g_free(base); g_free(name);
181 return doc;
182 }
184 void
185 XSLT::save(Inkscape::Extension::Output */*module*/, SPDocument *doc, gchar const *filename)
186 {
187 /* TODO: Should we assume filename to be in utf8 or to be a raw filename?
188 * See JavaFXOutput::save for discussion. */
189 g_return_if_fail(doc != NULL);
190 g_return_if_fail(filename != NULL);
192 Inkscape::XML::Node *repr = NULL;
193 repr = sp_document_repr_root (doc);
195 std::string tempfilename_out;
196 int tempfd_out = 0;
197 try {
198 tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX");
199 } catch (...) {
200 /// \todo Popup dialog here
201 return;
202 }
204 if (!sp_repr_save_rebased_file(repr->document(), tempfilename_out.c_str(), SP_SVG_NS_URI,
205 doc->base, filename)) {
206 throw Inkscape::Extension::Output::save_failed();
207 }
209 xmlDocPtr svgdoc = xmlParseFile(tempfilename_out.c_str());
210 close(tempfd_out);
211 if (svgdoc == NULL) {
212 return;
213 }
215 const char * params[1];
216 params[0] = NULL;
218 xmlDocPtr newdoc = xsltApplyStylesheet(_stylesheet, svgdoc, params);
219 xmlSaveFile(filename, newdoc);
221 xmlFreeDoc(newdoc);
222 xmlFreeDoc(svgdoc);
224 return;
225 }
228 } /* Implementation */
229 } /* module */
230 } /* Inkscape */
233 /*
234 Local Variables:
235 mode:c++
236 c-file-style:"stroustrup"
237 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
238 indent-tabs-mode:nil
239 fill-column:99
240 End:
241 */
242 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :