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

File: [OMI] / omi / protocol / Attic / wsmanbuffer.c (download)
Revision: 1.1.1.1 (vendor branch), Wed May 30 21:47:49 2012 UTC (12 years, 1 month ago) by mike
Branch: TOG
CVS Tags: OMI_1_0_2_Branch, OMI_1_0_2, OMI_1_0_1_PRE, 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 <common.h>
#include "wsmanbuffer.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>

#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;

typedef struct _Char_Encoding
{
    const MI_Char*  str;
    MI_Uint32       size;
} 
Char_Encoding;

/*
**==============================================================================
**
** Forward declarations:
**
**==============================================================================
*/
static MI_Result _PackInstance(
    WS_Buffer* 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(
    WS_Buffer* 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
};

// Defines encodings of special characters. Just use a 7-bit ASCII character
// as an index into this array to retrieve its string encoding and encoding
// length in bytes.
static const Char_Encoding s_encodedChars127[128] =
{
    {LIT(MI_T("&#0;"))},
    {LIT(MI_T("&#1;"))},
    {LIT(MI_T("&#2;"))},
    {LIT(MI_T("&#3;"))},
    {LIT(MI_T("&#4;"))},
    {LIT(MI_T("&#5;"))},
    {LIT(MI_T("&#6;"))},
    {LIT(MI_T("&#7;"))},
    {LIT(MI_T("&#8;"))},
    {LIT(MI_T("&#9;"))},
    {LIT(MI_T("&#10;"))},
    {LIT(MI_T("&#11;"))},
    {LIT(MI_T("&#12;"))},
    {LIT(MI_T("&#13;"))},
    {LIT(MI_T("&#14;"))},
    {LIT(MI_T("&#15;"))},
    {LIT(MI_T("&#16;"))},
    {LIT(MI_T("&#17;"))},
    {LIT(MI_T("&#18;"))},
    {LIT(MI_T("&#19;"))},
    {LIT(MI_T("&#20;"))},
    {LIT(MI_T("&#21;"))},
    {LIT(MI_T("&#22;"))},
    {LIT(MI_T("&#23;"))},
    {LIT(MI_T("&#24;"))},
    {LIT(MI_T("&#25;"))},
    {LIT(MI_T("&#26;"))},
    {LIT(MI_T("&#27;"))},
    {LIT(MI_T("&#28;"))},
    {LIT(MI_T("&#29;"))},
    {LIT(MI_T("&#30;"))},
    {LIT(MI_T("&#31;"))},
    {LIT(MI_T(" "))},
    {LIT(MI_T("!"))},
    {LIT(MI_T("&quot;"))},
    {LIT(MI_T("#"))},
    {LIT(MI_T("$"))},
    {LIT(MI_T("%"))},
    {LIT(MI_T("&amp;"))},
    {LIT(MI_T("&apos;"))},
    {LIT(MI_T("("))},
    {LIT(MI_T(")"))},
    {LIT(MI_T("*"))},
    {LIT(MI_T("+"))},
    {LIT(MI_T(","))},
    {LIT(MI_T("-"))},
    {LIT(MI_T("."))},
    {LIT(MI_T("/"))},
    {LIT(MI_T("0"))},
    {LIT(MI_T("1"))},
    {LIT(MI_T("2"))},
    {LIT(MI_T("3"))},
    {LIT(MI_T("4"))},
    {LIT(MI_T("5"))},
    {LIT(MI_T("6"))},
    {LIT(MI_T("7"))},
    {LIT(MI_T("8"))},
    {LIT(MI_T("9"))},
    {LIT(MI_T(":"))},
    {LIT(MI_T(";"))},
    {LIT(MI_T("&lt;"))},
    {LIT(MI_T("="))},
    {LIT(MI_T("&gt;"))},
    {LIT(MI_T("?"))},
    {LIT(MI_T("@"))},
    {LIT(MI_T("A"))},
    {LIT(MI_T("B"))},
    {LIT(MI_T("C"))},
    {LIT(MI_T("D"))},
    {LIT(MI_T("E"))},
    {LIT(MI_T("F"))},
    {LIT(MI_T("G"))},
    {LIT(MI_T("H"))},
    {LIT(MI_T("I"))},
    {LIT(MI_T("J"))},
    {LIT(MI_T("K"))},
    {LIT(MI_T("L"))},
    {LIT(MI_T("M"))},
    {LIT(MI_T("N"))},
    {LIT(MI_T("O"))},
    {LIT(MI_T("P"))},
    {LIT(MI_T("Q"))},
    {LIT(MI_T("R"))},
    {LIT(MI_T("S"))},
    {LIT(MI_T("T"))},
    {LIT(MI_T("U"))},
    {LIT(MI_T("V"))},
    {LIT(MI_T("W"))},
    {LIT(MI_T("X"))},
    {LIT(MI_T("Y"))},
    {LIT(MI_T("Z"))},
    {LIT(MI_T("["))},
    {LIT(MI_T("\\"))},
    {LIT(MI_T("]"))},
    {LIT(MI_T("^"))},
    {LIT(MI_T("_"))},
    {LIT(MI_T("`"))},
    {LIT(MI_T("a"))},
    {LIT(MI_T("b"))},
    {LIT(MI_T("c"))},
    {LIT(MI_T("d"))},
    {LIT(MI_T("e"))},
    {LIT(MI_T("f"))},
    {LIT(MI_T("g"))},
    {LIT(MI_T("h"))},
    {LIT(MI_T("i"))},
    {LIT(MI_T("j"))},
    {LIT(MI_T("k"))},
    {LIT(MI_T("l"))},
    {LIT(MI_T("m"))},
    {LIT(MI_T("n"))},
    {LIT(MI_T("o"))},
    {LIT(MI_T("p"))},
    {LIT(MI_T("q"))},
    {LIT(MI_T("r"))},
    {LIT(MI_T("s"))},
    {LIT(MI_T("t"))},
    {LIT(MI_T("u"))},
    {LIT(MI_T("v"))},
    {LIT(MI_T("w"))},
    {LIT(MI_T("x"))},
    {LIT(MI_T("y"))},
    {LIT(MI_T("z"))},
    {LIT(MI_T("{"))},
    {LIT(MI_T("|"))},
    {LIT(MI_T("}"))},
    {LIT(MI_T("~"))},
    {LIT(MI_T("&#127;"))}
};

/* Table used to identify special 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* buf)
{
    if (buf->page)
        free(buf->page);

    return MI_RESULT_OK;
}

#if (MI_CHAR_TYPE == 1)
Page* WSBuf_StealPage(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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)
            {
                item = s_encodedChars127[c].str;
                size_chars = s_encodedChars127[c].size;
            }
            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(
    WS_Buffer* buf,
    const char* str)
{
    return WSBuf_AddCharLit(buf, str, (MI_Uint32)strlen(str));
}

MI_Result WSBuf_AddCharLit(
    WS_Buffer* 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)(
    WS_Buffer* buf,
    const MI_Char* name,
    MI_Boolean start);

INLINE MI_Result PropertyTagWriter_PropStart(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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 MI_Result _PackFieldString(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* 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(
    WS_Buffer* buf,
    PropertyTagWriter writer,
    const MI_Char* name,
    const void* field, 
    MI_Type type)
{
    /* 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)
    {
        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 (MI_RESULT_OK != _PackValue(buf,writer,name,currentValue,stype))
                return MI_RESULT_FAILED;

            currentValue += Type_SizeOf(stype);
        }
        return MI_RESULT_OK;
    }

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

static MI_Result _PackEPR(
    WS_Buffer* 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 (MI_RESULT_OK != _PackValue(buf, PropertyTagWriter_EPR, pd->name, value, (MI_Type)pd->type))
            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_Result _PackInstance(
    WS_Buffer* 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;

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

            if (MI_RESULT_OK != _PackField(buf, PropertyTagWriter_Prop, pd->name, value, (MI_Type)pd->type))
                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)
{
    WS_Buffer 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(
    WS_Buffer   *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)
{
    WS_Buffer   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)
{
    WS_Buffer   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