1 /*
2 * This is the code that moves all of the SVG loading and saving into
3 * the module format. Really Inkscape is built to handle these formats
4 * internally, so this is just calling those internal functions.
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * Ted Gould <ted@gould.cx>
9 * Jon A. Cruz <jon@joncruz.org>
10 * Abhishek Sharma
11 *
12 * Copyright (C) 2002-2003 Authors
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include "sp-object.h"
21 #include "svg.h"
22 #include "file.h"
23 #include "extension/system.h"
24 #include "extension/output.h"
25 #include <vector>
26 #include "xml/attribute-record.h"
28 #ifdef WITH_GNOME_VFS
29 # include <libgnomevfs/gnome-vfs.h>
30 #endif
32 namespace Inkscape {
33 namespace Extension {
34 namespace Internal {
36 #include "clear-n_.h"
39 using Inkscape::Util::List;
40 using Inkscape::XML::AttributeRecord;
41 using Inkscape::XML::Node;
45 void pruneExtendedAttributes( Inkscape::XML::Node *repr )
46 {
47 if (repr) {
48 if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
49 std::vector<gchar const*> toBeRemoved;
50 for ( List<AttributeRecord const> it = repr->attributeList(); it; ++it ) {
51 const gchar* attrName = g_quark_to_string(it->key);
52 if ((strncmp("inkscape:", attrName, 9) == 0) || (strncmp("sodipodi:", attrName, 9) == 0)) {
53 toBeRemoved.push_back(attrName);
54 }
55 }
56 // Can't change the set we're interating over while we are iterating.
57 for ( std::vector<gchar const*>::iterator it = toBeRemoved.begin(); it != toBeRemoved.end(); ++it ) {
58 repr->setAttribute(*it, 0);
59 }
60 }
62 for ( Node *child = repr->firstChild(); child; child = child->next() ) {
63 pruneExtendedAttributes(child);
64 }
65 }
66 }
69 /**
70 \return None
71 \brief What would an SVG editor be without loading/saving SVG
72 files. This function sets that up.
74 For each module there is a call to Inkscape::Extension::build_from_mem
75 with a rather large XML file passed in. This is a constant string
76 that describes the module. At the end of this call a module is
77 returned that is basically filled out. The one thing that it doesn't
78 have is the key function for the operation. And that is linked at
79 the end of each call.
80 */
81 void
82 Svg::init(void)
83 {
84 Inkscape::Extension::Extension * ext;
86 /* SVG in */
87 ext = Inkscape::Extension::build_from_mem(
88 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
89 "<name>" N_("SVG Input") "</name>\n"
90 "<id>" SP_MODULE_KEY_INPUT_SVG "</id>\n"
91 "<input>\n"
92 "<extension>.svg</extension>\n"
93 "<mimetype>image/svg+xml</mimetype>\n"
94 "<filetypename>" N_("Scalable Vector Graphic (*.svg)") "</filetypename>\n"
95 "<filetypetooltip>" N_("Inkscape native file format and W3C standard") "</filetypetooltip>\n"
96 "<output_extension>" SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE "</output_extension>\n"
97 "</input>\n"
98 "</inkscape-extension>", new Svg());
100 /* SVG out Inkscape */
101 ext = Inkscape::Extension::build_from_mem(
102 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
103 "<name>" N_("SVG Output Inkscape") "</name>\n"
104 "<id>" SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE "</id>\n"
105 "<output>\n"
106 "<extension>.svg</extension>\n"
107 "<mimetype>image/x-inkscape-svg</mimetype>\n"
108 "<filetypename>" N_("Inkscape SVG (*.svg)") "</filetypename>\n"
109 "<filetypetooltip>" N_("SVG format with Inkscape extensions") "</filetypetooltip>\n"
110 "<dataloss>false</dataloss>\n"
111 "</output>\n"
112 "</inkscape-extension>", new Svg());
114 /* SVG out */
115 ext = Inkscape::Extension::build_from_mem(
116 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
117 "<name>" N_("SVG Output") "</name>\n"
118 "<id>" SP_MODULE_KEY_OUTPUT_SVG "</id>\n"
119 "<output>\n"
120 "<extension>.svg</extension>\n"
121 "<mimetype>image/svg+xml</mimetype>\n"
122 "<filetypename>" N_("Plain SVG (*.svg)") "</filetypename>\n"
123 "<filetypetooltip>" N_("Scalable Vector Graphics format as defined by the W3C") "</filetypetooltip>\n"
124 "</output>\n"
125 "</inkscape-extension>", new Svg());
127 #ifdef WITH_GNOME_VFS
128 gnome_vfs_init();
129 #endif
132 return;
133 }
136 #ifdef WITH_GNOME_VFS
137 #define BUF_SIZE 8192
139 static gchar *
140 _load_uri (const gchar *uri)
141 {
142 GnomeVFSHandle *handle = NULL;
143 GnomeVFSFileSize bytes_read;
145 gsize bytesRead = 0;
146 gsize bytesWritten = 0;
147 GError* error = NULL;
148 gchar* uri_local = g_filename_from_utf8( uri, -1, &bytesRead, &bytesWritten, &error);
150 if ( uri_local == NULL ) {
151 g_warning( "Error converting filename to locale encoding.");
152 }
154 GnomeVFSResult result = gnome_vfs_open (&handle, uri_local, GNOME_VFS_OPEN_READ);
156 if (result != GNOME_VFS_OK) {
157 g_warning("%s", gnome_vfs_result_to_string(result));
158 }
160 std::vector<gchar> doc;
161 while (result == GNOME_VFS_OK) {
162 gchar buffer[BUF_SIZE];
163 result = gnome_vfs_read (handle, buffer, BUF_SIZE, &bytes_read);
164 doc.insert(doc.end(), buffer, buffer+bytes_read);
165 }
167 return g_strndup(&doc[0], doc.size());
168 }
169 #endif
172 /**
173 \return A new document just for you!
174 \brief This function takes in a filename of a SVG document and
175 turns it into a SPDocument.
176 \param mod Module to use
177 \param uri The path to the file (UTF-8)
179 This function is really simple, it just calls sp_document_new...
180 */
181 SPDocument *
182 Svg::open (Inkscape::Extension::Input */*mod*/, const gchar *uri)
183 {
184 #ifdef WITH_GNOME_VFS
185 if (!gnome_vfs_initialized() || gnome_vfs_uri_is_local(gnome_vfs_uri_new(uri))) {
186 // Use built-in loader instead of VFS for this
187 return SPDocument::createNewDoc(uri, TRUE);
188 }
189 gchar * buffer = _load_uri(uri);
190 if (buffer == NULL) {
191 g_warning("Error: Could not open file '%s' with VFS\n", uri);
192 return NULL;
193 }
194 SPDocument * doc = SPDocument::createNewDocFromMem(buffer, strlen(buffer), 1);
196 g_free(buffer);
197 return doc;
198 #else
199 return SPDocument::createNewDoc(uri, TRUE);
200 #endif
201 }
203 /**
204 \return None
205 \brief This is the function that does all of the SVG saves in
206 Inkscape. It detects whether it should do a Inkscape
207 namespace save internally.
208 \param mod Extension to use.
209 \param doc Document to save.
210 \param uri The filename to save the file to.
212 This function first checks its parameters, and makes sure that
213 we're getting good data. It also checks the module ID of the
214 incoming module to figure out whether this save should include
215 the Inkscape namespace stuff or not. The result of that comparison
216 is stored in the exportExtensions variable.
218 If there is not to be Inkscape name spaces a new document is created
219 without. (I think, I'm not sure on this code)
221 All of the internally referenced imageins are also set to relative
222 paths in the file. And the file is saved.
224 This really needs to be fleshed out more, but I don't quite understand
225 all of this code. I just stole it.
226 */
227 void
228 Svg::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
229 {
230 g_return_if_fail(doc != NULL);
231 g_return_if_fail(filename != NULL);
233 gchar *save_path = g_path_get_dirname(filename);
235 bool const exportExtensions = ( !mod->get_id()
236 || !strcmp (mod->get_id(), SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)
237 || !strcmp (mod->get_id(), SP_MODULE_KEY_OUTPUT_SVGZ_INKSCAPE));
239 Inkscape::XML::Document *rdoc = NULL;
240 Inkscape::XML::Node *repr = NULL;
241 if (exportExtensions) {
242 repr = doc->getReprRoot();
243 } else {
244 rdoc = sp_repr_document_new ("svg:svg");
245 repr = rdoc->root();
246 repr = doc->getRoot()->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
248 pruneExtendedAttributes(repr);
249 }
251 if (!sp_repr_save_rebased_file(repr->document(), filename, SP_SVG_NS_URI,
252 doc->getBase(), filename)) {
253 throw Inkscape::Extension::Output::save_failed();
254 }
256 if (!exportExtensions) {
257 Inkscape::GC::release(rdoc);
258 }
260 g_free(save_path);
262 return;
263 }
265 } } } /* namespace inkscape, module, implementation */
267 /*
268 Local Variables:
269 mode:c++
270 c-file-style:"stroustrup"
271 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
272 indent-tabs-mode:nil
273 fill-column:99
274 End:
275 */
276 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :