/* * Copyright (c) Likewise Software. All rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Module Name: * * data-graph.c * * Abstract: * * Data graph operations * * Authors: Brian Koropoff (bkoropoff@likewisesoftware.com) * */ #include #include #include "convert.h" #include "context-private.h" #include "type-private.h" #include "data-private.h" #include "util-private.h" LWMsgStatus lwmsg_data_extract_discrim_tag( LWMsgTypeIter* iter, unsigned char* dominating_struct, intmax_t* tag ) { return lwmsg_convert_integer( dominating_struct + iter->info.kind_compound.discrim.offset, iter->info.kind_compound.discrim.size, LWMSG_NATIVE_ENDIAN, tag, sizeof(*tag), LWMSG_NATIVE_ENDIAN, LWMSG_SIGNED); } LWMsgStatus lwmsg_data_extract_length( LWMsgTypeIter* iter, unsigned char* dominating_struct, size_t *length ) { return lwmsg_convert_integer( dominating_struct + iter->info.kind_indirect.term_info.member.offset, iter->info.kind_indirect.term_info.member.size, LWMSG_NATIVE_ENDIAN, length, sizeof(*length), LWMSG_NATIVE_ENDIAN, LWMSG_SIGNED); } LWMsgStatus lwmsg_data_extract_active_arm( LWMsgTypeIter* iter, unsigned char* dominating_struct, LWMsgTypeIter* active_iter ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; intmax_t tag; BAIL_ON_ERROR(status = lwmsg_data_extract_discrim_tag( iter, dominating_struct, &tag)); for (lwmsg_type_enter(iter, active_iter); lwmsg_type_valid(active_iter); lwmsg_type_next(active_iter)) { if (tag == active_iter->tag) { goto done; } } BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND); done: return status; error: goto done; } static LWMsgStatus lwmsg_object_is_zero( LWMsgTypeIter* iter, unsigned char* object, int* is_zero ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; size_t i; *is_zero = 1; for (i = 0; i < iter->size; i++) { if (object[i] != 0) { *is_zero = 0; break; } } return status; } LWMsgStatus lwmsg_data_calculate_indirect_metrics( LWMsgTypeIter* iter, unsigned char* object, size_t* count, size_t* element_size ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; unsigned char* element = NULL; int is_zero; LWMsgTypeIter inner; lwmsg_type_enter(iter, &inner); switch (iter->info.kind_indirect.term) { case LWMSG_TERM_STATIC: *count = iter->info.kind_indirect.term_info.static_length; break; case LWMSG_TERM_MEMBER: /* Extract the length out of the field of the actual structure */ BAIL_ON_ERROR(status = lwmsg_data_extract_length( iter, iter->dom_object, count)); break; case LWMSG_TERM_ZERO: element = object; is_zero = 0; /* We have to calculate the count by searching for the zero element */ for (*count = 0;;*count += 1) { BAIL_ON_ERROR(status = lwmsg_object_is_zero( &inner, element, &is_zero)); if (is_zero) { break; } element += inner.size; } } *element_size = inner.size; error: return status; } LWMsgStatus lwmsg_data_verify_range( LWMsgErrorContext* error, LWMsgTypeIter* iter, void* object, size_t object_size ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; size_t value; BAIL_ON_ERROR(status = lwmsg_convert_integer( object, object_size, LWMSG_NATIVE_ENDIAN, &value, sizeof(value), LWMSG_NATIVE_ENDIAN, iter->info.kind_integer.sign)); if (value < iter->attrs.range_low || value > iter->attrs.range_high) { status = RAISE(error, LWMSG_STATUS_MALFORMED, "Integer value did not fall within specified range"); BAIL_ON_ERROR(status); } error: return status; } LWMsgStatus lwmsg_data_visit_graph( LWMsgTypeIter* iter, unsigned char* object, LWMsgGraphVisitFunction func, void* data ) { return func(iter, object, data); } static inline LWMsgBool lwmsg_is_zero( unsigned char* object, size_t size ) { size_t i; for (i = 0; i < size; i++) { if (object[i] != 0) { return LWMSG_FALSE; } } return LWMSG_TRUE; } static LWMsgStatus lwmsg_data_visit_graph_indirect( LWMsgTypeIter* iter, unsigned char* object, LWMsgGraphVisitFunction func, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; size_t count = 0; size_t i; void* element; LWMsgTypeIter inner; lwmsg_type_enter(iter, &inner); switch (iter->info.kind_indirect.term) { case LWMSG_TERM_STATIC: count = iter->info.kind_indirect.term_info.static_length; break; case LWMSG_TERM_MEMBER: BAIL_ON_ERROR(status = lwmsg_data_extract_length( iter, iter->dom_object, &count)); break; case LWMSG_TERM_ZERO: count = 1; for (element = object; !lwmsg_is_zero(element, inner.size); element += inner.size) { count++; } break; } element = object; for (i = 0; i < count; i++) { BAIL_ON_ERROR(status = func(&inner, element, data)); element += inner.size; } error: return status; } LWMsgStatus lwmsg_data_visit_graph_children( LWMsgTypeIter* iter, unsigned char* object, LWMsgGraphVisitFunction func, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgTypeIter inner; switch (iter->kind) { case LWMSG_KIND_STRUCT: lwmsg_type_enter(iter, &inner); inner.dom_object = object; for (; lwmsg_type_valid(&inner); lwmsg_type_next(&inner)) { BAIL_ON_ERROR(status = func(&inner, object + inner.offset, data)); } break; case LWMSG_KIND_UNION: /* Find the active arm */ BAIL_ON_ERROR(status = lwmsg_data_extract_active_arm( iter, iter->dom_object, &inner)); BAIL_ON_ERROR(status = func(&inner, object, data)); break; case LWMSG_KIND_POINTER: if (*(void**) object) { BAIL_ON_ERROR(status = lwmsg_data_visit_graph_indirect( iter, *(unsigned char**) object, func, data)); } break; case LWMSG_KIND_ARRAY: BAIL_ON_ERROR(status = lwmsg_data_visit_graph_indirect( iter, object, func, data)); break; default: break; } error: return status; } typedef struct freeinfo { LWMsgDataContext* context; LWMsgFreeFunction free; void* data; } freeinfo; static LWMsgStatus lwmsg_data_free_graph_visit( LWMsgTypeIter* iter, unsigned char* object, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; freeinfo* info = (freeinfo*) data; switch(iter->kind) { case LWMSG_KIND_CUSTOM: if (iter->info.kind_custom.typeclass->free) { iter->info.kind_custom.typeclass->free( info->context->context, iter->size, &iter->attrs, object, iter->info.kind_custom.typedata); } break; case LWMSG_KIND_POINTER: BAIL_ON_ERROR(status = lwmsg_data_visit_graph_children( iter, object, lwmsg_data_free_graph_visit, data)); info->free(*(void **) object, info->data); break; default: BAIL_ON_ERROR(status = lwmsg_data_visit_graph_children( iter, object, lwmsg_data_free_graph_visit, data)); break; } error: return status; } LWMsgStatus lwmsg_data_free_graph_internal( LWMsgDataContext* context, LWMsgTypeIter* iter, unsigned char* object ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; freeinfo info; lwmsg_context_get_memory_functions(context->context, NULL, &info.free, NULL, &info.data); info.context = context; BAIL_ON_ERROR(status = lwmsg_data_visit_graph( iter, object, lwmsg_data_free_graph_visit, &info)); error: return status; } LWMsgStatus lwmsg_data_free_graph( LWMsgDataContext* context, LWMsgTypeSpec* type, void* root ) { LWMsgTypeIter iter; lwmsg_type_iterate_promoted(type, &iter); return lwmsg_data_free_graph_internal(context, &iter, (unsigned char*) &root); }