Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / extension / internal / svg.cpp
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;
136 #ifdef WITH_GNOME_VFS
137 #define BUF_SIZE 8192
139 static gchar *
140 _load_uri (const gchar *uri)
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());
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)
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
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)
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;
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 :