STREXPAND() と WSTRCOMPRESS() について(2)

STREXPAND() で文字列を変換する場合、単純に変換元の文字列に大して strlen で長さを取得して2倍の大きさでメモリを確保すると、全角文字が含まれていた場合に無駄な領域が出るのでもったいないです。
また、静的に領域を用意しても、場合によってはその大きさを超える場合があるので、あまり好ましくないです。
同様のことが WSTRCOMPRESS() にも言えます。変換元の文字列に大して WSTRLEN 取得した長さの半分の大きさでメモリを確保すると、全角文字が含まれていた場合に全ての文字が収まらなくなります。


なので、メモリの無駄を回避して、全ての文字を正常に変換するためには、事前に変換後の長さを取得するためのヘルパ関数を作っておくといいと思います。
id:melpon:20061204 で書いたとおり、日本の場合は半角文字の扱いに注意です。

// str を AECHAR に拡張したときの文字数を返します
int exstrlen(const char* str)
{
    if (str == null)
    {
        return 0;
    }
    int len = 0;
    int s = 0;
    while (true)
    {
        unsigned char c = str[s];
        if (c == '\0')
        {
            break;
        }
        if (IsSingleByte(c))
        {
            s += 1;
        }
        else
        {
            s += 2;
        }
        len++;
    }
    return len;
}

// str を char に圧縮したときの文字数を返します
int cpstrlen(const AECHAR* str)
{
    if (str == null)
    {
        return 0;
    }
    int len = 0;
    int s = 0;
    while (true)
    {
        AECHAR c = str[s];
        if (c == '\0')
        {
            break;
        }
        if (IsSingleByte(c))
        {
            len += 1;
        }
        else
        {
            len += 2;
        }
        s++;
    }
    return len;
}

// c が 128 未満であるか、又は BREW_JP が定義されていて、
// c が 0xa0〜0xdf の間であれば true を返します。
// 0xa0〜0xdf は半角カナです。
bool IsSingleByte(AECHAR c)
{
    if (c < 128 
#if defined(BREW_JP)
    || (0xa0 <= c && c <= 0xdf)
#endif
    )
    {
        return true;
    }
    else
    {
        return false;
    }
}
const char* str = "あiueお";
int size = (exstrlen( str ) + 1) * sizeof(AECHAR);
AECHAR* p = (AECHAR*)MALLOC(size);
STREXPAND((const byte*)str, STRLEN(str), p, size);

これで p に無駄なくワイド文字がセットされます。