File: [OMI] / omi / base / field.c
(download)
Revision: 1.1,
Wed May 30 21:47:49 2012 UTC (12 years, 1 month ago) by mike
Branch: MAIN
Initial revision
|
/*
**==============================================================================
**
** Open Management Infrastructure (OMI)
**
** Copyright (c) Microsoft Corporation
**
** Licensed under the Apache License, Version 2.0 (the "License"); you may not
** use this file except in compliance with the License. You may obtain a copy
** of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABLITY OR NON-INFRINGEMENT.
**
** See the Apache 2 License for the specific language governing permissions
** and limitations under the License.
**
**==============================================================================
*/
#include "field.h"
#include "types.h"
#include "alloc.h"
#include "instance.h"
#include "return.h"
#include "types.h"
#include "indent.h"
#include "strings.h"
#include "io.h"
#include "helpers.h"
#define T MI_T
#define _BORROW 0x01
/*
**==============================================================================
**
** Local definitions
**
**==============================================================================
*/
static unsigned char _fieldSizes[] =
{
sizeof(MI_BooleanField),
sizeof(MI_Uint8Field),
sizeof(MI_Sint8Field),
sizeof(MI_Uint16Field),
sizeof(MI_Sint16Field),
sizeof(MI_Uint32Field),
sizeof(MI_Sint32Field),
sizeof(MI_Uint64Field),
sizeof(MI_Sint64Field),
sizeof(MI_Real32Field),
sizeof(MI_Real64Field),
sizeof(MI_Char16Field),
sizeof(MI_DatetimeField),
sizeof(MI_StringField),
sizeof(MI_ReferenceField),
sizeof(MI_InstanceField),
sizeof(MI_BooleanAField),
sizeof(MI_Uint8AField),
sizeof(MI_Sint8AField),
sizeof(MI_Uint16AField),
sizeof(MI_Sint16AField),
sizeof(MI_Uint32AField),
sizeof(MI_Sint32AField),
sizeof(MI_Uint64AField),
sizeof(MI_Sint64AField),
sizeof(MI_Real32AField),
sizeof(MI_Real64AField),
sizeof(MI_Char16AField),
sizeof(MI_DatetimeAField),
sizeof(MI_StringAField),
sizeof(MI_ReferenceAField),
sizeof(MI_InstanceAField),
};
static void* _CloneSimpleArray(
const void* data,
MI_Uint32 size,
MI_Uint32 type,
Batch* batch)
{
void* array;
size_t m;
/* Handle empty arrays up front */
if (!data || size == 0)
return NULL;
/* Get element size in bytes */
m = Type_SizeOf(Type_ScalarOf((MI_Type)type));
/* Allocate memory for array elements */
array = BAlloc(batch, size * m, CALLSITE);
if (!array)
return NULL;
/* Copy elements to the new array */
memcpy(array, data, m * size);
return array;
}
static MI_Char** _CloneStringArray(
const MI_Char** data,
MI_Uint32 size,
Batch* batch)
{
size_t n;
MI_Uint32 i;
MI_Char* ptr;
MI_Char** array;
/* Empty arrays are represented by NULL */
if (!data || size == 0)
return NULL;
/* Calculate space for pointer array */
n = size * sizeof(MI_Char*);
/* Calculate space for strings (add space for zero terminators) */
for (i = 0; i < size; i++)
{
if (!data[i])
{
/* Null elements are illegal */
return NULL;
}
n += (Zlen(data[i]) + 1) * sizeof(MI_Char);
}
/* Allocate memory */
array = (MI_Char**)BAlloc(batch, n, CALLSITE);
if (!array)
return NULL;
ptr = (MI_Char*)&array[size];
/* Copy the strings */
for (i = 0; i < size; i++)
{
size_t count = Zlen(data[i]) + 1;
memcpy(ptr, data[i], count * sizeof(MI_Char));
array[i] = ptr;
ptr += count;
}
return array;
}
static void* _CloneInstanceArray(
const void* data_,
MI_Uint32 size,
Batch* batch)
{
const MI_Instance** data = (const MI_Instance**)data_;
MI_Instance** array;
MI_Uint32 i;
/* Handle empty arrays up front */
if (!data || size == 0)
return NULL;
/* validate entries */
for (i = 0; i < size; i++ )
{
if (!data[i])
{
/* Null elements are illegal */
return NULL;
}
}
/* Allocate memory for the new array */
array = BCalloc(batch, size * sizeof(MI_Instance*), CALLSITE);
if (!array)
return NULL;
/* Clone each reference (or instance) */
for (i = 0; i < size; i++)
{
MI_Result r = Instance_Clone(data[i], &array[i], batch);
if (r != MI_RESULT_OK)
return NULL;
}
return array;
}
INLINE void _Copy(
Field* dest,
const Field* src,
MI_Type type)
{
memcpy(dest, src, _fieldSizes[(int)type]);
}
static void _Swap(
Field* field1,
Field* field2,
MI_Type type)
{
Field tmp;
_Copy(&tmp, field1, type);
_Copy(field1, field2, type);
_Copy(field2, &tmp, type);
}
static void _Fill(
Field* self,
MI_Type type,
MI_Uint8 x)
{
memset(self, x, _fieldSizes[(int)type]);
}
/*
**==============================================================================
**
** Public definitions
**
**==============================================================================
*/
MI_Result Field_Construct(
Field* self,
MI_Type type,
const MI_Value* value,
MI_Uint32 flags,
Batch* batch)
{
MI_Result r;
/* Zero out self */
_Fill(self, type, 0);
/* Handle null case up front */
if (flags & MI_FLAG_NULL)
MI_RETURN(MI_RESULT_OK);
/* Reject null values */
/* ATTN: Tolerate this for now */
if (!value)
MI_RETURN(MI_RESULT_OK);
switch (type)
{
case MI_BOOLEAN:
{
self->boolean.value = value->boolean;
self->boolean.exists = MI_TRUE;
break;
}
case MI_UINT8:
{
self->uint8.value = value->uint8;
self->uint8.exists = MI_TRUE;
break;
}
case MI_SINT8:
{
self->sint8.value = value->sint8;
self->sint8.exists = MI_TRUE;
break;
}
case MI_UINT16:
{
self->uint16.value = value->uint16;
self->uint16.exists = MI_TRUE;
break;
}
case MI_SINT16:
{
self->sint16.value = value->sint16;
self->sint16.exists = MI_TRUE;
break;
}
case MI_UINT32:
{
self->uint32.value = value->uint32;
self->uint32.exists = MI_TRUE;
break;
}
case MI_SINT32:
{
self->sint32.value = value->sint32;
self->sint32.exists = MI_TRUE;
break;
}
case MI_UINT64:
{
self->uint64.value = value->uint64;
self->uint64.exists = MI_TRUE;
break;
}
case MI_SINT64:
{
self->sint64.value = value->sint64;
self->sint64.exists = MI_TRUE;
break;
}
case MI_REAL32:
{
self->real32.value = value->real32;
self->real32.exists = MI_TRUE;
break;
}
case MI_REAL64:
{
self->real64.value = value->real64;
self->real64.exists = MI_TRUE;
break;
}
case MI_CHAR16:
{
self->char16.value = value->char16;
self->char16.exists = MI_TRUE;
break;
}
case MI_DATETIME:
{
self->datetime.value = value->datetime;
self->datetime.exists = MI_TRUE;
break;
}
case MI_STRING:
{
if (value->string)
{
MI_Char* str;
if (flags & MI_FLAG_BORROW)
{
self->string.value = value->string;
self->string.exists = MI_TRUE;
self->string.flags = _BORROW;
break;
}
str = BStrdup(batch, value->string, CALLSITE);
if (!str)
MI_RETURN(MI_RESULT_FAILED);
self->string.value = str;
self->string.exists = MI_TRUE;
}
else
{
self->string.value = NULL;
self->string.exists = MI_FALSE;
self->string.flags = 0;
}
break;
}
case MI_INSTANCE:
case MI_REFERENCE:
{
if (value->instance)
{
MI_Instance* instance;
if (flags & MI_FLAG_BORROW)
{
self->instance.value = value->instance;
self->instance.exists = MI_TRUE;
self->instance.flags = _BORROW;
break;
}
r = Instance_Clone(value->instance, &instance, batch);
if (r != MI_RESULT_OK)
MI_RETURN(r);
self->instance.value = instance;
self->instance.exists = MI_TRUE;
}
else
{
self->instance.value = NULL;
self->instance.exists = MI_FALSE;
self->instance.flags = 0;
}
break;
}
case MI_BOOLEANA:
case MI_UINT8A:
case MI_SINT8A:
case MI_UINT16A:
case MI_SINT16A:
case MI_UINT32A:
case MI_SINT32A:
case MI_UINT64A:
case MI_SINT64A:
case MI_REAL32A:
case MI_REAL64A:
case MI_CHAR16A:
case MI_DATETIMEA:
{
if (value->array.data)
{
void* data;
if (flags & MI_FLAG_BORROW)
{
self->array.value = value->array;
self->array.exists = MI_TRUE;
self->array.flags = _BORROW;;
break;
}
data = _CloneSimpleArray(
value->array.data, value->array.size, type, batch);
if (!data)
MI_RETURN(MI_RESULT_FAILED);
self->array.value.data = data;
self->array.value.size = value->array.size;
self->array.exists = MI_TRUE;
}
else
{
self->array.value.data = NULL;
self->array.value.size = 0;
self->array.exists = MI_FALSE;
}
break;
}
case MI_STRINGA:
{
MI_Char** data;
if (value->array.data)
{
if (flags & MI_FLAG_BORROW)
{
self->stringa.value = value->stringa;
self->stringa.exists = MI_TRUE;
self->stringa.flags = _BORROW;;
break;
}
data = _CloneStringArray((const MI_Char**)value->stringa.data,
value->stringa.size, batch);
if (!data)
MI_RETURN(MI_RESULT_FAILED);
self->stringa.value.data = data;
self->stringa.value.size = value->array.size;
self->stringa.exists = MI_TRUE;
}
else
{
self->stringa.value.data = NULL;
self->stringa.value.size = 0;
self->stringa.exists = MI_FALSE;
}
break;
}
case MI_INSTANCEA:
case MI_REFERENCEA:
{
if (value->instancea.data)
{
MI_Instance** data;
if (flags & MI_FLAG_BORROW)
{
self->instancea.value = value->instancea;
self->instancea.exists = MI_TRUE;
self->instancea.flags = _BORROW;;
break;
}
data = _CloneInstanceArray(value->instancea.data,
value->instancea.size, batch);
if (!data)
MI_RETURN(MI_RESULT_FAILED);
self->instancea.value.data = data;
self->instancea.value.size = value->array.size;
self->instancea.exists = MI_TRUE;
}
else
{
self->instancea.value.data = NULL;
self->instancea.value.size = 0;
self->instancea.exists = MI_FALSE;
}
break;
}
}
return MI_RESULT_OK;
}
void Field_Destruct(
Field* self,
MI_Type type,
Batch* batch)
{
switch (type)
{
case MI_STRING:
{
MI_StringField* f = &self->string;
if (!(f->flags & _BORROW) && f->value)
BFree(batch, f->value, CALLSITE);
break;
}
case MI_BOOLEANA:
case MI_SINT8A:
case MI_UINT8A:
case MI_SINT16A:
case MI_UINT16A:
case MI_SINT32A:
case MI_UINT32A:
case MI_SINT64A:
case MI_UINT64A:
case MI_REAL32A:
case MI_REAL64A:
case MI_CHAR16A:
case MI_DATETIMEA:
case MI_STRINGA:
{
MI_ArrayField* f = &self->array;
if (!(f->flags & _BORROW) && f->value.data)
BFree(batch, f->value.data, CALLSITE);
break;
}
case MI_INSTANCE:
case MI_REFERENCE:
{
MI_InstanceField* f = &self->instance;
if (!(f->flags & _BORROW) && f->value)
MI_Instance_Delete(f->value);
break;
}
case MI_INSTANCEA:
case MI_REFERENCEA:
{
MI_InstanceAField* f = &self->instancea;
if (!(f->flags & _BORROW) && f->value.data)
{
MI_Uint32 j;
for (j = 0; j < f->value.size; j++ )
MI_Instance_Delete(f->value.data[j]);
BFree(batch, f->value.data, CALLSITE);
}
break;
}
default:
break;
}
/* Fill with illegal character */
_Fill(self, type, 0xDD);
}
MI_Result Field_Set(
Field* self,
MI_Type type,
const MI_Value* value,
MI_Uint32 flags,
Batch* batch)
{
Field field;
MI_Result r;
/* Initialize new field */
r = Field_Construct(&field, type, value, flags, batch);
if (r != MI_RESULT_OK)
MI_RETURN(r);
/* Destroy self */
Field_Destruct(self, type, batch);
/* Swap new field with self */
_Swap(self, &field, type);
return MI_RESULT_OK;
}
MI_Result Field_Copy(
Field* self,
MI_Type type,
const Field* field,
Batch* batch)
{
MI_Value value;
MI_Boolean exists;
MI_Uint8 flags;
MI_Uint32 tflags = 0;
MI_Result r;
Field_Extract(field, type, &value, &exists, &flags);
if (!exists)
tflags |= MI_FLAG_NULL;
r = Field_Construct(self, type, &value, tflags, batch);
return r;
}
void Field_Clear(
Field* self,
MI_Type type,
Batch* batch)
{
Field_Destruct(self, type, batch);
_Fill(self, type, 0);
}
void Field_Extract(
const Field* self,
MI_Type type,
MI_Value* valueOut,
MI_Boolean* existsOut,
MI_Uint8* flagsOut)
{
size_t size = Type_SizeOf(type);
memcpy(valueOut, self, size);
*existsOut = *(MI_Boolean*)((char*)self + size);
*flagsOut = *(MI_Uint8*)((char*)self + size + sizeof(MI_Boolean));
}
void Field_Print(
const Field* self,
FILE* os,
MI_Type type,
MI_Uint32 level)
{
MI_Value v;
MI_Boolean e;
MI_Uint8 f;
Field_Extract(self, type, &v, &e, &f);
if (!e)
{
fprintf(os, "NULL");
return;
}
else
{
switch (type)
{
case MI_BOOLEAN:
{
const MI_Boolean* p = (const MI_Boolean*)&v;
fprintf(os, "%s", *p ? "true" : "false");
break;
}
case MI_SINT8:
{
fprintf(os, "%d", *((const MI_Sint8*)&v));
break;
}
case MI_UINT8:
{
fprintf(os, "%u", *((const MI_Uint8*)&v));
break;
}
case MI_SINT16:
{
fprintf(os, "%d", *((const MI_Sint16*)&v));
break;
}
case MI_UINT16:
{
fprintf(os, "%u", *((const MI_Uint16*)&v));
break;
}
case MI_SINT32:
{
fprintf(os, "%d", *((const MI_Sint32*)&v));
break;
}
case MI_UINT32:
{
fprintf(os, "%u", *((const MI_Uint32*)&v));
break;
}
case MI_SINT64:
{
fprintf(os, SINT64_FMT, *((const MI_Sint64*)&v));
break;
}
case MI_UINT64:
{
fprintf(os, UINT64_FMT, *((const MI_Uint64*)&v));
break;
}
case MI_REAL32:
{
fprintf(os, "%g", *((const MI_Real32*)&v));
break;
}
case MI_REAL64:
{
fprintf(os, "%g", *((const MI_Real64*)&v));
break;
}
case MI_CHAR16:
{
fprintf(os, "%u", *((const MI_Char16*)&v));
break;
}
case MI_DATETIME:
{
MI_Char buf[26];
DatetimeToStr((const MI_Datetime*)&v, buf);
Fzprintf(os, T("%s"), buf);
break;
}
case MI_STRING:
{
Fzprintf(os, T("%s"), *((MI_Char**)&v));
break;
}
case MI_BOOLEANA:
case MI_SINT8A:
case MI_UINT8A:
case MI_SINT16A:
case MI_UINT16A:
case MI_SINT32A:
case MI_UINT32A:
case MI_SINT64A:
case MI_UINT64A:
case MI_REAL32A:
case MI_REAL64A:
case MI_CHAR16A:
case MI_DATETIMEA:
{
MI_BooleanA* arr = (MI_BooleanA*)&v;
char* ptr = (char*)arr->data;
MI_Uint32 i;
fprintf(os, "{");
for (i = 0; i < arr->size; i++)
{
MI_Type stype = Type_ScalarOf(type);
MI_Type ssize = Type_SizeOf(stype);
Field field;
/* Build dummy field */
memcpy(&field, ptr, ssize);
*(MI_Boolean*)((char*)&field + ssize) = MI_TRUE;
*(MI_Uint8*)((char*)&field + ssize + 1) = 0;
/* Print dummy field */
Field_Print(&field, os, stype, level);
ptr += ssize;
if (i + 1 != arr->size)
fprintf(os, ", ");
}
fprintf(os, "}");
break;
}
case MI_STRINGA:
{
MI_StringA* arr = (MI_StringA*)&v;
MI_Uint32 i;
fprintf(os, "{");
for (i = 0; i < arr->size; i++)
{
Fzprintf(os, T("%s"), arr->data[i]);
if (i + 1 != arr->size)
fprintf(os, ", ");
}
fprintf(os, "}");
break;
}
case MI_INSTANCE:
case MI_REFERENCE:
{
MI_Instance* inst = *((MI_Instance**)&v);
if ( type == MI_REFERENCE)
fprintf(os, " REF ");
__MI_Instance_Print(inst, os, level);
break;
}
case MI_INSTANCEA:
case MI_REFERENCEA:
{
MI_InstanceA* inst = ((MI_InstanceA*)&v);
MI_Uint32 i;
if ( type == MI_REFERENCEA)
fprintf(os, " REF ");
#if 0
fprintf(os, "[%d]\n", (int)inst->size);
#endif
fprintf(os, "\n");
Indent(os, level);
fprintf(os, "{\n");
for (i = 0; i < inst->size; i++)
{
__MI_Instance_Print(inst->data[i], os, level + 1);
}
Indent(os, level);
fprintf(os, "}");
break;
}
default:
break;
}
}
}
static MI_Boolean _MatchDatetime(
const MI_Datetime* x,
const MI_Datetime* y)
{
if (x->isTimestamp)
{
if (!y->isTimestamp)
return MI_FALSE;
return
x->u.timestamp.year == y->u.timestamp.year &&
x->u.timestamp.month == y->u.timestamp.month &&
x->u.timestamp.day == y->u.timestamp.day &&
x->u.timestamp.hour == y->u.timestamp.hour &&
x->u.timestamp.minute == y->u.timestamp.minute &&
x->u.timestamp.second == y->u.timestamp.second &&
x->u.timestamp.microseconds == y->u.timestamp.microseconds &&
x->u.timestamp.utc == y->u.timestamp.utc;
}
else
{
if (y->isTimestamp)
return MI_FALSE;
return
x->u.interval.days == y->u.interval.days &&
x->u.interval.hours == y->u.interval.hours &&
x->u.interval.minutes == y->u.interval.minutes &&
x->u.interval.seconds == y->u.interval.seconds &&
x->u.interval.microseconds == y->u.interval.microseconds;
}
}
MI_Boolean Field_MatchKey(
const Field* f1,
const Field* f2,
MI_Type type)
{
MI_Boolean e1 = Field_GetExists(f1, type);
MI_Boolean e2 = Field_GetExists(f2, type);
int f = MI_FALSE;
if ((e1 && !e2) || (e2 && !e1))
return MI_FALSE;
switch (type)
{
case MI_BOOLEAN:
f = f1->boolean.value == f2->boolean.value;
break;
case MI_UINT8:
f = f1->uint8.value == f2->uint8.value;
break;
case MI_SINT8:
f = f1->sint8.value == f2->sint8.value;
break;
case MI_UINT16:
f = f1->uint16.value == f2->uint16.value;
break;
case MI_SINT16:
f = f1->sint16.value == f2->sint16.value;
break;
case MI_UINT32:
f = f1->uint32.value == f2->uint32.value;
break;
case MI_SINT32:
f = f1->sint32.value == f2->sint32.value;
break;
case MI_UINT64:
f = f1->uint64.value == f2->uint64.value;
break;
case MI_SINT64:
f = f1->sint64.value == f2->sint64.value;
break;
case MI_REAL32:
f = f1->real32.value == f2->real32.value;
break;
case MI_REAL64:
f = f1->real64.value == f2->real64.value;
break;
case MI_CHAR16:
f = f1->char16.value == f2->char16.value;
break;
case MI_DATETIME:
f = _MatchDatetime(&f1->datetime.value, &f2->datetime.value);
break;
case MI_STRING:
f = Zcmp(f1->string.value, f2->string.value) == 0;
break;
case MI_REFERENCE:
{
if (!f1->reference.value && !f2->reference.value)
return MI_TRUE;
f = Instance_MatchKeys(f1->reference.value, f2->reference.value);
break;
}
case MI_INSTANCE:
/* Instances cannot be keys */
f = MI_FALSE;
break;
default:
/* Arrays cannot be keys */
f = MI_FALSE;
break;
}
return f ? MI_TRUE : MI_FALSE;
}