ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "xml/rebase-hrefs.h"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "dir-util.h"
09ba3247163582bf2e30e17c4c154aa259ce038acilix#include "../document.h" /* Unfortunately there's a separate xml/document.h. */
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "io/sys.h"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "sp-object.h"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "streq.h"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "util/share.h"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "xml/attribute-record.h"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm#include "xml/node.h"
c0537dcfe264414d52ad86579d57cb0cb2183dcbAlex Valavanis#include <glib.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/miscutils.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/convert.h>
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz#include <glibmm/uriutils.h>
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzusing Inkscape::XML::AttributeRecord;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm/**
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Determine if a href needs rebasing.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzstatic bool href_needs_rebasing(std::string const &href)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz bool ret = true;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( href.empty() || (href[0] == '#') ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = false;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* False (no change) is the right behaviour even when the base URI differs from the
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * document URI: RFC 3986 defines empty string relative URL as referring to the containing
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * document, rather than referring to the base URI. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz } else {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /* Don't change data or http hrefs. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string scheme = Glib::uri_parse_scheme(href);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !scheme.empty() ) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* Assume it shouldn't be changed. This is probably wrong if the scheme is `file'
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * (or if the scheme of the new base is non-file, though I believe that never
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * happens at the time of writing), but that's rare, and we won't try too hard to
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * handle this now: wait until after the freeze, then add liburiparser (or similar)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * as a dependency and do it properly. For now we'll just try to be simple (while
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * at least still correctly handling data hrefs). */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = false;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz } else if (Glib::path_is_absolute(href)) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /* If absolute then keep it as is.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Even in the following borderline cases:
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * - We keep it absolute even if it is in new_base (directly or indirectly).
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz *
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * - We assume that if xlink:href is absolute then we honour it in preference to
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * sodipodi:absref even if sodipodi:absref points to an existing file while xlink:href
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * doesn't. This is because we aren't aware of any bugs in xlink:href handling when
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * it's absolute, so we assume that it's the best value to use even in this case.)
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /* No strong preference on what we do for sodipodi:absref. Once we're
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * confident of our handling of xlink:href and xlink:base, we should clear it.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * Though for the moment we do the simple thing: neither clear nor set it. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = false;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return ret;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm}
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzstatic std::string calc_abs_href(std::string const &abs_base_dir, std::string const &href,
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz gchar const *const sp_absref)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm{
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string ret = Glib::build_filename(abs_base_dir, href);
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm if ( sp_absref
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz && !Inkscape::IO::file_test(ret.c_str(), G_FILE_TEST_EXISTS)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm && Inkscape::IO::file_test(sp_absref, G_FILE_TEST_EXISTS) )
ec35142cad8ce4f534989cacd6cc98e276263548pjrm {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* sodipodi:absref points to an existing file while xlink:href doesn't.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * This could mean that xlink:href is wrong, or it could mean that the user
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * intends to supply the missing file later.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * Given that we aren't sure what the right behaviour is, and given that a
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * wrong xlink:href value may mean a bug (as has occurred in the past), we
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * write a message to stderr. */
ec35142cad8ce4f534989cacd6cc98e276263548pjrm g_warning("xlink:href points to non-existent file, so using sodipodi:absref instead");
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* Currently, we choose to use sodipodi:absref in this situation (because we
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * aren't yet confident in xlink:href interpretation); though note that
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * honouring a foreign attribute in preference to standard SVG xlink:href and
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * xlink:base means that we're not a conformant SVG user agent, so eventually
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * we hope to have enough confidence in our xlink:href and xlink:base handling
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * to be able to disregard sodipodi:absref.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * effic: Once we no longer consult sodipodi:absref, we can do
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * `if (base unchanged) { return; }' at the start of rebase_hrefs.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = sp_absref;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm return ret;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm}
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrmInkscape::Util::List<AttributeRecord const>
ec35142cad8ce4f534989cacd6cc98e276263548pjrmInkscape::XML::rebase_href_attrs(gchar const *const old_abs_base,
ec35142cad8ce4f534989cacd6cc98e276263548pjrm gchar const *const new_abs_base,
ec35142cad8ce4f534989cacd6cc98e276263548pjrm Inkscape::Util::List<AttributeRecord const> attributes)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm{
ec35142cad8ce4f534989cacd6cc98e276263548pjrm using Inkscape::Util::List;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm using Inkscape::Util::cons;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm using Inkscape::Util::ptr_shared;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm using Inkscape::Util::share_string;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
ec35142cad8ce4f534989cacd6cc98e276263548pjrm if (old_abs_base == new_abs_base) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm return attributes;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm GQuark const href_key = g_quark_from_static_string("xlink:href");
ec35142cad8ce4f534989cacd6cc98e276263548pjrm GQuark const absref_key = g_quark_from_static_string("sodipodi:absref");
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* First search attributes for xlink:href and sodipodi:absref, putting the rest in ret.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * However, if we find that xlink:href doesn't need rebasing, then return immediately
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * with no change to attributes. */
ec35142cad8ce4f534989cacd6cc98e276263548pjrm ptr_shared<char> old_href;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm ptr_shared<char> sp_absref;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm List<AttributeRecord const> ret;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm for (List<AttributeRecord const> ai(attributes); ai; ++ai) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm if (ai->key == href_key) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm old_href = ai->value;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if (!href_needs_rebasing(static_cast<char const *>(old_href))) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm return attributes;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm } else if (ai->key == absref_key) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm sp_absref = ai->value;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm } else {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm ret = cons(AttributeRecord(ai->key, ai->value), ret);
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm if (!old_href) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm return attributes;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* We could instead return ret in this case, i.e. ensure that sodipodi:absref is cleared if
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * no xlink:href attribute. However, retaining it might be more cautious.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * (For the usual case of not present, attributes and ret will be the same except
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * reversed.) */
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string abs_href = calc_abs_href(old_abs_base, static_cast<char const *>(old_href), sp_absref);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string new_href = sp_relative_path_from_path(abs_href, new_abs_base);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = cons(AttributeRecord(href_key, share_string(new_href.c_str())), ret); // Check if this is safe/copied or if it is only held.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm if (sp_absref) {
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* We assume that if there wasn't previously a sodipodi:absref attribute
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * then we shouldn't create one. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = cons(AttributeRecord(absref_key, ( streq(abs_href.c_str(), sp_absref)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm ? sp_absref
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz : share_string(abs_href.c_str()) )),
ec35142cad8ce4f534989cacd6cc98e276263548pjrm ret);
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
ec35142cad8ce4f534989cacd6cc98e276263548pjrm return ret;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm}
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// std::string Inkscape::XML::rebase_href_attrs( std::string const &oldAbsBase, std::string const &newAbsBase, gchar const * /*href*/, gchar const */*absref*/ )
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// std::string ret;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// //g_message( "XX need to flip from [%s] to [%s]", oldAbsBase.c_str(), newAbsBase.c_str() );
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// if ( oldAbsBase != newAbsBase ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// return ret;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz// }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruzstd::string Inkscape::XML::calc_abs_doc_base(gchar const *doc_base)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm{
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* Note that we don't currently try to handle the case of doc_base containing
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * `..' or `.' path components. This non-handling means that sometimes
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * sp_relative_path_from_path will needlessly give an absolute path.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * It's probably not worth trying to address this until we're using proper
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * relative URL/IRI href processing (with liburiparser).
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * (Note that one possibile difficulty with `..' is symlinks.) */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string ret;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm if (!doc_base) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = Glib::get_current_dir();
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz } else if (Glib::path_is_absolute(doc_base)) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = doc_base;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm } else {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ret = Glib::build_filename( Glib::get_current_dir(), doc_base );
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz return ret;
ec35142cad8ce4f534989cacd6cc98e276263548pjrm}
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
09ba3247163582bf2e30e17c4c154aa259ce038acilixvoid Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_base, bool const spns)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm{
9dc68827cbd515262ecb8d5ae8547d9e82c72e00Jon A. Cruz if (!doc->getBase()) {
d8c9253bfa94c54b96975f010756c657b6e9bb30buliabyak return;
9dc68827cbd515262ecb8d5ae8547d9e82c72e00Jon A. Cruz }
d8c9253bfa94c54b96975f010756c657b6e9bb30buliabyak
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string old_abs_base = calc_abs_doc_base(doc->getBase());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string new_abs_base = calc_abs_doc_base(new_base);
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* TODO: Should handle not just image but also:
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * a, altGlyph, animElementAttrs, animate, animateColor, animateMotion, animateTransform,
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * animation, audio, color-profile, cursor, definition-src, discard, feImage, filter,
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * font-face-uri, foreignObject, glyphRef, handler, linearGradient, mpath, pattern,
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * prefetch, radialGradient, script, set, textPath, tref, use, video
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * (taken from the union of the xlink:href elements listed at
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * http://www.w3.org/TR/SVG11/attindex.html and
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * http://www.w3.org/TR/SVGMobile12/attributeTable.html).
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * Also possibly some other attributes of type <URI> or <IRI> or list-thereof, or types like
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * <paint> that can include an IRI/URI, and stylesheets and style attributes. (xlink:base is a
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * special case. xlink:role and xlink:arcrole can be assumed to be already absolute, based on
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * http://www.w3.org/TR/SVG11/struct.html#xlinkRefAttrs .)
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * Note that it may not useful to set sodipodi:absref for anything other than image.
ec35142cad8ce4f534989cacd6cc98e276263548pjrm *
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * Note also that Inkscape only supports fragment hrefs (href="#pattern257") for many of these
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * cases. */
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin std::set<SPObject *> images = doc->getResourceList("image");
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin for (std::set<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
7548eff1649daed7052b1cd38de60a02207dad22Marc Jeanmougin Inkscape::XML::Node *ir = (*it)->getRepr();
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string uri;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz gchar const *tmp = ir->attribute("xlink:href");
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( !tmp ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz continue;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uri = tmp;
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico }
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( uri.substr(0, 7) == "file://" ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz uri = Glib::filename_from_uri(uri);
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico }
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico // The following two cases are for absolute hrefs that can be converted to relative.
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico // Imported images, first time rebased, need an old base.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string href = uri;
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( Glib::path_is_absolute(href) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz href = sp_relative_path_from_path(uri, old_abs_base);
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico }
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico // Files moved from a absolute path need a new one.
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( Glib::path_is_absolute(href) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz href = sp_relative_path_from_path(uri, new_abs_base);
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico }
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico // Other bitmaps are either really absolute, or already relative.
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico#ifdef WIN32
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico /* Windows relative path needs their native separators before we
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico * compare it to native baserefs. */
dba000f5d57805a180d88629c546271da730f6c4Jon A. Cruz if ( !Glib::path_is_absolute(href) ) {
dba000f5d57805a180d88629c546271da730f6c4Jon A. Cruz std::replace(href.begin(), href.end(), '/', '\\');
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico }
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico#endif
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico
ec35142cad8ce4f534989cacd6cc98e276263548pjrm /* TODO: Most of this function currently treats href as if it were a simple filename
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * (e.g. passing it to g_path_is_absolute, g_build_filename or IO::file_test, or avoiding
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * changing non-file hrefs), which breaks if href starts with a scheme or if href contains
ec35142cad8ce4f534989cacd6cc98e276263548pjrm * any escaping. */
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if ( href_needs_rebasing(href) ) {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string abs_href = calc_abs_href(old_abs_base, href, ir->attribute("sodipodi:absref"));
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /* todo: One difficult case once we support writing to non-file locations is where
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * existing hrefs in the document point to local files. In this case, we should
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * probably copy those referenced files to the new location at the same time. It's
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * less clear what to do when copying from one non-file location to another. We may
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * need to ask the user in some way (even if it's as a checkbox), but we'd like to
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * bother the user as little as possible yet also want to warn the user about the case
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * of file hrefs. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz std::string new_href = sp_relative_path_from_path(abs_href, new_abs_base);
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ir->setAttribute("sodipodi:absref", ( spns
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ? abs_href.c_str()
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz : NULL ));
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz if (!Glib::path_is_absolute(new_href)) {
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico#ifdef WIN32
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /* Native Windows path separators are replaced with / so that the href
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * also works on Gnu/Linux and OSX */
dba000f5d57805a180d88629c546271da730f6c4Jon A. Cruz std::replace(href.begin(), href.end(), '\\', '/');
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico#endif
dba000f5d57805a180d88629c546271da730f6c4Jon A. Cruz ir->setAttribute("xlink:href", new_href.c_str());
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz } else {
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz ir->setAttribute("xlink:href", g_filename_to_uri(new_href.c_str(), NULL, NULL));
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
0bdee8efb29c7a4a6e6e7c583ae5e710256e1a2eJazzyNico
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz /* impl: I assume that if !spns then any existing sodipodi:absref is about to get
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * cleared (or is already cleared) anyway, in which case it doesn't matter whether we
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * clear or leave any existing sodipodi:absref value. If that assumption turns out to
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * be wrong, then leaving it means risking leaving the wrong value (if xlink:href
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * referred to a different file than sodipodi:absref) while clearing it means risking
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz * losing information. */
a63dbee6633e3ed991bb2b34cbed7c9f02c1a839Jon A. Cruz }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm }
ec35142cad8ce4f534989cacd6cc98e276263548pjrm}
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm
ec35142cad8ce4f534989cacd6cc98e276263548pjrm/*
ec35142cad8ce4f534989cacd6cc98e276263548pjrm Local Variables:
ec35142cad8ce4f534989cacd6cc98e276263548pjrm mode:c++
ec35142cad8ce4f534989cacd6cc98e276263548pjrm c-file-style:"stroustrup"
ec35142cad8ce4f534989cacd6cc98e276263548pjrm c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
ec35142cad8ce4f534989cacd6cc98e276263548pjrm indent-tabs-mode:nil
ec35142cad8ce4f534989cacd6cc98e276263548pjrm fill-column:99
ec35142cad8ce4f534989cacd6cc98e276263548pjrm End:
ec35142cad8ce4f534989cacd6cc98e276263548pjrm*/
ec35142cad8ce4f534989cacd6cc98e276263548pjrm// vi: set autoindent shiftwidth=4 tabstop=8 filetype=cpp expandtab softtabstop=4 encoding=utf-8 textwidth=99 :