(file) Return to buf.c CVS log (file) (dir) Up to [OMI] / omi / base

File: [OMI] / omi / base / buf.c (download)
Revision: 1.1.1.1 (vendor branch), Wed May 30 21:47:49 2012 UTC (12 years ago) by mike
Branch: TOG
CVS Tags: OMI_1_0_2_Branch, OMI_1_0_2, OMI_1_0_1_PRE, OMI_1_0_1, OMI_1_0_0
Changes since 1.1: +0 -0 lines
Initial Import

/*
**==============================================================================
**
** 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;
}

ViewCVS 0.9.2