Git init
[external/xmlsec1.git] / src / list.c
1 /** 
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  * List of pointers.
5  *
6  * This is free software; see Copyright file in the source
7  * distribution for preciese wording.
8  * 
9  * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
10  */
11 #include "globals.h"
12
13 #include <stdlib.h>
14 #include <string.h>
15  
16 #include <libxml/tree.h>
17
18 #include <xmlsec/xmlsec.h>
19 #include <xmlsec/list.h>
20 #include <xmlsec/errors.h>
21
22
23 static int              xmlSecPtrListEnsureSize                 (xmlSecPtrListPtr list,
24                                                                  xmlSecSize size);
25                                                                  
26 static xmlSecAllocMode gAllocMode = xmlSecAllocModeDouble;
27 static xmlSecSize gInitialSize = 64;
28
29 /** 
30  * xmlSecPtrListSetDefaultAllocMode:
31  * @defAllocMode:       the new default memory allocation mode.
32  * @defInitialSize:     the new default minimal initial size.
33  *
34  * Sets new default allocation mode and minimal initial list size.
35  */
36 void 
37 xmlSecPtrListSetDefaultAllocMode(xmlSecAllocMode defAllocMode, xmlSecSize defInitialSize) {
38     xmlSecAssert(defInitialSize > 0);
39     
40     gAllocMode = defAllocMode;
41     gInitialSize = defInitialSize;
42 }
43
44 /**
45  * xmlSecPtrListCreate:
46  * @id:                 the list klass.
47  * 
48  * Creates new list object. Caller is responsible for freeing returned list
49  * by calling #xmlSecPtrListDestroy function.
50  *
51  * Returns: pointer to newly allocated list or NULL if an error occurs.
52  */
53 xmlSecPtrListPtr 
54 xmlSecPtrListCreate(xmlSecPtrListId id) {
55     xmlSecPtrListPtr list;
56     int ret;
57     
58     xmlSecAssert2(id != xmlSecPtrListIdUnknown, NULL);
59     
60     /* Allocate a new xmlSecPtrList and fill the fields. */
61     list = (xmlSecPtrListPtr)xmlMalloc(sizeof(xmlSecPtrList));
62     if(list == NULL) {
63         xmlSecError(XMLSEC_ERRORS_HERE,
64                     xmlSecErrorsSafeString(xmlSecPtrListKlassGetName(id)),
65                     NULL,
66                     XMLSEC_ERRORS_R_MALLOC_FAILED,
67                     "sizeof(xmlSecPtrList)=%d", 
68                     sizeof(xmlSecPtrList));
69         return(NULL);
70     }
71     
72     ret = xmlSecPtrListInitialize(list, id);
73     if(ret < 0) {
74         xmlSecError(XMLSEC_ERRORS_HERE,
75                     xmlSecErrorsSafeString(xmlSecPtrListKlassGetName(id)),
76                     "xmlSecPtrListInitialize",
77                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
78                     XMLSEC_ERRORS_NO_MESSAGE);
79         xmlFree(list);
80         return(NULL);
81     }
82     
83     return(list);    
84 }
85
86 /**
87  * xmlSecPtrListDestroy:
88  * @list:               the pointer to list.
89  *
90  * Destroys @list created with #xmlSecPtrListCreate function.
91  */
92 void 
93 xmlSecPtrListDestroy(xmlSecPtrListPtr list) {
94     xmlSecAssert(xmlSecPtrListIsValid(list));
95     xmlSecPtrListFinalize(list);
96     xmlFree(list);
97 }
98
99 /**
100  * xmlSecPtrListInitialize:
101  * @list:               the pointer to list.
102  * @id:                 the list klass.
103  *
104  * Initializes the list of given klass. Caller is responsible 
105  * for cleaning up by calling #xmlSecPtrListFinalize function.
106  *
107  * Returns: 0 on success or a negative value if an error occurs.
108  */
109 int 
110 xmlSecPtrListInitialize(xmlSecPtrListPtr list, xmlSecPtrListId id) {
111     xmlSecAssert2(id != xmlSecPtrListIdUnknown, -1);
112     xmlSecAssert2(list != NULL, -1);
113
114     memset(list, 0, sizeof(xmlSecPtrList));    
115     list->id = id;
116     list->allocMode = gAllocMode;
117     
118     return(0);
119 }
120
121 /**
122  * xmlSecPtrListFinalize:
123  * @list:               the pointer to list.
124  *  
125  * Cleans up the list initialized with #xmlSecPtrListInitialize
126  * function.
127  */
128 void
129 xmlSecPtrListFinalize(xmlSecPtrListPtr list) {
130     xmlSecAssert(xmlSecPtrListIsValid(list));
131
132     xmlSecPtrListEmpty(list);
133     memset(list, 0, sizeof(xmlSecPtrList));    
134 }
135
136 /**
137  * xmlSecPtrListEmpty:
138  * @list:               the pointer to list.
139  *
140  * Remove all items from @list (if any).
141  */
142 void 
143 xmlSecPtrListEmpty(xmlSecPtrListPtr list) {
144     xmlSecAssert(xmlSecPtrListIsValid(list));
145
146     if(list->id->destroyItem != NULL) {
147         xmlSecSize pos;
148         
149         for(pos = 0; pos < list->use; ++pos) {
150             xmlSecAssert(list->data != NULL);
151             if(list->data[pos] != NULL) {
152                 list->id->destroyItem(list->data[pos]);
153             }
154         }
155     }
156     if(list->max > 0) {
157         xmlSecAssert(list->data != NULL);
158
159         memset(list->data, 0, sizeof(xmlSecPtr) * list->use);
160         xmlFree(list->data);
161     }
162     list->max = list->use = 0;
163     list->data = NULL;
164 }
165
166 /**
167  * xmlSecPtrListCopy:
168  * @dst:                the pointer to destination list.
169  * @src:                the pointer to source list.
170  *
171  * Copies @src list items to @dst list using #duplicateItem method
172  * of the list klass. If #duplicateItem method is NULL then 
173  * we jsut copy pointers to items.
174  *
175  * Returns: 0 on success or a negative value if an error occurs.
176  */
177 int
178 xmlSecPtrListCopy(xmlSecPtrListPtr dst, xmlSecPtrListPtr src) {
179     xmlSecSize i;
180     int ret;
181     
182     xmlSecAssert2(xmlSecPtrListIsValid(dst), -1);
183     xmlSecAssert2(xmlSecPtrListIsValid(src), -1);
184     xmlSecAssert2(dst->id == src->id, -1);
185     
186     /* allocate memory */
187     ret = xmlSecPtrListEnsureSize(dst, dst->use + src->use);
188     if(ret < 0) {
189         xmlSecError(XMLSEC_ERRORS_HERE,
190                     xmlSecErrorsSafeString(xmlSecPtrListGetName(src)),
191                     "xmlSecPtrListEnsureSize",
192                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
193                     "size=%d", src->use);
194         return(-1);
195     }
196
197     /* copy one item after another */    
198     for(i = 0; i < src->use; ++i, ++dst->use) {
199         xmlSecAssert2(src->data != NULL, -1);
200         xmlSecAssert2(dst->data != NULL, -1);
201         
202         if((dst->id->duplicateItem != NULL) && (src->data[i] != NULL)) {
203             dst->data[dst->use] = dst->id->duplicateItem(src->data[i]);
204             if(dst->data[dst->use] == NULL) {
205                 xmlSecError(XMLSEC_ERRORS_HERE,
206                             xmlSecErrorsSafeString(xmlSecPtrListGetName(src)),
207                             "duplicateItem",
208                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
209                             XMLSEC_ERRORS_NO_MESSAGE);
210                 return(-1);
211             }
212         } else {
213             dst->data[dst->use] = src->data[i];
214         }
215     }
216     
217     return(0);
218 }
219
220 /**
221  * xmlSecPtrListDuplicate:
222  * @list:               the pointer to list.
223  *  
224  * Creates a new copy of @list and all its items.
225  *
226  * Returns: pointer to newly allocated list or NULL if an error occurs.
227  */
228 xmlSecPtrListPtr 
229 xmlSecPtrListDuplicate(xmlSecPtrListPtr list) {
230     xmlSecPtrListPtr newList;
231     int ret;
232     
233     xmlSecAssert2(xmlSecPtrListIsValid(list), NULL);
234     
235     newList = xmlSecPtrListCreate(list->id);
236     if(newList == NULL) {
237         xmlSecError(XMLSEC_ERRORS_HERE,
238                     xmlSecErrorsSafeString(xmlSecPtrListGetName(list)),
239                     "xmlSecPtrListCreate",
240                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
241                     XMLSEC_ERRORS_NO_MESSAGE);
242         return(NULL);
243     }
244     
245     ret = xmlSecPtrListCopy(newList, list);
246     if(ret < 0) {
247         xmlSecError(XMLSEC_ERRORS_HERE,
248                     xmlSecErrorsSafeString(xmlSecPtrListGetName(list)),
249                     "xmlSecPtrListCopy",
250                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
251                     XMLSEC_ERRORS_NO_MESSAGE);
252         xmlSecPtrListDestroy(newList);
253         return(NULL);
254     }
255     return(newList);
256 }
257
258 /**
259  * xmlSecPtrListGetSize:
260  * @list:               the pointer to list.
261  *
262  * Gets list size.
263  * 
264  * Returns: the number of itmes in @list.
265  */
266 xmlSecSize      
267 xmlSecPtrListGetSize(xmlSecPtrListPtr list) {
268     xmlSecAssert2(xmlSecPtrListIsValid(list), 0);
269     
270     return(list->use);
271 }
272
273 /**
274  * xmlSecPtrListGetItem:
275  * @list:               the pointer to list.
276  * @pos:                the item position.
277  *
278  * Gets item from the list.
279  *
280  * Returns: the list item at position @pos or NULL if @pos is greater
281  * than the number of items in the list or an error occurs.
282  */
283 xmlSecPtr 
284 xmlSecPtrListGetItem(xmlSecPtrListPtr list, xmlSecSize pos) {
285     xmlSecAssert2(xmlSecPtrListIsValid(list), NULL);
286     xmlSecAssert2(list->data != NULL, NULL);
287     xmlSecAssert2(pos < list->use, NULL);
288
289     return(list->data[pos]);
290 }
291
292 /**
293  * xmlSecPtrListAdd:
294  * @list:               the pointer to list.
295  * @item:               the item.
296  *
297  * Adds @item to the end of the @list.
298  *
299  * Returns: 0 on success or a negative value if an error occurs.
300  */
301 int 
302 xmlSecPtrListAdd(xmlSecPtrListPtr list, xmlSecPtr item) {
303     int ret;
304     
305     xmlSecAssert2(xmlSecPtrListIsValid(list), -1);
306     
307     ret = xmlSecPtrListEnsureSize(list, list->use + 1);
308     if(ret < 0) {
309         xmlSecError(XMLSEC_ERRORS_HERE,
310                     xmlSecErrorsSafeString(xmlSecPtrListGetName(list)),
311                     "xmlSecPtrListAdd",
312                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
313                     "size=%d", list->use + 1);
314         return(-1);
315     }
316     
317     list->data[list->use++] = item;
318     return(0);
319 }
320
321 /**
322  * xmlSecPtrListSet:
323  * @list:               the pointer to list.
324  * @item:               the item.
325  * @pos:                the pos.
326  *
327  * Sets the value of list item at position @pos. The old value
328  * is destroyed.
329  *
330  * Returns: 0 on success or a negative value if an error occurs.
331  */
332 int 
333 xmlSecPtrListSet(xmlSecPtrListPtr list, xmlSecPtr item, xmlSecSize pos) {
334     xmlSecAssert2(xmlSecPtrListIsValid(list), -1);
335     xmlSecAssert2(list->data != NULL, -1);
336     xmlSecAssert2(pos < list->use, -1);
337
338     if((list->id->destroyItem != NULL) && (list->data[pos] != NULL)) {
339         list->id->destroyItem(list->data[pos]);
340     }
341     list->data[pos] = item;
342     return(0);
343 }
344
345 /**
346  * xmlSecPtrListRemove:
347  * @list:               the pointer to list.
348  * @pos:                the position.
349  *
350  * Destroys list item at the position @pos and sets it value to NULL.
351  *
352  * Returns: 0 on success or a negative value if an error occurs.
353  */
354 int 
355 xmlSecPtrListRemove(xmlSecPtrListPtr list, xmlSecSize pos) {
356     xmlSecAssert2(xmlSecPtrListIsValid(list), -1);
357     xmlSecAssert2(list->data != NULL, -1);
358     xmlSecAssert2(pos < list->use, -1);
359
360     if((list->id->destroyItem != NULL) && (list->data[pos] != NULL)) {
361         list->id->destroyItem(list->data[pos]);
362     }
363     list->data[pos] = NULL;
364     if(pos == list->use - 1) {
365         --list->use;
366     }
367     return(0);
368 }
369
370 /**
371  * xmlSecPtrListDebugDump:
372  * @list:               the pointer to list.
373  * @output:             the pointer to output FILE.
374  *
375  * Prints debug information about @list to the @output.
376  */
377 void 
378 xmlSecPtrListDebugDump(xmlSecPtrListPtr list, FILE* output) {
379     xmlSecAssert(xmlSecPtrListIsValid(list));
380     xmlSecAssert(output != NULL);
381
382     fprintf(output, "=== list size: %d\n", list->use);    
383     if(list->id->debugDumpItem != NULL) {
384         xmlSecSize pos;
385         
386         for(pos = 0; pos < list->use; ++pos) {
387             xmlSecAssert(list->data != NULL);
388             if(list->data[pos] != NULL) {
389                 list->id->debugDumpItem(list->data[pos], output);
390             }
391         }       
392     }
393 }
394
395 /**
396  * xmlSecPtrListDebugXmlDump:
397  * @list:               the pointer to list.
398  * @output:             the pointer to output FILE.
399  *
400  * Prints debug information about @list to the @output in XML format.
401  */
402 void 
403 xmlSecPtrListDebugXmlDump(xmlSecPtrListPtr list, FILE* output) {
404     xmlSecAssert(xmlSecPtrListIsValid(list));
405     xmlSecAssert(output != NULL);
406     
407     fprintf(output, "<List size=\"%d\">\n", list->use);    
408     if(list->id->debugXmlDumpItem != NULL) {
409         xmlSecSize pos;
410         
411         for(pos = 0; pos < list->use; ++pos) {
412             xmlSecAssert(list->data != NULL);
413             if(list->data[pos] != NULL) {
414                 list->id->debugXmlDumpItem(list->data[pos], output);
415             }
416         }       
417     }
418     fprintf(output, "</List>\n");    
419 }
420
421 static int 
422 xmlSecPtrListEnsureSize(xmlSecPtrListPtr list, xmlSecSize size) {
423     xmlSecPtr* newData;
424     xmlSecSize newSize = 0;
425
426     xmlSecAssert2(xmlSecPtrListIsValid(list), -1);
427     
428     if(size < list->max) {
429         return(0);
430     }
431
432     switch(list->allocMode) {
433         case xmlSecAllocModeExact:
434             newSize = size + 8;
435             break;
436         case xmlSecAllocModeDouble:
437             newSize = 2 * size + 32;
438             break;
439     }
440     
441     if(newSize < gInitialSize) {
442         newSize = gInitialSize;
443     }
444     
445     if(list->data != NULL) {
446         newData = (xmlSecPtr*)xmlRealloc(list->data, sizeof(xmlSecPtr) * newSize);
447     } else {
448         newData = (xmlSecPtr*)xmlMalloc(sizeof(xmlSecPtr) * newSize);
449     }
450     if(newData == NULL) {
451         xmlSecError(XMLSEC_ERRORS_HERE,
452                     xmlSecErrorsSafeString(xmlSecPtrListGetName(list)),
453                     NULL,
454                     XMLSEC_ERRORS_R_MALLOC_FAILED,
455                     "sizeof(xmlSecPtr)*%d=%d", 
456                     newSize, sizeof(xmlSecPtr) * newSize);
457         return(-1);
458     }
459     
460     list->data = newData;
461     list->max = newSize;
462     
463     return(0);
464 }
465
466 /***********************************************************************
467  *
468  * strings list
469  *
470  **********************************************************************/
471 static xmlSecPtr        xmlSecStringListDuplicateItem           (xmlSecPtr ptr);
472 static void             xmlSecStringListDestroyItem             (xmlSecPtr ptr);
473
474 static xmlSecPtrListKlass xmlSecStringListKlass = {
475     BAD_CAST "strings-list",
476     xmlSecStringListDuplicateItem,              /* xmlSecPtrDuplicateItemMethod duplicateItem; */
477     xmlSecStringListDestroyItem,                /* xmlSecPtrDestroyItemMethod destroyItem; */
478     NULL,                                       /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
479     NULL,                                       /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
480 };
481
482 /**
483  * xmlSecStringListGetKlass:
484  * 
485  * The strins list class.
486  *
487  * Returns: strings list klass.
488  */
489 xmlSecPtrListId 
490 xmlSecStringListGetKlass(void) {
491     return(&xmlSecStringListKlass);
492 }
493
494 static xmlSecPtr 
495 xmlSecStringListDuplicateItem(xmlSecPtr ptr) {
496     xmlSecAssert2(ptr != NULL, NULL);
497     
498     return(xmlStrdup((xmlChar*)ptr));
499 }
500
501 static void 
502 xmlSecStringListDestroyItem(xmlSecPtr ptr) {
503     xmlSecAssert(ptr != NULL);
504     
505     xmlFree(ptr);
506 }
507
508