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

File: [OMI] / omi / base / helpers.c (download)
Revision: 1.4, Fri Sep 25 19:24:20 2015 UTC (8 years, 7 months ago) by krisbash
Branch: MAIN
CVS Tags: OMI_1_0_8_2, HEAD
Changes since 1.3: +55 -39 lines
OMI 1.0.8-2 commit

/*
**==============================================================================
**
** 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 <ctype.h>
#include "helpers.h"
#include "types.h"
#include <pal/strings.h>
#include "alloc.h"
#include <pal/intsafe.h>
#include <pal/format.h>
#include "class.h"
#include "base64.h"
#include "log.h"
#include "messages.h"

static const ZChar* _ParseNumber(const ZChar* p, unsigned long* n)
{
    ZChar* end;

    *n = Tcstoul(p, &end, 10);

    if (end == p)
        return NULL;

    return end;
}

static const ZChar* _ParseDecimalPart(
    const ZChar* p,
    unsigned long* n)
{
    ZChar* end;
    int i;
    ZChar buf[7];

    Tcstoul(p, &end, 10);

    if (end == p)
    {
        /* Zero decimal part */
        *n = 0;
        return p;
    }

    for (i = 0; i < 6 && p != end; i++, p++)
        buf[i] = *p;

    for (; i < 6; i++)
        buf[i] = '0';

    buf[6] = '\0';

    *n = Tcstoul(buf, NULL, 10);

    return end;
}

static int _ParseWSManDuration(const ZChar* str, MI_Datetime* x)
{
    const ZChar* p = str;
    int foundT = 0;
    unsigned long years = 0;
    unsigned long months = 0;
    unsigned long days = 0;
    unsigned long hours = 0;
    unsigned long minutes = 0;
    unsigned long seconds = 0;
    unsigned long microseconds = 0;

    /* xs:duration: PnYnMnDTnHnMnS */
    if (*p != 'P')
        return -1;

    /* [xs:duration]
     *
     * Format: "PnYnMnDTnHnMnS", where
     *     P - period (required)
     *     nY - number of years
     *     nM - number of month
     *     nD - number of days
     *     ZT - start of time section (required for the following)
     *     nH - number of hours
     *     nM - number of minutes
     *     nS - number of seconds
     *
     * Examples:
     *     -P10D (rejected)
     *     -P1347M (rejected)
     *     P5Y
     *     P5Y2M10D
     *     P5Y2M10DT15H
     *     PT15H
     *     P1347Y
     *     P1347M
     *     P1Y2MT2H
     *     P0Y1347M
     *     P0Y1347M0D
     *     P1Y2M3DT10H30M
     *
     * Illegal:
     *     P-1347M (rejected)
     *     P1Y2MT (tolerated)
     */

    p++;

    while (*p)
    {
        unsigned long n = 0;

        if (*p == 'T')
        {
            foundT = 1;
            p++;
        }
        else if (foundT)
        {
            p = _ParseNumber(p, &n);

            if (!p)
                break;

            switch (*p)
            {
                case 'H':
                    hours = n;
                    break;
                case 'M':
                    minutes = n;
                    break;
                case 'S':
                    seconds = n;
                    break;
                case '.':
                {
                    p++;
                    p = _ParseDecimalPart(p, &microseconds);

                    if (*p != 'S')
                        return -1;

                    seconds = n;
                    break;
                }
                default:
                    return -1;
            }

            p++;
        }
        else
        {
            p = _ParseNumber(p, &n);

            if (!p)
                break;

            switch (*p)
            {
                case 'Y':
                    years = n;
                    break;
                case 'M':
                    months = n;
                    break;
                case 'D':
                    days = n;
                    break;
                default:
                    return -1;
            }

            p++;
        }
    }

    /* ATTN: check for overflow */

    /* Normalize seconds (possibly increasing minutes) */
    minutes += seconds / 60;
    seconds = seconds % 60;

    /* Normalize minutes (possibly increasing hours) */
    hours += minutes / 60;
    minutes = minutes % 60;

    /* Normalize hours (possibly increasing days) */
    days += hours / 24;
    hours = hours % 24;

    /* Approximate days from years-months-days */
    days += years * 365;
    days += years / 4;
    days += months * 30;
    days += months / 2;

    /* Set CIM datetime fields */
    x->isTimestamp = MI_FALSE;
    x->u.interval.days = (unsigned int)days;
    x->u.interval.hours = (unsigned int)hours;
    x->u.interval.minutes = (unsigned int)minutes;
    x->u.interval.seconds = (unsigned int)seconds;
    x->u.interval.microseconds = microseconds;

    return (p && *p == '\0') ? 0 : -1;
}

static const ZChar* _ParseWSManUTC(const ZChar* str, MI_Datetime* x)
{
    const ZChar* p = str;
    unsigned long utcHours = 0;
    unsigned long utcMinutes = 0;
    long utcSign = 0; /* '1' is positive, '-1' is negative */

    if (*p == 'Z')
    {
        p++;
        return p;
    }
    else if (*p == '+' || *p == '-')
    {
        /* Parse UTC "HH:SS" */
        const ZChar* end;

        utcSign = (*p == '-') ? -1 : 1;

        p++;
        end = _ParseNumber(p, &utcHours);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;

        if (*p != ':')
            return NULL;

        p++;
        end = _ParseNumber(p, &utcMinutes);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;
    }
    else
    {
        return NULL;
    }

    /* Set CIM datetime fields */
    x->u.timestamp.utc = utcSign * ((utcHours * 60) + utcMinutes);

    return p;
}

static const ZChar* _ParseWSManDate(const ZChar* str, MI_Datetime* x)
{
    const ZChar* p = str;
    unsigned long year = 0;
    unsigned long month = 0;
    unsigned long day = 0;

    /* Parse YYYY */
    {
        const ZChar* end = _ParseNumber(p, &year);

        if (!end || (end - p) != 4)
            return NULL;

        p = end;
    }

    /* Expect '-' */
    if (*p++ != '-')
        return NULL;

    /* Parse MM */
    {
        const ZChar* end = _ParseNumber(p, &month);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;
    }

    /* Expect '-' */
    if (*p++ != '-')
        return NULL;

    /* Parse DD */
    {
        const ZChar* end = _ParseNumber(p, &day);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;
    }

    /* Set CIM datetime fields */
    memset(x, 0, sizeof(MI_Datetime));
    x->isTimestamp = MI_TRUE;
    x->u.timestamp.year = (unsigned int)year;
    x->u.timestamp.month = (unsigned int)month;
    x->u.timestamp.day = (unsigned int)day;

    /* Parse UTC part */
    if (*p == 'Z' || *p == '+' || *p == '-')
    {
        p = _ParseWSManUTC(p, x);

        if (!p)
            return NULL;
    }

    return p;
}

static const ZChar* _ParseWSManTime(const ZChar* str, MI_Datetime* x)
{
    const ZChar* p = str;
    unsigned long hour = 0;
    unsigned long minute = 0;
    unsigned long second = 0;
    unsigned long microseconds = 0;

    /* Parse "HH" */
    {
        const ZChar* end = _ParseNumber(p, &hour);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;
    }

    /* Expect ':' */
    if (*p++ != ':')
        return NULL;

    /* Parse "MM" */
    {
        const ZChar* end = _ParseNumber(p, &minute);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;
    }

    /* Expect ":" */
    if (*p++ != ':')
        return NULL;

    /* Parse "SS" */
    {
        const ZChar* end = _ParseNumber(p, &second);

        if (!end || (end - p) != 2)
            return NULL;

        p = end;
    }

    /* Parse decimal part */
    if (*p == '.')
    {
        p++;
        p = _ParseDecimalPart(p, &microseconds);

        if (!p)
            return NULL;
    }

    /* Set CIM datetime fields */
    x->isTimestamp = MI_TRUE;
    x->u.timestamp.hour = (unsigned int)hour;
    x->u.timestamp.minute = (unsigned int)minute;
    x->u.timestamp.second = (unsigned int)second;
    x->u.timestamp.microseconds = (unsigned int)microseconds;

    /* Parse UTC part */
    if (*p == 'Z' || *p == '+' || *p == '-')
    {
        p = _ParseWSManUTC(p, x);

        if (!p)
            return NULL;
    }

    return p;
}

int ParseWSManDatetime(const ZChar* str, MI_Datetime* x)
{
    const ZChar* p = str;

    /* Clear datetime */
    memset(x, 0, sizeof(MI_Datetime));

    /* negative xs:duration */
    if (*p == '-')
    {
        /* Negative intervals not supported by CIM */
        return -1;
    }

    /* xs:duration: "PnYnMnDTnHnMnS" */
    if (*p == 'P')
    {
        return _ParseWSManDuration(str, x);
    }

    /* xs:date: "YYYY-MM-DD" plus UTC */
    if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]))
    {
        p = _ParseWSManDate(str, x);

        if (!p)
            return -1;

        if (*p == '\0')
            return 0;

        /* xs:time "HH:MM:SS" plus UTC */
        if (*p == 'T')
        {
            p++;
            p = _ParseWSManTime(p, x);

            if (!p)
                return -1;

            if (*p == '\0')
                return 0;
        }
    }

    /* xs:time: "HH:MM:SS" plus UTC */
    if (isdigit(p[0]) && isdigit(p[1]) && p[2] == ':')
    {
        p = _ParseWSManTime(str, x);

        if (!p)
            return -1;

        if (*p == '\0')
            return 0;
    }

    /* Failed */
    return -1;
}

_Use_decl_annotations_
void FormatWSManDatetime(const MI_Datetime* x, ZChar buffer[64])
{
    int n = 64;

    *buffer = '\0';

    if (x->isTimestamp)
    {
        /* Example output: "2010-12-31T12:30:03.123456+06:00" */
        ZChar tmpbuf[64];

        /* As per section 8.2 in DSP0230_1.1.0 date (year, month, day) containing all zero's is considered valida date.
            Time containing all zeros is also considred as valid time.

            MI_Datetime cannot store asterics ('*') as part of date or time.
            So with MI_Datetime we will never get into case of not having time or date */
        Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%04u-%02u-%02u"),
            x->u.timestamp.year,
            x->u.timestamp.month,
            x->u.timestamp.day);
        Tcslcat(buffer, tmpbuf, n);

        Tcslcat(buffer, ZT("T"), n);

        Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%02u:%02u:%02u"),
            x->u.timestamp.hour,
            x->u.timestamp.minute,
            x->u.timestamp.second);
        Tcslcat(buffer, tmpbuf, n);

        if (x->u.timestamp.microseconds)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT(".%06u"),
                x->u.timestamp.microseconds);
            Tcslcat(buffer, tmpbuf, n);
        }

        if (x->u.timestamp.utc > 0)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("+%02u:%02u"),
                x->u.timestamp.utc / 60, x->u.timestamp.utc % 60);
            Tcslcat(buffer, tmpbuf, n);
        }
        else if (x->u.timestamp.utc < 0)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("-%02u:%02u"),
                -x->u.timestamp.utc / 60, -x->u.timestamp.utc % 60);
            Tcslcat(buffer, tmpbuf, n);
        }
        else
        {
            Tcslcat(buffer, ZT("Z"), n);
        }
    }
    else
    {
        ZChar tmpbuf[64];

        /* Example: "P1Y1M22DT10H11M12S" */

        Tcslcat(buffer, ZT("P"), n);

        if (x->u.interval.days)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%uD"), x->u.interval.days);
            Tcslcat(buffer, tmpbuf, n);
        }

        if (x->u.interval.hours || x->u.interval.minutes ||
            x->u.interval.seconds || x->u.interval.microseconds)
        {
            Tcslcat(buffer, ZT("T"), n);
        }

        if (x->u.interval.hours)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%uH"), x->u.interval.hours);
            Tcslcat(buffer, tmpbuf, n);
        }

        if (x->u.interval.minutes)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%uM"), x->u.interval.minutes);
            Tcslcat(buffer, tmpbuf, n);
        }

        if (x->u.interval.seconds && x->u.interval.microseconds)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%u.%06uS"),
                x->u.interval.seconds, x->u.interval.microseconds);
            Tcslcat(buffer, tmpbuf, n);
        }
        else if (x->u.interval.seconds && !x->u.interval.microseconds)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("%uS"), x->u.interval.seconds);
            Tcslcat(buffer, tmpbuf, n);
        }
        else if (!x->u.interval.seconds && x->u.interval.microseconds)
        {
            Stprintf(tmpbuf, MI_COUNT(tmpbuf), ZT("0.%06uS"),
                x->u.interval.microseconds);
            Tcslcat(buffer, tmpbuf, n);
        }
    }
}

int StrToChar16(const ZChar* str, MI_Char16* x)
{
    ZChar* end;
    *x = (MI_Char16)Tcstoul(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

static int _StrDatetime_CheckAsterisk_ToU32(const ZChar* s, size_t offset, size_t size, MI_Uint32* x)
{
    ZChar buf[64];
    ZChar* end;

    if (size >= MI_COUNT(buf))
        return -1;

    memcpy(buf, &s[offset], size * sizeof(ZChar));
    buf[size] = '\0';

    if (buf[0] == '*')
    {
        size_t i;
        MI_Boolean allAsterisk = MI_TRUE;
        for (i = 0; i < size; ++i)
        {
            if (buf[i] != '*')
            {
                allAsterisk = MI_FALSE;
                break;
            }
        }

        *x = 0;

        if (allAsterisk == MI_TRUE)
            return 0;
        else
            return -1;
    }
    else
    {
        *x = (MI_Uint32)Tcstoul(buf, &end, 10);

        if (*end != '\0')
            return -1;
    }

    /* Success */
    return 0;
}

int StrToDatetime(const ZChar* s, MI_Datetime* x)
{
    if (Tcslen(s) != 25)
        return -1;

    memset(x, 0, sizeof(MI_Datetime));

    if (s[21] == '+' || s[21] == '-')
    {
        MI_Uint32 utc;

        /* It must be a timestamp (YYYYMMDDHHMMSS.MMMMMMSUTC) */
        if (_StrDatetime_CheckAsterisk_ToU32(s, 0, 4, &x->u.timestamp.year) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 4, 2, &x->u.timestamp.month) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 6, 2, &x->u.timestamp.day) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 8, 2, &x->u.timestamp.hour) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 10, 2, &x->u.timestamp.minute) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 12, 2, &x->u.timestamp.second) != 0 ||
            s[14] != '.' ||
            _StrDatetime_CheckAsterisk_ToU32(s, 15, 6, &x->u.timestamp.microseconds) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 22, 3, &utc) != 0)
        {
            return -1;
        }

        if (s[21] == '+')
             x->u.timestamp.utc = (MI_Sint32)utc;
        else
             x->u.timestamp.utc = -(MI_Sint32)utc;

        x->isTimestamp = 1;
    }
    else if (s[21] == ':')
    {
        /* It must be an interval (DDDDDDDDHHMMSS.MMMMMM:000) */
        if (_StrDatetime_CheckAsterisk_ToU32(s, 0, 8, &x->u.interval.days) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 8, 2, &x->u.interval.hours) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 10, 2, &x->u.interval.minutes) != 0 ||
            _StrDatetime_CheckAsterisk_ToU32(s, 12, 2, &x->u.interval.seconds) != 0 ||
            s[14] != '.' ||
            _StrDatetime_CheckAsterisk_ToU32(s, 15, 6, &x->u.interval.microseconds) != 0 ||
            s[22] != '0' || s[23] != '0' || s[24] != '0')
        {
            return -1;
        }

        x->isTimestamp = 0;
    }
    else
        return -1;

    return 0;
}

static int _ParseDatetime(const ZChar* str, MI_Datetime* x)
{
    if (StrToDatetime(str, x) == 0)
        return 0;

    if (ParseWSManDatetime(str, x) == 0)
        return 0;

    return -1;
}

int StrToBoolean(const ZChar* str, MI_Boolean* x)
{
    if (Tcscasecmp(str, ZT("true")) == 0)
        *x = MI_TRUE;
    else if (Tcscasecmp(str, ZT("false")) == 0)
        *x = MI_FALSE;
    else
        return -1;

    return 0;
}

int StrToUint8(const ZChar* str, MI_Uint8* x)
{
    ZChar* end;
    *x = (MI_Uint8)Tcstoul(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToSint8(const ZChar* str, MI_Sint8* x)
{
    ZChar* end;
    *x = (MI_Sint8)Tcstol(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToUint16(const ZChar* str, MI_Uint16* x)
{
    ZChar* end;
    *x = (MI_Uint16)Tcstoul(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToSint16(const ZChar* str, MI_Sint16* x)
{
    ZChar* end;
    *x = (MI_Sint16)Tcstol(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToUint32(const ZChar* str, MI_Uint32* x)
{
    ZChar* end;
    *x = (MI_Uint32)Tcstoul(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToSint32(const ZChar* str, MI_Sint32* x)
{
    ZChar* end;
    *x = (MI_Sint32)Tcstol(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToUint64(const ZChar* str, MI_Uint64* x)
{
    ZChar* end;
    *x = (MI_Uint64)Tcstoull(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToSint64(const ZChar* str, MI_Sint64* x)
{
    ZChar* end;
    *x = (MI_Sint64)Tcstoll(str, &end, 0);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToReal32(const ZChar* str, MI_Real32* x)
{
    ZChar* end;
    *x = (MI_Real32)Tcstod(str, &end);

    if (*end != '\0')
        return -1;

    return 0;
}

int StrToReal64(const ZChar* str, MI_Real64* x)
{
    ZChar* end;
    *x = (MI_Real64)Tcstod(str, &end);

    if (*end != '\0')
        return -1;

    return 0;
}

typedef int (*StrToType)(const ZChar* str, void* x);

static StrToType _converters[] =
{
    (StrToType)StrToBoolean,
    (StrToType)StrToUint8,
    (StrToType)StrToSint8,
    (StrToType)StrToUint16,
    (StrToType)StrToSint16,
    (StrToType)StrToUint32,
    (StrToType)StrToSint32,
    (StrToType)StrToUint64,
    (StrToType)StrToSint64,
    (StrToType)StrToReal32,
    (StrToType)StrToReal64,
    (StrToType)StrToChar16,
    (StrToType)_ParseDatetime,
    NULL, /* STRING */
    NULL, /* REFERENCE */
    NULL, /* INSTANCE */
};

MI_Result MI_CALL Instance_SetElementFromString(
    MI_Instance* self,
    const ZChar* name,
    const ZChar* str,
    MI_Uint32 flags)
{
    /* ATTN: check for integer value truncation (see use of Ztol) */
    /* ATTN: implement array types! */
    /* ATTN: implement instance and reference types! */
    MI_Type type;
    MI_Value value;

    /* Check arguments */
    if (!self || !name || !str)
    {
        MI_RETURN(MI_RESULT_INVALID_PARAMETER);
    }

    /* Obtain type of named property */
    {
        MI_Result r = MI_Instance_GetElement(self, name, NULL, &type,
            NULL, NULL);

        if (r != MI_RESULT_OK)
        {
            return r;
        }
    }

    /* If type is array and value is string,
        try to create a single item array from this string
    */
    if (0 != (MI_ARRAY_BIT & type))
    {
        return Instance_SetElementFromStringA(self, name, &str, 1, flags);
    }


    /* Convert string to value */
    if (type == MI_STRING)
    {
        value.string = (ZChar*)str;
    }
    else
    {
        StrToType func = _converters[Type_ScalarOf(type)];

        if (func)
        {
            if ((*func)(str, &value) != 0)
                MI_RETURN(MI_RESULT_FAILED);
        }
        else
        {
            MI_RETURN(MI_RESULT_FAILED);
        }
    }

    MI_RETURN(MI_Instance_SetElement(self, name, &value, type, 0));
}

// Allocates the buffer inside the callback
static int _Base64DecCallback(
    const void* data,
    size_t size,
    void* callbackData)
{
    MI_Array* arr= (MI_Array*)callbackData;
    char** str = (char**)&arr->data;
    size_t i;
    char* start = NULL;
    size_t totalSize = 0;
    size_t skipSize = 4; // Skip first 4 bytes that contains buffer size

    if( *str == NULL ) // This is the first time we are called
    {
        size_t allocSize = 0;
        if (SizeTAdd(size, 4, &allocSize) == S_OK &&
            SizeTMult(allocSize, sizeof(unsigned char), &allocSize) == S_OK)
        {
            // prepend length in 4 bytes
            *str = (char*)PAL_Malloc(allocSize);
        }
        else
        {
            // Overflow
            return -1;
        }

        if (!*str)
            return -1;
        totalSize = size + 4;
    }
    else
    {
        char *newStr = NULL;
        unsigned int p1 = ((unsigned char)(*str)[3]);
        unsigned int p2 = ((unsigned char)(*str)[2]) << 8;
        unsigned int p3 = ((unsigned char)(*str)[1]) << 16;
        unsigned int p4 = ((unsigned char)(*str)[0]) << 24;
        totalSize = p1 + p2 + p3 + p4;
        skipSize = totalSize;
        totalSize += size;
        size_t allocSize = 0;
        if (SizeTMult(totalSize, sizeof(unsigned char), &allocSize) == S_OK)
        {
            newStr = (char*)PAL_Malloc(allocSize);
        }

        if (!newStr)
        {
            PAL_Free(arr->data);
            arr->data = NULL;
            arr->size = 0;
            return -1;
        }
        memcpy(newStr+4, (*str) + 4, skipSize-4);
        PAL_Free(*str);
        *str = newStr;
    }

    start = *str;
    {
        unsigned char b1 = (totalSize & 0xFF000000) >> 24;
        unsigned char b2 = (totalSize & 0x00FF0000) >> 16;
        unsigned char b3 = (totalSize & 0x0000FF00) >> 8;
        unsigned char b4 = (totalSize & 0x000000FF);
        (*str)[0] = b1;
        (*str)[1] = b2;
        (*str)[2] = b3;
        (*str)[3] = b4;
        (*str) += skipSize;
    }

    for (i = 0; i < size; i++)
    {
        **str = ((unsigned char*)data)[i];
        (*str)++;
    }

    *str = start;
    arr->size = totalSize;

    return 0;
}

MI_Result MI_CALL Instance_SetElementFromStringA(
    MI_Instance* self_,
    const ZChar* name,
    const ZChar** data,
    MI_Uint32 size,
    MI_Uint32 msgFlags)
{
    Instance* self = (Instance*)self_;
    MI_Type type = MI_BOOLEAN;
    MI_Value v;
    MI_Result result = MI_RESULT_OK;
    MI_Uint32 flags = 0;

    /* Clear value first */
    memset(&v, 0, sizeof(v));

    /* Check arguments */
    if (!self || !name || !data)
    {
        /* return instead of goto failed: 'v' is not initialized yet */
        return MI_RESULT_INVALID_PARAMETER;
    }

    /* Obtain type of named property */
    result = MI_Instance_GetElement(self_, name, NULL, &type, NULL, NULL);
    if (result != MI_RESULT_OK)
    {
        /* return instead of goto failed: 'v' is not initialized yet */
        return result;
    }

    /* handling octet uint8 string */
    if (type == MI_UINT8A)
    {
        MI_Type qType;
        MI_Value qValue;
        MI_Uint32 qFlags, qIndex;
        MI_QualifierSet qSet;
        MI_Class * schema = NULL;

        MI_Result result = Class_New(
            self->classDecl,
            NULL,
            NULL,
            &schema);
        if (result != MI_RESULT_OK || schema == NULL)
        {
            if (schema)
                MI_Class_Delete(schema);
            return result;
        }

        result = MI_Class_GetElement(schema, name, NULL, NULL, &type, NULL, &qSet, NULL, NULL);
        if (result != MI_RESULT_OK)
        {
            MI_Class_Delete(schema);
            return result;
        }

        result = MI_QualifierSet_GetQualifier(&qSet, MI_T("Octetstring"), &qType, &qFlags, &qValue, &qIndex);
        MI_Class_Delete(schema);
        MI_UNUSED(qFlags);
        MI_UNUSED(qIndex);

        //If the qualifier is present and set to "true", this is an OctetString.
        if (result == MI_RESULT_OK && qType == MI_BOOLEAN && qValue.boolean == MI_TRUE
            && ((msgFlags & WSMANFlag) == WSMANFlag))
        {
            size_t sizeIncoming = Tcslen(*data);
            size_t sizeDec = 0;

#if defined(CONFIG_ENABLE_WCHAR)
            void* src = PAL_Calloc(sizeIncoming + 1, sizeof(char));
            if (!src)
            {
                return MI_RESULT_FAILED;
            }

            if (StrWcslcpy((char *)src, *data, sizeIncoming + 1) >= sizeIncoming + 1)
            {
                PAL_Free(src);
                return MI_RESULT_FAILED;
            }
#else
            char * src = (char*) *data;
#endif
            sizeDec = Base64Dec((const void *)src, sizeIncoming, _Base64DecCallback, &v.array);
#if defined(CONFIG_ENABLE_WCHAR)
            PAL_Free(src);
#endif
            if (sizeDec == -1)
            {
                trace_Base64Dec_Failed();
                return MI_RESULT_FAILED;
            }
            // handle an empty array
            else if (v.array.size == 0)
            {
                // prepend length in 4 bytes
                v.uint8a.data = (MI_Uint8*)PAL_Calloc(4, sizeof(MI_Uint8));
                if (!v.uint8a.data)
                {
                    trace_OutOfMemory();
                    return MI_RESULT_FAILED;
                }

               v.uint8a.data[3] = 4;
               v.uint8a.size = 4;
            }

#if !defined(USE_ALLOCATOR)
            flags |= MI_FLAG_ADOPT;
#endif

            result = MI_Instance_SetElement(self_, name, &v, type, flags);

#if defined(USE_ALLOCATOR)
            if (v.array.data)
                PAL_Free(v.array.data);
#endif
            goto done;
        }
    }

    /* Allocate array (allocate extra element for possible empty array) */
    if (type == MI_STRINGA)
    {
        v.array.data = (ZChar**)data;
        v.array.size = size;
    }
    else
    {
        MI_Uint32 esize = (MI_Uint32)Type_SizeOf(Type_ScalarOf(type));
        v.array.data = BAlloc(self->batch, (size + 1) * esize, CALLSITE);

        if (!v.array.data)
        {
            result = MI_RESULT_SERVER_LIMITS_EXCEEDED;
            goto done;
        }

        v.array.size = size;
        flags |= MI_FLAG_ADOPT;
    }

    /* Convert string to array */

    if (type != MI_STRINGA)
    {
        StrToType func = _converters[Type_ScalarOf(type)];
        char* ptr = v.array.data;
        MI_Uint32 i;

        if (!func)
        {
            result = MI_RESULT_FAILED;
            goto done;
        }

        for (i = 0; i < size; i++)
        {
            if ((*func)(data[i], ptr) != 0)
            {
                result = MI_RESULT_INVALID_PARAMETER;
                goto done;
            }

            ptr += Type_SizeOf(Type_ScalarOf(type));
        }
    }

    result = MI_Instance_SetElement(self_, name, &v, type, flags);
    if (result != MI_RESULT_OK)
    {
        goto done;
    }

done:

    if (result && v.array.data && type != MI_STRINGA)
        BFree(self->batch, v.array.data, CALLSITE);

    return result;
}

MI_Result MI_CALL Instance_GetValue(
    MI_Instance* self,
    const ZChar* name,
    void* value,
    MI_Type type)
{
    MI_Result r;
    MI_Value v;
    MI_Type t;
    MI_Uint32 f;

    r = MI_Instance_GetElement(self, name, &v, &t, &f, NULL);

    if (r != MI_RESULT_OK)
        MI_RETURN(r);

    if (t != type)
        MI_RETURN(MI_RESULT_TYPE_MISMATCH);

    if (f & MI_FLAG_NULL)
        MI_RETURN(MI_RESULT_NOT_FOUND);

    if (!value)
        MI_RETURN(MI_RESULT_INVALID_PARAMETER);

    memcpy(value, &v, Type_SizeOf(type));

    MI_RETURN(MI_RESULT_OK);
}

_Use_decl_annotations_
void DatetimeToStr(const MI_Datetime* x, ZChar buf[26])
{
    if (x->isTimestamp)
    {
        const ZChar FMT[] =  MI_T("%04d%02d%02d%02d%02d%02d.%06d%c%03d");
        MI_Sint32 utc = x->u.timestamp.utc;
        Stprintf(buf, 26, FMT,
            x->u.timestamp.year,
            x->u.timestamp.month,
            x->u.timestamp.day,
            x->u.timestamp.hour,
            x->u.timestamp.minute,
            x->u.timestamp.second,
            x->u.timestamp.microseconds,
            utc < 0 ? '-' : '+',
            utc < 0 ? -utc : utc);
    }
    else
    {
        const ZChar FMT[] = MI_T("%08u%02u%02u%02u.%06u:000");
        Stprintf(buf, 26, FMT,
            x->u.interval.days,
            x->u.interval.hours,
            x->u.interval.minutes,
            x->u.interval.seconds,
            x->u.interval.microseconds);
    }
}

int DatetimeToUsec(
    const MI_Datetime* x,
    MI_Uint64* dateTimeAsUsec )
{
    MI_Uint64 tally = 0;    /* Accumulator for converted values*/

    /* Check for NULL input and invalid datetime format */
    if ( !x ||
         !dateTimeAsUsec ||
         x->isTimestamp )
    {
        return -1;
    }

    tally += x->u.interval.seconds;
    tally += x->u.interval.minutes * 60;         /* minutes to seconds */
    tally += x->u.interval.hours * 60 * 60;      /* hours to seconds */
    tally += x->u.interval.days * 24 * 60 * 60;  /* days to seconds */
    tally *= 1000000;                           /* seconds to microseconds */

    *dateTimeAsUsec = x->u.interval.microseconds + tally;
    return 0;
}


ViewCVS 0.9.2