getdns/src/list.c

393 lines
12 KiB
C

/**
*
* /brief getdns list management functions
*
* This is the meat of the API
* Originally taken from the getdns API description pseudo implementation.
*
*/
/* The MIT License (MIT)
* Copyright (c) 2013 Verisign, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include <getdns/getdns.h>
/*---------------------------------------- getdns_list_get_length */
getdns_return_t
getdns_list_get_length(struct getdns_list *list, size_t *answer)
{
int retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && answer != NULL)
{
retval = GETDNS_RETURN_GOOD;
*answer = list->numinuse;
}
return retval;
} /* getdns_list_get_length */
/*---------------------------------------- getdns_list_get_data_type */
getdns_return_t
getdns_list_get_data_type(struct getdns_list *list, size_t index, getdns_data_type *answer)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && index < list->numinuse)
{
*answer = list->items[index].dtype;
retval = GETDNS_RETURN_GOOD;
}
return retval;
} /* getdns_list_get_data_type */
/*---------------------------------------- getdns_list_get_dict */
getdns_return_t
getdns_list_get_dict(struct getdns_list *list, size_t index, struct getdns_dict **answer)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && index < list->numinuse)
{
if(list->items[index].dtype != t_dict)
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
else
{
*answer = list->items[index].data.dict;
retval = GETDNS_RETURN_GOOD;
}
}
return retval;
} /* getdns_list_get_dict */
/*---------------------------------------- getdns_list_get_list */
getdns_return_t
getdns_list_get_list(struct getdns_list *list, size_t index, struct getdns_list **answer)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && index < list->numinuse)
{
if(list->items[index].dtype != t_list)
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
else
{
*answer = list->items[index].data.list;
retval = GETDNS_RETURN_GOOD;
}
}
return retval;
} /* getdns_list_get_list */
/*---------------------------------------- getdns_list_get_bindata */
getdns_return_t getdns_list_get_bindata(struct getdns_list *list, size_t index, struct getdns_bindata **answer)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && index < list->numinuse)
{
if(list->items[index].dtype != t_bindata)
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
else
{
*answer = list->items[index].data.bindata;
retval = GETDNS_RETURN_GOOD;
}
}
return retval;
} /* getdns_list_get_bindata */
/*---------------------------------------- getdns_list_get_int */
getdns_return_t
getdns_list_get_int(struct getdns_list *list, size_t index, uint32_t *answer)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && index < list->numinuse)
{
if(list->items[index].dtype != t_int)
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
else
{
*answer = list->items[index].data.n;
retval = GETDNS_RETURN_GOOD;
}
}
return retval;
} /* getdns_list_get_int */
/*---------------------------------------- getdns_list_realloc */
/**
* private function (API users should not be calling this)
* allocates a block of items, should be called when a list needs to grow
* preserves the existing items
* in case of an error the list should be considered unusable
* @return GETDNS_RETURN_GOOD on success, GETDNS_RETURN_GENERIC_ERROR if out of memory
*/
getdns_return_t
getdns_list_realloc(struct getdns_list *list)
{
getdns_return_t retval = GETDNS_RETURN_GENERIC_ERROR;
int i;
struct getdns_list_item *newlist;
if(list != NULL)
{
newlist = (struct getdns_list_item *) realloc(list->items
, (list->numalloc + GETDNS_LIST_BLOCKSZ) * sizeof(struct getdns_list_item));
if(newlist != NULL)
{
list->items = newlist;
for(i=list->numalloc; i<list->numalloc + GETDNS_LIST_BLOCKSZ; i++)
{
list->items[i].inuse = false;
list->items[i].dtype = t_invalid;
}
list->numalloc += GETDNS_LIST_BLOCKSZ;
retval = GETDNS_RETURN_GOOD;
}
}
return retval;
} /* getdns_list_realloc */
/*---------------------------------------- getdns_list_copy */
getdns_return_t
getdns_list_copy(struct getdns_list *srclist, struct getdns_list **dstlist)
{
int i;
size_t index;
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(srclist != NULL && dstlist != NULL)
{
*dstlist = getdns_list_create();
if(*dstlist != NULL)
{
retval = GETDNS_RETURN_GOOD;
for(i=0; i<srclist->numinuse; i++)
{
if(getdns_list_add_item(*dstlist, &index) == GETDNS_RETURN_GOOD)
{
(*dstlist)->items[index].inuse = true;
(*dstlist)->items[index].dtype = srclist->items[i].dtype;
if(srclist->items[i].dtype == t_int)
(*dstlist)->items[index].data.n = srclist->items[i].data.n;
else if(srclist->items[i].dtype == t_list)
retval = getdns_list_copy(srclist->items[index].data.list
, &((*dstlist)->items[i].data.list));
else if(srclist->items[i].dtype == t_bindata)
{
(*dstlist)->items[i].data.bindata = (struct getdns_bindata *)
malloc(sizeof(getdns_bindata));
(*dstlist)->items[i].data.bindata->size = srclist->items[i].data.bindata->size;
(*dstlist)->items[i].data.bindata->data = (uint8_t *)
malloc(srclist->items[i].data.bindata->size);
if((*dstlist)->items[i].data.bindata->data != NULL)
memcpy((*dstlist)->items[i].data.bindata->data,
srclist->items[i].data.bindata->data
, srclist->items[i].data.bindata->size);
else
retval = GETDNS_RETURN_GENERIC_ERROR;
}
else if (srclist->items[i].dtype == t_dict)
{
retval = getdns_dict_copy(srclist->items[index].data.dict,
&((*dstlist)->items[i].data.dict));
}
}
else
retval = GETDNS_RETURN_GENERIC_ERROR;
if(retval != GETDNS_RETURN_GOOD)
break;
}
}
else
retval = GETDNS_RETURN_GENERIC_ERROR;
}
return retval;
} /* getdns_list_copy */
/*---------------------------------------- getdns_list_create */
struct getdns_list *
getdns_list_create()
{
struct getdns_list *list = NULL;
list = (struct getdns_list *) malloc(sizeof(struct getdns_list));
if(list != NULL)
{
list->numalloc = 0;
list->numinuse = 0;
list->items = NULL;
getdns_list_realloc(list);
}
return list;
} /* getdns_list_create */
/*---------------------------------------- getdns_list_destroy */
void
getdns_list_destroy(struct getdns_list *list)
{
int i;
if(list != NULL)
{
if(list->items != NULL)
{
for(i=0; i<list->numinuse; i++)
{
if(list->items[i].dtype == t_list)
{
if(list->items[i].dtype == t_list)
getdns_list_destroy(list->items[i].data.list);
}
else if(list->items[i].dtype == t_bindata)
{
if(list->items[i].data.bindata->size > 0)
free(list->items[i].data.bindata->data);
free(list->items[i].data.bindata);
}
}
free(list->items);
}
free(list);
}
} /* getdns_list_destroy */
/*---------------------------------------- getdns_list_add_item */
getdns_return_t
getdns_list_add_item(struct getdns_list *list, size_t *index)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && index != NULL)
{
if(list->numalloc == list->numinuse)
retval = getdns_list_realloc(list);
else
retval = GETDNS_RETURN_GOOD;
if(retval == GETDNS_RETURN_GOOD)
{
*index = list->numinuse;
list->items[*index].inuse = true;
list->numinuse++;
}
}
return retval;
} /* getdns_list_add_item */
/*---------------------------------------- getdns_list_set_dict */
getdns_return_t
getdns_list_set_dict(struct getdns_list *list, size_t index, struct getdns_dict *child_dict)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && child_dict != NULL)
{
if(list->numinuse > index)
{
list->items[index].dtype = t_dict;
retval = getdns_dict_copy(child_dict, &(list->items[index].data.dict));
}
}
return retval;
} /* getdns_list_set_dict */
/*---------------------------------------- getdns_set_list */
getdns_return_t
getdns_list_set_list(struct getdns_list *list, size_t index, struct getdns_list *child_list)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && child_list != NULL)
{
if(list->numinuse > index)
{
list->items[index].dtype = t_list;
retval = getdns_list_copy(child_list, &(list->items[index].data.list));
}
}
return retval;
} /* getdns_set_list */
/*---------------------------------------- getdns_list_set_bindata */
getdns_return_t
getdns_list_set_bindata(struct getdns_list *list, size_t index, struct getdns_bindata *child_bindata)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL && child_bindata != NULL)
{
if(list->numinuse > index)
{
list->items[index].dtype = t_bindata;
list->items[index].data.bindata = (struct getdns_bindata *)
malloc(sizeof(struct getdns_bindata));
if(list->items[index].data.bindata != NULL)
{
list->items[index].data.bindata->size = child_bindata->size;
list->items[index].data.bindata->data = (uint8_t *) malloc(child_bindata->size
* sizeof(uint8_t));
memcpy(list->items[index].data.bindata->data, child_bindata->data, child_bindata->size);
retval = GETDNS_RETURN_GOOD;
}
else
retval = GETDNS_RETURN_GENERIC_ERROR;
}
}
return retval;
} /* getdns_list_set_bindata */
/*---------------------------------------- getdns_list_set_int */
getdns_return_t
getdns_list_set_int(struct getdns_list *list, size_t index, uint32_t child_uint32)
{
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if(list != NULL)
{
if(list->numinuse > index)
{
list->items[index].dtype = t_int;
list->items[index].data.n = child_uint32;
retval = GETDNS_RETURN_GOOD;
}
}
return retval;
} /* getdns_list_set_int */
/* getdns_list.c */