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

File: [OMI] / omi / protocol / Attic / wsbuf.c (download)
Revision: 1.2, Mon Jun 25 18:59:25 2012 UTC (11 years, 11 months ago) by mike
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
FILE REMOVED
1.0.2

/*
**==============================================================================
**
** 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 <common.h>
#include "wsbuf.h"
#include <base/log.h>
#include <base/result.h>
#include <base/instance.h>
#include <base/strings.h>
#include <base/field.h>
#include <base/messages.h>
#include <base/helpers.h>
#include <base/time.h>
#include <base/io.h>
#include <base/base64.h>

#if defined(WSBUF_DISABLE_INLINING)
# include "wsbufinline.h"
#endif

#define T MI_T

#if 0
#define ENABLE_TRACING
#endif

#ifdef  ENABLE_TRACING
#define PRINTF(a) printf a
#else
#define PRINTF(a)
#endif

#define XML_CR MI_T("\n")

/*
**==============================================================================
**
** Local datatypes:
**
**==============================================================================
*/
typedef struct _BUF_FaultItem
{
    const MI_Char* action;
    MI_Uint32 actionSize;
    const char* code; /* sender/receiver */
    const char* subCode; /* wsa:XXX */
    const char* defaultTest;
}
BUF_FaultItem;

typedef struct _BUF_CIMErrorItem
{
    WSBUF_FAULT_CODE faultCode;
    const MI_Char* description;
} 
BUF_CIMErrorItem;

/*
**==============================================================================
**
** Forward declarations:
**
**==============================================================================
*/
static MI_Result _PackInstance(
    WSBuf* buf,
    const MI_Instance* instance,
    MI_Boolean (*filterProperty)(const MI_Char* name, void* data),
    void* filterPropertyData,
    const MI_ClassDecl* castToClassDecl,
    MI_Uint32 flags,
    MI_Boolean embedded);

static MI_Result _PackEPR(
    WSBuf* buf,
    const MI_Instance* instance);

/*
**==============================================================================
**
** Static data:
**
**==============================================================================
*/

static const BUF_FaultItem s_faults[] = {
    /* WSBUF_FAULT_INTERNAL_ERROR */
    {
        LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")),
        "SOAP-ENV:Receiver",
        "wsman:InternalError",
        "The service cannot comply with the request due to internal processing errors."
    },
    /* WSBUF_FAULT_NOT_SUPPORTED */
    {
        LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")),
        "SOAP-ENV:Sender",
        "wsman:UnsupportedFeature",
        "not supported"
    },
    /* WSBUF_FAULT_NOT_UNDERSTOOD */
    {
        LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/08/addressing/fault")),
        "SOAP-ENV:MustUnderstand",
        0,
        "Header not understood"
    },
    /* WSBUF_FAULT_DESTINATION_UNREACHABLE */
    {
        LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/08/addressing/fault")),
        "SOAP-ENV:Sender",
        "wsa:DestinationUnreachable",
        "No route can be determined to reach the destination role defined by the Addressing To header."
    },
    /* WSBUF_FAULT_ACCESS_DENIED */
    {
        LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")),
        "SOAP-ENV:Sender",
        "wsman:AccessDenied",
        "The sender was not authorized to access the resource."
    },
    /* WSBUF_FAULT_ENCODING_LIMIT */
    {
        LIT(MI_T("http://schemas.dmtf.org/wbem/wsman/1/wsman/fault")),
        "SOAP-ENV:Sender",
        "wsman:EncodingLimit",
        "An internal encoding limit was exceeded in a request or would be violated if the message were processed."
    }
};

static const BUF_CIMErrorItem   s_cimerrors[] = {
    /* MI_RESULT_OK = 0, */
    {
        0,
        0
    },
    /* MI_RESULT_FAILED = 1, */
    {
        WSBUF_FAULT_INTERNAL_ERROR,
        MI_T("CIM ERROR:FAILED: A general error occurred, not covered by a more specific error code.")
    },

    /* MI_RESULT_ACCESS_DENIED = 2, */
    {
        WSBUF_FAULT_ACCESS_DENIED,
        MI_T("CIM ERROR:ACCESS_DENIED: Access to a CIM resource is not available to the client.")
    },

    /* MI_RESULT_INVALID_NAMESPACE = 3, */
    {
        WSBUF_FAULT_DESTINATION_UNREACHABLE,
        MI_T("CIM ERROR:INVALID_NAMESPACE: The target namespace does not exist.")
    },

    /* MI_RESULT_INVALID_PARAMETER  = 4,*/
    {
        WSBUF_FAULT_INTERNAL_ERROR,
        MI_T("CIM ERROR:INVALID_PARAMETER: One or more parameter values passed to the method are not valid.")
    },

    /* MI_RESULT_INVALID_CLASS = 5, */
    {
        WSBUF_FAULT_DESTINATION_UNREACHABLE,
        MI_T("CIM ERROR:INVALID_CLASS: The specified class does not exist.")
    },

    /* MI_RESULT_NOT_FOUND = 6,*/
    {
        WSBUF_FAULT_DESTINATION_UNREACHABLE,
        MI_T("CIM ERROR:NOT_FOUND: The requested object cannot be found.")
    },

    /* MI_RESULT_NOT_SUPPORTED = 7, */
    {
        WSBUF_FAULT_NOT_SUPPORTED,
        MI_T("CIM ERROR:NOT_SUPPORTED: The requested operation is not supported.")
    }

#if 0
    /* The operation cannot be invoked because the class has subclasses. */
    MI_RESULT_CLASS_HAS_CHILDREN = 8,

    /* The operation cannot be invoked because the class has instances. */
    MI_RESULT_CLASS_HAS_INSTANCES = 9,

    /* The operation cannot be invoked because the superclass does not exist. */
    MI_RESULT_INVALID_SUPERCLASS = 10,

    /* The operation cannot be invoked because an object already exists. */
    MI_RESULT_ALREADY_EXISTS = 11,

    /* The specified property does not exist. */
    MI_RESULT_NO_SUCH_PROPERTY = 12,

    /* The value supplied is not compatible with the type. */
    MI_RESULT_TYPE_MISMATCH = 13,

    /* The query language is not recognized or supported. */
    MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED = 14,

    /* The query is not valid for the specified query language. */
    MI_RESULT_INVALID_QUERY = 15,

    /* The extrinsic method cannot be invoked. */
    MI_RESULT_METHOD_NOT_AVAILABLE = 16,

    /* The specified extrinsic method does not exist. */
    MI_RESULT_METHOD_NOT_FOUND = 17,

    /* The specified namespace is not empty. */
    MI_RESULT_NAMESPACE_NOT_EMPTY = 20,

    /* The enumeration identified by the specified context is invalid. */
    MI_RESULT_INVALID_ENUMERATION_CONTEXT = 21,

    /* The specified operation timeout is not supported by the CIM Server. */
    MI_RESULT_INVALID_OPERATION_TIMEOUT = 22,

    /* The Pull operation has been abandoned. */
    MI_RESULT_PULL_HAS_BEEN_ABANDONED = 23,

    /* The attempt to abandon a concurrent Pull operation failed. */
    MI_RESULT_PULL_CANNOT_BE_ABANDONED = 24,

    /* Using a filter in the enumeration is not supported by the CIM server. */
    MI_RESULT_FILTERED_ENUMERATION_NOT_SUPPORTED = 25,

    /* The CIM server does not support continuation on error. */
    MI_RESULT_CONTINUATION_ON_ERROR_NOT_SUPPORTED = 26,

    /* The operation failed because server limits were exceeded. */
    MI_RESULT_SERVER_LIMITS_EXCEEDED = 27,

    /* The CIM server is shutting down and cannot process the operation. */
    MI_RESULT_SERVER_IS_SHUTTING_DOWN = 28
#endif
};

/* Encodings for special XML characters */
static const char* s_specialCharEncodings[128] =
{
    "\004&#0;",
    "\004&#1;",
    "\004&#2;",
    "\004&#3;",
    "\004&#4;",
    "\004&#5;",
    "\004&#6;",
    "\004&#7;",
    "\004&#8;",
    "\004&#9;",
    "\005&#10;",
    "\005&#11;",
    "\005&#12;",
    "\005&#13;",
    "\005&#14;",
    "\005&#15;",
    "\005&#16;",
    "\005&#17;",
    "\005&#18;",
    "\005&#19;",
    "\005&#20;",
    "\005&#21;",
    "\005&#22;",
    "\005&#23;",
    "\005&#24;",
    "\005&#25;",
    "\005&#26;",
    "\005&#27;",
    "\005&#28;",
    "\005&#29;",
    "\005&#30;",
    "\005&#31;",
    "\001 ",
    "\001!",
    "\006&quot;",
    "\001#",
    "\001$",
    "\001%",
    "\005&amp;",
    "\006&apos;",
    "\001(",
    "\001)",
    "\001*",
    "\001+",
    "\001,",
    "\001-",
    "\001.",
    "\001/",
    "\0010",
    "\0011",
    "\0012",
    "\0013",
    "\0014",
    "\0015",
    "\0016",
    "\0017",
    "\0018",
    "\0019",
    "\001:",
    "\001;",
    "\004&lt;",
    "\001=",
    "\004&gt;",
    "\001?",
    "\001@",
    "\001A",
    "\001B",
    "\001C",
    "\001D",
    "\001E",
    "\001F",
    "\001G",
    "\001H",
    "\001I",
    "\001J",
    "\001K",
    "\001L",
    "\001M",
    "\001N",
    "\001O",
    "\001P",
    "\001Q",
    "\001R",
    "\001S",
    "\001T",
    "\001U",
    "\001V",
    "\001W",
    "\001X",
    "\001Y",
    "\001Z",
    "\001[",
    "\001\\",
    "\001]",
    "\001^",
    "\001_",
    "\001`",
    "\001a",
    "\001b",
    "\001c",
    "\001d",
    "\001e",
    "\001f",
    "\001g",
    "\001h",
    "\001i",
    "\001j",
    "\001k",
    "\001l",
    "\001m",
    "\001n",
    "\001o",
    "\001p",
    "\001q",
    "\001r",
    "\001s",
    "\001t",
    "\001u",
    "\001v",
    "\001w",
    "\001x",
    "\001y",
    "\001z",
    "\001{",
    "\001|",
    "\001}",
    "\001~",
    "\006&#127;",
};

/* This table idnetifies special XML characters. */
static const char s_specialChars[256] =
{
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
};

/*
**==============================================================================
**
** Local definitions:
**
**==============================================================================
*/
MI_INLINE MI_Boolean _Field_GetExists(
    const void* field, 
    MI_Type type)
{
    return Field_GetExists((const Field*)field, type);
}

static MI_Result _ReallocPage(
    WSBuf* buf,
    MI_Uint32 newSize)
{
    Page* new_page;

    /* round up to next 1k */
#define WSMAN_BUF_CAPACITY 1024
    newSize = ((newSize + WSMAN_BUF_CAPACITY) / WSMAN_BUF_CAPACITY)  * WSMAN_BUF_CAPACITY;
    new_page = (Page*)realloc(buf->page, sizeof(Page) + newSize);

    if (!new_page)
        return MI_RESULT_FAILED;

    buf->page = new_page;
    buf->page->u.s.size = newSize;
    return MI_RESULT_OK;
}

#if 0
#if (MI_CHAR_TYPE == 1)
#define FIRST_HIGH_SURROGATE  0xD800
#define LAST_HIGH_SURROGATE   0xDBFF

static void _UTF16toUTF8(
    MI_Char16 c,
    char* s)
{
    static const MI_Uint8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
    MI_Uint8* tgt = (MI_Uint8*)s;
    MI_Uint32 numberOfBytes;

    /* not a valid single char */
    if (c >= FIRST_HIGH_SURROGATE
        && c <= LAST_HIGH_SURROGATE)
    {
        s[0] = '?';
        s[1] = 0;
        return;
    }

    if (c < 0x80)
    {
        numberOfBytes = 1;
    }
    else if (c < 0x800)
    {
        numberOfBytes = 2;
    }
    else 
    {
        numberOfBytes = 3;
    }

    tgt += numberOfBytes;

    switch (numberOfBytes)
    {
        case 3:
        *--tgt = (MI_Uint8)((c | 0x80) & 0xBF);
        c >>= 6;
        case 2:
        *--tgt = (MI_Uint8)((c | 0x80) & 0xBF);
        c >>= 6;
        case 1:
        *--tgt =  (MI_Uint8)(c | firstByteMark[numberOfBytes]);
    }
}
#endif
#endif

/*
**==============================================================================
**
** Public API:
**
**==============================================================================
*/
MI_Result WSBuf_Init(
    WSBuf* buf,
    MI_Uint32 initialSize)
{
    buf->page = (Page*)malloc(sizeof(Page) + initialSize);
    buf->position = 0;

    if (!buf->page)
    {
        return MI_RESULT_FAILED;
    }

    buf->page->u.s.size = initialSize;
    buf->page->u.s.next = 0;
    /* Put empty string inside */
    ((MI_Char*)(buf->page +1))[0] = 0;
    return MI_RESULT_OK;
}

MI_Result WSBuf_Destroy(
    WSBuf* buf)
{
    if (buf->page)
        free(buf->page);

    return MI_RESULT_OK;
}

#if (MI_CHAR_TYPE == 1)
Page* WSBuf_StealPage(
    WSBuf* buf)
{
    Page* res = buf->page;

    if (!res)
        return 0;

    buf->page = 0;
    res->u.s.size = buf->position;
    buf->position = 0;

    return res;
}
#else
Page* WSBuf_StealPage(
    WSBuf* buf)
{

    if (!buf->page)
        return 0;

    /* convert wchar_t to utf-8 
        unfortunately, Windows does not support wchat -> utf8 conversion in crt */

    {
        Page* res;
        const MI_Char* text = ((MI_Char*)(buf->page +1));
        int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, 0, NULL);

        if (size == 0)
            goto failed;

        res = (Page*)malloc(sizeof(Page) + size);

        if (!res)
            goto failed;

        if (WideCharToMultiByte(CP_UTF8, 0, text, -1, (char*)(res + 1), size, 0, NULL) == 0) 
        {
            free(res);
            goto failed;
        }

        res->u.s.size = size - 1;
        res->u.s.next = 0;

        free(buf->page);
        buf->page = 0;
        buf->position = 0;
        return res;
    }

failed:
    free(buf->page);
    buf->page = 0;
    return 0;
}
#endif

MI_Result WSBuf_AddUint32(
    WSBuf* buf,
    MI_Uint32 x)
{
    MI_Char tmp[12];
    size_t size;
    const MI_Char* s = Uint32ToZStr(tmp, x, &size);
    return WSBuf_AddLit(buf, s, (MI_Uint32)size);
}

MI_Result __WSBuf_AddLit(
    WSBuf* buf,
    const MI_Char* str,
    MI_Uint32 size)
{
    MI_Uint32 n = (size + 1) * sizeof(MI_Char);

    /* Extend buffer (WSBuf_AddLit determined it was too small) */
    if (_ReallocPage(buf, n + buf->position) != MI_RESULT_OK)
        return MI_RESULT_FAILED;

    /* Add string */
    {
        char* data = ((char*)(buf->page+1)) + buf->position;
        memcpy( data, str, n - sizeof(MI_Char));
        ((MI_Char*)data)[size] = 0;

        buf->position += n - sizeof(MI_Char);
    }

    return MI_RESULT_OK;
}

/* Add string with proper xml encoding */
MI_Result WSBuf_AddString(
    WSBuf* buf,
    const MI_Char* str)
{
#if (MI_CHAR_TYPE == 1)
    /* Process leading non-special characters in the hope that little will
     * be left over to be encoded the expensive way below this block.
     */
    {
        const unsigned char* start = (const unsigned char*)str;
        const unsigned char* p = start;

        while (!s_specialChars[*p])
            p++;

        if (p != start)
        {
            if (WSBuf_AddLit(buf, (const char*)start, (MI_Uint32)(p - start)))
                return MI_RESULT_FAILED;

            str = (const char*)p;
        }

        if (!*str)
            return MI_RESULT_OK;
    }
#endif

    /* Now encode what remains (starting with first special char hit above) */
    {
        /*MI_Uint32 size = (MI_Uint32)((MI_Strlen(str) + 1)*sizeof(MI_Char));*/
        MI_Char* pos = (MI_Char*)(((char*)(buf->page +1)) + buf->position);
        MI_Char* end = (MI_Char*)(((char*)(buf->page +1)) + buf->page->u.s.size);

        /* Add reamingin characters (next character is special) */
        while (*str)
        {
            const MI_Char* item;
            size_t size_chars;
            MI_Uint32 c = (MI_Uint32)(MI_Sint16)*str;

            /* if c is ascii ?*/
            if (c < 128)
            {
                /* First byte is the length */
                item = s_specialCharEncodings[c] + 1;
                size_chars = s_specialCharEncodings[c][0];
            }
            else
            {
                item = str;
                size_chars = 1;
            }

            /* Extend buffer if needed */
            if ( (size_t)(end - pos) <= (size_chars + 1))
            {
                size_t current_pos = 
                    (pos - ((MI_Char*)(buf->page +1))) * sizeof(MI_Char);

                if (_ReallocPage(buf, (MI_Uint32)(buf->page->u.s.size + size_chars * sizeof(MI_Char))) != MI_RESULT_OK)
                    return MI_RESULT_FAILED;

                pos = (MI_Char*)(((char*)(buf->page +1)) + current_pos);
                end = (MI_Char*)(((char*)(buf->page +1)) + buf->page->u.s.size);
            }

            if (1 == size_chars)
                *pos = *item;
            else
                memcpy( pos, item, size_chars * sizeof(MI_Char));

            pos += size_chars;
            str++;
        }

        buf->position = (MI_Uint32)((pos - ((MI_Char*)(buf->page +1))) * sizeof(MI_Char));

        /* put \0 at the end */
        ((MI_Char*)(((char*)(buf->page +1)) + buf->position))[0] = 0;

        return MI_RESULT_OK;
    }
}

#if (MI_CHAR_TYPE != 1)
MI_Result WSBuf_AddCharStringNoEncoding(
    WSBuf* buf,
    const char* str)
{
    return WSBuf_AddCharLit(buf, str, (MI_Uint32)strlen(str));
}

MI_Result WSBuf_AddCharLit(
    WSBuf* buf,
    const char* str,
    MI_Uint32 size_)
{
    MI_Uint32 size = (MI_Uint32)((size_ + 1)*sizeof(MI_Char));

    /* Extend buffer if needed */
    if (size + buf->position > buf->page->u.s.size &&
        _ReallocPage(buf, size + buf->position) != MI_RESULT_OK)
        return MI_RESULT_FAILED;

    {
        MI_Char* data = (MI_Char*)(((char*)(buf->page +1)) + buf->position);
        MI_Uint32 i;

        for (i = 0; i < size_; i++)
        {
            *data++ = *str++;
        }
        buf->position += size - sizeof(MI_Char);
    }

    return MI_RESULT_OK;
}

#endif

/* Callback to tag writer:
    allows to write properties for both values/EPRs with the same routine */
typedef MI_Result (*PropertyTagWriter)(
    WSBuf* buf,
    const MI_Char* name,
    MI_Boolean start);

INLINE MI_Result PropertyTagWriter_PropStart(
    WSBuf* buf,
    const MI_Char* name)
{
    MI_Uint32 n = (MI_Uint32)Zlen(name);

    if (MI_RESULT_OK != WSBuf_AddLit3(buf, '<', 'p', ':') ||
        MI_RESULT_OK != WSBuf_AddLit(buf, name, n) ||
        MI_RESULT_OK != WSBuf_AddLit1(buf,'>'))
    {
        return MI_RESULT_FAILED;
    }

    return MI_RESULT_OK;
}

INLINE MI_Result PropertyTagWriter_PropEnd(
    WSBuf* buf,
    const MI_Char* name)
{
    MI_Uint32 n = (MI_Uint32)Zlen(name);

    if (MI_RESULT_OK != WSBuf_AddLit4(buf, '<', '/', 'p', ':') || 
        MI_RESULT_OK != WSBuf_AddLit(buf, name, n) ||
        MI_RESULT_OK != WSBuf_AddLit2(buf, '>', '\n'))
    {
        return MI_RESULT_FAILED;
    }

    return MI_RESULT_OK;
}

static MI_Result PropertyTagWriter_Prop(
    WSBuf* buf,
    const MI_Char* name,
    MI_Boolean start)
{
    if (start)
        return PropertyTagWriter_PropStart(buf, name);
    else
        return PropertyTagWriter_PropEnd(buf, name);
}

static MI_Result PropertyTagWriter_EPR(
    WSBuf* buf,
    const MI_Char* name,
    MI_Boolean start)
{
    if (start)
    {
        if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("<wsman:Selector Name=\""))) ||
            MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,name) ||
            MI_RESULT_OK != WSBuf_AddLit2(buf, '"', '>')
            )
            return MI_RESULT_FAILED;
    }
    else
    {
        if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("</wsman:Selector>") XML_CR)) 
            )
            return MI_RESULT_FAILED;
    }

    return MI_RESULT_OK;
}

static MI_Result _PackFieldNil(
    WSBuf* buf,
    const MI_Char* name)
{
    if ( MI_RESULT_OK != WSBuf_AddLit3(buf, '<', 'p', ':') ||
        MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,name) ||
        MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T(" xsi:nil=\"true\"/>") XML_CR)) )
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static int _Base64Callback(
    const char* data, 
    size_t size, 
    void* callbackData)
{
    WSBuf* buf = callbackData;
    return WSBuf_AddLit(buf, data, size) == MI_RESULT_OK ? 0 : -1;
}

static MI_Result _PackFieldOctetString(
    WSBuf* buf,
    const MI_Char* name,
    const MI_Uint8* data,
    size_t size)
{
    /* Validate first 4 bytes which contain the length then remove them */
    {
        size_t length = 0;

        if (size < 4)
            return MI_RESULT_FAILED;

        length |= data[0] << 24;
        length |= data[1] << 16;
        length |= data[2] << 8;
        length |= data[3];

        if (length != size)
            return MI_RESULT_FAILED;

        data += 4;
        size -= 4;
    }

    if (WSBuf_AddLit3(buf, '<', 'p', ':') != MI_RESULT_OK)
        return MI_RESULT_FAILED;

    if (WSBuf_AddStringNoEncoding(buf, name) != MI_RESULT_OK)
        return MI_RESULT_FAILED;

    if (WSBuf_AddLit(buf,
        LIT(MI_T(" xsi:type=\"cim:cimBase64Binary\">"))) != MI_RESULT_OK)
    {
        return MI_RESULT_FAILED;
    }

    if (Base64Enc(data, size, _Base64Callback, buf) != 0)
        return MI_RESULT_FAILED;

    if (PropertyTagWriter_PropEnd(buf, name) != MI_RESULT_OK)
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static MI_Result _PackFieldString(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    const MI_Char* value)
{
    if ( MI_RESULT_OK != writer(buf,name,MI_TRUE) ||
        MI_RESULT_OK != WSBuf_AddString(buf,value) ||
        MI_RESULT_OK != writer(buf,name,MI_FALSE)
        )
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static MI_Result _PackFieldStringLit(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    const MI_Char* value,
    MI_Uint32 valueSize)
{
    if ( MI_RESULT_OK != writer(buf,name,MI_TRUE) ||
        MI_RESULT_OK != WSBuf_AddLit(buf,value,valueSize) ||
        MI_RESULT_OK != writer(buf,name,MI_FALSE)  
        )
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static MI_Result _PackFieldEmbeddedInstance(
    WSBuf* buf,
    const MI_Char* name,
    const MI_Instance* value)
{
    if ( MI_RESULT_OK != PropertyTagWriter_PropStart(buf,name) ||
        MI_RESULT_OK != _PackInstance(buf,value,NULL,NULL,0,WSMAN_ObjectFlag,MI_TRUE) ||
        MI_RESULT_OK != PropertyTagWriter_PropEnd(buf,name)  
        )
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static MI_Result _PackFieldRef(
    WSBuf* buf,
    const MI_Char* name,
    const MI_Instance* value)
{
    if ( MI_RESULT_OK != PropertyTagWriter_PropStart(buf,name) ||
        MI_RESULT_OK != _PackEPR(buf,value) ||
        MI_RESULT_OK != PropertyTagWriter_PropEnd(buf,name)  
        )
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static MI_Result _PackFieldUint32(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    MI_Uint32 value)
{
    MI_Char tmp[11];
    size_t size;
    const MI_Char* str = Uint32ToZStr(tmp, value, &size);
    return _PackFieldStringLit(buf,writer, name, str, (MI_Uint32)size);
}

static MI_Result _PackFieldUint64(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    MI_Uint64 value)
{
    MI_Char tmp[21];
    size_t size;
    const MI_Char* str = Uint64ToZStr(tmp, value, &size);
    return _PackFieldStringLit(buf, writer, name, str, (MI_Uint32)size);
}

static MI_Result _PackFieldSint32(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    MI_Sint32 value)
{
    MI_Char s[24];

    MI_Sint32 size = Szprintf(s, MI_COUNT(s), MI_T("%d"), value);
    return _PackFieldStringLit(buf,writer,name,s,size);
}

static MI_Result _PackFieldSint64(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    MI_Sint64 value)
{
    MI_Char s[24];

    MI_Sint32 size = Szprintf(s, MI_COUNT(s), SINT64_FMT_T, value);
    return _PackFieldStringLit(buf,writer,name,s,size);
}

static MI_Result _PackFieldReal64(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    MI_Real64 value)
{
    MI_Char s[24];

    MI_Sint32 size = Szprintf(s, MI_COUNT(s), MI_T("%g"), value);
    return _PackFieldStringLit(buf,writer,name,s,size);
}

static MI_Result _PackFieldDatetime(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    const MI_Datetime* p)
{
    MI_Char tmp[64];
    FormatWSManDatetime(p, tmp);
    return _PackFieldStringLit(buf, writer, name, tmp, (MI_Uint32)Zlen(tmp));
}

static MI_Result _PackValue(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    const void* field, 
    MI_Type type)
{
    switch(type)
    {
        case MI_BOOLEAN:
        {
            MI_Boolean* f = (MI_Boolean*)field;

            if (*f)
                return _PackFieldStringLit(buf,writer,name,LIT(MI_T("TRUE")));
            else
                return _PackFieldStringLit(buf,writer,name,LIT(MI_T("FALSE")));
        }
        case MI_UINT8:
        {
            MI_Uint8* f = (MI_Uint8*)field;

            return _PackFieldUint32(buf,writer,name,*f);
        }
        case MI_UINT16:
        {
            MI_Uint16* f = (MI_Uint16*)field;

            return _PackFieldUint32(buf,writer,name,*f);
        }
        case MI_UINT32:
        {
            MI_Uint32* f = (MI_Uint32*)field;

            return _PackFieldUint32(buf,writer,name,*f);
        }
        case MI_UINT64:
        {
            MI_Uint64* f = (MI_Uint64*)field;

            return _PackFieldUint64(buf,writer,name,*f);
        }
        case MI_SINT8:
        {
            MI_Sint8* f = (MI_Sint8*)field;

            return _PackFieldSint32(buf,writer,name,*f);
        }
        case MI_SINT16:
        {
            MI_Sint16* f = (MI_Sint16*)field;

            return _PackFieldSint32(buf,writer,name,*f);
        }
        case MI_SINT32:
        {
            MI_Sint32* f = (MI_Sint32*)field;

            return _PackFieldSint32(buf,writer,name,*f);
        }
        case MI_SINT64:
        {
            MI_Sint64* f = (MI_Sint64*)field;

            return _PackFieldSint64(buf,writer,name,*f);
        }
        case MI_REAL32:
        {
            MI_Real32* f = (MI_Real32*)field;

            return _PackFieldReal64(buf,writer,name,*f);
        }
        case MI_REAL64:
        {
            MI_Real64* f = (MI_Real64*)field;

            return _PackFieldReal64(buf,writer,name,*f);
        }
        case MI_DATETIME:
        {
            MI_Datetime* f = (MI_Datetime*)field;

            return _PackFieldDatetime(buf,writer,name,&*f);
        }
        case MI_CHAR16:
        {
            MI_Char16* f = (MI_Char16*)field;
#if 0
#if (MI_CHAR_TYPE == 1)
            char s[6];
            memset(s,0,sizeof(s));

            _UTF16toUTF8(*f,s);
#else
            /* whcar_t - 
            steal page will translate it */
            wchar_t s[2] = {0, 0};

            s[0] = *f;
#endif

            /* ATTN: convert it to utf8 and encode as a string */
            return _PackFieldString(buf,writer,name,s);
#else
            return _PackFieldUint32(buf,writer,name,(MI_Uint32)*f);
#endif
        }
        case MI_INSTANCE:
        {
            MI_Instance** f = (MI_Instance**)field;

            return _PackFieldEmbeddedInstance(buf,name,*f);
        }
        case MI_REFERENCE:
        {
            MI_Instance** f = (MI_Instance**)field;

            return _PackFieldRef(buf,name,*f);
        }
        case MI_STRING:
        {
            MI_String* f = (MI_String*)field;

            return _PackFieldString(buf,writer,name,*f);
        }
        default:
            break;
    }

    return MI_RESULT_OK;
}

static MI_Result _PackField(
    WSBuf* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    const void* field, 
    MI_Type type,
    MI_Boolean isOctetString)
{
    /* Check if value is null */
    if (!_Field_GetExists(field, type))
        return _PackFieldNil(buf, name);

    /* Check if type is array:
        Arrays are encoded the same way regular instances are 
        with repeating instance as many times as many elements are in array */
    if (type & MI_ARRAY_BIT)
    {
        if (isOctetString && type == MI_UINT8A)
        {
            MI_Uint8AField* f = (MI_Uint8AField*)field;
            return _PackFieldOctetString(buf, name, f->value.data, 
                f->value.size);
        }

        /* ATTN: STRING OctetString not handled! */

        {
            MI_ArrayField* f = (MI_ArrayField*)field;
            MI_Uint32 i;
            MI_Type stype = type & ~MI_ARRAY_BIT;
            char* currentValue = (char*)f->value.data;

            for (i = 0; i < f->value.size; i++)
            {
                if (_PackValue(
                    buf, 
                    writer, 
                    name, 
                    currentValue, 
                    stype) != MI_RESULT_OK)
                {
                    return MI_RESULT_FAILED;
                }

                currentValue += Type_SizeOf(stype);
            }

            return MI_RESULT_OK;
        }
    }

    return _PackValue(buf, writer, name, field, type);
}

static MI_Result _PackEPR(
    WSBuf* buf,
    const MI_Instance* instance)
{
    Instance* self = (Instance*)instance;
    const MI_ClassDecl* cd = self->classDecl;
    MI_Uint32 i;

    /* Put EPR header */
    if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>") XML_CR
            MI_T("<wsa:ReferenceParameters>") XML_CR 
            MI_T("<wsman:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/") )) ||
        MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) ||
        MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("</wsman:ResourceURI>") XML_CR 
            MI_T("<wsman:SelectorSet>") XML_CR )) )
        return MI_RESULT_FAILED;

    /* namespace (if present)*/
    if (self->nameSpace)
    {
    }

    /* Put properties */
    for ( i = 0; i < cd->numProperties; i++ )
    {
        const MI_PropertyDecl* pd = cd->properties[i];
        const void* value = (char*)self + pd->offset;

        if ((pd->flags & MI_FLAG_KEY) == 0)
            continue;

        /* skip null values */
        if (!_Field_GetExists(value,(MI_Type)pd->type))
            continue;

        if (_PackValue(
            buf, 
            PropertyTagWriter_EPR, 
            pd->name, value, 
            (MI_Type)pd->type) != MI_RESULT_OK)
        {
            return MI_RESULT_FAILED;
        }
    }

    /* close EPR */
    if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("</wsman:SelectorSet>") XML_CR
            MI_T("</wsa:ReferenceParameters>") XML_CR )) )
        return MI_RESULT_FAILED;

    return MI_RESULT_OK;
}

static MI_Boolean TestOctetStringQualifier(
    const MI_PropertyDecl* pd)
{
    size_t i;

    for (i = 0; i < pd->numQualifiers; i++)
    {
        const MI_Qualifier* q = pd->qualifiers[i];

        if (Zcasecmp(q->name, T("OctetString")) == 0 
            && q->type == MI_BOOLEAN
            && q->value)
        {
            return *((const MI_Boolean*)q->value);
        }
    }

    return MI_FALSE;
}

static MI_Result _PackInstance(
    WSBuf* buf,
    const MI_Instance* instance,
    MI_Boolean (*filterProperty)(const MI_Char* name, void* data),
    void* filterPropertyData,
    const MI_ClassDecl* castToClassDecl,
    MI_Uint32 flags,
    MI_Boolean embedded)
{
    Instance* self = (Instance*)instance;
    const MI_ClassDecl* cd = castToClassDecl ? castToClassDecl : self->classDecl;
    MI_Uint32 i;

    /* Check for null arguments */
    if (!self || !buf)
        MI_RETURN(MI_RESULT_INVALID_PARAMETER);

    /* For Object & EPR, add <Item> tag */
    if ((flags & WSMAN_ObjectAndEPRFlag) == WSMAN_ObjectAndEPRFlag)
    {
        if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("<wsman:Item>") XML_CR)))
            return MI_RESULT_FAILED;
    }

    /* If object was requested */
    if ((flags & WSMAN_ObjectFlag) == WSMAN_ObjectFlag)
    {
        /* Put classname */
        if ( MI_RESULT_OK != WSBuf_AddLit3(buf, '<', 'p', ':') ||
            MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) ||
            MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T(" xmlns:p=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/"))) ||
            MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) ||
            MI_RESULT_OK != WSBuf_AddLit2(buf, '"', '\n'))
            return MI_RESULT_FAILED;

        if (embedded)
        {
            if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T(" xsi:type=\""))) ||
                MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) ||
                MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("_Type\"") XML_CR)))
                return MI_RESULT_FAILED;
        }
        if ( MI_RESULT_OK != WSBuf_AddLit2(buf, '>', '\n'))
            return MI_RESULT_FAILED;

        /* Put properties */
        for ( i = 0; i < cd->numProperties; i++ )
        {
            const MI_PropertyDecl* pd = cd->properties[i];
            const void* value = (char*)self + pd->offset;
            MI_Boolean isOctetString = MI_FALSE;

            if (filterProperty && 
                (*filterProperty)(pd->name, filterPropertyData))
            {
                continue;
            }

            /* Search for OctetString qualifier */

            if (pd->type == MI_UINT8A || pd->type == MI_STRINGA)
                isOctetString = TestOctetStringQualifier(pd);

            /* Pack the field */

            if (_PackField(
                buf, 
                PropertyTagWriter_Prop, 
                pd->name, 
                value, 
                (MI_Type)pd->type,
                isOctetString) != MI_RESULT_OK)
            {
                return MI_RESULT_FAILED;
            }
        }

        /* close class */
        if ( MI_RESULT_OK != WSBuf_AddLit4(buf, '<', '/', 'p', ':') ||
            MI_RESULT_OK != WSBuf_AddStringNoEncoding(buf,cd->name) ||
            MI_RESULT_OK != WSBuf_AddLit2(buf, '>', '\n'))
            return MI_RESULT_FAILED;
    }

    /* If EPR was requested */
    if ((flags & WSMAN_EPRFlag) == WSMAN_EPRFlag)
    {
        if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("<wsa:EndpointReference>") XML_CR)) ||
            MI_RESULT_OK != _PackEPR(buf,instance) ||
            MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("</wsa:EndpointReference>") XML_CR)))
            return MI_RESULT_FAILED;
    }

    /* If EPR was requested */
    if ((flags & WSMAN_CreatedEPRFlag) == WSMAN_CreatedEPRFlag)
    {
        if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("<wxf:ResourceCreated>") XML_CR)) ||
            MI_RESULT_OK != _PackEPR(buf,instance) ||
            MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("</wxf:ResourceCreated>") XML_CR)))
            return MI_RESULT_FAILED;
    }

    /* For Object & EPR, add </Item> tag */
    if ((flags & WSMAN_ObjectAndEPRFlag) == WSMAN_ObjectAndEPRFlag)
    {
        if ( MI_RESULT_OK != WSBuf_AddLit(buf,LIT(MI_T("</wsman:Item>") XML_CR)))
            return MI_RESULT_FAILED;
    }


    return MI_RESULT_OK;
}

MI_Result WSBuf_InstanceToBuf(
    const MI_Instance* instance,
    MI_Boolean (*filterProperty)(const MI_Char* name, void* data),
    void* filterPropertyData,
    const MI_ClassDecl* castToClassDecl,
    Batch* batch,
    MI_Uint32 flags,
    void** ptrOut,
    MI_Uint32* sizeOut)
{
    WSBuf buf;
    MI_Result r;
    Page* page;

    r = WSBuf_Init(&buf,1024);

    if (MI_RESULT_OK != r)
        return r;

    r = _PackInstance(&buf, instance, filterProperty, 
        filterPropertyData, castToClassDecl, flags,MI_FALSE);

    if (MI_RESULT_OK != r)
    {
        WSBuf_Destroy(&buf);
        return r;
    }

    page = WSBuf_StealPage(&buf);
    Batch_AttachPage(batch, page);

    *ptrOut = page + 1;
    *sizeOut = (MI_Uint32)page->u.s.size;
    return MI_RESULT_OK;
}

void WSBuf_GenerateMessageID(
    MI_Char msgID[WS_MSG_ID_SIZE])
{
    //WS-Management qualifies the use of wsa:MessageID and wsa:RelatesTo as follows:
    //R5.4.6.4-1: The MessageID and RelatesTo URIs may be of any format, as long as they are valid
    //URIs according to RFC 3986. Two URIs are considered different even if the characters in the
    //URIs differ only by case.
    //The following two formats are endorsed by this specification. The first is considered a best
    //practice because it is backed by RFC 4122:
    //urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    //or
    //uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    //In these formats, each x is an uppercase or lowercase hexadecimal digit (lowercase is required
    //by RFC 4122); there are no spaces or other tokens. The value may be a DCE-style universally
    //unique identifier (UUID) with provable uniqueness properties in this format, however, it is not
    //necessary to have provable uniqueness properties in the URIs used in the wsa:MessageID and
    //wsa:RelatesTo headers.
    //Regardless of format, the URI should not exceed the maximum defined in R13.1-6.
    //UUIDs have a numeric meaning as well as a string meaning, and this can lead to confusion. A UUID
    //in lowercase is a different URI from the same UUID in uppercase. This is because URIs are case1619
    //tive. If a UUID is converted to its decimal equivalent the case of the original characters is lost.
    //WS-Management works with the URI value itself, not the underlying decimal equivalent
    //representation. Services are free to interpret the URI in any way, but are not allowed to alter the case
    //usage when repeating the message or any of the MessageID values in subsequent messages.
    //The RFC 4122 requires the digits to be lowercase, which is the responsibility of the client. The service
    //simply processes the values as URI values and is not required to analyze the URI for correctness or
    //compliance. The service replicates the client usage in the wsa:RelatesTo reply header and is not
    //allowed to alter the case usage.
    //R5.4.6.4-2: The MessageID should be generated according to any algorithm that ensures that no
    //two MessageIDs are repeated. Because the value is treated as case-sensitive (R5.4.6.4-1),
    //confusion can arise if the same value is reused differing only in case. As a result, the service shall
    //not create or employ MessageID values that differ only in case. For any message transmitted by
    //the service, the MessageID shall not be reused.

    static MI_Uint64  s1, s2;

    if (!s1)
        Time_Now(&s1);

    s2++;

    /* ADC */
    if (!s2)
        s1++;

    Szprintf(msgID, WS_MSG_ID_SIZE,
        MI_T("uuid:%08X-%04X-%04X-%04X-%08X%04X"),
        (MI_Uint32)(s1 & 0xFFFFFFFF),
        (MI_Uint32)((s1 >> 32) & 0xFFFF),
        (MI_Uint32)((s1 >> 48) & 0xFFFF),
        (MI_Uint32)((s2 >> 48) & 0xFFFF),
        (MI_Uint32)(s2 & 0xFFFFFFFF),
        (MI_Uint32)((s2 >> 32) & 0xFFFF) );
}

MI_Result WSBuf_CreateSoapResponseHeader(
    WSBuf   *buf,
    const MI_Char*  action,
    MI_Uint32       actionSize,
    const char*     relatesTo)
{
    MI_Char msgID[WS_MSG_ID_SIZE];

    /* Response header */
    if (MI_RESULT_OK != WSBuf_AddLit(buf, 
        LIT(
        MI_T("<SOAP-ENV:Envelope ")         
        MI_T("xmlns:SOAP-ENV=\"http://www.w3.org/2003/05/soap-envelope\" ")
        MI_T("xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" ")
        MI_T("xmlns:wsen=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\" ")
        MI_T("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ")
        MI_T("xmlns:wsmb=\"http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd\" ")
        MI_T("xmlns:wsman=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\" ")
        MI_T("xmlns:wxf=\"http://schemas.xmlsoap.org/ws/2004/09/transfer\" ")
        MI_T("xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" ")
        MI_T("xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\" >")
        XML_CR
        MI_T("<SOAP-ENV:Header>")                                                       XML_CR
        MI_T("<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>")    XML_CR
        MI_T("<wsa:Action>")))  )
    {
        goto failed;
    }

    if (MI_RESULT_OK != WSBuf_AddLit(buf, action, actionSize))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(buf, 
            LIT(MI_T("</wsa:Action>")           XML_CR
            MI_T("<wsa:MessageID>" ))))
        goto failed;

    /* Generate new uniqueue msg id */
    WSBuf_GenerateMessageID(msgID);

    if (MI_RESULT_OK != WSBuf_AddLit(buf, msgID, WS_MSG_ID_SIZE - 1))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(buf,
        LIT(MI_T("</wsa:MessageID>")    XML_CR)))
        goto failed;

    if (relatesTo)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(buf,
            LIT(MI_T("<wsa:RelatesTo>"))))
            goto failed;

        if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(buf, relatesTo))
            goto failed;

        if (MI_RESULT_OK != WSBuf_AddLit(buf,
            LIT(MI_T("</wsa:RelatesTo>")        XML_CR)))
            goto failed;
    }

    return MI_RESULT_OK;

failed:
    return MI_RESULT_FAILED;
}



Page* WSBuf_CreateFaultResponsePage(
    WSBUF_FAULT_CODE faultCode,
    const char* notUnderstoodTag,
    const char* requestMessageID,
    const MI_Char* descriptionText)
{
    WSBuf   outBuf;
    const BUF_FaultItem* fault;

    if ( ((MI_Uint32)faultCode) >= MI_COUNT(s_faults))
    {
        fault = s_faults + 0; /* internal error */
    }
    else
    {
        fault = s_faults + (MI_Uint32)faultCode;
    }


    /* prepare soap response with error */
    if (WSBuf_Init(&outBuf, 1024) != MI_RESULT_OK)
        return 0;

    /* fault header */
    if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
        fault->action, fault->actionSize, requestMessageID))
        goto failed;

    if (notUnderstoodTag)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBuf, 
                LIT(MI_T("<SOAP-ENV:NotUnderstood qname=\""))))
            goto failed;

        if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, notUnderstoodTag ))
            goto failed;

        if (MI_RESULT_OK != WSBuf_AddLit3(&outBuf, '"', '/', '>'))
            goto failed;
    }

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(
        MI_T("</SOAP-ENV:Header>")      XML_CR  XML_CR
        MI_T("<SOAP-ENV:Body>")         XML_CR
        MI_T("<SOAP-ENV:Fault>")        XML_CR
        MI_T("<SOAP-ENV:Code>")         XML_CR
        MI_T("<SOAP-ENV:Value>")))  )
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, fault->code))
        goto failed;
        //SOAP-ENV:Sender

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(MI_T("</SOAP-ENV:Value>")       XML_CR)))
        goto failed;

    if (fault->subCode)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
            LIT(MI_T("<SOAP-ENV:Subcode>")      XML_CR
            MI_T("<SOAP-ENV:Value>"))))
            goto failed;

        if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, fault->subCode))
            goto failed;

        if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
            LIT(MI_T("</SOAP-ENV:Value>")       XML_CR
            MI_T("</SOAP-ENV:Subcode>")     XML_CR)))
            goto failed;
    }

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(MI_T("</SOAP-ENV:Code>")        XML_CR
        MI_T("<SOAP-ENV:Reason>")       XML_CR
        MI_T("<SOAP-ENV:Text xml:lang=\"en-US\">"))))
        goto failed;

    if ( descriptionText )
    {
        if (MI_RESULT_OK != WSBuf_AddString(&outBuf, descriptionText))
            goto failed;
    }
    else
    {
        if (MI_RESULT_OK != WSBuf_AddCharStringNoEncoding(&outBuf, fault->defaultTest))
            goto failed;
    }

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT( MI_T("</SOAP-ENV:Text>")      XML_CR
        MI_T("</SOAP-ENV:Reason>")      XML_CR
        MI_T("</SOAP-ENV:Fault>")       XML_CR
        MI_T("</SOAP-ENV:Body>")        XML_CR
        MI_T("</SOAP-ENV:Envelope>")    XML_CR)) )
        goto failed;


    return WSBuf_StealPage(&outBuf);

failed:

    WSBuf_Destroy(&outBuf);
    return 0;
}

Page* WSBuf_CreateReleaseResponsePage(
    const char* requestMessageID)
{
    WSBuf   outBuf;

    /* prepare soap response with error */
    if (WSBuf_Init(&outBuf, 1024) != MI_RESULT_OK)
        return 0;

    /* fault header */
    if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
        LIT(MI_T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/ReleaseResponse")), 
        requestMessageID))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(
        MI_T("</SOAP-ENV:Header>")      XML_CR  XML_CR
        MI_T("<SOAP-ENV:Body/>")         XML_CR
        MI_T("</SOAP-ENV:Envelope>")    XML_CR)) )
        goto failed;

    return WSBuf_StealPage(&outBuf);

failed:

    WSBuf_Destroy(&outBuf);
    return 0;
}

WSBUF_FAULT_CODE    WSBuf_CIMErrorToWSFault(
    MI_Uint32       cimErrorCode,
    const MI_Char** description )
{
    MI_Uint32 index = cimErrorCode < MI_COUNT(s_cimerrors) ? cimErrorCode : MI_RESULT_FAILED;

    if ( description )
        *description = s_cimerrors[index].description;

    return s_cimerrors[index].faultCode;
}

ViewCVS 0.9.2