diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp
index bb62393fc541981002e120d4e03b1db8d14e89e4..b1320a4a399d9eb54fc06671da6cb5b779d6e431 100644 (file)
--- a/src/xml/repr-io.cpp
+++ b/src/xml/repr-io.cpp
# include <config.h>
#endif
+#include <cstring>
+#include <string>
#include <stdexcept>
+#include <libxml/parser.h>
+
#include "xml/repr.h"
#include "xml/attribute-record.h"
+#include "xml/rebase-hrefs.h"
+#include "xml/simple-document.h"
#include "io/sys.h"
#include "io/uristream.h"
+#include "io/stringstream.h"
#include "io/gzipstream.h"
+#include "extension/extension.h"
+
+#include "preferences.h"
using Inkscape::IO::Writer;
using Inkscape::Util::List;
using Inkscape::Util::cons;
using Inkscape::XML::Document;
+using Inkscape::XML::SimpleDocument;
using Inkscape::XML::Node;
using Inkscape::XML::AttributeRecord;
+using Inkscape::XML::calc_abs_doc_base;
+using Inkscape::XML::rebase_href_attrs;
-static Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns);
-static Node *sp_repr_svg_read_node (xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map);
+Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns);
+static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map);
static gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar *default_ns, GHashTable *prefix_map);
-static void sp_repr_write_stream_root_element (Node *repr, Writer &out, gboolean add_whitespace, gchar const *default_ns);
-static void sp_repr_write_stream (Node *repr, Writer &out, gint indent_level, gboolean add_whitespace, Glib::QueryQuark elide_prefix);
-static void sp_repr_write_stream_element (Node *repr, Writer &out, gint indent_level, gboolean add_whitespace, Glib::QueryQuark elide_prefix, List<AttributeRecord const> attributes);
+static void sp_repr_write_stream_root_element(Node *repr, Writer &out,
+ bool add_whitespace, gchar const *default_ns,
+ int inlineattrs, int indent,
+ gchar const *old_href_abs_base,
+ gchar const *new_href_abs_base);
+static void sp_repr_write_stream_element(Node *repr, Writer &out,
+ gint indent_level, bool add_whitespace,
+ Glib::QueryQuark elide_prefix,
+ List<AttributeRecord const> attributes,
+ int inlineattrs, int indent,
+ gchar const *old_href_abs_base,
+ gchar const *new_href_abs_base);
#ifdef HAVE_LIBWMF
static xmlDocPtr sp_wmf_convert (const char * file_name);
public:
XmlSource()
: filename(0),
+ encoding(0),
fp(0),
- first(false),
+ firstFewLen(0),
dummy("x"),
instr(0),
gzin(0)
virtual ~XmlSource()
{
close();
+ if ( encoding ) {
+ g_free(encoding);
+ encoding = 0;
+ }
}
- void setFile( char const * filename );
-
- static int readCb( void * context, char * buffer, int len);
- static int closeCb(void * context);
+ int setFile( char const * filename );
+ static int readCb( void * context, char * buffer, int len );
+ static int closeCb( void * context );
+ char const* getEncoding() const { return encoding; }
int read( char * buffer, int len );
int close();
private:
const char* filename;
+ char* encoding;
FILE* fp;
- bool first;
+ unsigned char firstFew[4];
+ int firstFewLen;
Inkscape::URI dummy;
Inkscape::IO::UriInputStream* instr;
Inkscape::IO::GzipInputStream* gzin;
};
-void XmlSource::setFile(char const *filename)
+int XmlSource::setFile(char const *filename)
{
+ int retVal = -1;
+
this->filename = filename;
+
fp = Inkscape::IO::fopen_utf8name(filename, "r");
- if (fp == NULL) {
- throw std::runtime_error("Could not open file for reading");
+ if ( fp ) {
+ // First peek in the file to see what it is
+ memset( firstFew, 0, sizeof(firstFew) );
+
+ size_t some = fread( firstFew, 1, 4, fp );
+ if ( fp ) {
+ // first check for compression
+ if ( (some >= 2) && (firstFew[0] == 0x1f) && (firstFew[1] == 0x8b) ) {
+ //g_message(" the file being read is gzip'd. extract it");
+ fclose(fp);
+ fp = 0;
+ fp = Inkscape::IO::fopen_utf8name(filename, "r");
+ instr = new Inkscape::IO::UriInputStream(fp, dummy);
+ gzin = new Inkscape::IO::GzipInputStream(*instr);
+
+ memset( firstFew, 0, sizeof(firstFew) );
+ some = 0;
+ int single = 0;
+ while ( some < 4 && single >= 0 )
+ {
+ single = gzin->get();
+ if ( single >= 0 ) {
+ firstFew[some++] = 0x0ff & single;
+ } else {
+ break;
+ }
+ }
+ }
+
+ int encSkip = 0;
+ if ( (some >= 2) &&(firstFew[0] == 0xfe) && (firstFew[1] == 0xff) ) {
+ encoding = g_strdup("UTF-16BE");
+ encSkip = 2;
+ } else if ( (some >= 2) && (firstFew[0] == 0xff) && (firstFew[1] == 0xfe) ) {
+ encoding = g_strdup("UTF-16LE");
+ encSkip = 2;
+ } else if ( (some >= 3) && (firstFew[0] == 0xef) && (firstFew[1] == 0xbb) && (firstFew[2] == 0xbf) ) {
+ encoding = g_strdup("UTF-8");
+ encSkip = 3;
+ }
+
+ if ( encSkip ) {
+ memmove( firstFew, firstFew + encSkip, (some - encSkip) );
+ some -= encSkip;
+ }
+
+ firstFewLen = some;
+ retVal = 0; // no error
+ }
}
- first = true;
+
+ return retVal;
}
int retVal = 0;
size_t got = 0;
- if ( first ) {
- first = false;
- char tmp[] = {0,0};
- size_t some = fread( tmp, 1, 2, fp );
-
- if ( (some >= 2) && (tmp[0] == 0x1f) && ((unsigned char)(tmp[1]) == 0x8b) ) {
- //g_message(" the file being read is gzip'd. extract it");
- fclose(fp);
- fp = 0;
- fp = Inkscape::IO::fopen_utf8name(filename, "r");
- instr = new Inkscape::IO::UriInputStream(fp, dummy);
- gzin = new Inkscape::IO::GzipInputStream(*instr);
- int single = 0;
- while ( (int)got < len && single >= 0 )
- {
- single = gzin->get();
- if ( single >= 0 ) {
- buffer[got++] = 0x0ff & single;
- } else {
- break;
- }
- }
- //g_message(" extracted %d bytes this pass", got );
- } else {
- memcpy( buffer, tmp, some );
- got = some;
+ if ( firstFewLen > 0 ) {
+ int some = (len < firstFewLen) ? len : firstFewLen;
+ memcpy( buffer, firstFew, some );
+ if ( len < firstFewLen ) {
+ memmove( firstFew, firstFew + some, (firstFewLen - some) );
}
+ firstFewLen -= some;
+ got = some;
} else if ( gzin ) {
int single = 0;
- while ( (int)got < len && single >= 0 )
+ while ( (static_cast<int>(got) < len) && (single >= 0) )
{
single = gzin->get();
if ( single >= 0 ) {
break;
}
}
- //g_message(" extracted %d bytes this pass b", got );
} else {
got = fread( buffer, 1, len, fp );
}
if ( feof(fp) ) {
retVal = got;
- }
- else if ( ferror(fp) ) {
+ } else if ( ferror(fp) ) {
retVal = -1;
- }
- else {
+ } else {
retVal = got;
}
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (Inkscape::IO::file_test( filename, G_FILE_TEST_EXISTS ), NULL);
+ /* fixme: A file can disappear at any time, including between now and when we actually try to
+ * open it. Get rid of the above test once we're sure that we correctly handle
+ * non-existence. */
// TODO: bulia, please look over
gsize bytesRead = 0;
Inkscape::IO::dump_fopen_call( filename, "N" );
- XmlSource src;
- try
- {
- src.setFile(filename);
- }
- catch (...)
- {
- return NULL;
- }
-
- xmlDocPtr doubleDoc = xmlReadIO( XmlSource::readCb,
- XmlSource::closeCb,
- &src,
- localFilename,
- NULL, //"UTF-8",
- XML_PARSE_NOENT );
-
-
#ifdef HAVE_LIBWMF
if (strlen (localFilename) > 4) {
if ( (strcmp (localFilename + strlen (localFilename) - 4,".wmf") == 0)
- || (strcmp (localFilename + strlen (localFilename) - 4,".WMF") == 0))
+ || (strcmp (localFilename + strlen (localFilename) - 4,".WMF") == 0)) {
doc = sp_wmf_convert (localFilename);
- else
- doc = xmlParseFile (localFilename);
- }
- else {
- doc = xmlParseFile (localFilename);
+ }
}
-#else /* !HAVE_LIBWMF */
- //doc = xmlParseFile (localFilename);
-#endif /* !HAVE_LIBWMF */
+#endif // !HAVE_LIBWMF
- //rdoc = sp_repr_do_read (doc, default_ns);
- rdoc = sp_repr_do_read (doubleDoc, default_ns);
- if (doc)
- xmlFreeDoc (doc);
+ if ( !doc ) {
+ XmlSource src;
+
+ if ( (src.setFile(filename) == 0) ) {
+ doc = xmlReadIO( XmlSource::readCb,
+ XmlSource::closeCb,
+ &src,
+ localFilename,
+ src.getEncoding(),
+ XML_PARSE_NOENT | XML_PARSE_HUGE);
+ }
+ }
- if ( localFilename != NULL )
- g_free (localFilename);
+ rdoc = sp_repr_do_read( doc, default_ns );
+ if ( doc ) {
+ xmlFreeDoc( doc );
+ }
- if ( doubleDoc != NULL )
- {
- xmlFreeDoc( doubleDoc );
+ if ( localFilename ) {
+ g_free( localFilename );
}
return rdoc;
g_return_val_if_fail (buffer != NULL, NULL);
- doc = xmlParseMemory ((gchar *) buffer, length);
+ doc = xmlParseMemory (const_cast<gchar *>(buffer), length);
rdoc = sp_repr_do_read (doc, default_ns);
- if (doc)
+ if (doc) {
xmlFreeDoc (doc);
+ }
return rdoc;
}
+/**
+ * Reads and parses XML from a buffer, returning it as an Document
+ */
+Document *
+sp_repr_read_buf (const Glib::ustring &buf, const gchar *default_ns)
+{
+ return sp_repr_read_mem(buf.c_str(), buf.size(), default_ns);
+}
+
+
namespace Inkscape {
struct compare_quark_ids {
namespace {
-void promote_to_svg_namespace(Node *repr) {
+void promote_to_namespace(Node *repr, const gchar *prefix) {
if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
GQuark code = repr->code();
if (!qname_prefix(code).id()) {
- gchar *svg_name = g_strconcat("svg:", g_quark_to_string(code), NULL);
+ gchar *svg_name = g_strconcat(prefix, ":", g_quark_to_string(code), NULL);
repr->setCodeUnsafe(g_quark_from_string(svg_name));
g_free(svg_name);
}
for ( Node *child = sp_repr_children(repr) ; child ; child = sp_repr_next(child) ) {
- promote_to_svg_namespace(child);
+ promote_to_namespace(child, prefix);
}
}
}
Document *
sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns)
{
- if (doc == NULL) return NULL;
+ if (doc == NULL) {
+ return NULL;
+ }
xmlNodePtr node=xmlDocGetRootElement (doc);
- if (node == NULL) return NULL;
+ if (node == NULL) {
+ return NULL;
+ }
GHashTable * prefix_map;
prefix_map = g_hash_table_new (g_str_hash, g_str_equal);
- GSList *reprs=NULL;
- Node *root=NULL;
+ Document *rdoc = new Inkscape::XML::SimpleDocument();
+ Node *root=NULL;
for ( node = doc->children ; node != NULL ; node = node->next ) {
if (node->type == XML_ELEMENT_NODE) {
- Node *repr=sp_repr_svg_read_node (node, default_ns, prefix_map);
- reprs = g_slist_append(reprs, repr);
+ Node *repr=sp_repr_svg_read_node(rdoc, node, default_ns, prefix_map);
+ rdoc->appendChild(repr);
+ Inkscape::GC::release(repr);
if (!root) {
root = repr;
root = NULL;
break;
}
- } else if ( node->type == XML_COMMENT_NODE ) {
- Node *comment=sp_repr_svg_read_node(node, default_ns, prefix_map);
- reprs = g_slist_append(reprs, comment);
+ } else if ( node->type == XML_COMMENT_NODE || node->type == XML_PI_NODE ) {
+ Node *repr=sp_repr_svg_read_node(rdoc, node, default_ns, prefix_map);
+ rdoc->appendChild(repr);
+ Inkscape::GC::release(repr);
}
}
- Document *rdoc=NULL;
-
if (root != NULL) {
- /* promote elements of SVG documents that don't use namespaces
- * into the SVG namespace */
- if ( default_ns && !strcmp(default_ns, SP_SVG_NS_URI)
- && !strcmp(root->name(), "svg") )
- {
- promote_to_svg_namespace(root);
+ /* promote elements of some XML documents that don't use namespaces
+ * into their default namespace */
+ if ( default_ns && !strchr(root->name(), ':') ) {
+ if ( !strcmp(default_ns, SP_SVG_NS_URI) ) {
+ promote_to_namespace(root, "svg");
+ }
+ if ( !strcmp(default_ns, INKSCAPE_EXTENSION_URI) ) {
+ promote_to_namespace(root, INKSCAPE_EXTENSION_NS_NC);
+ }
}
-
- rdoc = sp_repr_document_new_list(reprs);
- }
-
- for ( GSList *iter = reprs ; iter ; iter = iter->next ) {
- Node *repr=(Node *)iter->data;
- Inkscape::GC::release(repr);
}
- g_slist_free(reprs);
g_hash_table_destroy (prefix_map);
}
gint
-sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar *default_ns, GHashTable *prefix_map)
+sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar */*default_ns*/, GHashTable *prefix_map)
{
const xmlChar *prefix;
if ( ns && ns->href ) {
- prefix = (xmlChar*)sp_xml_ns_uri_prefix ((gchar*)ns->href, (char*)ns->prefix);
- g_hash_table_insert (prefix_map, (gpointer)prefix, (gpointer)ns->href);
+ prefix = reinterpret_cast<const xmlChar*>( sp_xml_ns_uri_prefix(reinterpret_cast<const gchar*>(ns->href),
+ reinterpret_cast<const char*>(ns->prefix)) );
+ void* p0 = reinterpret_cast<gpointer>(const_cast<xmlChar *>(prefix));
+ void* p1 = reinterpret_cast<gpointer>(const_cast<xmlChar *>(ns->href));
+ g_hash_table_insert( prefix_map, p0, p1 );
} else {
prefix = NULL;
}
- if (prefix)
- return g_snprintf (p, len, "%s:%s", (gchar*)prefix, name);
- else
+ if (prefix) {
+ return g_snprintf (p, len, "%s:%s", reinterpret_cast<const gchar*>(prefix), name);
+ } else {
return g_snprintf (p, len, "%s", name);
+ }
}
static Node *
-sp_repr_svg_read_node (xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map)
+sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map)
{
Node *repr, *crepr;
xmlAttrPtr prop;
@@ -424,8 +484,9 @@ sp_repr_svg_read_node (xmlNodePtr node, const gchar *default_ns, GHashTable *pre
if (node->type == XML_TEXT_NODE || node->type == XML_CDATA_SECTION_NODE) {
- if (node->content == NULL || *(node->content) == '\0')
+ if (node->content == NULL || *(node->content) == '\0') {
return NULL; // empty text node
+ }
bool preserve = (xmlNodeGetSpacePreserve (node) == 1);
@@ -437,33 +498,41 @@ sp_repr_svg_read_node (xmlNodePtr node, const gchar *default_ns, GHashTable *pre
return NULL; // we do not preserve all-whitespace nodes unless we are asked to
}
- Node *rdoc = sp_repr_new_text((const gchar *)node->content);
- return rdoc;
+ return xml_doc->createTextNode(reinterpret_cast<gchar *>(node->content));
+ }
+
+ if (node->type == XML_COMMENT_NODE) {
+ return xml_doc->createComment(reinterpret_cast<gchar *>(node->content));
}
- if (node->type == XML_COMMENT_NODE)
- return sp_repr_new_comment((const gchar *)node->content);
+ if (node->type == XML_PI_NODE) {
+ return xml_doc->createPI(reinterpret_cast<const gchar *>(node->name),
+ reinterpret_cast<const gchar *>(node->content));
+ }
- if (node->type == XML_ENTITY_DECL) return NULL;
+ if (node->type == XML_ENTITY_DECL) {
+ return NULL;
+ }
sp_repr_qualified_name (c, 256, node->ns, node->name, default_ns, prefix_map);
- repr = sp_repr_new (c);
+ repr = xml_doc->createElement(c);
/* TODO remember node->ns->prefix if node->ns != NULL */
for (prop = node->properties; prop != NULL; prop = prop->next) {
if (prop->children) {
sp_repr_qualified_name (c, 256, prop->ns, prop->name, default_ns, prefix_map);
- repr->setAttribute(c, (gchar*)prop->children->content);
+ repr->setAttribute(c, reinterpret_cast<gchar*>(prop->children->content));
/* TODO remember prop->ns->prefix if prop->ns != NULL */
}
}
- if (node->content)
- repr->setContent((gchar*)node->content);
+ if (node->content) {
+ repr->setContent(reinterpret_cast<gchar*>(node->content));
+ }
child = node->xmlChildrenNode;
for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
- crepr = sp_repr_svg_read_node (child, default_ns, prefix_map);
+ crepr = sp_repr_svg_read_node (xml_doc, child, default_ns, prefix_map);
if (crepr) {
repr->appendChild(crepr);
Inkscape::GC::release(crepr);
@@ -473,119 +542,200 @@ sp_repr_svg_read_node (xmlNodePtr node, const gchar *default_ns, GHashTable *pre
return repr;
}
-void
-sp_repr_save_stream (Document *doc, FILE *fp, gchar const *default_ns, bool compress)
-{
- Node *repr;
- const gchar *str;
- Inkscape::URI dummy("x");
- Inkscape::IO::UriOutputStream bout(fp, dummy);
- Inkscape::IO::GzipOutputStream *gout = compress ? new Inkscape::IO::GzipOutputStream(bout) : NULL;
- Inkscape::IO::OutputStreamWriter *out = compress ? new Inkscape::IO::OutputStreamWriter( *gout ) : new Inkscape::IO::OutputStreamWriter( bout );
+static void
+sp_repr_save_writer(Document *doc, Inkscape::IO::Writer *out,
+ gchar const *default_ns,
+ gchar const *old_href_abs_base,
+ gchar const *new_href_abs_base)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool inlineattrs = prefs->getBool("/options/svgoutput/inlineattrs");
+ int indent = prefs->getInt("/options/svgoutput/indent", 2);
/* fixme: do this The Right Way */
-
out->writeString( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" );
- str = ((Node *)doc)->attribute("doctype");
+ const gchar *str = static_cast<Node *>(doc)->attribute("doctype");
if (str) {
out->writeString( str );
}
- repr = sp_repr_document_first_child(doc);
- for ( repr = sp_repr_document_first_child(doc) ;
- repr ; repr = sp_repr_next(repr) )
+ for (Node *repr = sp_repr_document_first_child(doc);
+ repr; repr = sp_repr_next(repr))
{
- if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
- sp_repr_write_stream_root_element(repr, *out, TRUE, default_ns);
- } else if ( repr->type() == Inkscape::XML::COMMENT_NODE ) {
- sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0));
- out->writeChar( '\n' );
+ Inkscape::XML::NodeType const node_type = repr->type();
+ if ( node_type == Inkscape::XML::ELEMENT_NODE ) {
+ sp_repr_write_stream_root_element(repr, *out, TRUE, default_ns, inlineattrs, indent,
+ old_href_abs_base, new_href_abs_base);
} else {
- sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0));
+ sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent,
+ old_href_abs_base, new_href_abs_base);
+ if ( node_type == Inkscape::XML::COMMENT_NODE ) {
+ out->writeChar('\n');
+ }
}
}
- if ( out ) {
- delete out;
- out = NULL;
- }
- if ( gout ) {
- delete gout;
- gout = NULL;
- }
}
-/* Returns TRUE if file successfully saved; FALSE if not
+
+
+
+Glib::ustring
+sp_repr_save_buf(Document *doc)
+{
+ Inkscape::IO::StringOutputStream souts;
+ Inkscape::IO::OutputStreamWriter outs(souts);
+
+ sp_repr_save_writer(doc, &outs, SP_INKSCAPE_NS_URI, 0, 0);
+
+ outs.close();
+ Glib::ustring buf = souts.getString();
+
+ return buf;
+}
+
+
+
+
+
+void
+sp_repr_save_stream(Document *doc, FILE *fp, gchar const *default_ns, bool compress,
+ gchar const *const old_href_abs_base,
+ gchar const *const new_href_abs_base)
+{
+ Inkscape::URI dummy("x");
+ Inkscape::IO::UriOutputStream bout(fp, dummy);
+ Inkscape::IO::GzipOutputStream *gout = compress ? new Inkscape::IO::GzipOutputStream(bout) : NULL;
+ Inkscape::IO::OutputStreamWriter *out = compress ? new Inkscape::IO::OutputStreamWriter( *gout ) : new Inkscape::IO::OutputStreamWriter( bout );
+
+ sp_repr_save_writer(doc, out, default_ns, old_href_abs_base, new_href_abs_base);
+
+ delete out;
+ delete gout;
+}
+
+
+
+/**
+ * Returns true iff file successfully saved.
+ *
+ * \param filename The actual file to do I/O to, which might be a temp file.
+ *
+ * \param for_filename The base URI [actually filename] to assume for purposes of rewriting
+ * xlink:href attributes.
*/
-gboolean
-sp_repr_save_file (Document *doc, const gchar *filename,
- gchar const *default_ns)
+bool
+sp_repr_save_rebased_file(Document *doc, gchar const *const filename, gchar const *default_ns,
+ gchar const *old_base, gchar const *for_filename)
{
- if (filename == NULL) {
- return FALSE;
+ if (!filename) {
+ return false;
}
- bool compress = false;
+
+ bool compress;
{
- if (strlen (filename) > 5) {
- gchar tmp[] = {0,0,0,0,0,0};
- strncpy( tmp, filename + strlen (filename) - 5, 6 );
- tmp[5] = 0;
- if ( strcasecmp(".svgz", tmp ) == 0 )
- {
- //g_message("TIME TO COMPRESS THE OUTPUT FOR SVGZ");
- compress = true;
- }
- }
+ size_t const filename_len = strlen(filename);
+ compress = ( filename_len > 5
+ && strcasecmp(".svgz", filename + filename_len - 5) == 0 );
}
Inkscape::IO::dump_fopen_call( filename, "B" );
FILE *file = Inkscape::IO::fopen_utf8name(filename, "w");
if (file == NULL) {
- return FALSE;
+ return false;
}
- sp_repr_save_stream (doc, file, default_ns, compress);
+ gchar *old_href_abs_base = NULL;
+ gchar *new_href_abs_base = NULL;
+ if (for_filename) {
+ old_href_abs_base = calc_abs_doc_base(old_base);
+ if (g_path_is_absolute(for_filename)) {
+ new_href_abs_base = g_path_get_dirname(for_filename);
+ } else {
+ gchar *const cwd = g_get_current_dir();
+ gchar *const for_abs_filename = g_build_filename(cwd, for_filename, NULL);
+ g_free(cwd);
+ new_href_abs_base = g_path_get_dirname(for_abs_filename);
+ g_free(for_abs_filename);
+ }
+
+ /* effic: Once we're confident that we never need (or never want) to resort
+ * to using sodipodi:absref instead of the xlink:href value,
+ * then we should do `if streq() { free them and set both to NULL; }'. */
+ }
+ sp_repr_save_stream(doc, file, default_ns, compress, old_href_abs_base, new_href_abs_base);
+
+ g_free(old_href_abs_base);
+ g_free(new_href_abs_base);
if (fclose (file) != 0) {
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
-void
-sp_repr_print (Node * repr)
+/**
+ * Returns true iff file successfully saved.
+ */
+bool
+sp_repr_save_file(Document *doc, gchar const *const filename, gchar const *default_ns)
{
- Inkscape::IO::StdOutputStream bout;
- Inkscape::IO::OutputStreamWriter out(bout);
-
- sp_repr_write_stream (repr, out, 0, TRUE, GQuark(0));
-
- return;
+ return sp_repr_save_rebased_file(doc, filename, default_ns, NULL, NULL);
}
+
/* (No doubt this function already exists elsewhere.) */
static void
repr_quote_write (Writer &out, const gchar * val)
{
- if (!val) return;
+ if (val) {
+ for (; *val != '\0'; val++) {
+ switch (*val) {
+ case '"': out.writeString( """ ); break;
+ case '&': out.writeString( "&" ); break;
+ case '<': out.writeString( "<" ); break;
+ case '>': out.writeString( ">" ); break;
+ default: out.writeChar( *val ); break;
+ }
+ }
+ }
+}
- for (; *val != '\0'; val++) {
- switch (*val) {
- case '"': out.writeString( """ ); break;
- case '&': out.writeString( "&" ); break;
- case '<': out.writeString( "<" ); break;
- case '>': out.writeString( ">" ); break;
- default: out.writeChar( *val ); break;
+static void repr_write_comment( Writer &out, const gchar * val, bool addWhitespace, gint indentLevel, int indent )
+{
+ if ( indentLevel > 16 ) {
+ indentLevel = 16;
+ }
+ if (addWhitespace && indent) {
+ for (gint i = 0; i < indentLevel; i++) {
+ for (gint j = 0; j < indent; j++) {
+ out.writeString(" ");
+ }
}
}
+
+ out.writeString("<!--");
+ // WARNING out.printf() and out.writeString() are *NOT* non-ASCII friendly.
+ if (val) {
+ for (const gchar* cur = val; *cur; cur++ ) {
+ out.writeChar(*cur);
+ }
+ } else {
+ out.writeString(" ");
+ }
+ out.writeString("-->");
+
+ if (addWhitespace) {
+ out.writeString("\n");
+ }
}
namespace {
typedef std::map<Glib::QueryQuark, gchar const *, Inkscape::compare_quark_ids> LocalNameMap;
-typedef std::map<Glib::QueryQuark, Inkscape::Util::SharedCStringPtr, Inkscape::compare_quark_ids> NSMap;
+typedef std::map<Glib::QueryQuark, Inkscape::Util::ptr_shared<char>, Inkscape::compare_quark_ids> NSMap;
gchar const *qname_local_name(Glib::QueryQuark qname) {
static LocalNameMap local_name_map;
}
void add_ns_map_entry(NSMap &ns_map, Glib::QueryQuark prefix) {
- using Inkscape::Util::SharedCStringPtr;
+ using Inkscape::Util::ptr_shared;
+ using Inkscape::Util::share_unsafe;
static const Glib::QueryQuark xml_prefix("xml");
if (prefix.id()) {
gchar const *uri=sp_xml_ns_prefix_uri(g_quark_to_string(prefix));
if (uri) {
- ns_map.insert(NSMap::value_type(prefix, SharedCStringPtr::coerce(uri)));
+ ns_map.insert(NSMap::value_type(prefix, share_unsafe(uri)));
} else if ( prefix != xml_prefix ) {
g_warning("No namespace known for normalized prefix %s", g_quark_to_string(prefix));
}
} else {
- ns_map.insert(NSMap::value_type(prefix, SharedCStringPtr()));
+ ns_map.insert(NSMap::value_type(prefix, ptr_shared<char>()));
}
}
}
}
-void
-sp_repr_write_stream_root_element (Node *repr, Writer &out, gboolean add_whitespace, gchar const *default_ns)
+static void
+sp_repr_write_stream_root_element(Node *repr, Writer &out,
+ bool add_whitespace, gchar const *default_ns,
+ int inlineattrs, int indent,
+ gchar const *const old_href_base,
+ gchar const *const new_href_base)
{
- using Inkscape::Util::SharedCStringPtr;
+ using Inkscape::Util::ptr_shared;
+
g_assert(repr != NULL);
Glib::QueryQuark xml_prefix=g_quark_from_static_string("xml");
@@ -663,7 +819,7 @@ sp_repr_write_stream_root_element (Node *repr, Writer &out, gboolean add_whitesp
for ( NSMap::iterator iter=ns_map.begin() ; iter != ns_map.end() ; ++iter )
{
Glib::QueryQuark prefix=(*iter).first;
- SharedCStringPtr ns_uri=(*iter).second;
+ ptr_shared<char> ns_uri=(*iter).second;
if (prefix.id()) {
if ( prefix != xml_prefix ) {
@@ -683,42 +839,71 @@ sp_repr_write_stream_root_element (Node *repr, Writer &out, gboolean add_whitesp
}
}
- return sp_repr_write_stream_element(repr, out, 0, add_whitespace, elide_prefix, attributes);
+ return sp_repr_write_stream_element(repr, out, 0, add_whitespace, elide_prefix, attributes,
+ inlineattrs, indent, old_href_base, new_href_base);
}
-void
-sp_repr_write_stream (Node *repr, Writer &out, gint indent_level,
- gboolean add_whitespace, Glib::QueryQuark elide_prefix)
+void sp_repr_write_stream( Node *repr, Writer &out, gint indent_level,
+ bool add_whitespace, Glib::QueryQuark elide_prefix,
+ int inlineattrs, int indent,
+ gchar const *const old_href_base,
+ gchar const *const new_href_base)
{
- if (repr->type() == Inkscape::XML::TEXT_NODE) {
- repr_quote_write (out, repr->content());
- } else if (repr->type() == Inkscape::XML::COMMENT_NODE) {
- out.printf( "<!--%s-->", repr->content() );
- } else if (repr->type() == Inkscape::XML::ELEMENT_NODE) {
- sp_repr_write_stream_element(repr, out, indent_level, add_whitespace, elide_prefix, repr->attributeList());
- } else {
- g_assert_not_reached();
+ switch (repr->type()) {
+ case Inkscape::XML::TEXT_NODE: {
+ repr_quote_write( out, repr->content() );
+ break;
+ }
+ case Inkscape::XML::COMMENT_NODE: {
+ repr_write_comment( out, repr->content(), add_whitespace, indent_level, indent );
+ break;
+ }
+ case Inkscape::XML::PI_NODE: {
+ out.printf( "<?%s %s?>", repr->name(), repr->content() );
+ break;
+ }
+ case Inkscape::XML::ELEMENT_NODE: {
+ sp_repr_write_stream_element( repr, out, indent_level,
+ add_whitespace, elide_prefix,
+ repr->attributeList(),
+ inlineattrs, indent,
+ old_href_base, new_href_base);
+ break;
+ }
+ case Inkscape::XML::DOCUMENT_NODE: {
+ g_assert_not_reached();
+ break;
+ }
+ default: {
+ g_assert_not_reached();
+ }
}
}
-void
+
+static void
sp_repr_write_stream_element (Node * repr, Writer & out, gint indent_level,
- gboolean add_whitespace,
+ bool add_whitespace,
Glib::QueryQuark elide_prefix,
- List<AttributeRecord const> attributes)
+ List<AttributeRecord const> attributes,
+ int inlineattrs, int indent,
+ gchar const *const old_href_base,
+ gchar const *const new_href_base)
{
Node *child;
- gboolean loose;
- gint i;
+ bool loose;
g_return_if_fail (repr != NULL);
- if ( indent_level > 16 )
+ if ( indent_level > 16 ) {
indent_level = 16;
+ }
- if (add_whitespace) {
- for ( i = 0 ; i < indent_level ; i++ ) {
- out.writeString( " " );
+ if (add_whitespace && indent) {
+ for (gint i = 0; i < indent_level; i++) {
+ for (gint j = 0; j < indent; j++) {
+ out.writeString(" ");
+ }
}
}
// for its content and children:
gchar const *xml_space_attr = repr->attribute("xml:space");
if (xml_space_attr != NULL && !strcmp(xml_space_attr, "preserve")) {
- add_whitespace = FALSE;
+ add_whitespace = false;
}
- for ( List<AttributeRecord const> iter = attributes ;
+ for ( List<AttributeRecord const> iter = rebase_href_attrs(old_href_base, new_href_base,
+ attributes);
iter ; ++iter )
{
- out.writeString("\n");
- for ( i = 0 ; i < indent_level + 1 ; i++ ) {
- out.writeString(" ");
+ if (!inlineattrs) {
+ out.writeString("\n");
+ if (indent) {
+ for ( gint i = 0 ; i < indent_level + 1 ; i++ ) {
+ for ( gint j = 0 ; j < indent ; j++ ) {
+ out.writeString(" ");
+ }
+ }
+ }
}
out.printf(" %s=\"", g_quark_to_string(iter->key));
repr_quote_write(out, iter->value);
out.writeString( "\n" );
}
for (child = repr->firstChild(); child != NULL; child = child->next()) {
- sp_repr_write_stream (child, out, (loose) ? (indent_level + 1) : 0, add_whitespace, elide_prefix);
+ sp_repr_write_stream(child, out, ( loose ? indent_level + 1 : 0 ),
+ add_whitespace, elide_prefix, inlineattrs, indent,
+ old_href_base, new_href_base);
}
- if (loose && add_whitespace) {
- for (i = 0; i < indent_level; i++) {
- out.writeString( " " );
+ if (loose && add_whitespace && indent) {
+ for (gint i = 0; i < indent_level; i++) {
+ for ( gint j = 0 ; j < indent ; j++ ) {
+ out.writeString(" ");
+ }
}
}
out.printf( "</%s>", element_name );
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :