File: [OMI] / omi / base / buf.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 "buf.h"
#include "strings.h"
#define _MIN_CAPACITY 256
/*
**==============================================================================
**
** Local definitions
**
**==============================================================================
*/
/* Round x up to the nearest power of 2 */
static MI_Uint32 _RoundPow2(MI_Uint32 x)
{
MI_Uint32 r = x - 1;
r |= (r >> 1);
r |= (r >> 2);
r |= (r >> 4);
r |= (r >> 8);
r |= (r >> 16);
return r + 1;
}
/*
**==============================================================================
**
** Public definitions
**
**==============================================================================
*/
MI_Result Buf_Init(
Buf* self,
MI_Uint32 capacity)
{
Page* page;
/* Adjust capacity if too small */
if (capacity < _MIN_CAPACITY)
capacity = _MIN_CAPACITY;
/* Allocate data buffer */
page = (Page*)malloc(sizeof(Page) + capacity);
if (!page)
return MI_RESULT_FAILED;
page->u.s.size = capacity;
page->u.s.next = 0;
/* Set fields */
self->data = page + 1;
self->size = 0;
self->capacity = capacity;
self->offset = 0;
#ifdef CONFIG_ENABLE_DEBUG
memset(self->data,0xAA,self->capacity);
#endif
return MI_RESULT_OK;
}
void Buf_Destroy(
Buf* self)
{
if (self->data)
free((Page*)self->data - 1);
}
MI_Result Buf_Reserve(
Buf* self,
MI_Uint32 capacity)
{
/* Expand allocation if we need more space */
if (capacity > self->capacity)
{
Page* page;
capacity = _RoundPow2(capacity);
if (self->data)
{
page = (Page*)self->data - 1;
page = (Page*)realloc(page, sizeof(Page) + capacity);
#ifdef CONFIG_ENABLE_DEBUG
memset(((char*)(page+1)) + self->capacity,0xAA,capacity - self->capacity);
#endif
}
else
{
page = (Page*)malloc(sizeof(Page) + capacity);
#ifdef CONFIG_ENABLE_DEBUG
memset(page,0xAA,sizeof(Page) + capacity);
#endif
}
if (!page)
return MI_RESULT_FAILED;
page->u.s.size = capacity;
self->data = page + 1;
self->capacity = capacity;
}
return MI_RESULT_OK;
}
MI_Result Buf_App(
Buf* self,
const void* data,
MI_Uint32 size)
{
/* Calculate the new size */
MI_Uint32 newSize = self->size + size;
/* Expand allocation if we need more space */
if (newSize > self->capacity)
{
MI_Result r = Buf_Reserve(self, newSize);
if (r != MI_RESULT_OK)
return MI_RESULT_FAILED;
}
/* Copy in the new data */
memcpy((char*)self->data + self->size, data, size);
self->size += size;
return MI_RESULT_OK;
}
MI_Result Buf_PackStr(
Buf* self,
const MI_Char* x)
{
MI_Uint32 size;
/* Pack null strings as 0 */
if (!x)
return Buf_PackU32(self, 0);
/* Pack the size of the string (size including null terminator) */
size = (MI_Uint32)Zlen(x) + 1;
MI_RETURN_ERR(Buf_PackU32(self, size));
/* Pack the characters (including the null terminator) */
MI_RETURN_ERR(Buf_App(self, x, size * sizeof(MI_Char)));
return MI_RESULT_OK;
}
MI_Result Buf_UnpackU8A(
Buf* self,
const MI_Uint8** data,
MI_Uint32* size)
{
/* Unpack size */
MI_RETURN_ERR(Buf_UnpackU32(self, size));
if (*size == 0)
{
*data = NULL;
return MI_RESULT_OK;
}
/* Check whether there are enough bytes left */
if (self->offset + *size * sizeof(MI_Uint8) > self->size)
return MI_RESULT_FAILED;
/* Store pointer to array */
*data = (const MI_Uint8*)((char*)self->data + self->offset);
self->offset += *size * sizeof(MI_Uint8);
return MI_RESULT_OK;
}
MI_Result Buf_UnpackU16A(
Buf* self,
const MI_Uint16** data,
MI_Uint32* size)
{
/* Unpack size */
MI_RETURN_ERR(Buf_UnpackU32(self, size));
if (*size == 0)
{
*data = NULL;
return MI_RESULT_OK;
}
/* Check whether there are enough bytes left */
if (self->offset + *size * sizeof(MI_Uint16) > self->size)
return MI_RESULT_FAILED;
/* Store pointer to array */
*data = (const MI_Uint16*)((char*)self->data + self->offset);
self->offset += *size * sizeof(MI_Uint16);
return MI_RESULT_OK;
}
MI_Result Buf_UnpackU32A(
Buf* self,
const MI_Uint32** data,
MI_Uint32* size)
{
/* Unpack size */
MI_RETURN_ERR(Buf_UnpackU32(self, size));
if (*size == 0)
{
*data = NULL;
return MI_RESULT_OK;
}
/* Check whether there are enough bytes left */
if (self->offset + *size * sizeof(MI_Uint32) > self->size)
return MI_RESULT_FAILED;
/* Store pointer to array */
*data = (const MI_Uint32*)((char*)self->data + self->offset);
self->offset += *size * sizeof(MI_Uint32);
return MI_RESULT_OK;
}
MI_Result Buf_UnpackU64A(
Buf* self,
const MI_Uint64** data,
MI_Uint32* size)
{
/* Unpack size */
MI_RETURN_ERR(Buf_UnpackU32(self, size));
if (*size == 0)
{
*data = NULL;
return MI_RESULT_OK;
}
/* Align buffer on 8 byte boundary */
MI_RETURN_ERR(Buf_Align64(self));
/* Check whether there are enough bytes left */
if (self->offset + *size * sizeof(MI_Uint64) > self->size)
return MI_RESULT_FAILED;
/* Store pointer to array */
*data = (const MI_Uint64*)((char*)self->data + self->offset);
self->offset += *size * sizeof(MI_Uint64);
return MI_RESULT_OK;
}
MI_Result Buf_UnpackStr(
Buf* self,
const MI_Char** x)
{
MI_Uint32 size;
/* Unpack size */
MI_RETURN_ERR(Buf_UnpackU32(self, &size));
if (size == 0)
{
*x = NULL;
return MI_RESULT_OK;
}
/* Check whether there are enough bytes left */
if (self->offset + size * sizeof(MI_Char) > self->size)
return MI_RESULT_FAILED;
/* Store pointer to array */
*x = (const MI_Char*)((char*)self->data + self->offset);
self->offset += size * sizeof(MI_Char);
return MI_RESULT_OK;
}
MI_Result Buf_PackStrA(
Buf* self,
const MI_Char** data,
MI_Uint32 size)
{
MI_Uint32 i;
/* Pack the array size (the number of strings) */
MI_RETURN_ERR(Buf_PackU32(self, size));
if (size)
{
MI_Uint32 sizes[64];
if (!data)
return MI_RESULT_FAILED;
/* Put sizes of all strings first. Each size is encoded as a 64-bit
* integer. The unpack function replaces this integer with a pointer
* to the corresponding string. This avoids having to allocate memory
* for the pointer array while unpacking.
*/
for (i = 0; i < size; i++)
{
MI_Uint32 n;
if (!data[i])
return MI_RESULT_FAILED;
n = (MI_Uint32)Zlen(data[i]) + 1;
/* Save size so that it will not have to be recalculated by the
* next loop using strlen.
*/
if (i < MI_COUNT(sizes))
sizes[i] = n;
MI_RETURN_ERR(Buf_PackU64(self, (MI_Uint64)n));
}
/* Pack strings one after the other. */
for (i = 0; i < size; i++)
{
MI_Uint32 n;
if (i < MI_COUNT(sizes))
n = sizes[i];
else
n = (MI_Uint32)Zlen(data[i]) + 1;
MI_RETURN_ERR(Buf_App(self, data[i], n * sizeof(MI_Char)));
}
}
return MI_RESULT_OK;
}
MI_Result Buf_UnpackStrA(
Buf* self,
const MI_Char*** dataOut,
MI_Uint32* sizeOut)
{
const MI_Char** data;
MI_Uint32 size;
MI_Uint32 i;
MI_Uint32 offset;
/* Unpack the size of the array */
MI_RETURN_ERR(Buf_UnpackU32(self, &size));
/* Handle zero-size array case */
if (size == 0)
{
*dataOut = NULL;
*sizeOut = 0;
return MI_RESULT_OK;
}
/* Align to read uint64 sizes */
MI_RETURN_ERR(Buf_Align64(self));
/* Set pointer data array */
data = (const MI_Char**)((char*)self->data + self->offset);
/* Calculate offset to first string in array (data[0]) */
offset = self->offset + (size * sizeof(MI_Uint64));
/* Fail if offset is beyond end of buffer */
if (offset > self->size)
return MI_RESULT_FAILED;
/* Unpack the string sizes and covert to string pointers */
for (i = 0; i < size; i++)
{
MI_Uint64 tmp;
MI_Uint32 n;
/* Unpack size of next string in array */
MI_RETURN_ERR(Buf_UnpackU64(self, &tmp));
n = (MI_Uint32)tmp;
/* Fail if not enough room left in buffer for string */
if (offset + n * sizeof(MI_Char) > self->size)
return MI_RESULT_FAILED;
/* Add string to array */
data[i] = (MI_Char*)((char*)self->data + offset);
offset += n * sizeof(MI_Char);
}
/* Update the offset */
self->offset = offset;
/* Set the output parameters */
*dataOut = data;
*sizeOut = size;
return MI_RESULT_OK;
}
MI_Result Buf_PackDT(
Buf* self,
const MI_Datetime* x)
{
MI_RETURN_ERR(Buf_Pad32(self));
MI_RETURN_ERR(Buf_App(self, x, sizeof(MI_Datetime)));
return MI_RESULT_OK;
}
MI_Result Buf_UnpackDT(
Buf* self,
MI_Datetime* x)
{
MI_Uint32 offset;
MI_RETURN_ERR(Buf_Align32(self));
/* Find ending offset of datetime structure */
offset = self->offset + sizeof(MI_Datetime);
if (offset > self->size)
return MI_RESULT_FAILED;
memcpy(x, (char*)self->data + self->offset, sizeof(MI_Datetime));
self->offset = offset;
return MI_RESULT_OK;
}
MI_Result Buf_PackDTA(
Buf* self,
const MI_Datetime* data,
MI_Uint32 size)
{
MI_RETURN_ERR(Buf_PackU32(self, size));
MI_RETURN_ERR(Buf_App(self, data, size * sizeof(MI_Datetime)));
return MI_RESULT_OK;
}
MI_Result Buf_UnpackDTA(
Buf* self,
const MI_Datetime** dataPtr,
MI_Uint32* sizePtr)
{
MI_Uint32 offset;
/* Unpack the size */
MI_RETURN_ERR(Buf_UnpackU32(self, sizePtr));
/* Handle zero-sized array (null data pointer) */
if (*sizePtr == 0)
{
*dataPtr = NULL;
return MI_RESULT_OK;
}
/* Find ending offset of datetime array */
offset = self->offset + *sizePtr * sizeof(MI_Datetime);
/* Set pointer to data array */
*dataPtr = (const MI_Datetime*)((char*)self->data + self->offset);
/* Advance offset beyond array */
self->offset = offset;
return MI_RESULT_OK;
}
Page* Buf_StealPage(
Buf* self)
{
if (self->data)
{
Page* page = (Page*)self->data - 1;
self->data = NULL;
return page;
}
return NULL;
}