Logo Search packages:      
Sourcecode: inkscape version File versions  Download package

uri-references.cpp

#define __SP_URI_REFERENCES_C__

/*
 * Helper methods for resolving URI References
 *
 * Authors:
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *
 * Copyright (C) 2001-2002 Lauris Kaplinski
 * Copyright (C) 2001 Ximian, Inc.
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */

#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "document.h"
#include "sp-object.h"
#include "uri.h"
#include "uri-references.h"

static gchar *uri_to_id(SPDocument *document, const gchar *uri);

namespace Inkscape {

00027 URIReference::URIReference(SPObject *owner)
: _owner(owner), _obj(NULL), _uri(NULL)
{
      g_assert(_owner != NULL);
      /* FIXME !!! attach to owner's destroy signal to clean up in case */
}

00034 URIReference::~URIReference() {
      detach();
}

00038 void URIReference::attach(const URI &uri) throw(BadURIException)
{
      SPDocument *document = SP_OBJECT_DOCUMENT(_owner);
      gchar const *fragment = uri.getFragment();
      if ( !uri.isRelative() || uri.getQuery() || !fragment ) {
            throw UnsupportedURIException();
      }

      /* FIXME !!! real xpointer support should be delegated to document */
      /* for now this handles the minimal xpointer form that SVG 1.0
       * requires of us
       */
      gchar *id;
      if (!strncmp(fragment, "xpointer(", 9)) {
            /* FIXME !!! this is wasteful */
            /* FIXME: It looks as though this is including "))" in the id.  I suggest moving
               the strlen calculation and validity testing to before strdup, and copying just
               the id without the "))".  -- pjrm */
            if (!strncmp(fragment, "xpointer(id(", 12)) {
                  id = g_strdup(fragment+12);
                  size_t const len = strlen(id);
                  if ( len < 3 || strcmp(id+len-2, "))") ) {
                        g_free(id);
                        throw MalformedURIException();
                  }
            } else {
                  throw UnsupportedURIException();
            }
      } else {
            id = g_strdup(fragment);
      }

      /* FIXME !!! validate id as an NCName somewhere */

      if (_uri) {
            delete _uri;
      }
      _uri = new URI(uri);

      _connection.disconnect();
      _setObject(document->getObjectById(id));
      _connection = document->connectIdChanged(id, sigc::mem_fun(*this, &URIReference::_setObject));

      g_free(id);
}

00084 void URIReference::detach() {
      _connection.disconnect();
      delete _uri;
      _uri = NULL;
      _setObject(NULL);
}

void URIReference::_setObject(SPObject *obj) {
      if ( obj && !_acceptObject(obj) ) {
            obj = NULL;
      }

      if ( obj == _obj ) return;

      SPObject *old_obj=_obj;
      _obj = obj;

      if (_obj) {
            sp_object_href(_obj, _owner);
            g_signal_connect(G_OBJECT(_obj), "release", G_CALLBACK(&URIReference::_release), reinterpret_cast<gpointer>(this));
      }
      _changed_signal.emit(old_obj, _obj);
      if (old_obj) {
            /* release the old object _after_ the signal emission */
            g_signal_handlers_disconnect_by_func(G_OBJECT(old_obj), (void *)&URIReference::_release, reinterpret_cast<gpointer>(this));
            sp_object_hunref(old_obj, _owner);
      }
}

/* If an object is deleted, current semantics require that we release
 * it on its "release" signal, rather than later, when its ID is actually
 * unregistered from the document.
 */
void URIReference::_release(SPObject *obj, URIReference *reference) {
      g_assert( reference->_obj == obj );
      reference->_setObject(NULL);
}

} /* namespace Inkscape */

static gchar *
uri_to_id(SPDocument *document, const gchar *uri)
{
      const gchar *e;
      gchar *id;
      gint len;

      g_return_val_if_fail (document != NULL, NULL);

      if (!uri) return NULL;
      /* fixme: xpointer, everything */
      if (strncmp (uri, "url(#", 5)) return NULL;

      e = uri + 5;
      while (*e) {
            if (*e == ')') break;
            if (!isalnum (*e) && (*e != '_') && (*e != '-') && (*e != ':') && (*e != '.')) return NULL;
            e += 1;
            if (!*e) return NULL;
      }

      len = e - uri - 5;
      if (len < 1) return NULL;

      id = (gchar*)g_new(gchar, len + 1);
      memcpy (id, uri + 5, len);
      id[len] = '\0';

      return id;
}

SPObject *
sp_uri_reference_resolve (SPDocument *document, const gchar *uri)
{
      gchar *id;

      id = uri_to_id(document, uri);
      if (!id) return NULL;

      SPObject *ref;
      ref = document->getObjectById(id);
      g_free(id);
      return ref;
}


Generated by  Doxygen 1.6.0   Back to index