1 /*
2  * Portions of this file Copyright 1999-2005 University of Chicago
3  * Portions of this file Copyright 1999-2005 The University of Southern California.
4  *
5  * This file or a portion of this file is licensed under the
6  * terms of the Globus Toolkit Public License, found at
7  * http://www.globus.org/toolkit/download/license.html.
8  * If you redistribute this file, with or without
9  * modifications, you must include this notice in the file.
10  */
11
12 #include "globus_i_wsrf_resource.h"
13 #include "xsd_any.h"
14
15 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
16 /**
17  * @file globus_wsrf_resource_property.c
18  * Resource Property Functions
19  * @author $author$
20  * @date $date$
21  * @version $version$
22  */
23 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
24
25 static
26 xsd_QName globus_l_resource_properties_any_qname = {
27     "any",
28     "any"
29 };
30
31 const xsd_QName * globus_resource_properties_any_qname =
32     &globus_l_resource_properties_any_qname; 
33 static
34 globus_result_t
35 globus_l_resource_create_property(
36     globus_resource_t                   resource,
37     const xsd_QName *                   qname,
38     const globus_xsd_type_info_t        type_info,
39     void *                              property,
40     globus_resource_property_callback_t callback,
41     void *                              callback_arg);
42
43 static
44 globus_result_t
45 globus_l_resource_get_any_property(
46     globus_resource_t                   resource,
47     const xsd_QName *                   qname,
48     void **                             property,
49     globus_xsd_type_info_t *            info);
50
51 globus_result_t
52 globus_l_resource_set_any_property(
53     globus_resource_t                   resource,
54     const xsd_QName *                   qname,
55     void *                              property);
56
57 /**
58  * Get the value of the named Resource Property.
59  * @ingroup resource_property
60  *
61  * @param resource
62  *     Resource containing the property.
63  * @param qname
64  *     Name of the Resource Property element.
65  * @param property 
66  *     Pointer to return the value of the property.
67  * @param type_info
68  *     Pointer to return the type info for this property. This may be NULL.
69  *
70  * @retval GLOBUS_SUCCESS
71  *     Resource Property found and its value returned in @a property.
72  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
73  *     One of the parameters to this function was NULL.
74  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
75  *     The resource does not contain a property with the specified name.
76  */
77 globus_result_t
78 globus_resource_get_property(
79     globus_resource_t                   resource,
80     const xsd_QName *                   qname,
81     void **                             property,
82     globus_xsd_type_info_t *            type_info)
83 493509 {
84 493509     globus_result_t                     result = GLOBUS_SUCCESS;
85 493509     globus_resource_property_t *        prop = NULL;
86 493509     GlobusFuncName(globus_resource_get_property);
87
88 493509     if (resource == NULL || qname == NULL || property == NULL)
89     {
90 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
91     }
92
93 493509     *property = NULL;
94
95 493509     prop = globus_hashtable_lookup(
96             &resource->resource_properties,
97             (void *) qname);
98
99 493509     if (prop != NULL)
100     {
101 493391         if (prop->callback != NULL)
102         {
103 1             prop->callback(prop->callback_arg, qname, property);
104
105 1             if (prop->property != NULL)
106             {
107 0                 prop->type_info->destroy(prop->property);
108             }
109 1             prop->property = *property;
110         }
111         else
112         {
113 493390             *property = prop->property;
114         }
115 493391         if (type_info != NULL)
116         {
117 493379             (*type_info) = prop->type_info;
118         }
119     }
120     else
121     {
122 118         result = globus_l_resource_get_any_property(
123                 resource,
124                 qname,
125                 property,
126                 type_info);
127
128 118         if (result != GLOBUS_SUCCESS)
129         {
130 493509             goto out;
131         }
132     }
133
134 out:
135 493509     return result;
136 }
137 /* globus_resource_get_property() */
138
139 /**
140  * Set the value of the named Resource Property.
141  * @ingroup resource_property
142  *
143  * Changes the current value of the named Resource Property to be that of
144  * the @a property parameter. If the Resource Property already had a value
145  * set by a previous call to this function or
146  * #globus_resource_create_property(), the old value will be destroyed, using
147  * the functions included in the type info associated with the property.
148  *
149  * @param resource
150  *     Resource containing the property.
151  * @param qname
152  *     Name of the Resource Property element.
153  * @param property 
154  *     New value of the property.
155  *
156  * @retval GLOBUS_SUCCESS
157  *     Resource Property found and its value returned in @a property.
158  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
159  *     One of the parameters to this function was NULL.
160  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
161  *     The resource does not contain a property with the specified name.
162  */
163 globus_result_t
164 globus_resource_set_property(
165     globus_resource_t                   resource,
166     const xsd_QName *                   qname,
167     void *                              property)
168 53 {
169 53     globus_result_t                     result = GLOBUS_SUCCESS;
170 53     globus_resource_property_t *        prop = NULL;
171 53     GlobusFuncName(globus_resource_set_property);
172
173 53     if (resource == NULL || qname == NULL)
174     {
175 0         result =  GLOBUS_RESOURCE_ERROR_NULL_PARAM();
176
177 0         goto out;
178     }
179
180 53     prop = globus_hashtable_lookup(
181             &resource->resource_properties,
182             (void*) qname);
183
184 53     if (prop != NULL)
185     {
186 41         if (prop->property != NULL && prop->type_info->destroy != NULL)
187         {
188 6             prop->type_info->destroy(prop->property);
189         }
190
191 41         prop->property = property;
192     }
193     else
194     {
195 12         result = globus_l_resource_set_any_property(
196                 resource,
197                 qname,
198                 property);
199     }
200
201 out:
202 53     return result;
203 }
204 /* globus_resource_set_property() */
205
206 /**
207  * Create a new Resource Property.
208  * @ingroup resource_property
209  *
210  * Modifies the resource to contain a new Resource Property with the given
211  * element name and type information. The initial value of the property will
212  * be set to the @a property parameter's value.
213  *
214  * @param resource
215  *     Resource with which to associated the new resource property.
216  * @param qname
217  *     Name of the resource property element.
218  * @param type_info
219  *     XSD type mapping for this resource property type. This mapping
220  *     describes how to access the value contained in the @a property
221  *     parameter.
222  * @param property
223  *     Initial value of the property.
224  * 
225  * @retval GLOBUS_SUCCESS
226  *     Property successfully created.
227  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
228  *     One of the parameters to this function was NULL.
229  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
230  *     A Resource Property with the given QName already exists in this
231  *     resource.
232  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
233  *     Not enough memory to allocate the new Resource Property.
234  */
235 globus_result_t
236 globus_resource_create_property(
237     globus_resource_t                   resource,
238     const xsd_QName *                   qname,
239     const globus_xsd_type_info_t        type_info,
240     void *                              property)
241 80 {
242 80     return globus_l_resource_create_property(
243             resource,
244             qname,
245             type_info,
246             property,
247             NULL,
248             NULL);
249 }
250 /* globus_resource_create_property() */
251
252 /**
253  * Create a new dynamic-valued Resource Property.
254  * @ingroup resource_property
255  *
256  * Modifies the resource to contain a new Resource Property with the given
257  * element name and type information. The value of the property is determined
258  * by calling the callback function. Subsequent calls to
259  * globus_resource_get_property() will delete the previous value generated by
260  * the callback.
261  *
262  * @param resource
263  *     Resource with which to associated the new resource property.
264  * @param qname
265  *     Name of the resource property element.
266  * @param type_info
267  *     XSD type mapping for this resource property type. This mapping
268  *     describes how to access the value contained in the @a property
269  *     parameter.
270  * @param callback
271  *     Callback when creating a dynamic-valued Resource Property.
272  * @param callback_arg
273  *     User-specific callback argument for dynamic Resource Property
274  *     value callbacks.
275  * 
276  * @retval GLOBUS_SUCCESS
277  *     Property successfully created.
278  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
279  *     One of the parameters to this function was NULL.
280  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
281  *     A Resource Property with the given QName already exists in this
282  *     resource.
283  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
284  *     Not enough memory to allocate the new Resource Property.
285  */
286 globus_result_t
287 globus_resource_create_property_callback(
288     globus_resource_t                   resource,
289     const xsd_QName *                   qname,
290     const globus_xsd_type_info_t        type_info,
291     globus_resource_property_callback_t callback,
292     void *                              callback_arg)
293 25 {
294 25     GlobusFuncName(globus_resource_create_property_callback);
295
296 25     if (callback == NULL)
297     {
298 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
299     }
300
301 25     return globus_l_resource_create_property(
302             resource,
303             qname,
304             type_info,
305             NULL,
306             callback,
307             callback_arg);
308 }
309 /* globus_resource_create_property_callback() */
310
311 /**
312  * Remove the named resource property from a resource.
313  * @ingroup resource_property
314  *
315  * The property's current value and type info is returned in the @a property
316  * and @a type_info parameters respectively.
317  *
318  * @param resource
319  *     Resource containing the property.
320  * @param qname
321  *     Element name of the resource property.
322  * @param property
323  *     Pointer to be set to point to the value of the resource property.
324  * @param type_info
325  *     Pointer to be set to type information about the property value.
326  *
327  * @retval GLOBUS_SUCCESS
328  *     Resource Property successfully deleted.
329  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
330  *     One of the parameters to this function was NULL.
331  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
332  *     The resource does not contain a property with the specified name.
333  */
334 globus_result_t
335 globus_resource_delete_property(
336     globus_resource_t                   resource,
337     const xsd_QName *                   qname,
338     void **                             property,
339     globus_xsd_type_info_t *            type_info)
340 0 {
341 0     globus_resource_property_t *        prop = NULL;
342 0     GlobusFuncName(globus_resource_delete_property);
343
344 0     if (resource == NULL || qname == NULL || property == NULL ||
345             type_info == NULL)
346     {
347 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
348     }
349
350 0     if (resource->resource_properties != NULL)
351     {
352 0         prop = globus_hashtable_remove(
353                 &resource->resource_properties,
354                 (void*) qname);
355     }
356
357 0     if (prop == NULL)
358     {
359 0         return GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
360     }
361
362 0     *property = prop->property;
363 0     *type_info = prop->type_info;
364
365 0     globus_free(prop->name.Namespace);
366 0     globus_free(prop->name.local);
367 0     globus_free(prop);
368
369 0     return GLOBUS_SUCCESS;
370 }
371 /* globus_resource_delete_property() */
372
373 /**
374  * Destroy a named resource property.
375  * @ingroup resource_property
376  *
377  * The current value of the property is destroyed. Subsequent attempts to
378  * access the property will fail.
379  *
380  * and @a type_info parameters respectively.
381  *
382  * @param resource
383  *     Resource containing the property.
384  * @param qname
385  *     Element name of the resource property.
386  * @retval GLOBUS_SUCCESS
387  *     The property was successfully destroyed
388  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
389  *     One of the parameters to this function was NULL.
390  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
391  *     The resource does not contain a property with the specified name.
392  */
393 globus_result_t
394 globus_resource_destroy_property(
395     globus_resource_t                   resource,
396     const xsd_QName *                   qname)
397 0 {
398 0     globus_resource_property_t *        prop = NULL;
399 0     GlobusFuncName(globus_resource_destroy_property);
400
401 0     if (resource == NULL || qname == NULL)
402     {
403 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
404     }
405
406 0     if (resource->resource_properties != NULL)
407     {
408 0         prop = globus_hashtable_remove(
409                 &resource->resource_properties,
410                 (void *) qname);
411     }
412
413 0     if (prop == NULL)
414     {
415 0         return GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
416     }
417
418 0     if (prop->property != NULL)
419     {
420 0         prop->type_info->destroy(prop->property);
421     }
422
423 0     free(prop->name.Namespace);
424 0     free(prop->name.local);
425 0     free(prop);
426
427 0     return GLOBUS_SUCCESS;
428 }
429 /* globus_resource_destroy_property() */
430
431 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
432 /**
433  * Internal implementation of Resource Property creation.
434  * 
435  * Modifies the resource to contain a new Resource Property with the given
436  * element name and type information. The initial value of the property will
437  * be set to the @a property parameter's value.
438  *
439  * @param resource
440  *     Resource with which to associated the new resource property.
441  * @param qname
442  *     Name of the resource property element.
443  * @param type_info
444  *     XSD type mapping for this resource property type. This mapping
445  *     describes how to access the value contained in the @a property
446  *     parameter.
447  * @param property
448  *     Initial value of the property.
449  * @param callback
450  *     Callback when creating a dynamic-valued Resource Property.
451  * @param callback_arg
452  *     User-specific callback argument for dynamic Resource Property
453  *     value callbacks.
454  * 
455  * @retval GLOBUS_SUCCESS
456  *     Property successfully created.
457  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
458  *     One of the parameters to this function was NULL.
459  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
460  *     A Resource Property with the given QName already exists in this
461  *     resource.
462  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
463  *     Not enough memory to allocate the new Resource Property.
464  */
465 static
466 globus_result_t
467 globus_l_resource_create_property(
468     globus_resource_t                   resource,
469     const xsd_QName *                   qname,
470     const globus_xsd_type_info_t        type_info,
471     void *                              property,
472     globus_resource_property_callback_t callback,
473     void *                              callback_arg)
474 105 {
475 105     globus_resource_property_t *        prop;
476 105     globus_result_t                     result;
477 105     int                                 rc;
478 105     GlobusFuncName(globus_l_resource_create_property);
479
480 105     if (resource == NULL || qname == NULL || type_info == NULL)
481     {
482 0         result = GLOBUS_RESOURCE_ERROR_NULL_PARAM();
483
484 0         goto error;
485     }
486
487     /* If the globus_resource_properties_any_qname is used for the property
488      * name, it must be either an any or any_array and must not have a callback
489      */
490 105     if (xsd_QName_keyeq(
491                 (void *) qname,
492                 (void *) globus_resource_properties_any_qname) &&
493         ((type_info != &xsd_any_info && type_info != &xsd_any_array_info)
494             || (callback != NULL)))
495     {
496 0         result = GLOBUS_RESOURCE_ERROR_INVALID_ANY();
497
498 0         goto error;
499     }
500
501 105     prop = globus_hashtable_lookup(
502             &resource->resource_properties,
503             (void *) qname);
504
505 105     if (prop != NULL)
506     {
507 0         result = GLOBUS_RESOURCE_ERROR_DUPLICATE_PROPERTY(qname);
508
509 0         goto error;
510     }
511 105     prop = malloc(sizeof(struct globus_resource_property_s));
512
513 105     if (prop == NULL)
514     {
515 0         result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
516
517 0         goto error;
518     }
519     
520 105     result = xsd_QName_copy_contents(&prop->name, qname);
521 105     if(result != GLOBUS_SUCCESS)
522     {
523 0         goto free_prop_error;
524     }
525 105     prop->type_info = type_info;
526 105     prop->property = property;
527 105     prop->callback = callback;
528 105     prop->callback_arg = callback_arg;
529
530 105     rc = globus_hashtable_insert(
531             &resource->resource_properties,
532             &prop->name,
533             prop);
534
535 105     if (rc != GLOBUS_SUCCESS)
536     {
537 0         result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
538
539 0         goto free_qname_error;
540     }
541
542 105     if (xsd_QName_keyeq(
543                 (void *) qname,
544                 (void *) globus_resource_properties_any_qname)
545         && prop->property == NULL)
546     {
547 10         result = prop->type_info->initialize(&prop->property);
548
549 10         if (result != GLOBUS_SUCCESS)
550         {
551 0             goto remove_from_hashtable_error;
552         }
553     }
554
555 105     return GLOBUS_SUCCESS;
556
557 remove_from_hashtable_error:
558 0     globus_hashtable_remove(&resource->resource_properties, &prop->name);
559 free_qname_error:
560 0     xsd_QName_destroy_contents(&prop->name);
561 free_prop_error:
562 0     globus_libc_free(prop);
563 error:
564 0     return result;
565 }
566 /* globus_l_resource_create_property() */
567
568 /**
569  * Check to see if we can match the qname in the resource's any:any property 
570  * if it is present.
571  *
572  * @param resource
573  *     Resource containing the property.
574  * @param qname
575  *     Name of the Resource Property element.
576  * @param property 
577  *     Pointer to return the value of the property.
578  * @param type_info
579  *     Pointer to return the type info for this property. This may be NULL.
580  *
581  * @retval GLOBUS_SUCCESS
582  *     Resource Property found and its value returned in @a property.
583  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
584  *     One of the parameters to this function was NULL.
585  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
586  *     The resource does not contain a property with the specified name.
587  */
588 static
589 globus_result_t
590 globus_l_resource_get_any_property(
591     globus_resource_t                   resource,
592     const xsd_QName *                   qname,
593     void **                             property,
594     globus_xsd_type_info_t *            info)
595 118 {
596 118     globus_result_t                     result = GLOBUS_SUCCESS;
597 118     globus_resource_property_t *        prop;
598
599 118     prop = globus_hashtable_lookup(
600             &resource->resource_properties,
601             (void *) globus_resource_properties_any_qname);
602
603 118     if (prop == NULL)
604     {
605 16         result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
606
607 16         goto out;
608     }
609
610 102     if (prop->type_info == &xsd_any_info)
611     {
612 56         xsd_any *                   any = prop->property;
613
614 56         if (any->element != NULL &&
615             !xsd_QName_keyeq((void *) any->element, (void *) qname))
616         {
617 12             result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
618
619 12             goto out;
620         }
621 44         *property = any;
622     }
623 46     else if (prop->type_info == &xsd_any_array_info)
624     {
625 46         xsd_any_array *             any_array = prop->property;
626 46         int i;
627
628 64         for (i = 0; i < any_array->length; i++)
629         {
630 48             if (any_array->elements[i].element == NULL)
631             {
632 6                 *property = &any_array->elements[i];
633 6                 break;
634             }
635 42             else if (xsd_QName_keyeq(
636                         any_array->elements[i].element,
637                         (void *) qname))
638             {
639 24                 *property = &any_array->elements[i];
640 24                 break;
641             }
642         }
643 46         if (i == any_array->length)
644         {
645 16             xsd_any * any = xsd_any_array_push(any_array);
646 16             any->any_info = &xsd_any_array_info;
647 16             *property = any;
648         }
649     }
650 90     if (info != NULL)
651     {
652 90         *info = &xsd_any_info;
653     }
654 out:
655 118     return result;
656 }
657 /* globus_l_resource_get_any_property() */
658
659 /**
660  * Set the value of a named resource property stored within the special
661  * "any:any" resource property.
662  *
663  * Changes the current value of the named Resource Property to be that of
664  * the @a property parameter. If the Resource Property already had a value
665  * set by a previous call to this function or
666  * #globus_resource_create_property(), the old value will be destroyed, using
667  * the functions included in the type info associated with the property. If
668  * the @a property parameter is NULL and this is in the any resource property,
669  * it will be removed.
670  *
671  * @param resource
672  *     Resource containing the property.
673  * @param qname
674  *     Name of the Resource Property element.
675  * @param property 
676  *     New value of the property.
677  *
678  * @retval GLOBUS_SUCCESS
679  *     Resource Property found and its value returned in @a property.
680  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
681  *     One of the parameters to this function was NULL.
682  * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
683  *     The resource does not contain a property with the specified name.
684  */
685 globus_result_t
686 globus_l_resource_set_any_property(
687     globus_resource_t                   resource,
688     const xsd_QName *                   qname,
689     void *                              property)
690 12 {
691 12     globus_result_t                     result = GLOBUS_SUCCESS;
692 12     globus_resource_property_t *        prop = NULL;
693 12     xsd_any *                           any;
694 12     xsd_any_array *                     any_array;
695 12     int                                 i;
696 12     GlobusFuncName(globus_l_resource_set_any_property);
697
698 12     prop = globus_hashtable_lookup(
699             &resource->resource_properties,
700             (void*) globus_resource_properties_any_qname);
701
702 12     if (prop == NULL)
703     {
704 0         result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
705
706 0         goto out;
707     }
708
709 12     if (prop->type_info == &xsd_any_info)
710     {
711         /* Single any element */
712 8         any = prop->property;
713
714 8         if (any->element == NULL ||
715             xsd_QName_keyeq(any->element, (void *) qname))
716         {
717             /* The element name matches, so we'll destroy the old value */
718 8             if (any->value != NULL)
719             {
720 8                 any->any_info->destroy(any->value);
721 8                 any->value = NULL;
722             }
723             /*
724              * Insert the new prop value if we have one; otherwise, we remove
725              * the binding of the QName to this any.
726              */
727 8             if (property != NULL)
728             {
729 0                 any->value = property;
730             }
731             else
732             {
733 8                 any->value = NULL;
734 8                 if (any->element != NULL)
735                 {
736 8                     xsd_QName_destroy(any->element);
737 8                     any->element = NULL;
738                 }
739 8                 any->any_info = NULL;
740             }
741         }
742         else
743         {
744             /* element name doesn't match */
745 0             result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
746
747 0             goto out;
748         }
749     }
750     else
751     {
752 4         assert(prop->type_info == &xsd_any_array_info);
753 4         any_array = prop->property;
754
755         /* The value is an array of anys. We'll look for the one which
756          * matches our qname, and replace its contents with the new value.
757          * if property is null, we'll remove it from the array altogether
758          */
759 4         for (i = 0; i < any_array->length; i++)
760         {
761 4             any = &any_array->elements[i];
762
763 4             if (any->element != NULL &&
764                 xsd_QName_keyeq(any->element, (void *) qname))
765             {
766                 /* found a match */
767 4                 if (any->value != NULL)
768                 {
769                     /* old value -- gone! */
770 4                     any->any_info->destroy(any->value);
771 4                     any->value = NULL;
772                 }
773 4                 if (property != NULL)
774                 {
775                     /* replace with new value */
776 0                     any->value = property;
777                 }
778                 else
779                 {
780                     /* delete binding for this QName */
781 4                     xsd_QName_destroy(any->element);
782 4                     any->element = NULL;
783
784 4                     if (i + 1 < any_array->length)
785                     {
786                         /* pop this array element out of the array */
787 4                         memmove(
788                             &any_array->elements[i],
789                             &any_array->elements[i+1],
790                             sizeof(any_array->elements[i]) *
791                                 (any_array->length - (i + 1)));
792                     }
793                     /* And clear value at the tail of this array */
794 4                     memset(&any_array->elements[any_array->length-1],
795                             0,
796                             sizeof(any_array->elements[i]));
797 4                     any_array->length--;
798                 }
799 4                 break; /* only one match will be possible */
800             }
801         }
802     }
803 out:
804 12     return result;
805 }