/**************************************************************************\
* 
* Copyright (c) 1999  Microsoft Corporation
*
* Module Name:
*
*   Unicode strings
*
* Abstract:
*
*   Functions and classes which deal with Unicode strings
*
* Revision History:
*
*   02/22/1999 davidx
*       Created it.
*   09/08/1999 agodfrey
*       Moved to Runtime\unicode.hpp
*
\**************************************************************************/

#ifndef _UNICODE_HPP
#define _UNICODE_HPP

namespace GpRuntime
{
    
// These are replacements for some of the C runtime functions.

size_t  UnicodeStringLength(const WCHAR *str);
WCHAR * UnicodeStringDuplicate(const WCHAR *strSource);
INT     UnicodeStringCompare(const WCHAR *str1, const WCHAR *str2);
extern "C" INT     UnicodeStringCompareCI(const WCHAR *str1, const WCHAR *str2);
INT     UnicodeStringCompareCount(const WCHAR* str1, const WCHAR* str2, size_t count);
INT     UnicodeStringCompareCICount(const WCHAR* str1, const WCHAR* str2, size_t count);
void    UnicodeStringCopy(WCHAR *dest, const WCHAR *src);
void    UnicodeStringCopyCount(WCHAR *dest, const WCHAR *src, size_t count);
void    UnicodeStringToUpper(WCHAR* dest, WCHAR* src);
WCHAR * UnicodeStringConcat(WCHAR *dest, const WCHAR *src);
WCHAR * UnicodeStringReverseSearch(const WCHAR* str, WCHAR ch);
BOOL    UnicodeStringIIsEqual(
    const WCHAR* str1, 
    const WCHAR* str2u, 
    const WCHAR* str2l
    );

inline BOOL
UnicodeToAnsiStr(
    const WCHAR* unicodeStr,
    CHAR* ansiStr,
    INT ansiSize
    )
{
    return WideCharToMultiByte(
                CP_ACP,
                0,
                unicodeStr,
                -1,
                ansiStr,
                ansiSize,
                NULL,
                NULL) > 0;
}

class AnsiStrFromUnicode
{
private:
    // We now use an ObjectTag to determine if the object is valid
    // instead of using a BOOL.  This is much more robust and helps
    // with debugging.  It also enables us to version our objects
    // more easily with a version number in the ObjectTag.
    ObjectTag           Tag;    // Keep this as the 1st value in the object!

    VOID SetValid(BOOL valid)
    {
        Tag = valid ? ObjectTagAnsiStrFromUnicode : ObjectTagInvalid;
    }

public:

    AnsiStrFromUnicode(const WCHAR* unicodeStr)
    {
        if (unicodeStr == NULL)
        {
            SetValid(TRUE);
            ansiStr = NULL;
        }
        else
        {
            SetValid(UnicodeToAnsiStr(unicodeStr, buf, MAX_PATH));
            ansiStr = IsValid() ? buf : NULL;
        }
    }

    ~AnsiStrFromUnicode()
    {
        SetValid(FALSE);    // so we don't use a deleted object
    }

    BOOL IsValid() const
    {
        ASSERT((Tag == ObjectTagAnsiStrFromUnicode) || (Tag == ObjectTagInvalid));
    #if DBG
        if (Tag == ObjectTagInvalid)
        {
            WARNING1("Invalid AnsiStrFromUnicode");
        }
    #endif

        return (Tag == ObjectTagAnsiStrFromUnicode);
    }

    operator CHAR*()
    {
        return ansiStr;
    }

private:

    CHAR* ansiStr;
    CHAR buf[MAX_PATH];
};

inline BOOL
AnsiToUnicodeStr(
    const CHAR* ansiStr,
    WCHAR* unicodeStr,
    INT unicodeSize
    )
{
    return MultiByteToWideChar(
                CP_ACP,
                0,
                ansiStr,
                -1,
                unicodeStr,
                unicodeSize) > 0;
}

class UnicodeStrFromAnsi
{
private:
    // We now use an ObjectTag to determine if the object is valid
    // instead of using a BOOL.  This is much more robust and helps
    // with debugging.  It also enables us to version our objects
    // more easily with a version number in the ObjectTag.
    ObjectTag           Tag;    // Keep this as the 1st value in the object!

    VOID SetValid(BOOL valid)
    {
        Tag = valid ? ObjectTagUnicodeStrFromAnsi : ObjectTagInvalid;
    }

public:

    UnicodeStrFromAnsi(const CHAR* ansiStr)
    {
        if (ansiStr == NULL)
        {
            SetValid(TRUE);
            unicodeStr = NULL;
        }
        else
        {
            SetValid(AnsiToUnicodeStr(ansiStr, buf, MAX_PATH));
            unicodeStr = IsValid() ? buf : NULL;
        }
    }

    ~UnicodeStrFromAnsi()
    {
        SetValid(FALSE);    // so we don't use a deleted object
    }

    BOOL IsValid() const
    {
        ASSERT((Tag == ObjectTagUnicodeStrFromAnsi) || (Tag == ObjectTagInvalid));
    #if DBG
        if (Tag == ObjectTagInvalid)
        {
            WARNING1("Invalid UnicodeStrFromAnsi");
        }
    #endif

        return (Tag == ObjectTagUnicodeStrFromAnsi);
    }

    operator WCHAR*()
    {
        return unicodeStr;
    }

private:

    WCHAR* unicodeStr;
    WCHAR buf[MAX_PATH];
};

//--------------------------------------------------------------------------
// Represent a simple immutable Unicode string object used internally
// by GDI+ implementation. A string is represented by pieces of
// information:
//  - pointer to the character buffer
//  - number of characters in the string
//
// [agodfrey] Ack! Yet another string class. I'm just moving it here
// to be with its mates. It came from BaseTypes.hpp.
//--------------------------------------------------------------------------

class GpString
{
public:

    // NOTE:
    //  We're not making a copy of the characters here. Instead,
    //  we simply remember the character pointer. We assume the
    //  caller will ensure the input pointer's lifetime is longer
    //  than that of the newly constructed GpString object.

    GpString(const WCHAR* str, UINT len)
    {
        Buf = str;
        Len = len;
    }

    GpString(const WCHAR* str)
    {
        Buf = str;
        Len = UnicodeStringLength(str);
    }

    BOOL IsNull() const
    {
        return Buf == NULL;
    }

    const WCHAR* GetBuf() const
    {
        return Buf;
    }

    UINT GetLen() const
    {
        return Len;
    }

    // Return a copy of the string as a NUL-terminated C string.
    // Caller should call GpFree on the returned pointer after
    // it finishes using the C string.

    WCHAR* GetCString() const;

protected:

    const WCHAR* Buf;
    UINT Len;
};

}


#endif // !_UNICODE_HPP