File: [OMI] / omi / base / packing.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 "packing.h"
/** Magic number for MI_Instance objects (binary buffer pack/unpack) */
#define INSTANCE_MAGIC ((MI_Uint32)0x462b9957)
/* The magic number that occurs at the end of an instance serialization */
static const MI_Uint32 _END_MAGIC = 0x76f474e3;
MI_INLINE void* _Alloc(Batch* batch, size_t size)
{
return batch ? Batch_Get(batch, size) : malloc(size);
}
/* Obtain the self pointer from this instance */
MI_INLINE Instance* _SelfOf(const MI_Instance* instance)
{
if (instance && ((Instance*)instance)->self)
return ((Instance*)instance)->self;
else
return (Instance*)instance;
}
static MI_Result _PackField(Buf* buf, const void* field, MI_Type type)
{
switch (type)
{
case MI_BOOLEAN:
case MI_SINT8:
case MI_UINT8:
{
MI_Uint8Field* f = (MI_Uint8Field*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
MI_RETURN_ERR(Buf_PackU8(buf, f->value));
break;
}
case MI_SINT16:
case MI_UINT16:
case MI_CHAR16:
{
MI_Uint16Field* f = (MI_Uint16Field*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
MI_RETURN_ERR(Buf_PackU16(buf, f->value));
break;
}
case MI_SINT32:
case MI_UINT32:
case MI_REAL32:
{
MI_Uint32Field* f = (MI_Uint32Field*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
MI_RETURN_ERR(Buf_PackU32(buf, f->value));
break;
}
case MI_SINT64:
case MI_UINT64:
case MI_REAL64:
{
MI_Uint64Field* f = (MI_Uint64Field*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
MI_RETURN_ERR(Buf_PackU64(buf, f->value));
break;
}
case MI_DATETIME:
{
MI_DatetimeField* f = (MI_DatetimeField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
Buf_PackDT(buf, &f->value);
break;
}
case MI_STRING:
{
MI_StringField* f = (MI_StringField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
MI_RETURN_ERR(Buf_PackStr(buf, f->value));
break;
}
case MI_INSTANCE:
case MI_REFERENCE:
{
MI_InstanceField* f = ((MI_InstanceField*)field);
if (f->exists && !f->value)
MI_RETURN(MI_RESULT_FAILED);
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
MI_RETURN_ERR(Instance_Pack(f->value, type == MI_REFERENCE,
NULL, NULL, buf));
break;
}
case MI_BOOLEANA:
case MI_SINT8A:
case MI_UINT8A:
{
MI_Uint8AField* f = (MI_Uint8AField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
if (!f->value.data)
MI_RETURN(MI_RESULT_FAILED);
MI_RETURN_ERR(Buf_PackU8A(buf, f->value.data,
f->value.size));
}
break;
}
case MI_SINT16A:
case MI_UINT16A:
case MI_CHAR16A:
{
MI_Uint16AField* f = (MI_Uint16AField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
if (!f->value.data)
MI_RETURN(MI_RESULT_FAILED);
MI_RETURN_ERR(Buf_PackU16A(buf, f->value.data,
f->value.size));
}
break;
}
case MI_SINT32A:
case MI_UINT32A:
case MI_REAL32A:
{
MI_Uint32AField* f = (MI_Uint32AField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
if (!f->value.data)
MI_RETURN(MI_RESULT_FAILED);
MI_RETURN_ERR(Buf_PackU32A(buf, f->value.data,
f->value.size));
}
break;
}
case MI_SINT64A:
case MI_UINT64A:
case MI_REAL64A:
{
MI_Uint64AField* f = (MI_Uint64AField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
if (!f->value.data)
MI_RETURN(MI_RESULT_FAILED);
MI_RETURN_ERR(Buf_PackU64A(buf, f->value.data,
f->value.size));
}
break;
}
case MI_DATETIMEA:
{
MI_DatetimeAField* f = (MI_DatetimeAField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
if (!f->value.data)
MI_RETURN(MI_RESULT_FAILED);
MI_RETURN_ERR(Buf_PackDTA(buf, f->value.data,
f->value.size));
}
break;
}
case MI_STRINGA:
{
MI_StringAField* f = (MI_StringAField*)field;
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
MI_RETURN_ERR(Buf_PackStrA(buf,
(const MI_Char**)f->value.data, f->value.size));
}
break;
}
case MI_INSTANCEA:
case MI_REFERENCEA:
{
MI_InstanceAField* f = ((MI_InstanceAField*)field);
MI_RETURN_ERR(Buf_PackU8(buf, f->exists));
if (f->exists)
{
MI_Uint32 index;
MI_RETURN_ERR(Buf_PackU32(buf, f->value.size));
for ( index = 0; index < f->value.size; index++ )
{
MI_RETURN_ERR(Instance_Pack(f->value.data[index],
type == MI_REFERENCEA, NULL, NULL, buf));
}
}
break;
}
default:
break;
}
MI_RETURN(MI_RESULT_OK);
}
static MI_Result _UnpackField(
Buf* buf,
MI_Value* value,
MI_Boolean* exists,
MI_Type type,
Batch* batch,
MI_Boolean copy)
{
/* Get exists flag */
MI_RETURN_ERR(Buf_UnpackU8(buf, exists));
if (!*exists)
{
memset(value, 0, sizeof(MI_Value));
MI_RETURN(MI_RESULT_OK);
}
/* Get value */
switch (type)
{
case MI_UINT8:
case MI_SINT8:
case MI_BOOLEAN:
{
MI_RETURN_ERR(Buf_UnpackU8(buf, &value->uint8));
break;
}
case MI_UINT16:
case MI_SINT16:
case MI_CHAR16:
{
MI_RETURN_ERR(Buf_UnpackU16(buf, &value->uint16));
break;
}
case MI_UINT32:
case MI_SINT32:
case MI_REAL32:
{
MI_RETURN_ERR(Buf_UnpackU32(buf, &value->uint32));
break;
}
case MI_UINT64:
case MI_SINT64:
case MI_REAL64:
{
MI_RETURN_ERR(Buf_UnpackU64(buf, &value->uint64));
break;
}
case MI_DATETIME:
{
MI_RETURN_ERR(Buf_UnpackDT(buf, &value->datetime));
break;
}
case MI_STRING:
{
MI_RETURN_ERR(Buf_UnpackStr(
buf, (const MI_Char**)&value->string));
break;
}
case MI_REFERENCE:
case MI_INSTANCE:
{
MI_RETURN(Instance_Unpack((MI_Instance**)&value->instance, buf, batch, copy));
break;
}
case MI_BOOLEANA:
case MI_UINT8A:
case MI_SINT8A:
{
MI_RETURN_ERR(Buf_UnpackU8A(buf,
(const MI_Uint8**)&value->uint8a.data, &value->uint8a.size));
break;
}
case MI_UINT16A:
case MI_SINT16A:
case MI_CHAR16A:
{
MI_RETURN_ERR(Buf_UnpackU16A(buf,
(const MI_Uint16**)&value->uint16a.data, &value->uint16a.size));
break;
}
case MI_UINT32A:
case MI_SINT32A:
case MI_REAL32A:
{
MI_RETURN_ERR(Buf_UnpackU32A(buf,
(const MI_Uint32**)&value->uint32a.data, &value->uint32a.size));
break;
}
case MI_UINT64A:
case MI_SINT64A:
case MI_REAL64A:
{
MI_RETURN_ERR(Buf_UnpackU64A(buf,
(const MI_Uint64**)&value->uint64a.data, &value->uint64a.size));
break;
}
case MI_DATETIMEA:
{
MI_RETURN_ERR(Buf_UnpackDTA(buf,
(const MI_Datetime**)&value->datetimea.data,
&value->datetimea.size));
}
case MI_STRINGA:
{
MI_RETURN_ERR(Buf_UnpackStrA(buf,
(const MI_Char***)&value->stringa.data, &value->stringa.size));
break;
}
case MI_INSTANCEA:
case MI_REFERENCEA:
{
/* Unpack the size of the array */
MI_RETURN_ERR(Buf_UnpackU32(buf, &value->instancea.size));
if (!value->instancea.size)
{
value->instancea.data = 0;
}
else
{
MI_Uint32 index;
value->instancea.data = (MI_Instance**)_Alloc(batch,
sizeof(MI_Instance*) * value->instancea.size);
index = 0;
if (!value->instancea.data)
{
MI_RETURN(MI_RESULT_FAILED);
}
for ( index = 0; index < value->instancea.size; index++ )
{
MI_RETURN_ERR(Instance_Unpack(
&value->instancea.data[index], buf, batch, copy));
}
}
break;
}
}
MI_RETURN(MI_RESULT_OK);
}
MI_Result Instance_Pack(
const MI_Instance* self_,
MI_Boolean keysOnly,
MI_Boolean (*filterProperty)(const MI_Char* name, void* data),
void* filterPropertyData,
Buf* buf)
{
Instance* self = _SelfOf(self_);
MI_ClassDecl* cd = (MI_ClassDecl*)self->classDecl;
MI_Uint32 i;
/* Check for null arguments */
if (!self || !buf)
MI_RETURN(MI_RESULT_INVALID_PARAMETER);
/* Pack magic number */
MI_RETURN_ERR(Buf_PackU32(buf, INSTANCE_MAGIC));
/* Pack flags */
MI_RETURN_ERR(Buf_PackU32(buf, cd->flags));
/* Pack the classname */
MI_RETURN_ERR(Buf_PackStr(buf, cd->name));
/* namespace */
MI_RETURN_ERR(Buf_PackStr(buf, self->nameSpace));
/* Pack the properties */
if (keysOnly)
{
/* adjust number of properties based on Keys number */
MI_Uint32 keysNum = 0;
for (i = 0; i < cd->numProperties; i++)
{
const MI_PropertyDecl* pd = cd->properties[i];
if (pd->flags & MI_FLAG_KEY)
keysNum++;
}
MI_RETURN_ERR(Buf_PackU32(buf, keysNum));
}
else if (filterProperty)
{
/* Pack the number of unfiltered properties */
MI_Uint32 n = 0;
for (i = 0; i < cd->numProperties; i++)
{
const MI_PropertyDecl* pd = cd->properties[i];
if ((*filterProperty)(pd->name, filterPropertyData))
continue;
n++;
}
MI_RETURN_ERR(Buf_PackU32(buf, n));
}
else
{
MI_RETURN_ERR(Buf_PackU32(buf, cd->numProperties));
}
for (i = 0; i < cd->numProperties; i++)
{
const MI_PropertyDecl* pd = cd->properties[i];
const void* value = (char*)self + pd->offset;
/* Skip non-key properties (for references) */
if (keysOnly && (pd->flags & MI_FLAG_KEY) == 0)
continue;
/* Skip filtered properties */
if (filterProperty &&
(*filterProperty)(pd->name, filterPropertyData))
{
continue;
}
/* Pack the flags */
MI_RETURN_ERR(Buf_PackU32(buf, pd->flags));
/* Pack the propety name */
MI_RETURN_ERR(Buf_PackStr(buf, pd->name));
/* Pack the propety type */
MI_RETURN_ERR(Buf_PackU32(buf, pd->type));
/* Pack the value */
MI_RETURN_ERR(_PackField(buf, value, (MI_Type)pd->type));
}
/* Pack ending magic number */
MI_RETURN_ERR(Buf_PackU32(buf, _END_MAGIC));
MI_RETURN(MI_RESULT_OK);
}
MI_Result Instance_Unpack(
MI_Instance** selfOut,
Buf* buf,
Batch* batch,
MI_Boolean copy)
{
MI_Uint32 magic;
MI_Uint32 flags;
const MI_Char* className;
const MI_Char* nameSpace = 0;
MI_Instance* self;
/* Check parameters */
if (!selfOut || !buf)
MI_RETURN(MI_RESULT_INVALID_PARAMETER);
/* Clear output parameter */
*selfOut = NULL;
/* Unpack magic number */
MI_RETURN_ERR(Buf_UnpackU32(buf, &magic));
if (INSTANCE_MAGIC != magic)
MI_RETURN(MI_RESULT_FAILED);
/* Unpack flags */
MI_RETURN_ERR(Buf_UnpackU32(buf, &flags));
/* Unpack the class name */
MI_RETURN_ERR(Buf_UnpackStr(buf, &className));
/* Unpack the namespace */
MI_RETURN_ERR(Buf_UnpackStr(buf, &nameSpace));
/* Unpack properties */
{
MI_Uint32 numProperties;
MI_Uint32 i;
MI_RETURN_ERR(Buf_UnpackU32(buf, &numProperties));
/* ATTN-B: prevent copying of className and superClass strings */
/* Create dynamic instance */
MI_RETURN_ERR(Instance_NewDynamic(&self, className, flags, batch));
MI_RETURN_ERR(MI_Instance_SetNameSpace(self, nameSpace));
for (i = 0; i < numProperties; i++)
{
const MI_Char* name;
MI_Uint32 type, prop_flags;
MI_Value value;
const MI_Value* valuePtr;
MI_Boolean exists;
/* ATTN-B: prevent copying of name by Instance_Add */
/* Unpack the propety type */
MI_RETURN_ERR(Buf_UnpackU32(buf, &prop_flags));
/* Unpack the propety name */
MI_RETURN_ERR(Buf_UnpackStr(buf, &name));
/* Unpack the propety type */
MI_RETURN_ERR(Buf_UnpackU32(buf, &type));
/* Unpack the value */
MI_RETURN_ERR(_UnpackField(buf, &value, &exists, (MI_Type)type,
batch, copy));
/* Set valuePtr */
if (exists)
valuePtr = &value;
else
valuePtr = NULL;
/* ATTN-A: Handle prop_flags and className parameters */
/* Add the property to the instance */
if (!copy)
prop_flags |= MI_FLAG_BORROW;
MI_RETURN_ERR(MI_Instance_AddElement(self, name, valuePtr,
(MI_Type)type, prop_flags));
}
}
/* Check the ending magic number */
{
MI_Uint32 endMagic;
MI_RETURN_ERR(Buf_UnpackU32(buf, &endMagic));
if (endMagic != _END_MAGIC)
MI_RETURN(MI_RESULT_INVALID_PARAMETER);
}
/* Set output parameter */
*selfOut = self;
/* ATTN-A: if batch is non-null, then attach buffer to batch */
MI_RETURN(MI_RESULT_OK);
}
MI_Result InstanceToBatch(
const MI_Instance* instance,
MI_Boolean (*filterProperty)(const MI_Char* name, void* data),
void* filterPropertyData,
Batch* batch,
void** ptrOut,
MI_Uint32* sizeOut)
{
Buf buf;
MI_Result r;
Page* page;
r = Buf_Init(&buf, 16*1024);
if (MI_RESULT_OK != r)
return r;
r = Instance_Pack(
instance, MI_FALSE, filterProperty, filterPropertyData, &buf);
if (MI_RESULT_OK != r)
{
Buf_Destroy(&buf);
return r;
}
page = Buf_StealPage(&buf);
page->u.s.size = buf.size;
Batch_AttachPage(batch, page);
*ptrOut = page + 1;
*sizeOut = (MI_Uint32)page->u.s.size;
return MI_RESULT_OK;
}