summaryrefslogtreecommitdiffstats
path: root/src/uri-references.cpp
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/uri-references.cpp
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/uri-references.cpp')
-rw-r--r--src/uri-references.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/uri-references.cpp b/src/uri-references.cpp
new file mode 100644
index 000000000..fff985139
--- /dev/null
+++ b/src/uri-references.cpp
@@ -0,0 +1,165 @@
+#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 "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 {
+
+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 */
+}
+
+URIReference::~URIReference() {
+ detach();
+}
+
+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);
+}
+
+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;
+}
+