1 #define __SP_URI_REFERENCES_C__
3 /*
4 * Helper methods for resolving URI References
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * Copyright (C) 2001-2002 Lauris Kaplinski
10 * Copyright (C) 2001 Ximian, Inc.
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #include <cstring>
16 #include <string>
18 #include "document.h"
19 #include "sp-object.h"
20 #include "uri.h"
21 #include "uri-references.h"
22 #include "extract-uri.h"
24 #include <sigc++/functors/mem_fun.h>
26 namespace Inkscape {
28 URIReference::URIReference(SPObject *owner)
29 : _owner(owner), _owner_document(NULL), _obj(NULL), _uri(NULL)
30 {
31 g_assert(_owner != NULL);
32 /* FIXME !!! attach to owner's destroy signal to clean up in case */
33 }
35 URIReference::URIReference(SPDocument *owner_document)
36 : _owner(NULL), _owner_document(owner_document), _obj(NULL), _uri(NULL)
37 {
38 g_assert(_owner_document != NULL);
39 }
41 URIReference::~URIReference()
42 {
43 detach();
44 }
46 void URIReference::attach(const URI &uri) throw(BadURIException)
47 {
48 SPDocument *document;
49 if (_owner) {
50 document = SP_OBJECT_DOCUMENT(_owner);
51 } else if (_owner_document) {
52 document = _owner_document;
53 } else {
54 g_assert_not_reached();
55 }
57 gchar const *fragment = uri.getFragment();
58 if ( !uri.isRelative() || uri.getQuery() || !fragment ) {
59 throw UnsupportedURIException();
60 }
62 /* FIXME !!! real xpointer support should be delegated to document */
63 /* for now this handles the minimal xpointer form that SVG 1.0
64 * requires of us
65 */
66 gchar *id;
67 if (!strncmp(fragment, "xpointer(", 9)) {
68 /* FIXME !!! this is wasteful */
69 /* FIXME: It looks as though this is including "))" in the id. I suggest moving
70 the strlen calculation and validity testing to before strdup, and copying just
71 the id without the "))". -- pjrm */
72 if (!strncmp(fragment, "xpointer(id(", 12)) {
73 id = g_strdup(fragment+12);
74 size_t const len = strlen(id);
75 if ( len < 3 || strcmp(id+len-2, "))") ) {
76 g_free(id);
77 throw MalformedURIException();
78 }
79 } else {
80 throw UnsupportedURIException();
81 }
82 } else {
83 id = g_strdup(fragment);
84 }
86 /* FIXME !!! validate id as an NCName somewhere */
88 if (_uri) {
89 delete _uri;
90 }
91 _uri = new URI(uri);
93 _connection.disconnect();
94 _setObject(document->getObjectById(id));
95 _connection = document->connectIdChanged(id, sigc::mem_fun(*this, &URIReference::_setObject));
97 g_free(id);
98 }
100 void URIReference::detach()
101 {
102 _connection.disconnect();
103 delete _uri;
104 _uri = NULL;
105 _setObject(NULL);
106 }
108 void URIReference::_setObject(SPObject *obj)
109 {
110 if ( obj && !_acceptObject(obj) ) {
111 obj = NULL;
112 }
114 if ( obj == _obj ) return;
116 SPObject *old_obj=_obj;
117 _obj = obj;
119 _release_connection.disconnect();
120 if (_obj) {
121 sp_object_href(_obj, _owner);
122 _release_connection = _obj->connectRelease(sigc::mem_fun(*this, &URIReference::_release));
123 }
124 _changed_signal.emit(old_obj, _obj);
125 if (old_obj) {
126 /* release the old object _after_ the signal emission */
127 sp_object_hunref(old_obj, _owner);
128 }
129 }
131 /* If an object is deleted, current semantics require that we release
132 * it on its "release" signal, rather than later, when its ID is actually
133 * unregistered from the document.
134 */
135 void URIReference::_release(SPObject *obj)
136 {
137 g_assert( _obj == obj );
138 _setObject(NULL);
139 }
141 } /* namespace Inkscape */
145 SPObject* sp_css_uri_reference_resolve( SPDocument *document, const gchar *uri )
146 {
147 SPObject* ref = 0;
149 if ( document && uri && ( strncmp(uri, "url(", 4) == 0 ) ) {
150 gchar *trimmed = extract_uri( uri );
151 if ( trimmed ) {
152 ref = sp_uri_reference_resolve( document, trimmed );
153 g_free( trimmed );
154 }
155 }
157 return ref;
158 }
160 SPObject *
161 sp_uri_reference_resolve (SPDocument *document, const gchar *uri)
162 {
163 SPObject* ref = 0;
165 if ( uri && (*uri == '#') ) {
166 ref = document->getObjectById( uri + 1 );
167 }
169 return ref;
170 }