void lwmsg_type_iterate_promoted( LWMsgTypeSpec* spec, LWMsgTypeIter* iter ) { switch (*spec & LWMSG_CMD_MASK) { case LWMSG_CMD_POINTER: lwmsg_type_iterate(spec, iter); break; case LWMSG_CMD_CUSTOM: lwmsg_type_iterate(spec, iter); if (!iter->info.kind_custom.typeclass->is_pointer) { lwmsg_type_promote(spec, iter); } break; default: lwmsg_type_promote(spec, iter); break; } }
LWMsgStatus lwmsg_data_unmarshal_into( LWMsgDataContext* context, LWMsgTypeSpec* type, LWMsgBuffer* buffer, void* object, size_t size ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgObjectMap map; LWMsgUnmarshalState my_state = {NULL, &map}; LWMsgTypeIter iter; memset(&map, 0, sizeof(map)); lwmsg_type_iterate(type, &iter); if (size < iter.size) { BAIL_ON_ERROR(status = LWMSG_STATUS_BUFFER_TOO_SMALL); } BAIL_ON_ERROR(status = lwmsg_data_unmarshal_internal(context, &my_state, &iter, buffer, object)); if (buffer->wrap) { BAIL_ON_ERROR(status = buffer->wrap(buffer, 0)); } error: lwmsg_data_object_map_destroy(&map); return status; }
static LWMsgStatus lwmsg_data_unmarshal_struct_pointee( LWMsgDataContext* context, LWMsgUnmarshalState* state, LWMsgTypeIter* pointer_iter, LWMsgTypeIter* struct_iter, LWMsgBuffer* buffer, unsigned char** out ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; unsigned char* base_object = NULL; unsigned char* full_object = NULL; LWMsgTypeSpec* flexible_member = NULL; size_t base_size = 0; size_t full_size = 0; LWMsgObjectID id = 0; base_size = struct_iter->size; if (pointer_iter->attrs.flags & LWMSG_TYPE_FLAG_ALIASABLE && base_size < sizeof(void*)) { base_size = sizeof(void*); } /* Enforce MAX_ALLOC attribute */ if (pointer_iter->attrs.max_alloc && base_size > pointer_iter->attrs.max_alloc) { BAIL_ON_ERROR(status = DATA_RAISE( context, pointer_iter, LWMSG_STATUS_OVERFLOW, "Pointer referent exceeded max allocation size of %lu", (unsigned long) pointer_iter->attrs.max_alloc)); } /* Allocate enough memory to hold the base of the object */ BAIL_ON_ERROR(status = lwmsg_object_alloc( context, base_size, &base_object)); if (pointer_iter->attrs.flags & LWMSG_TYPE_FLAG_ALIASABLE) { /* If this is the referent of an aliasable pointer, insert it into the object map now */ BAIL_ON_ERROR(status = lwmsg_data_object_map_insert( state->map, base_object, pointer_iter, &id)); } /* Unmarshal all base members of the structure and find any flexible member */ BAIL_ON_ERROR(status = lwmsg_data_unmarshal_struct( context, state, struct_iter, buffer, base_object, &flexible_member)); /* Now that the base of the object is unmarshalled, we can see if we need to reallocate space for a flexible member */ if (flexible_member) { LWMsgTypeIter flex_iter; LWMsgTypeIter inner_iter; LWMsgUnmarshalState my_state = {base_object, state->map}; size_t count = 0; size_t full_count = 0; size_t flexible_size = 0; lwmsg_type_iterate(flexible_member, &flex_iter); lwmsg_type_enter(&flex_iter, &inner_iter); BAIL_ON_ERROR(status = lwmsg_data_unmarshal_indirect_prologue( context, &my_state, &flex_iter, &inner_iter, buffer, &count)); /* Calculate total number of elements */ if (flex_iter.info.kind_indirect.term == LWMSG_TERM_ZERO) { /* If the referent is zero-terminated, we need to allocate an extra element */ BAIL_ON_ERROR(status = DATA_RAISE( context, pointer_iter, lwmsg_add_unsigned(count, 1, &full_count), "Integer overflow in pointer referent length")); } else { full_count = count; } /* Calculate the size of the flexible member */ BAIL_ON_ERROR(status = DATA_RAISE( context, pointer_iter, lwmsg_multiply_unsigned(full_count, inner_iter.size, &flexible_size), "Integer overflow in pointer referent size")); /* Calculate the size of the full structure */ BAIL_ON_ERROR(status = DATA_RAISE( context, pointer_iter, lwmsg_add_unsigned(struct_iter->size, flexible_size, &full_size), "Integer overflow in pointer referent size")); if (pointer_iter->attrs.flags & LWMSG_TYPE_FLAG_ALIASABLE && full_size < sizeof(void*)) { full_size = sizeof(void*); } /* Enforce MAX_ALLOC attribute */ if (pointer_iter->attrs.max_alloc && full_size > pointer_iter->attrs.max_alloc) { BAIL_ON_ERROR(status = DATA_RAISE( context, pointer_iter, LWMSG_STATUS_OVERFLOW, "Pointer referent exceeded max allocation size of %lu", (unsigned long) pointer_iter->attrs.max_alloc)); } /* Allocate the full object */ BAIL_ON_ERROR(status = lwmsg_object_realloc( context, base_object, struct_iter->size, full_size, &full_object)); base_object = NULL; /* Unmarshal the flexible array member */ BAIL_ON_ERROR(status = lwmsg_data_unmarshal_indirect( context, &my_state, &flex_iter, &inner_iter, buffer, full_object + flex_iter.offset, count)); } else { full_object = base_object; base_object = NULL; } *out = full_object; done: return status; error: if (base_object) { /* We must avoid visiting flexible array members when freeing the base object because it does not have space for them in the allocated block */ lwmsg_data_unmarshal_free_partial_struct( context, struct_iter, base_object); } if (full_object) { lwmsg_data_free_graph_internal(context, pointer_iter, (unsigned char*) &base_object); } goto done; }
static LWMsgStatus lwmsg_data_unmarshal_custom( LWMsgDataContext* context, LWMsgUnmarshalState* state, LWMsgTypeIter* iter, LWMsgBuffer* buffer, unsigned char* object ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgTypeClass* typeclass = iter->info.kind_custom.typeclass; LWMsgTypeIter transmit_iter; void* transmit_object = NULL; LWMsgUnmarshalState my_state = {NULL, state->map}; lwmsg_type_iterate(typeclass->transmit_type, &transmit_iter); if (typeclass->unmarshal) { /* Allocate memory for transmitted object */ BAIL_ON_ERROR(status = lwmsg_data_alloc_memory(context, transmit_iter.size, &transmit_object)); /* Unmarshal transmitted object */ BAIL_ON_ERROR(status = lwmsg_data_unmarshal_internal( context, &my_state, &transmit_iter, buffer, transmit_object)); /* Convert transmitted object into presented object */ BAIL_ON_ERROR(status = iter->info.kind_custom.typeclass->unmarshal( context, &iter->attrs, transmit_object, object, iter->info.kind_custom.typedata)); } else { /* Just unmarshal the transmitted type */ BAIL_ON_ERROR(status = lwmsg_data_unmarshal_internal( context, state, &transmit_iter, buffer, object)); } error: if (transmit_object) { /* Since we constructed the transmitted object ourselves, we do not call the destroy_transmitted function of the type class */ lwmsg_data_free_graph_internal(context, &transmit_iter, transmit_object); /* Free object itself */ lwmsg_data_free_memory(context, transmit_object); } return status; }