Code

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