1 /* $Id$
2  *
3  * Lasso - A free implementation of the Liberty Alliance specifications.
4  *
5  * Copyright (C) 2004-2007 Entr'ouvert
6  * http://lasso.entrouvert.org
7  *
8  * Authors: See AUTHORS file in top-level directory.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include <glib.h>
25 #include "registry-private.h"
26 #include "errors.h"
27 #include "utils.h"
28 
29 
30 /**
31  * SECTION:registry
32  * @short_description: Class to store a mapping of qualified names (QName) to other qualified names.
33  *
34  * A qualified name is a name or a string in the context of another name, or namespace.
35  * This object implement a function of a tuple (namespace, name, namespace) to a name.  For the
36  * moment there is no need to enumerate all tuples (namespace, name) pair given a base pair, i.e. a
37  * function from tuple (namespace, name) to a list of tuples (namespace,name).
38  *
39  * We support two kinds of mapping:
40  * <itemizedlist>
41  * <listitem><para>you can give a direct mapping between two QName,</para></listitem>
42  * <listitem><para>or you can give a function that will manage mapping between one namespace and
43  * another one.</para></listitem>
44  * </itemizedlist>
45  *
46  * For internal use inside lasso we define the following namespaces:
47  * <itemizedlist>
48  * <listitem><para>#LASSO_LASSO_HREF and,</para></listitem>
49  * <listitem><para>#LASSO_PYTHON_HREF.</para></listitem>
50  * </itemizedlist>
51  *
52  * For functional mappings the mapping function must return constant strings created using
53  * g_intern_string() or using g_type_name().
54  */
55 
56 typedef struct _LassoRegistryDirectMappingRecord LassoRegistryDirectMappingRecord;
57 
58 struct _LassoRegistryDirectMappingRecord {
59 	GQuark from_namespace;
60 	GQuark from_name;
61 	GQuark to_namespace;
62 	GQuark to_name;
63 };
64 
65 typedef struct _LassoRegistryFunctionalMappingRecord LassoRegistryFunctionalMappingRecord;
66 
67 struct _LassoRegistryFunctionalMappingRecord {
68 	GQuark from_namespace;
69 	GQuark to_namespace;
70 	LassoRegistryTranslationFunction translation_function;
71 };
72 
73 static LassoRegistry *default_registry = NULL;
74 
lasso_registry_get_default()75 static LassoRegistry *lasso_registry_get_default() {
76 	if (default_registry == NULL) {
77 		default_registry = lasso_registry_new();
78 	}
79 	return default_registry;
80 }
81 
lasso_registry_default_shutdown()82 void lasso_registry_default_shutdown()
83 {
84 	if (default_registry)
85 		lasso_registry_destroy(default_registry);
86 	default_registry = NULL;
87 }
88 
89 /**
90  * lasso_registry_direct_mapping_equal:
91  * @record1: left record
92  * @record2: right record
93  *
94  * Tests if two #LassoRegistryDirectMappingRecord are equal.
95  *
96  * Return value: TRUE if all field of record1 are equal to record2.
97  */
lasso_registry_direct_mapping_equal(LassoRegistryDirectMappingRecord * record1,LassoRegistryDirectMappingRecord * record2)98 gboolean lasso_registry_direct_mapping_equal(LassoRegistryDirectMappingRecord *record1,
99 		LassoRegistryDirectMappingRecord *record2)
100 {
101 	return record1->from_namespace == record2->from_namespace
102 		&& record1->from_name == record2->from_name
103 		&& record1->to_namespace == record2->to_namespace;
104 }
105 
106 /**
107  * lasso_registry_functional_mapping_equal:
108  * @record1: left record
109  * @record2: right record
110  *
111  * Tests if two #LassoRegistryFunctionalMappingRecord are equal, i.e.  if they are functional
112  * mapping between the same namespace.
113  *
114  * Return value: TRUE if record1 is equal to record2
115  */
lasso_registry_functional_mapping_equal(LassoRegistryFunctionalMappingRecord * record1,LassoRegistryFunctionalMappingRecord * record2)116 gboolean lasso_registry_functional_mapping_equal(LassoRegistryFunctionalMappingRecord *record1,
117 		LassoRegistryFunctionalMappingRecord *record2)
118 {
119 	return record1->from_namespace == record2->from_namespace &&
120 		record1->to_namespace == record2->to_namespace;
121 }
122 
123 /**
124  * lasso_registry_direct_mapping_hash:
125  * @record: a #LassoRegistryDirectMappingRecord structure
126  *
127  * Return a hash value obtained from the three first fields of a #LassoRecordRegistry structure.
128  *
129  * Return value: an integer hash for the record.
130  */
lasso_registry_direct_mapping_hash(LassoRegistryDirectMappingRecord * record)131 guint lasso_registry_direct_mapping_hash(LassoRegistryDirectMappingRecord *record)
132 {
133 	return g_direct_hash((gpointer)((ptrdiff_t)record->from_namespace
134 		^ (ptrdiff_t)record->from_name
135 		^ (ptrdiff_t)record->to_namespace));
136 }
137 
138 /**
139  * lasso_registry_functional_mapping_hash:
140  * @record: a #LassoRegistryFunctionalMappingRecord structure
141  *
142  * Return a hash value obtained from the source and destination namespace of the mapping.
143  *
144  * Return value: an integer hash for the record.
145  */
lasso_registry_functional_mapping_hash(LassoRegistryFunctionalMappingRecord * record)146 guint lasso_registry_functional_mapping_hash(LassoRegistryFunctionalMappingRecord *record)
147 {
148 	return g_direct_hash((gpointer)((ptrdiff_t)record->from_namespace
149 				^ (ptrdiff_t)record->to_namespace));
150 }
151 
152 /**
153  * lasso_registry_new:
154  *
155  * Allocate a new #LassoRegistry structure and initialize its fields.
156  *
157  * Return value: a newly allocated #LassoRegistry object.
158  */
lasso_registry_new()159 LassoRegistry *lasso_registry_new()
160 {
161 	LassoRegistry *ret = g_new0(LassoRegistry, 1);
162 
163 	ret->direct_mapping = g_hash_table_new_full(
164 			(GHashFunc) lasso_registry_direct_mapping_hash,
165 			(GEqualFunc) lasso_registry_direct_mapping_equal,
166 			NULL,
167 			g_free);
168 
169 	ret->functional_mapping = g_hash_table_new_full(
170 			(GHashFunc) lasso_registry_functional_mapping_hash,
171 			(GEqualFunc) lasso_registry_functional_mapping_equal,
172 			NULL,
173 			g_free);
174 
175 	return ret;
176 }
177 
178 /**
179  * lasso_registry_destroy:
180  * @registry: the #LassoRegistry object
181  *
182  * Destroy a #LassoRegistry.
183  */
lasso_registry_destroy(LassoRegistry * registry)184 void lasso_registry_destroy(LassoRegistry *registry)
185 {
186 	g_return_if_fail(registry);
187 
188 	lasso_release_ghashtable(registry->direct_mapping);
189 	lasso_release_ghashtable(registry->functional_mapping);
190 	lasso_release(registry);
191 }
192 
lasso_registry_get_translation_function(GHashTable * functional_mappings,GQuark from_ns_quark,GQuark to_ns_quark)193 static LassoRegistryTranslationFunction lasso_registry_get_translation_function(GHashTable *functional_mappings, GQuark from_ns_quark, GQuark to_ns_quark)
194 {
195 		LassoRegistryFunctionalMappingRecord functional_mapping, *functional_mapping_found;
196 		functional_mapping.from_namespace = from_ns_quark;
197 		functional_mapping.to_namespace = to_ns_quark;
198 		functional_mapping_found = g_hash_table_lookup(functional_mappings, &functional_mapping);
199 
200 		if (functional_mapping_found) {
201 			return functional_mapping_found->translation_function;
202 		}
203 		return NULL;
204 }
205 
lasso_registry_get_functional_mapping(GHashTable * functional_mappings,GQuark from_ns_namespace,const char * from_name,GQuark to_ns_namespace)206 static const char *lasso_registry_get_functional_mapping(GHashTable *functional_mappings,
207 		GQuark from_ns_namespace, const char *from_name, GQuark to_ns_namespace)
208 {
209 	LassoRegistryTranslationFunction translation_function;
210 
211 	translation_function = lasso_registry_get_translation_function(functional_mappings, from_ns_namespace, to_ns_namespace);
212 	if (translation_function) {
213 		return translation_function(g_quark_to_string(from_ns_namespace), from_name, g_quark_to_string(to_ns_namespace));
214 	}
215 	return NULL;
216 }
217 
lasso_registry_get_direct_mapping(GHashTable * direct_mappings,GQuark from_ns_quark,const char * from_name,GQuark to_ns_quark)218 static const char *lasso_registry_get_direct_mapping(GHashTable *direct_mappings,
219 		GQuark from_ns_quark, const char *from_name, GQuark to_ns_quark)
220 {
221 	GQuark from_name_quark = g_quark_try_string(from_name);
222 	LassoRegistryDirectMappingRecord record, *found;
223 
224 	if (from_name_quark == 0)
225 		return NULL;
226 
227 	record.from_namespace = from_ns_quark;
228 	record.from_name = from_name_quark;
229 	record.to_namespace = to_ns_quark;
230 
231 	found = g_hash_table_lookup(direct_mappings, &record);
232 
233 	if (found) {
234 		return g_quark_to_string(found->to_name);
235 	}
236 	return NULL;
237 }
238 
239 /**
240  * lasso_regsitry_get_mapping:
241  *
242  * Retrieve the mapping of a QName into another namespace, i.e. to another
243  * QName. It first tries the functional mapping, then tries with the direct mapping.
244  *
245  * Return value: a constant string of NULL if no mapping exist.
246  */
lasso_registry_get_mapping(LassoRegistry * registry,const char * from_namespace,const char * from_name,const char * to_namespace)247 const char* lasso_registry_get_mapping(LassoRegistry *registry, const char *from_namespace,
248 		const char *from_name, const char *to_namespace)
249 {
250 	GQuark from_ns_quark, to_ns_quark;
251 	const char *ret = NULL;
252 
253 	from_ns_quark = g_quark_try_string(from_namespace);
254 	to_ns_quark = g_quark_try_string(to_namespace);
255 
256 	if (from_ns_quark == 0 || to_ns_quark == 0) {
257 		return NULL;
258 	}
259 
260 	ret = lasso_registry_get_functional_mapping(registry->functional_mapping, from_ns_quark, from_name, to_ns_quark);
261 	if (ret == NULL) {
262 		ret = lasso_registry_get_direct_mapping(registry->direct_mapping, from_ns_quark, from_name, to_ns_quark);
263 	}
264 
265 	return ret;
266 }
267 
268 /**
269  * lasso_registry_add_direct_mapping:
270  *
271  * Add a new mapping from a QName to a QName.
272  *
273  * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if it already exists,
274  * LASSO_PARAM_ERROR_INVALID_VALUE if arguments
275  * are invalid.
276  */
lasso_registry_add_direct_mapping(LassoRegistry * registry,const char * from_namespace,const char * from_name,const char * to_namespace,const char * to_name)277 gint lasso_registry_add_direct_mapping(LassoRegistry *registry, const char *from_namespace,
278 		const char *from_name, const char *to_namespace, const char *to_name)
279 {
280 	LassoRegistryDirectMappingRecord *a_record;
281 
282 	g_return_val_if_fail(registry && from_namespace && from_name && to_namespace && to_name, LASSO_PARAM_ERROR_INVALID_VALUE);
283 
284 	if (lasso_registry_get_mapping(registry, from_namespace, from_name, to_namespace)) {
285 		return LASSO_REGISTRY_ERROR_KEY_EXISTS;
286 	}
287 	a_record = g_new0(LassoRegistryDirectMappingRecord, 1);
288 	a_record->from_namespace = g_quark_from_string(from_namespace);
289 	a_record->from_name = g_quark_from_string(from_name);
290 	a_record->to_namespace = g_quark_from_string(to_namespace);
291 	a_record->to_name = g_quark_from_string(to_name);
292 	g_hash_table_insert(registry->direct_mapping, a_record, a_record);
293 	return 0;
294 }
295 
296 /**
297  * lasso_registry_add_functional_mapping:
298  * @registry: a #LassoRegistry
299  * @from_namespace: URI of the source namespace
300  * @to_namespace: URI of the destination namespace
301  * @translation_function: a function mapping string to string from the first namespace to the second one
302  *
303  * Register a new mapping from from_namesapce to to_namespace using the
304  * translation_function. This functions is not forced to return a value for
305  * any string, it can return NULL.
306  *
307  * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if this mapping is already registered,
308  * LASSO_PARAM_ERROR_INVALID_VALUE if one the argument is invalid.
309  */
lasso_registry_add_functional_mapping(LassoRegistry * registry,const char * from_namespace,const char * to_namespace,LassoRegistryTranslationFunction translation_function)310 gint lasso_registry_add_functional_mapping(LassoRegistry *registry, const char *from_namespace,
311 		const char *to_namespace, LassoRegistryTranslationFunction translation_function)
312 {
313 	LassoRegistryFunctionalMappingRecord *a_record;
314 	GQuark to_ns_quark, from_ns_quark;
315 
316 	g_return_val_if_fail(registry != NULL && from_namespace != NULL && to_namespace != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
317 	from_ns_quark = g_quark_from_string(from_namespace);
318 	to_ns_quark = g_quark_from_string(to_namespace);
319 	if (lasso_registry_get_translation_function(registry->functional_mapping, from_ns_quark, to_ns_quark)) {
320 		return LASSO_REGISTRY_ERROR_KEY_EXISTS;
321 	}
322 	a_record = g_new0(LassoRegistryFunctionalMappingRecord, 1);
323 	a_record->from_namespace = from_ns_quark;
324 	a_record->to_namespace = to_ns_quark;
325 	a_record->translation_function = translation_function;
326 
327 	g_hash_table_insert(registry->functional_mapping, a_record, a_record);
328 
329 	return 0;
330 }
331 
332 /**
333  * lasso_registry_default_add_direct_mapping:
334  * @from_namespace: the namespace of the mapped QName
335  * @from_name: the name of the mapped QName
336  * @to_namespace: the namepsace of the mapped to QName
337  * @to_name: the name of the mapped to QName
338  *
339  * Add a new mapping from a QName to a QName.
340  *
341  * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if this mapping is already registered,
342  * LASSO_PARAM_ERROR_INVALID_VALUE if one the argument is invalid.
343  */
lasso_registry_default_add_direct_mapping(const char * from_namespace,const char * from_name,const char * to_namespace,const char * to_name)344 gint lasso_registry_default_add_direct_mapping(const char *from_namespace,
345 		const char *from_name, const char *to_namespace, const char *to_name)
346 {
347 	LassoRegistry *default_registry = lasso_registry_get_default();
348 
349 	return lasso_registry_add_direct_mapping(default_registry, from_namespace, from_name, to_namespace, to_name);
350 }
351 
352 /**
353  * lasso_registry_default_add_functional_mapping:
354  *
355  * @from_namespace: URI of the source namespace
356  * @to_namespace: URI of the destination namespace
357  * @translation_function: a function mapping string to string from the first namespace to the second one
358  *
359  * Register a new mapping from from_namesapce to to_namespace using the translation_function into
360  * the default mapping. This functions is not forced to return a value for any string, it can return
361  * NULL.
362  *
363  * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if this mapping is already registered,
364  * LASSO_PARAM_ERROR_INVALID_VALUE if one the argument is invalid.
365  */
lasso_registry_default_add_functional_mapping(const char * from_namespace,const char * to_namespace,LassoRegistryTranslationFunction translation_function)366 gint lasso_registry_default_add_functional_mapping(const char *from_namespace,
367 		const char *to_namespace, LassoRegistryTranslationFunction translation_function)
368 {
369 	LassoRegistry *default_registry = lasso_registry_get_default();
370 
371 	return lasso_registry_add_functional_mapping(default_registry, from_namespace, to_namespace, translation_function);
372 }
373 
374 
375 /**
376  * lasso_registry_default_get_mapping:
377  * @from_namespace: the namespace of the mapped QName
378  * @from_name: the name of the mapped QName
379  * @to_namespace: the namepsace of the mapped to QName
380  *
381  * Retrieve the name of the QName in the namespace to_namespace that maps the
382  * QName from_namespace:from_name.
383  *
384  * Return value: the name string of the QName or NULL if no mapping exists.
385  */
lasso_registry_default_get_mapping(const char * from_namespace,const char * from_name,const char * to_namespace)386 const char* lasso_registry_default_get_mapping(const char *from_namespace,
387 		const char *from_name, const char *to_namespace)
388 {
389 	LassoRegistry *default_registry = lasso_registry_get_default();
390 
391 	return lasso_registry_get_mapping(default_registry, from_namespace, from_name, to_namespace);
392 }
393