//%LICENSE////////////////////////////////////////////////////////////////
//
// Licensed to The Open Group (TOG) under one or more contributor license
// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
// this work for additional information regarding copyright ownership.
// Each contributor licenses this file to you under the OpenPegasus Open
// Source License; you may not use this file except in compliance with the
// License.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////
//
// Local routines:
//
//==============================================================================

static size_t _indent = 0;

class Str
{
public:
    Str(const String& s) : _cstr(s.getCString()) { }
    Str(const CIMName& n) : _cstr(n.getString().getCString()) { }
    Str(const CIMNamespaceName& n) : _cstr(n.getString().getCString()) { }
    Str(const Exception& e) : _cstr(e.getMessage().getCString()) { }
    Str(const CIMDateTime& x) : _cstr(x.toString().getCString()) { }
    Str(const CIMObjectPath& x) : _cstr(x.toString().getCString()) { }
    const char* operator*() const { return (const char*)_cstr; }
    operator const char*() const { return (const char*)_cstr; }
private:
    CString _cstr;
};

static void _vout(FILE* os, const char* format, va_list ap)
{
    for (size_t i = 0; i < _indent; i++)
        fprintf(os, "    ");

    vfprintf(os, format, ap);
}

PEGASUS_FORMAT(2, 3)
static void _throw(CIMStatusCode code, const char* format, ...)
{
    char buffer[4096];

    va_list ap;
    va_start(ap, format);
    vsprintf(buffer, format, ap);
    va_end(ap);
    throw CIMException(code, format);
}

static void _line(FILE* os)
{
    fprintf(os, "//");

    for (size_t i = 0; i < 78; i++)
        fputc('=', os);

    fputc('\n', os);
}

PEGASUS_FORMAT(2, 3)
static void _box(FILE* os, const char* format, ...)
{
    _line(os);

    fprintf(os, "//\n");

    fprintf(os, "// ");

    va_list ap;
    va_start(ap, format);
    vfprintf(os, format, ap);
    va_end(ap);

    fputc('\n', os);
    fprintf(os, "//\n");

    _line(os);
}

static void _writeHeaderFile(const String& ns)
{
    const char format[] =
        "\n"
        "#ifndef _%s_namespace_h\n"
        "#define _%s_namespace_h\n"
        "\n"
        "#include <Pegasus/Repository/MRRTypes.h>\n"
        "\n"
        "PEGASUS_NAMESPACE_BEGIN\n"
        "\n"
        "extern const MRRNameSpace %s_namespace;\n"
        "\n"
        "PEGASUS_NAMESPACE_END\n"
        "\n"
        "#endif /* _%s_namespace_h */\n"
        ;

    String path = ns + "_namespace.h";
    FILE* os = fopen(*Str(path), "wb");

    if (!os)
    {
        fprintf(stderr, "cimmofl: failed to open \"%s\" for write\n",
            *Str(path));
        exit(1);
    }

    _box(os, "CAUTION: THIS FILE WAS GENERATED BY CIMMOFL; "
        "PLEASE DO NOT EDIT IT.");
    fprintf(stderr, "\n");

    fprintf(os, format, *Str(ns), *Str(ns), *Str(ns), *Str(ns));

    fclose(os);
}

static String _makeIdent(const String& str)
{
    // Build a legal C identifier from str. Translate all illegal characters
    // to underscores.

    String r;

    for (Uint32 i = 0; i < str.size(); i++)
    {
        Uint16 c = str[i];

        if (c < 127 && (isalnum(c) || c == '_'))
            r.append(c);
        else
            r.append('_');
    }

    return r;
}


static const char* _typeNames[] =
{
    "CIMTYPE_BOOLEAN",
    "CIMTYPE_UINT8",
    "CIMTYPE_SINT8",
    "CIMTYPE_UINT16",
    "CIMTYPE_SINT16",
    "CIMTYPE_UINT32",
    "CIMTYPE_SINT32",
    "CIMTYPE_UINT64",
    "CIMTYPE_SINT64",
    "CIMTYPE_REAL32",
    "CIMTYPE_REAL64",
    "CIMTYPE_CHAR16",
    "CIMTYPE_STRING",
    "CIMTYPE_DATETIME",
    "CIMTYPE_REFERENCE",
    "CIMTYPE_OBJECT",
    "CIMTYPE_INSTANCE",
};

static bool _is_printable(const char* s)
{
    for (; *s; s++)
    {
        if (!isprint(*s))
            return false;
    }

    return true;
}

template<class C>
static void _writeFlags(
    FILE* os,
    const C& c,
    bool isProperty,
    bool isParameter)
{
    // Build up flags mask:

    Uint32 flags = 0;

    if (isProperty)
        flags |= MRR_FLAG_READ;

    if (isParameter)
        flags |= MRR_FLAG_IN;

    for (Uint32 i = 0; i < c.getQualifierCount(); i++)
    {
        CIMConstQualifier cq = c.getQualifier(i);
        const CIMName& qn = cq.getName();

        if (cq.getType() != CIMTYPE_BOOLEAN || cq.isArray())
            continue;

        Boolean x;
        cq.getValue().get(x);


        if (System::strcasecmp(*Str(qn), "KEY") == 0)
        {
            if (x)
                flags |= MRR_FLAG_KEY;
            else
                flags &= ~MRR_FLAG_KEY;
        }
        else if (System::strcasecmp(*Str(qn), "IN") == 0)
        {
            if (x)
                flags |= MRR_FLAG_IN;
            else
                flags &= ~MRR_FLAG_IN;
        }
        else if (System::strcasecmp(*Str(qn), "OUT") == 0)
        {
            if (x)
                flags |= MRR_FLAG_OUT;
            else
                flags &= ~MRR_FLAG_OUT;
        }
        else if (System::strcasecmp(*Str(qn), "ABSTRACT") == 0)
        {
            if (x)
                flags |= MRR_FLAG_ABSTRACT;
            else
                flags &= ~MRR_FLAG_ABSTRACT;
        }
        else if (System::strcasecmp(*Str(qn), "AGGREGATE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_AGGREGATE;
            else
                flags &= ~MRR_FLAG_AGGREGATE;
        }
        else if (System::strcasecmp(*Str(qn), "AGGREGATION") == 0)
        {
            if (x)
                flags |= MRR_FLAG_AGGREGATION;
            else
                flags &= ~MRR_FLAG_AGGREGATION;
        }
        else if (System::strcasecmp(*Str(qn), "COUNTER") == 0)
        {
            if (x)
                flags |= MRR_FLAG_COUNTER;
            else
                flags &= ~MRR_FLAG_COUNTER;
        }
        else if (System::strcasecmp(*Str(qn), "DELETE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_DELETE;
            else
                flags &= ~MRR_FLAG_DELETE;
        }
        else if (System::strcasecmp(*Str(qn), "DN") == 0)
        {
            if (x)
                flags |= MRR_FLAG_DN;
            else
                flags &= ~MRR_FLAG_DN;
        }
        else if (System::strcasecmp(*Str(qn), "EMBEDDEDOBJECT") == 0)
        {
            if (x)
                flags |= MRR_FLAG_EMBEDDEDOBJECT;
            else
                flags &= ~MRR_FLAG_EMBEDDEDOBJECT;
        }
        else if (System::strcasecmp(*Str(qn), "EXPENSIVE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_EXPENSIVE;
            else
                flags &= ~MRR_FLAG_EXPENSIVE;
        }
        else if (System::strcasecmp(*Str(qn), "EXPERIMENTAL") == 0)
        {
            if (x)
                flags |= MRR_FLAG_EXPERIMENTAL;
            else
                flags &= ~MRR_FLAG_EXPERIMENTAL;
        }
        else if (System::strcasecmp(*Str(qn), "GAUGE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_GAUGE;
            else
                flags &= ~MRR_FLAG_GAUGE;
        }
        else if (System::strcasecmp(*Str(qn), "IFDELETED") == 0)
        {
            if (x)
                flags |= MRR_FLAG_IFDELETED;
            else
                flags &= ~MRR_FLAG_IFDELETED;
        }
        else if (System::strcasecmp(*Str(qn), "INVISIBLE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_INVISIBLE;
            else
                flags &= ~MRR_FLAG_INVISIBLE;
        }
        else if (System::strcasecmp(*Str(qn), "LARGE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_LARGE;
            else
                flags &= ~MRR_FLAG_LARGE;
        }
        else if (System::strcasecmp(*Str(qn), "OCTETSTRING") == 0)
        {
            if (x)
                flags |= MRR_FLAG_OCTETSTRING;
            else
                flags &= ~MRR_FLAG_OCTETSTRING;
        }
        else if (System::strcasecmp(*Str(qn), "READ") == 0)
        {
            if (x)
                flags |= MRR_FLAG_READ;
            else
                flags &= ~MRR_FLAG_READ;
        }
        else if (System::strcasecmp(*Str(qn), "REQUIRED") == 0)
        {
            if (x)
                flags |= MRR_FLAG_REQUIRED;
            else
                flags &= ~MRR_FLAG_REQUIRED;
        }
        else if (System::strcasecmp(*Str(qn), "STATIC") == 0)
        {
            if (x)
                flags |= MRR_FLAG_STATIC;
            else
                flags &= ~MRR_FLAG_STATIC;
        }
        else if (System::strcasecmp(*Str(qn), "TERMINAL") == 0)
        {
            if (x)
                flags |= MRR_FLAG_TERMINAL;
            else
                flags &= ~MRR_FLAG_TERMINAL;
        }
        else if (System::strcasecmp(*Str(qn), "WEAK") == 0)
        {
            if (x)
                flags |= MRR_FLAG_WEAK;
            else
                flags &= ~MRR_FLAG_WEAK;
        }
        else if (System::strcasecmp(*Str(qn), "WRITE") == 0)
        {
            if (x)
                flags |= MRR_FLAG_WRITE;
            else
                flags &= ~MRR_FLAG_WRITE;
        }
        else
        {
            // ATTN: Composition qualifier not handled (no more room in mask).
        }
    }

    // Write flags mask:

    if (flags & MRR_FLAG_KEY)
        fprintf(os, "|MRR_FLAG_KEY");
    if (flags && (flags & MRR_FLAG_IN))
        fprintf(os, "|MRR_FLAG_IN");
    if (flags && (flags & MRR_FLAG_OUT))
        fprintf(os, "|MRR_FLAG_OUT");
    if (flags & MRR_FLAG_ABSTRACT)
        fprintf(os, "|MRR_FLAG_ABSTRACT");
    if (flags & MRR_FLAG_AGGREGATE)
        fprintf(os, "|MRR_FLAG_AGGREGATE");
    if (flags & MRR_FLAG_AGGREGATION)
        fprintf(os, "|MRR_FLAG_AGGREGATION");
    if (flags & MRR_FLAG_COUNTER)
        fprintf(os, "|MRR_FLAG_COUNTER");
    if (flags & MRR_FLAG_DELETE)
        fprintf(os, "|MRR_FLAG_DELETE");
    if (flags & MRR_FLAG_DN)
        fprintf(os, "|MRR_FLAG_DN");
    if (flags & MRR_FLAG_EMBEDDEDOBJECT)
        fprintf(os, "|MRR_FLAG_EMBEDDEDOBJECT");
    if (flags & MRR_FLAG_EXPENSIVE)
        fprintf(os, "|MRR_FLAG_EXPENSIVE");
    if (flags & MRR_FLAG_EXPERIMENTAL)
        fprintf(os, "|MRR_FLAG_EXPERIMENTAL");
    if (flags & MRR_FLAG_GAUGE)
        fprintf(os, "|MRR_FLAG_GAUGE");
    if (flags & MRR_FLAG_IFDELETED)
        fprintf(os, "|MRR_FLAG_IFDELETED");
    if (flags & MRR_FLAG_INVISIBLE)
        fprintf(os, "|MRR_FLAG_INVISIBLE");
    if (flags & MRR_FLAG_LARGE)
        fprintf(os, "|MRR_FLAG_LARGE");
    if (flags & MRR_FLAG_OCTETSTRING)
        fprintf(os, "|MRR_FLAG_OCTETSTRING");
    if (flags & MRR_FLAG_READ)
        fprintf(os, "|MRR_FLAG_READ");
    if (flags & MRR_FLAG_REQUIRED)
        fprintf(os, "|MRR_FLAG_REQUIRED");
    if (flags & MRR_FLAG_STATIC)
        fprintf(os, "|MRR_FLAG_STATIC");
    if (flags & MRR_FLAG_TERMINAL)
        fprintf(os, "|MRR_FLAG_TERMINAL");
    if (flags & MRR_FLAG_WEAK)
        fprintf(os, "|MRR_FLAG_WEAK");
    if (flags & MRR_FLAG_WRITE)
        fprintf(os, "|MRR_FLAG_WRITE");
}

static bool _testBooleanQualifier(const CIMClass& cc, const CIMName& name)
{
    Uint32 pos = cc.findQualifier(name);

    if (pos == PEG_NOT_FOUND)
        return false;

    CIMConstQualifier cq = cc.getQualifier(pos);

    if (cq.getType() != CIMTYPE_BOOLEAN || cq.isArray())
        return false;

    Boolean x;
    cq.getValue().get(x);
    return x;
}

static void _writeBoolean(FILE* os, Boolean x)
{
    fprintf(os, "\\%03o", (int)x);
}

static void _writeUint8(FILE* os, Uint8 x)
{
    fprintf(os, "\\%03o", (int)x);
}

static void _writeSint8(FILE* os, Sint8 x)
{
    _writeUint8(os, Uint8(x));
}

static void _writeUint16(FILE* os, Uint16 x)
{
    Uint16 x0 = (x >> 8) & 0x00FF;
    Uint16 x1 = (x >> 0) & 0x00FF;
    fprintf(os, "\\%03o", (int)x0);
    fprintf(os, "\\%03o", (int)x1);
}

static void _writeSint16(FILE* os, Sint16 x)
{
    _writeUint16(os, Uint16(x));
}

static void _writeUint32(FILE* os, Uint32 x)
{
    Uint32 x0 = (x >> 24) & 0x000000FF;
    Uint32 x1 = (x >> 16) & 0x000000FF;
    Uint32 x2 = (x >>  8) & 0x000000FF;
    Uint32 x3 = (x >>  0) & 0x000000FF;
    fprintf(os, "\\%03o", (int)x0);
    fprintf(os, "\\%03o", (int)x1);
    fprintf(os, "\\%03o", (int)x2);
    fprintf(os, "\\%03o", (int)x3);
}

static void _writeSint32(FILE* os, Sint32 x)
{
    _writeUint32(os, Uint32(x));
}

static void _writeUint64(FILE* os, Uint64 x)
{
    Uint64 x0 = (x >> 56) & 0x00000000000000FF;
    Uint64 x1 = (x >> 48) & 0x00000000000000FF;
    Uint64 x2 = (x >> 40) & 0x00000000000000FF;
    Uint64 x3 = (x >> 32) & 0x00000000000000FF;
    Uint64 x4 = (x >> 24) & 0x00000000000000FF;
    Uint64 x5 = (x >> 16) & 0x00000000000000FF;
    Uint64 x6 = (x >>  8) & 0x00000000000000FF;
    Uint64 x7 = (x >>  0) & 0x00000000000000FF;
    fprintf(os, "\\%03o", (int)x0);
    fprintf(os, "\\%03o", (int)x1);
    fprintf(os, "\\%03o", (int)x2);
    fprintf(os, "\\%03o", (int)x3);
    fprintf(os, "\\%03o", (int)x4);
    fprintf(os, "\\%03o", (int)x5);
    fprintf(os, "\\%03o", (int)x6);
    fprintf(os, "\\%03o", (int)x7);
}

static void _writeSint64(FILE* os, Sint64 x)
{
    _writeUint64(os, Uint64(x));
}

static void _writeReal32(FILE* os, Real32 x)
{
    _writeUint32(os, *((Uint32*)(void*)&x));
}

static void _writeReal64(FILE* os, Real64 x)
{
    _writeUint64(os, *((Uint64*)(void*)&x));
}

static void _writeChar16(FILE* os, const Char16& x)
{
    _writeUint16(os, x);
}

static void _writeString(FILE* os, const char* s)
{
    size_t n = strlen(s);

    for (size_t i = 0; i < n; i++)
    {
        char c = s[i];

        if (isprint(c) && c != '"')
            fprintf(os, "%c", c);
        else
            fprintf(os, "\\%03o", c);
    }
}

static void _writeString(FILE* os, const String& x)
{
    _writeString(os, *Str(x));
}

static void _writeDateTime(FILE* os, const CIMDateTime& x)
{
    _writeString(os, x.toString());
}

static int _writeValue(FILE* os, const CIMValue& cv, bool quote)
{
    if (cv.isNull())
    {
        fprintf(os, "0");
        return 0;
    }

    if (quote)
        fputc('"', os);

    if (cv.isArray())
    {
        switch (cv.getType())
        {
            case CIMTYPE_BOOLEAN:
            {
                Array<Boolean> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeBoolean(os, x[i]);
                break;
            }

            case CIMTYPE_UINT8:
            {
                Array<Uint8> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeUint8(os, x[i]);
                break;
            }

            case CIMTYPE_SINT8:
            {
                Array<Sint8> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeSint8(os, x[i]);
                break;
            }

            case CIMTYPE_UINT16:
            {
                Array<Uint16> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeUint16(os, x[i]);
                break;
            }

            case CIMTYPE_SINT16:
            {
                Array<Sint16> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeSint16(os, x[i]);
                break;
            }

            case CIMTYPE_UINT32:
            {
                Array<Uint32> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeUint32(os, x[i]);
                break;
            }

            case CIMTYPE_SINT32:
            {
                Array<Sint32> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeSint32(os, x[i]);
                break;
            }

            case CIMTYPE_UINT64:
            {
                Array<Uint64> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeUint64(os, x[i]);
                break;
            }

            case CIMTYPE_SINT64:
            {
                Array<Sint64> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeSint64(os, x[i]);
                break;
            }

            case CIMTYPE_REAL32:
            {
                Array<Real32> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeReal32(os, x[i]);
                break;
            }

            case CIMTYPE_REAL64:
            {
                Array<Real64> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeReal64(os, x[i]);
                break;
            }

            case CIMTYPE_CHAR16:
            {
                Array<Char16> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeChar16(os, x[i]);
                break;
            }

            case CIMTYPE_STRING:
            {
                Array<String> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                {
                    _writeString(os, x[i]);
                    _writeUint8(os, 0);
                }
                break;
            }

            case CIMTYPE_DATETIME:
            {
                Array<CIMDateTime> x;
                cv.get(x);

                _writeUint16(os, x.size());

                for (Uint32 i = 0; i < x.size(); i++)
                    _writeDateTime(os, x[i]);
                break;
            }

            default:
                return -1;
        }
    }
    else
    {
        switch (cv.getType())
        {
            case CIMTYPE_BOOLEAN:
            {
                Boolean x;
                cv.get(x);
                _writeBoolean(os, x);
                break;
            }

            case CIMTYPE_UINT8:
            {
                Uint8 x;
                cv.get(x);
                _writeUint8(os, x);
                break;
            }

            case CIMTYPE_SINT8:
            {
                Sint8 x;
                cv.get(x);
                _writeSint8(os, x);
                break;
            }

            case CIMTYPE_UINT16:
            {
                Uint16 x;
                cv.get(x);
                _writeUint16(os, x);
                break;
            }

            case CIMTYPE_SINT16:
            {
                Sint16 x;
                cv.get(x);
                _writeSint16(os, x);
                break;
            }

            case CIMTYPE_UINT32:
            {
                Uint32 x;
                cv.get(x);
                _writeUint32(os, x);
                break;
            }

            case CIMTYPE_SINT32:
            {
                Sint32 x;
                cv.get(x);
                _writeSint32(os, x);
                break;
            }

            case CIMTYPE_UINT64:
            {
                Uint64 x;
                cv.get(x);
                _writeUint64(os, x);
                break;
            }

            case CIMTYPE_SINT64:
            {
                Sint64 x;
                cv.get(x);
                _writeSint64(os, x);
                break;
            }

            case CIMTYPE_REAL32:
            {
                Real32 x;
                cv.get(x);
                _writeReal32(os, x);
                break;
            }

            case CIMTYPE_REAL64:
            {
                Real64 x;
                cv.get(x);
                _writeReal64(os, x);
                break;
            }

            case CIMTYPE_CHAR16:
            {
                Char16 x;
                cv.get(x);
                _writeChar16(os, x);
                break;
            }

            case CIMTYPE_STRING:
            {
                String x;
                cv.get(x);
                _writeString(os, x);
                break;
            }

            case CIMTYPE_DATETIME:
            {
                CIMDateTime x;
                cv.get(x);
                _writeDateTime(os, x);
                break;
            }

            default:
                return -1;
        }
    }

    if (quote)
        fputc('"', os);

    return 0;
}

//==============================================================================
//
// cimmofMRR
//
//==============================================================================

cimmofMRR::cimmofMRR(bool discard) :
    _discard(discard), _os(0)
{
}

cimmofMRR::~cimmofMRR()
{
}

void cimmofMRR::addClass(
    const CIMNamespaceName& nameSpace,
    CIMClass& cimClass)
{
    if (_findClass(cimClass.getClassName()) != PEG_NOT_FOUND)
    {
        _throw(CIM_ERR_ALREADY_EXISTS, "class already defined: %s:%s",
            *Str(nameSpace), *Str(cimClass.getClassName()));
    }

    _classes.append(cimClass);
}

void cimmofMRR::addQualifier(
    const CIMNamespaceName& nameSpace,
    CIMQualifierDecl& cimQualifierDecl)
{
    if (_findQualifier(cimQualifierDecl.getName()) != PEG_NOT_FOUND)
    {
        _throw(CIM_ERR_ALREADY_EXISTS, "qualifier already defined: %s:%s",
            *Str(nameSpace), *Str(cimQualifierDecl.getName()));
    }

    _qualifiers.append(cimQualifierDecl);
}

void cimmofMRR::addInstance(
    const CIMNamespaceName& nameSpace,
    CIMInstance& instance)
{
    const CIMObjectPath& cop = instance.getPath();

    for (Uint32 i = 0; i < _instances.size(); i++)
    {
        if (_instances[i].getPath() == cop)
        {
            _throw(CIM_ERR_ALREADY_EXISTS,
                "instances already exists: %s", *Str(cop));
        }
    }

    _instances.append(instance);
}

CIMQualifierDecl cimmofMRR::getQualifierDecl(
    const CIMNamespaceName& nameSpace,
    const CIMName& qualifierName)
{
    Uint32 pos = _findQualifier(qualifierName);

    if (pos == PEG_NOT_FOUND)
    {
        _throw(CIM_ERR_NOT_FOUND,
            "undefined qualifier: %s:%s", *Str(nameSpace), *Str(qualifierName));
    }

    return _qualifiers[pos];
}

CIMClass cimmofMRR::getClass(
    const CIMNamespaceName& nameSpace,
    const CIMName& className)
{
    Uint32 pos = _findClass(className);

    if (pos == PEG_NOT_FOUND)
    {
        _throw(CIM_ERR_NOT_FOUND,
            "undefined class: %s:%s", *Str(nameSpace), *Str(className));
    }

    return _classes[pos];
}

void cimmofMRR::modifyClass(
    const CIMNamespaceName& nameSpace,
    CIMClass& cimClass)
{
    Uint32 pos = _findClass(cimClass.getClassName());

    if (pos == PEG_NOT_FOUND)
    {
        _throw(CIM_ERR_NOT_FOUND, "undefined class: %s:%s",
            *Str(nameSpace), *Str(cimClass.getClassName()));
    }

    _classes[pos] = cimClass;
}

void cimmofMRR::createNameSpace(
    const CIMNamespaceName& nameSpace)
{
    if (_nameSpace == nameSpace)
    {
        _throw(CIM_ERR_ALREADY_EXISTS, "namespace already exists: %s",
            *Str(nameSpace));
    }

    if (!_nameSpace.isNull())
    {
        _throw(CIM_ERR_FAILED, "cannot create more than one namespace");
    }

    _nameSpace = nameSpace;
}

void cimmofMRR::start()
{
}

void cimmofMRR::_loadClassFile(
    Array<CIMName>& classes, const String& path)
{
    classes.clear();

    // Open class file:

    FILE* is = fopen(*Str(path), "r");

    if (!is)
        return;

    char buffer[1024];

    for (int line = 1; fgets(buffer, sizeof(buffer), is) != NULL; line++)
    {
        if (buffer[0] == '#')
            continue;

        char* start = buffer;

        // Remove leading whitespace.

        while (isspace(*start))
            start++;

        // Remove trailing whitespace.

        char* p = start;

        while (*p)
            p++;

        while (p != start && isspace(p[-1]))
            *--p = '\0';

        // Skip empty lines.

        if (*start == '\0')
            continue;

        // Skip comment lines:

        if (*start == '#')
            continue;

        /* Check whether legal class name. */

        if (_findClass(start) == PEG_NOT_FOUND)
        {
            fprintf(stderr,
                "cimmofl: unknown class on line %d of %s: \"%s\"\n",
                line, *Str(path), start);
            exit(1);
        }

        /* Append class to list. */

        bool found = false;

        for (Uint32 i = 0; i < classes.size(); i++)
        {
            if (classes[i] == start)
            {
                found = true;
                break;
            }
        }

        if (!found)
            classes.append(start);
    }

    fclose(is);
}

void cimmofMRR::finish()
{
    String ns = _makeIdent(_nameSpace.getString());

    // Open classes file, if any.

    Array<CIMName> classNames;
    String classFile = ns + "_namespace.classes";
    _loadClassFile(classNames, classFile);

    // Find closure of select classes:

    _closure.clear();

    if (classNames.size())
    {
        printf("Using %s to reduce class list\n", *Str(classFile));

        // Find closure of classes from class file:

        for (Uint32 i = 0; i < classNames.size(); i++)
        {
            const CIMName& cn = classNames[i];

            if (Closure(cn, _classes, _closure) != 0)
            {
                printf("cimmofl: failed to calculate closure for class %s\n",
                    *Str(cn));
            }
        }

        // Find closure of classes referred to by instances:

        for (Uint32 i = 0; i < _instances.size(); i++)
        {
            const CIMInstance& ci = _instances[i];
            const CIMName& cn = ci.getClassName();

            if (Closure(cn, _classes, _closure) != 0)
            {
                printf("cimmofl: failed to calculate closure for class %s\n",
                    *Str(cn));
            }
        }
    }

    // Write header file:

    _writeHeaderFile(ns);

    // Open source file:

    String path = ns + "_namespace.cpp";
    _os = fopen(*Str(path), "wb");

    if (!_os)
    {
        fprintf(stderr, "cimmofl: failed to open \"%s\" for write\n",
            *Str(path));
        exit(1);
    }

    // Write prologue:

    _writeMetaPrologue();

    // Write namespace:

    _writeNameSpace(_nameSpace);

    // Write epilogue:

    _writeMetaEpilogue();

    // Close file:

    fclose(_os);

    // Write instances file (if any instances encountered).

    if (_instances.size())
    {
        // Serialize all instances into a buffer:

        Buffer out;

        for (Uint32 i = 0; i < _instances.size(); i++)
        {
            MRRSerializeNameSpace(out, _nameSpace);
            MRRSerializeInstance(out, _instances[i]);
        }

        // Open instances output file:

        String path = ns + "_namespace.mrr";
        FILE* os = fopen(*Str(path), "wb");

        if (!os)
        {
            fprintf(stderr, "cimmofl: failed to open \"%s\" for write\n",
                *Str(path));
            exit(1);
        }

        // Write instances to a file.

        if (fwrite(out.getData(), 1, out.size(), os) != out.size())
        {
            fprintf(stderr, "cimmofl: failed to write to \"%s\"\n",
                *Str(path));
            exit(1);
        }

        // Close output file:

        fclose(os);
    }

    // Write messages:

    printf("Created %s_namespace.h\n", *Str(ns));
    printf("Created %s_namespace.cpp\n", *Str(ns));

    if (_instances.size())
        printf("Created %s_namespace.mrr\n", *Str(ns));

    printf("\n");
}

Uint32 cimmofMRR::_findClass(const CIMName& className) const
{
    for (Uint32 i = 0; i < _classes.size(); i++)
    {
        if (_classes[i].getClassName() == className)
            return i;
    }

    // Not found!
    return PEG_NOT_FOUND;
}

Uint32 cimmofMRR::_findQualifier(const CIMName& qualifierName) const
{
    for (Uint32 i = 0; i < _qualifiers.size(); i++)
    {
        if (_qualifiers[i].getName() == qualifierName)
            return i;
    }

    // Not found!
    return PEG_NOT_FOUND;
}

void cimmofMRR::_writeMetaPrologue()
{
    String ns = _makeIdent(_nameSpace.getString());
    String path = ns + "_namespace.h";

    _box(_os, "CAUTION: THIS FILE WAS GENERATED BY CIMMOFL; "
        "PLEASE DO NOT EDIT IT.");
    _nl();

    _outn("#include \"%s\"", *Str(path));
    _nl();
    _outn("/*NOCHKSRC*/");
    _nl();
    _outn("PEGASUS_NAMESPACE_BEGIN");
    _nl();
}

void cimmofMRR::_writeMetaEpilogue()
{
    _outn("PEGASUS_NAMESPACE_END");
}

void cimmofMRR::_writeQualifier(
    const Array<CIMQualifierDecl>& qualifierDecls,
    const CIMConstQualifier& cq)
{
    CIMName qn = cq.getName();
    CIMType qt = cq.getType();
    CIMValue qv = cq.getValue();

    Uint32 pos = _findQualifier(qn);

    if (pos == PEG_NOT_FOUND)
        _throw(CIM_ERR_FAILED, "undefined qualifier: %s", *Str(qn));

    // Write the qualifier string literal:

    _outn("    /* %s */", *Str(qn));
    _out("    (char*)\"");
    _writeUint8(_os, pos);
    _writeValue(_os, qv, false);
    _outn("\",");
}

void cimmofMRR::_writeQualifierDecl(const CIMConstQualifierDecl& cq)
{
    CIMName qn = cq.getName();
    CIMType qt = cq.getType();
    const CIMValue& cv = cq.getValue();

    // Write value definition (if any).

    String path = "_" + qn.getString() + "_qualifier_decl";

    // Write MRRQualifierDecl header:

    _outn("static MRRQualifierDecl");
    _outn("%s =", *Str(path));
    _outn("{");

    // MRRQualifierDecl.name:

    _outn("    /* name */");
    _outn("    (char*)\"%s\",", *Str(qn));

    // MRRQualifierDecl.type:

    _outn("    /* type */");
    _outn("    %s,", _typeNames[qt]);

    // MRRQualifierDecl.subscript:

    _outn("    /* subscript */");

    if (cq.isArray())
    {
        Uint32 n = cq.getArraySize();
        _outn("    %u,", n);
    }
    else
    {
        _outn("    -1,");
    }

    // MRRQualifierDecl.scope:
    {
        _outn("    /* scope */");

        CIMScope scope = cq.getScope();
        Array<String> scopes;

        if (scope.hasScope(CIMScope::ANY))
            scopes.append("MRR_SCOPE_ANY");
        else
        {
            if (scope.hasScope(CIMScope::CLASS))
                scopes.append("MRR_SCOPE_CLASS");
            if (scope.hasScope(CIMScope::ASSOCIATION))
                scopes.append("MRR_SCOPE_ASSOCIATION");
            if (scope.hasScope(CIMScope::INDICATION))
                scopes.append("MRR_SCOPE_INDICATION");
            if (scope.hasScope(CIMScope::PROPERTY))
                scopes.append("MRR_SCOPE_PROPERTY");
            if (scope.hasScope(CIMScope::REFERENCE))
                scopes.append("MRR_SCOPE_REFERENCE");
            if (scope.hasScope(CIMScope::METHOD))
                scopes.append("MRR_SCOPE_METHOD");
            if (scope.hasScope(CIMScope::PARAMETER))
                scopes.append("MRR_SCOPE_PARAMETER");
        }

        _out("    ");

        for (Uint32 i = 0; i < scopes.size(); i++)
        {
            _out("%s", *Str(scopes[i]));

            if (i + 1 != scopes.size())
                _out("|");
        }

        _outn(",");
    }

    // MRRQualifierDecl.flavor:
    {
        _outn("    /* flavor */");

        CIMFlavor flavor = cq.getFlavor();
        Array<String> flavors;

        if (flavor.hasFlavor(CIMFlavor::OVERRIDABLE))
            flavors.append("MRR_FLAVOR_OVERRIDABLE");
        if (flavor.hasFlavor(CIMFlavor::TOSUBCLASS))
            flavors.append("MRR_FLAVOR_TOSUBCLASS");
        if (flavor.hasFlavor(CIMFlavor::TOINSTANCE))
            flavors.append("MRR_FLAVOR_TOINSTANCE");
        if (flavor.hasFlavor(CIMFlavor::TRANSLATABLE))
            flavors.append("MRR_FLAVOR_TRANSLATABLE");
        if (flavor.hasFlavor(CIMFlavor::DISABLEOVERRIDE))
            flavors.append("MRR_FLAVOR_DISABLEOVERRIDE");
        if (flavor.hasFlavor(CIMFlavor::RESTRICTED))
            flavors.append("MRR_FLAVOR_RESTRICTED");

        _out("    ");

        for (Uint32 i = 0; i < flavors.size(); i++)
        {
            _out("%s", *Str(flavors[i]));

            if (i + 1 != flavors.size())
                _out("|");
        }

        _outn(",");
    }

    // MRRQualifierDecl.value:

    _outn("    /* value */");
    _out("    ");
    _writeValue(_os, cv, true);
    _outn(",");

    _outn("};");
    _nl();
}

template<class C>
Array<CIMConstQualifier> _Qualifiers(const C& c)
{
    Array<CIMConstQualifier> tmp;

    for (Uint32 i = 0; i < c.getQualifierCount(); i++)
        tmp.append(c.getQualifier(i));

    return tmp;
}

void cimmofMRR::_writeQualifierArray(
    const String& root,
    const Array<CIMConstQualifier>& qualifiers)
{
    _outn("static const char*");
    _outn("%s_qualifiers[] =", *Str(root));
    _outn("{");

    for (Uint32 i = 0; i < qualifiers.size(); i++)
    {
        CIMConstQualifier cq = qualifiers[i];
        CIMName qn = cq.getName();
        CIMType qt = cq.getType();

        if (_discard && qn == "Description")
            continue;

#if 0
        if (qt == CIMTYPE_BOOLEAN && !cq.isArray())
            continue;
#endif

        _writeQualifier(_qualifiers, cq);
    }

    // Write terminator:
    _outn("    0,");

    _outn("};");
    _nl();
}

void cimmofMRR::_writeProperty(
    const CIMNamespaceName& nameSpace,
    const CIMName& cn,
    const CIMConstProperty& cp)
{
    String ns = _makeIdent(nameSpace.getString());
    CIMName pn = cp.getName();
    CIMType ct = cp.getType();
    CIMValue cv = cp.getValue();

    String path = "_" + cn.getString() + "_" + pn.getString();

    // Write qualifiers:

    _writeQualifierArray(path, _Qualifiers(cp));

    // Header:

    if (ct == CIMTYPE_REFERENCE)
        _outn("static MRRReference");
    else
        _outn("static MRRProperty");

    _outn("%s =", *Str(path));
    _outn("{");

    // MRRProperty.flags:

    _outn("    /* flags */");

    if (ct == CIMTYPE_REFERENCE)
        _out("    MRR_FLAG_REFERENCE");
    else
        _out("    MRR_FLAG_PROPERTY");

    _writeFlags(_os, cp, true, false);
    fprintf(_os, ",\n");

    // MRRProperty.name:

    _outn("    /* name */");
    _outn("    (char*)\"%s\",", *Str(pn));

    // MRRProperty.qualifiers:

    _outn("    /* qualifiers */");
    _outn("    %s_qualifiers,", *Str(path));

    // MRRProperty.type:

    if (ct != CIMTYPE_REFERENCE)
    {
        _outn("    /* type */");
        _outn("    %s,", _typeNames[ct]);
    }

    // MRRProperty.subscript:

    _outn("    /* subscript */");

    if (cp.isArray())
    {
        Uint32 n = cp.getArraySize();
        _outn("    %u,", n);
    }
    else
    {
        _outn("    -1,");
    }

    // MRRReference.ref:

    if (ct == CIMTYPE_REFERENCE)
    {
        const CIMName& rcn = cp.getReferenceClassName();
        _outn("    /* refId */");
        _outn("    &__%s_%s,", *Str(ns), *Str(rcn));
    }

    // MRRQualifierDecl.value:

    if (ct != CIMTYPE_REFERENCE)
    {
        _outn("    /* value */");
        _out("    ");
        _writeValue(_os, cv, true);
        _outn(",");
    }

    _outn("};");
    _nl();
}

void cimmofMRR::_writeParameter(
    const CIMNamespaceName& nameSpace,
    const CIMName& cn,
    const CIMName& mn,
    const CIMConstParameter& cp)
{
    String ns = _makeIdent(nameSpace.getString());
    CIMName pn = cp.getName();
    CIMType ct = cp.getType();

    String path =
        "_" + cn.getString() + "_" + mn.getString() + "_" + pn.getString();

    _writeQualifierArray(path, _Qualifiers(cp));

    if (ct == CIMTYPE_REFERENCE)
        _outn("static MRRReference");
    else
        _outn("static MRRProperty");

    _outn("%s =", *Str(path));
    _outn("{");

    // MRRProperty.flags:

    _outn("    /* flags */");

    if (ct == CIMTYPE_REFERENCE)
        _out("    MRR_FLAG_REFERENCE");
    else
        _out("    MRR_FLAG_PROPERTY");

    _writeFlags(_os, cp, false, true);
    fprintf(_os, ",\n");

    // MRRProperty.name:

    _outn("    /* name */");
    _outn("    (char*)\"%s\",", *Str(pn));

    // MRRProperty.qualifiers:

    _outn("    /* qualifiers */");
    _outn("    %s_qualifiers,", *Str(path));

    // MRRProperty.type:

    if (ct != CIMTYPE_REFERENCE)
    {
        _outn("    /* type */");
        _outn("    %s,", _typeNames[ct]);
    }

    // MRRProperty.subscript:

    _outn("    /* subscript */");

    if (cp.isArray())
    {
        Uint32 n = cp.getArraySize();
        _outn("    %u,", n);
    }
    else
    {
        _outn("    -1,");
    }

    // MRRProperty.ref:

    if (ct == CIMTYPE_REFERENCE)
    {
        const CIMName& rcn = cp.getReferenceClassName();
        _outn("    /* ref */");
        _outn("    &__%s_%s,", *Str(ns), *Str(rcn));
    }

    // MRRQualifierDecl.value:

    if (ct != CIMTYPE_REFERENCE)
    {
        _outn("    /* value */");
        _outn("    0,");
    }

    _outn("};");
    _nl();
}

void cimmofMRR::_writeMethod(
    const CIMNamespaceName& nameSpace,
    const CIMName& cn,
    const CIMConstMethod& cm)
{
    CIMName mn = cm.getName();

    // Write parameter definitions:

    Array<CIMName> parameterNames;

    for (Uint32 i = 0; i < cm.getParameterCount(); i++)
    {
        CIMConstParameter cp = cm.getParameter(i);
        _writeParameter(nameSpace, cn, mn, cp);
        parameterNames.append(cp.getName());
    }

    // Write parameters array:

    _outn("static MRRFeature*");
    _outn("_%s_%s_parameters[] =", *Str(cn), *Str(mn));
    _outn("{");

    for (Uint32 i = 0; i < parameterNames.size(); i++)
    {
        const CIMName& pn = parameterNames[i];
        _outn("    (MRRFeature*)&_%s_%s_%s,", *Str(cn), *Str(mn), *Str(pn));
    }

    _outn("    0,");
    _outn("};");
    _nl();

    // Method header:

    String path = "_" + cn.getString() + "_" + mn.getString();

    _writeQualifierArray(path, _Qualifiers(cm));

    _outn("static MRRMethod");
    _outn("%s =", *Str(path));
    _outn("{");

    // MRRMethod.flags:

    _outn("    /* flags */");
    _out("    MRR_FLAG_METHOD");
    _writeFlags(_os, cm, false, false);
    fprintf(_os, ",\n");

    // MRRMethod.name:

    _outn("    /* name */");
    _outn("    (char*)\"%s\",", *Str(mn));

    // MRRMethod.qualifiers:

    _outn("    /* qualifiers */");
    _outn("    %s_qualifiers,", *Str(path));

    // MRRProperty.type:

    _outn("    /* type */");
    _outn("    %s,", _typeNames[cm.getType()]);

    // MRRMethod.parameters:

    _outn("    /* parameters */");
    _outn("    _%s_%s_parameters,", *Str(cn), *Str(mn));

    // Method footer:

    _outn("};");
    _nl();
}

void cimmofMRR::_writeClass(
    const CIMNamespaceName& nameSpace,
    const CIMClass& cc)
{
    String ns = _makeIdent(nameSpace.getString());
    CIMName cn = cc.getClassName();

    // Write comment:

    _box(_os, "Class: %s", *Str(cn));
    _nl();

    // Write property definitions:

    Array<CIMName> featureNames;

    for (Uint32 i = 0; i < cc.getPropertyCount(); i++)
    {
        CIMConstProperty cp = cc.getProperty(i);
        _writeProperty(nameSpace, cc.getClassName(), cp);
        featureNames.append(cp.getName());
    }

    // Write method definitions:

    for (Uint32 i = 0; i < cc.getMethodCount(); i++)
    {
        CIMConstMethod cm = cc.getMethod(i);
        _writeMethod(nameSpace, cc.getClassName(), cm);
        featureNames.append(cm.getName());
    }

    // Write feature array:

    _outn("static MRRFeature*");
    _outn("_%s_features[] =", *Str(cn));
    _outn("{");

    for (Uint32 i = 0; i < featureNames.size(); i++)
    {
        const CIMName& fn = featureNames[i];
        _outn("    (MRRFeature*)&_%s_%s,", *Str(cn), *Str(fn));
    }

    _outn("    0,");
    _outn("};");
    _nl();

    // Class header:

    String path = "__" + ns + "_" + cn.getString();

    _writeQualifierArray(path, _Qualifiers(cc));

    _outn("MRRClass");
    _outn("%s =", *Str(path));
    _outn("{");

    // MRRClass.flags:

    _outn("    /* flags */");

    if (_testBooleanQualifier(cc, "Association"))
        _out("    MRR_FLAG_ASSOCIATION");
    else if (_testBooleanQualifier(cc, "Indication"))
        _out("    MRR_FLAG_INDICATION");
    else
        _out("    MRR_FLAG_CLASS");

    _writeFlags(_os, cc, false, false);
    fprintf(_os, ",\n");

    // MRRClass.name:

    _outn("    /* name */");
    _outn("    (char*)\"%s\",", *Str(cn));

    // MRRClass.qualifiers:

    _outn("    /* qualifiers */");
    _outn("    %s_qualifiers,", *Str(path));

    // MRRClass.super:

    const CIMName& scn = cc.getSuperClassName();
    _outn("    /* super */");

    if (scn.isNull())
        _outn("    0,");
    else
        _outn("    &__%s_%s,", *Str(ns), *Str(scn));

    // MRRClass.features:

    _outn("    /* features */");
    _outn("    _%s_features,", *Str(cn));

    // Class footer:

    _outn("};");
    _nl();
}

void cimmofMRR::_writeNameSpace(const CIMNamespaceName& nameSpace)
{
    String ns = _makeIdent(nameSpace.getString());

    // Write qualifiers:

    _box(_os, "Qualifiers");
    _nl();

    for (Uint32 i = 0; i < _qualifiers.size(); i++)
    {
        _writeQualifierDecl(_qualifiers[i]);
    }

    // Forward declare all classes:

    _box(_os, "Forward class declarations");

    _nl();

    for (Uint32 i = 0; i < _classes.size(); i++)
    {
        CIMName cn = _classes[i].getClassName();

        if (_includeClass(cn))
            _outn("extern MRRClass __%s_%s;", *Str(ns), *Str(cn));
    }

    _nl();

    // Write classes:

    for (Uint32 i = 0; i < _classes.size(); i++)
    {
        CIMName cn = _classes[i].getClassName();

        if (_includeClass(cn))
            _writeClass(nameSpace, _classes[i]);
    }

    // Write qualifiers list:

    _box(_os, "Qualifier array");
    _nl();

    _outn("static MRRQualifierDecl*");
    _outn("_qualifiers[] =");
    _outn("{");
    _indent++;

    for (Uint32 i = 0; i < _qualifiers.size(); i++)
    {
        _outn("&_%s_qualifier_decl,", *Str(_qualifiers[i].getName()));
    }

    _outn("0,");

    _indent--;
    _outn("};");
    _nl();

    // Write classes list:

    _box(_os, "Class array");
    _nl();

    _outn("static MRRClass*");
    _outn("_classes[] =");
    _outn("{");
    _indent++;

    for (Uint32 i = 0; i < _classes.size(); i++)
    {
        CIMName cn = _classes[i].getClassName();

        if (_includeClass(cn))
            _outn("&__%s_%s,", *Str(ns), *Str(cn));
    }

    _outn("0,");

    _indent--;
    _outn("};");
    _nl();

    // Write MRRNameSpace structure:

    _outn("const MRRNameSpace %s_namespace =", *Str(ns));
    _outn("{");
    _outn("    (char*)\"%s\",", *Str(nameSpace));
    _outn("    _qualifiers,");
    _outn("    _classes,");
    _outn("};");
    _nl();
}

PEGASUS_FORMAT(2, 3)
void cimmofMRR::_out(const char* format, ...)
{
    va_list ap;
    va_start(ap, format);
    _vout(_os, format, ap);
    va_end(ap);
}

PEGASUS_FORMAT(2, 3)
void cimmofMRR::_outn(const char* format, ...)
{
    va_list ap;
    va_start(ap, format);
    _vout(_os, format, ap);
    va_end(ap);
    fputc('\n', _os);
}

void cimmofMRR::_nl()
{
    _out("\n");
}

bool cimmofMRR::_includeClass(const CIMName& cn)
{
    if (_closure.size() == 0)
        return true;

    for (Uint32 i = 0; i < _closure.size(); i++)
    {
        if (_closure[i] == cn)
            return true;
    }

    return false;
}

PEGASUS_NAMESPACE_END
