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 #ifndef __LASSO_UTILS_H__
25 #define __LASSO_UTILS_H__
26 
27 #include <stdio.h>
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <xmlsec/keys.h>
31 #include "debug.h"
32 #include "backward_comp.h"
33 #include "xml/tools.h"
34 #include "logging.h"
35 
36 #ifdef LASSO_DEBUG
37 #ifdef __GNUC__
38 #define lasso_check_type_equality(a,b) \
39 	{ \
40 		enum { TYPE_MISMATCH = (1 / __builtin_types_compatible_p(typeof(a), typeof(b))) }; \
41 	}
42 #else
43 #define lasso_check_type_equality(a,b)
44 #endif
45 #else
46 #define lasso_check_type_equality(a,b)
47 #endif
48 
49 #ifdef __GNUC__
50 #define lasso_check_type_equality2(a,b,c) \
51 	{ \
52 		enum { TYPE_MISMATCH = (1 / (__builtin_types_compatible_p(typeof(a), typeof(b))+__builtin_types_compatible_p(typeof(a), typeof(c)))) }; \
53 	}
54 #else
55 #define lasso_check_type_equality2(a,b,c)
56 #endif
57 
58 #define lasso_private_data(object) ((object)->private_data)
59 
60 /**
61  * lasso_ref:
62  * @object: an object whose reference count must be incremented.
63  *
64  * Increment the reference count of an object, do not emit warning if it is NULL.
65  *
66  * Return value: the @object.
67  */
68 #define lasso_ref(object) ((object) != NULL ? (g_object_ref(object), object) : NULL)
69 
70 /**
71  * lasso_unref:
72  * @object: an object whose reference count must be decremented.
73  *
74  * Decrement the reference count of an object, do not emit warnings if it is NULL.
75  *
76  * Return value: the @object.
77  */
78 #define lasso_unref(object) ((object) != NULL ? (g_object_unref(object), object) : NULL)
79 
80 /* Freeing */
81 
82 /*
83  * lasso_release_xxx are macros which ensure you do not get 'double free' errors, they first check
84  * that the variable is not NULL before calling the deallocation function, and after deallocation
85  * they reset the variable to NULL, preventing 'double free'.
86  */
87 #define lasso_release(dest) \
88 	{ \
89 		if (dest) { \
90 			g_free(dest); dest = NULL; \
91 		} \
92 	}
93 
94 #define lasso_release_full(dest, free_function) \
95 	{ \
96 		if (dest) { \
97 			free_function(dest); dest = NULL; \
98 		} \
99 	}
100 
101 #define lasso_release_full2(dest, free_function, type) \
102 	{ \
103 		lasso_check_type_equality(dest, type); \
104 		if (dest) { \
105 			free_function(dest); dest = NULL; \
106 		} \
107 	}
108 
109 #define lasso_release_gobject(dest) \
110 	{ \
111 		if (G_IS_OBJECT(dest) || dest == NULL) { \
112 			lasso_release_full(dest, g_object_unref); \
113 		} else { \
114 			message(G_LOG_LEVEL_CRITICAL, "Trying to unref a non GObject pointer file=%s:%u pointerbybname=%s pointer=%p", __FILE__, __LINE__, #dest, dest); \
115 		} \
116 	}
117 
118 #define lasso_release_string(dest) \
119 	lasso_release_full(dest, g_free)
120 
121 #define lasso_release_list(dest) \
122 	lasso_release_full2(dest, g_list_free, GList*)
123 
124 #define lasso_release_slist(dest) \
125 	lasso_release_full2(dest, g_slist_free, GSList*)
126 
127 #define lasso_release_list_of_full(dest, free_function) \
128 	{ \
129 		GList **__tmp = &(dest); \
130 		if (*__tmp) { \
131 			g_list_foreach(*__tmp, (GFunc)(void*)free_function, NULL); \
132 			lasso_release_list(*__tmp); \
133 		} \
134 	}
135 
136 #define lasso_release_list_of_strings(dest) \
137 	lasso_release_list_of_full(dest, g_free)
138 
139 #define lasso_release_list_of_gobjects(dest) \
140 	lasso_release_list_of_full(dest, g_object_unref)
141 
142 #define lasso_release_list_of_xml_node(dest) \
143 	lasso_release_list_of_full(dest, xmlFreeNode)
144 
145 #define lasso_release_list_of_xml_node_list(dest) \
146 	lasso_release_list_of_full(dest, xmlFreeNodeList)
147 
148 #define lasso_release_list_of_sec_key(dest) \
149 	lasso_release_list_of_full(dest, xmlSecKeyDestroy)
150 
151 #define lasso_release_xml_node(node) \
152 	lasso_release_full2(node, xmlFreeNode, xmlNodePtr)
153 
154 #define lasso_release_xml_node_list(node) \
155 	lasso_release_full2(node, xmlFreeNodeList, xmlNodePtr)
156 
157 #define lasso_release_doc(doc) \
158 	lasso_release_full2(doc, xmlFreeDoc, xmlDocPtr)
159 
160 #define lasso_release_xml_string(dest) \
161 	lasso_release_full2(dest, xmlFree, xmlChar*)
162 
163 #define lasso_release_encrypt_context(dest) \
164 	lasso_release_full2(dest, xmlSecEncCtxDestroy, xmlSecEncCtxPtr)
165 
166 #define lasso_release_signature_context(dest) \
167 	lasso_release_full2(dest, xmlSecDSigCtxDestroy,xmlSecDSigCtxPtr)
168 
169 #define lasso_release_key_manager(dest) \
170 	lasso_release_full2(dest, xmlSecKeysMngrDestroy, xmlSecKeysMngrPtr)
171 
172 #define lasso_release_output_buffer(dest) \
173 	lasso_release_full2(dest, xmlOutputBufferClose, xmlOutputBufferPtr)
174 
175 #define lasso_release_xpath_object(dest) \
176 	lasso_release_full2(dest, xmlXPathFreeObject, xmlXPathObjectPtr)
177 
178 #define lasso_release_xpath_context(dest) \
179 	lasso_release_full2(dest, xmlXPathFreeContext, xmlXPathContextPtr)
180 
181 #define lasso_release_xpath_job(xpathObject, xpathContext, xmlDocument) \
182 	lasso_release_xpath_object(xpathObject); \
183 	lasso_release_xpath_context(xpathContext); \
184 	lasso_release_doc(xmlDocument)
185 
186 #define lasso_release_sec_key(dest) \
187 	lasso_release_full2(dest, xmlSecKeyDestroy, xmlSecKeyPtr)
188 
189 #define lasso_release_ghashtable(dest) \
190 	lasso_release_full(dest, g_hash_table_destroy)
191 
192 #define lasso_release_gstring(dest, b) \
193 	{ \
194 		GString **__tmp = &(dest); \
195 		if (*__tmp) {\
196 			g_string_free(*__tmp, (b)); \
197 			*__tmp = NULL; \
198 		} \
199 	}
200 
201 #define lasso_release_array_of_xml_strings(dest) \
202 	{ \
203 		xmlChar ***__tmp = &(dest);\
204 		if (*__tmp) {\
205 			int i = 0;\
206 			for (i = 0; (*__tmp)[i]; i++) {\
207 				lasso_release_xml_string((*__tmp)[i]);\
208 			}\
209 			lasso_release((*__tmp));\
210 		}\
211 	}
212 
213 /* Assignment and list appending */
214 /*
215  * lasso_assign_xxx macros ensure that you dot leak previous value of assigned things, they use
216  * lasso_release_xxx macros to deallocate, they also ensure proper reference counting on passed by
217  * references values and proper copying on passed by value values.
218  */
219 #define lasso_assign_string(dest,src) \
220 	{ \
221 		char *__tmp = g_strdup(src);\
222 		lasso_release_string(dest); \
223 		dest = __tmp; \
224 	}
225 
226 #define lasso_assign_xml_string(dest,src) \
227 	{ \
228 		xmlChar *__tmp = xmlStrdup(src); \
229 		lasso_release_xml_string(dest); \
230 		dest = __tmp; \
231 	}
232 
233 #define lasso_assign_new_string(dest,src) \
234 	{ \
235 		char *__tmp = src; \
236 		if (dest != __tmp) \
237 			lasso_release_string(dest); \
238 		dest = __tmp; \
239 	}
240 
241 #define lasso_assign_gobject(dest,src) \
242 	{ \
243 		GObject *__tmp = G_OBJECT(src); \
244 		if (__tmp) \
245 			g_object_ref(__tmp); \
246 		lasso_release_gobject(dest); \
247 		dest = (void*)(__tmp); \
248 	}
249 
250 #define lasso_assign_new_gobject(dest,src) \
251 	{ \
252 		GObject *__tmp = G_OBJECT(src); \
253 		if (dest != (void*)__tmp) \
254 			lasso_release_gobject(dest); \
255 		dest = (void*)(__tmp); \
256 	}
257 
258 #define lasso_assign_xml_node(dest,src) \
259 	{ \
260 		xmlNode *__tmp = (src); \
261 		lasso_check_type_equality(dest, src); \
262 		if (dest) \
263 			xmlFreeNode(dest); \
264 		dest = xmlCopyNode(__tmp, 1); \
265 	}
266 
267 #define lasso_assign_new_xml_node(dest,src) \
268 	{ \
269 		xmlNode *__tmp = (src); \
270 		lasso_check_type_equality(dest, src); \
271 		if (dest) \
272 			xmlFreeNode(dest); \
273 		dest = __tmp; \
274 	}
275 
276 #define lasso_assign_xml_node_list(dest,src) \
277 	{ \
278 		xmlNode *__tmp = (src); \
279 		lasso_check_type_equality(dest, src); \
280 		if (dest) \
281 			xmlFreeNode(dest); \
282 		dest = xmlCopyNodeList(__tmp); \
283 	}
284 
285 #define lasso_assign_new_xml_node_list(dest,src) \
286 	lasso_assign_new_xml(dest, src)
287 
288 #define lasso_assign_list(dest, src) \
289 	{ \
290 		GList **__tmp = &(dest); \
291 		if (*__tmp) \
292 			g_list_free(*__tmp); \
293 		*__tmp = g_list_copy((src)); \
294 	}
295 
296 #define lasso_assign_new_list_of_gobjects(dest, src) \
297 	{ \
298 		GList *__tmp = (src); \
299 		lasso_release_list_of_gobjects(dest); \
300 		dest = (GList*)__tmp; \
301 	}
302 
303 #define lasso_assign_new_list_of_strings(dest, src) \
304 	{ \
305 		GList *__tmp = (src); \
306 		lasso_release_list_of_strings(dest); \
307 		dest = (GList*)__tmp; \
308 	}
309 
310 #define lasso_assign_new_list_of_xml_node(dest, src) \
311 	{ \
312 		GList *__tmp = (src); \
313 		lasso_release_list_of_xml_node(dest); \
314 		dest = (GList*)__tmp; \
315 	}
316 
317 #define lasso_assign_list_of_gobjects(dest, src) \
318 	{ \
319 		GList *__tmp = (src); \
320 		lasso_release_list_of_gobjects(dest); \
321 		dest = g_list_copy(__tmp); \
322 		for (;__tmp != NULL; __tmp = g_list_next(__tmp)) { \
323 			if (G_IS_OBJECT(__tmp->data)) { \
324 				g_object_ref(__tmp->data); \
325 			} \
326 		} \
327 	}
328 
329 #define lasso_assign_list_of_strings(dest, src) \
330 	{ \
331 		GList *__tmp = src; \
332 		GList *__iter_dest; \
333 		lasso_release_list_of_strings(dest); \
334 		dest = g_list_copy(__tmp); \
335 		for (__iter_dest = dest ; __iter_dest != NULL ; __iter_dest = g_list_next(__iter_dest)) { \
336 			__iter_dest->data = g_strdup(__iter_dest->data); \
337 		} \
338 	}
339 
340 #define lasso_assign_list_of_xml_node(dest, src) \
341 	{ \
342 		GList *__tmp = src; \
343 		GList *__iter_dest; \
344 		lasso_release_list_of_xml_node(dest); \
345 		dest = g_list_copy(__tmp); \
346 		for (__iter_dest = dest ; __iter_dest != NULL ; __iter_dest = g_list_next(__iter_dest)) { \
347 			__iter_dest->data = xmlCopyNode(__iter_dest->data, 1); \
348 		} \
349 	}
350 
351 #define lasso_assign_new_sec_key(dest, src) \
352 	{ \
353 		xmlSecKey *__tmp = (src); \
354 		if (dest) \
355 			lasso_release_sec_key(dest); \
356 		dest = __tmp; \
357 	}
358 
359 #define lasso_assign_sec_key(dest, src) \
360 	{ \
361 		xmlSecKey *__tmp = NULL; \
362 		if (src) {\
363 			__tmp = xmlSecKeyDuplicate(src); \
364 		} \
365 		if (dest) \
366 			lasso_release_sec_key(dest); \
367 		dest = __tmp; \
368 	}
369 
370 G_GNUC_UNUSED static void
_lasso_copy_helper_assign_table_of_attributes(gpointer key,gpointer val,gpointer dest)371 _lasso_copy_helper_assign_table_of_attributes(gpointer key, gpointer val, gpointer dest){
372 	    g_hash_table_insert((GHashTable*) dest, g_strdup(key), g_strdup(val));
373 }
374 
375 #define lasso_assign_table_of_attributes(dest, src) \
376 	{\
377 		if (!dest) {\
378 			(dest) = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);\
379 		}\
380 		g_hash_table_remove_all(dest);\
381 		g_hash_table_foreach(src, _lasso_copy_helper_assign_table_of_attributes, dest);\
382 	}
383 
384 
385 /* List appending */
386 
387 /* lasso_list_add_xxx macros, simplify code around list manipulation (g_list_append needs to be
388  * used like this 'l = g_list_appen(l, value)' ) and ensure proper reference count or copying of
389  * values.
390  */
391 #define lasso_list_add(dest, src) \
392 	{ \
393 		lasso_check_type_equality((src), void*); \
394 		dest = g_list_append(dest, (src)); \
395 	}
396 
397 #define lasso_list_add_non_null(dest, src) \
398 	{ \
399 		void *__tmp_non_null_src = (src); \
400 		if (__tmp_non_null_src != NULL) { \
401 			dest = g_list_append(dest, __tmp_non_null_src); \
402 		} else { \
403 			message(G_LOG_LEVEL_CRITICAL, "Adding a NULL value to a non-NULL content list: dest=%s src=%s", #dest, #src); \
404 		} \
405 	}
406 
407 #define lasso_list_add_string(dest, src) \
408 	{ \
409 		lasso_list_add_non_null(dest, g_strdup(src));\
410 	}
411 
412 #define lasso_list_add_new_string(dest, src) \
413 	{ \
414 		gchar *__tmp = src; \
415 		lasso_list_add_non_null(dest, __tmp); \
416 	}
417 
418 #define lasso_list_add_xml_string(dest, src) \
419 	{\
420 		xmlChar *__tmp_src = (src);\
421 		lasso_list_add_non_null(dest, (void*)g_strdup((char*)__tmp_src));\
422 	}
423 
424 #define lasso_list_add_gobject(dest, src) \
425 	{ \
426 		void *__tmp_src = (src); \
427 		if (G_IS_OBJECT(__tmp_src)) { \
428 			dest = g_list_append(dest, g_object_ref(__tmp_src)); \
429 		} else { \
430 			message(G_LOG_LEVEL_CRITICAL, "Trying to add to a GList* a non GObject pointer dest=%s src=%s", #dest, #src); \
431 		} \
432 	}
433 
434 #define lasso_list_add_new_gobject(dest, src) \
435 	{ \
436 		void *__tmp_src = (src); \
437 		if (G_IS_OBJECT(__tmp_src)) { \
438 			dest = g_list_append(dest, __tmp_src); \
439 		} else { \
440 			message(G_LOG_LEVEL_CRITICAL, "Trying to add to a GList* a non GObject pointer dest=%s src=%s", #dest, #src); \
441 		} \
442 	}
443 
444 #define lasso_list_add_xml_node(dest, src) \
445 	{ \
446 		xmlNode *__tmp_src = xmlCopyNode(src, 1); \
447 		lasso_list_add_non_null(dest, __tmp_src); \
448 	}
449 
450 #define lasso_list_add_new_xml_node(dest, src) \
451 	{ \
452 		xmlNode *__tmp_src = src; \
453 		lasso_list_add_non_null(dest, __tmp_src); \
454 	}
455 
456 #define lasso_list_add_xml_node_list(dest, src) \
457 	{ \
458 		xmlNode *__tmp_src = xmlCopyNodeList(src); \
459 		lasso_list_add_non_null(dest, __tmp_src); \
460 	}
461 
462 #define lasso_list_add_new_xml_node_list(dest, src) \
463 	lasso_list_add_new_xml_node(dest, src)
464 
465 #define lasso_list_add_gstrv(dest, src) \
466 	{ \
467 		GList **__tmp_dest = &(dest); \
468 		const char **__iter = (const char**)(src); \
469 		while (__iter && *__iter) { \
470 			lasso_list_add_string(*__tmp_dest, *__iter); \
471 		} \
472 	}
473 
474 #define lasso_list_add_new_sec_key(dest, src) \
475 	{ \
476 		xmlSecKey *__tmp_src = (src); \
477 		lasso_list_add_non_null(dest, __tmp_src); \
478 	}
479 
480 /* List element removal */
481 #define lasso_list_remove_gobject(list, gobject) \
482 	do { void *__tmp = gobject; GList **__tmp_list = &(list); \
483 		*__tmp_list = g_list_remove(*__tmp_list, __tmp); \
484 		lasso_unref(__tmp); } while(0)
485 
486 /* List element membership */
487 #define lasso_is_in_list_of_strings(list, item) \
488 	g_list_find_custom(list, item, (GCompareFunc)g_strcmp0) == NULL ? FALSE : TRUE
489 
490 
491 /* Pointer ownership transfer */
492 
493 /* lasso_transfer_xxx macros are like lasso_assign_xxx but they do not increment reference count or
494  * copy the source value, instead they steal the value (and set the source to NULL, preventing stale
495  * references).
496  */
497 #define lasso_transfer_full(dest, src, kind) \
498 	{\
499 		lasso_release_##kind((dest)); \
500 		lasso_check_type_equality(dest, src); \
501 		(dest) = (void*)(src); \
502 		(src) = NULL; \
503 	}
504 
505 #define lasso_transfer_xpath_object(dest, src) \
506 	lasso_transfer_full(dest, src, xpath_object)
507 
508 #define lasso_transfer_string(dest, src) \
509 	lasso_transfer_full(dest, src, string)
510 
511 #define lasso_transfer_gobject(dest, src) \
512 	lasso_transfer_full(dest, src, gobject)
513 
514 #define lasso_transfer_xml_node(dest, src) \
515 	lasso_transfer_full(dest, src, xml_node)
516 
517 /* Node extraction */
518 #define lasso_extract_node_or_fail(to, from, kind, error) \
519 	{\
520 		void *__tmp = (from); \
521 		if (LASSO_IS_##kind(__tmp)) { \
522 			to = LASSO_##kind(__tmp); \
523 		} else { \
524 			rc = error; \
525 			goto cleanup; \
526 		}\
527 	}
528 
529 /* Bad param handling */
530 #define lasso_return_val_if_invalid_param(kind, name, val) \
531 	g_return_val_if_fail(LASSO_IS_##kind(name), val)
532 
533 #define lasso_bad_param(kind, name) \
534 	lasso_return_val_if_invalid_param(kind, name, \
535 		LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
536 
537 #define lasso_null_param(name) \
538 	g_return_val_if_fail(name != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
539 
540 /**
541  * lasso_check_non_empty_string:
542  * @str: a char pointer
543  *
544  * Check that @str is non-NULL and not empty, otherwise jump to cleanup and return
545  * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ.
546  */
547 #define lasso_check_non_empty_string(str) \
548 	goto_cleanup_if_fail_with_rc(! lasso_strisempty(str), \
549 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
550 
551 /*
552  * We extensively use goto operator but in a formalized way, i.e. only for error checking code
553  * paths.
554  *
555  * The next macros goto_cleanup_xxxx encapsulate idioms used in lasso, like checking for a condition
556  * or setting the return code which must be called 'rc' and be of an 'int' type.
557  */
558 
559 /*
560  * The following macros are made to create some formalism for function's cleanup code.
561  *
562  * The exit label should be called 'cleanup'. And for functions returning an integer error code, the
563  * error code should be named 'rc' and 'return rc;' should be the last statement of the function.
564  */
565 
566 /**
567  * goto_cleanup_with_rc:
568  * @rc_value: integer return value
569  *
570  * This macro jump to the 'cleanup' label and set the return value to @rc_value.
571  *
572  */
573 #define goto_cleanup_with_rc(rc_value) \
574 	do {\
575 		rc = (rc_value); \
576 		goto cleanup; \
577 	} while(0);
578 
579 /**
580  * goto_cleanup_if_fail:
581  * @condition: a boolean condition
582  *
583  * Jump to the 'cleanup' label if the @condition is FALSE.
584  *
585  */
586 #define goto_cleanup_if_fail(condition) \
587 	{\
588 		if (! (condition) ) {\
589 			goto cleanup; \
590 		} \
591 	}
592 
593 /**
594  * goto_cleanup_if_fail_with_rc:
595  * @condition: a boolean condition
596  * @rc_value: integer return value
597  *
598  * Jump to the 'cleanup' label if the @condition is FALSE and set the return value to
599  * @rc_value.
600  *
601  */
602 #define goto_cleanup_if_fail_with_rc(condition, rc_value) \
603 	{\
604 		if (! (condition) ) {\
605 			rc = (rc_value); \
606 			goto cleanup; \
607 		} \
608 	}
609 
610 /**
611  * goto_cleanup_if_fail_with_rc_with_warning:
612  * @condition: a boolean condition
613  * @rc_value: integer return value
614  *
615  * Jump to the 'cleanup' label if the @condition is FALSE and set the return value to
616  * @rc_value. Also emit a warning, showing the condition and the return value.
617  *
618  */
619 #define goto_cleanup_if_fail_with_rc_with_warning(condition, rc_value) \
620 	{\
621 		if (! (condition) ) {\
622 			message(G_LOG_LEVEL_WARNING, "%s failed, returning %s", #condition, #rc_value);\
623 			rc = (rc_value); \
624 			goto cleanup; \
625 		} \
626 	}
627 
628 /**
629  * check_good_rc:
630  * @what: a call to a function returning a lasso error code
631  *
632  * Check if return code is 0, if not store it in rc and jump to cleanup label.
633  */
634 #define lasso_check_good_rc(what) \
635 	{ \
636 		int __rc = (what);\
637 		goto_cleanup_if_fail_with_rc(__rc == 0, __rc); \
638 	}
639 
640 #define lasso_mem_debug(who, what, where) \
641 	{ \
642 		if (lasso_flag_memory_debug) \
643 		fprintf(stderr, "  freeing %s/%s (at %p)\n", who, what, (void*)where); \
644 	}
645 
646 /**
647  * lasso_foreach:
648  * @_iter: a #GList variable, which will server to traverse @_list
649  * @_list: a #GList value, which we will traverse
650  *
651  * Traverse a #GList list using 'for' construct. It must be followed by a block or a statement.
652  */
653 #define lasso_foreach(_iter, _list) \
654 	for (_iter = (_list); _iter; _iter = g_list_next(_iter))
655 
656 /**
657  * lasso_foreach_full_begin:
658  * @_type: the type of the variable @_data
659  * @_data: the name of the variable to define to store data values
660  * @_iter: the name of the variable to define to store the iterator
661  * @_list: the GList* to iterate
662  *
663  * Traverse a GList* @_list, using @_iter as iteration variable extract data field to variable
664  * @_data of type @_type.
665  */
666 #define lasso_foreach_full_begin(_type, _data, _iter, _list) \
667 	{ \
668 		_type _data = NULL; \
669 		GList *_iter = NULL; \
670 		for (_iter = (_list); _iter && ((_data = _iter->data), 1); _iter = g_list_next(_iter)) \
671 		{
672 
673 #define lasso_foreach_full_end() \
674 				} }
675 
676 /**
677  * lasso_list_get_first_child:
678  * @list:(allowed-none): a #GList node or NULL.
679  *
680  * Return the first child in a list, or NULL.
681  */
682 #define lasso_list_get_first_child(list) \
683 	((list) ? (list)->data : NULL)
684 
685 /* Get a printable extract for error messages */
686 char* lasso_safe_prefix_string(const char *str, gsize length);
687 
688 int lasso_gobject_is_of_type(GObject *a, GType b);
689 
690 GObject *lasso_extract_gtype_from_list(GType type, GList *list);
691 
692 GObject * lasso_extract_gtype_from_list_or_new(GType type, GList **list, gboolean create);
693 
694 /* Get first node of this type in a list */
695 /* ex: lasso_extract_node (LassoNode, LASSO_TYPE_NODE, list) */
696 #define lasso_extract_gobject_from_list(type, gobjecttype, list) \
697 	((type*) lasso_extract_gtype_from_list(gobjecttype, list))
698 
699 /*
700  * Simplify simple accessors argument checking.
701  *
702  */
703 #define lasso_return_val_if_fail(assertion, value) \
704 	if (!(assertion)) return (value);
705 
706 #define lasso_return_null_if_fail(assertion) \
707 	lasso_return_val_if_fail(assertion, NULL)
708 
709 #define lasso_return_if_fail(assertion) \
710 	if (!(assertion)) return;
711 
712 #define lasso_trace(args...) \
713 	if (lasso_flag_memory_debug) { \
714 		fprintf(stderr, ## args); \
715 	}
716 
717 /* Lasso string data helpers */
718 inline static gboolean
lasso_strisequal(const char * a,const char * b)719 lasso_strisequal(const char *a, const char *b) {
720 	return (g_strcmp0(a,b) == 0);
721 }
722 inline static gboolean
lasso_strisnotequal(const char * a,const char * b)723 lasso_strisnotequal(const char *a, const char *b) {
724 	return ! lasso_strisequal(a,b);
725 }
726 inline static gboolean
lasso_strisempty(const char * str)727 lasso_strisempty(const char *str) {
728 	return ((str) == NULL || (str)[0] == '\0');
729 }
730 inline static gboolean
lasso_xmlstrisnotequal(const xmlChar * a,const xmlChar * b)731 lasso_xmlstrisnotequal(const xmlChar *a, const xmlChar *b) {
732 	return lasso_strisnotequal((char*)a, (char*)b);
733 }
734 
735 /**
736  * lasso_crypto_memequal:
737  * @a: first buffer
738  * @b: second buffer
739  * @l: common length
740  *
741  * Compare two buffers, preventing timing attacks.
742  */
743 static inline gboolean
lasso_crypto_memequal(void * a,void * b,unsigned int l)744 lasso_crypto_memequal(void *a, void *b, unsigned int l)
745 {
746 	unsigned char *x = a, *y = b;
747 	gboolean result = TRUE;
748 
749 	for (;l;l--, x++, y++) {
750 		result = result && (*x == *y);
751 	}
752 	return result;
753 }
754 
755 #endif /* __LASSO_UTILS_H__ */
756