kernel32: Reimplement FoldStringW() to support composition.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
95c9dee30a
commit
e89bbd5244
|
@ -2125,8 +2125,7 @@ INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen,
|
|||
return 0;
|
||||
}
|
||||
|
||||
srclenW = MultiByteToWideChar(CP_ACP, dwFlags & MAP_COMPOSITE ? MB_COMPOSITE : 0,
|
||||
src, srclen, NULL, 0);
|
||||
srclenW = MultiByteToWideChar(CP_ACP, 0, src, srclen, NULL, 0);
|
||||
srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR));
|
||||
|
||||
if (!srcW)
|
||||
|
@ -2135,10 +2134,7 @@ INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen,
|
|||
goto FoldStringA_exit;
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_ACP, dwFlags & MAP_COMPOSITE ? MB_COMPOSITE : 0,
|
||||
src, srclen, srcW, srclenW);
|
||||
|
||||
dwFlags = (dwFlags & ~MAP_PRECOMPOSED) | MAP_FOLDCZONE;
|
||||
MultiByteToWideChar(CP_ACP, 0, src, srclen, srcW, srclenW);
|
||||
|
||||
ret = FoldStringW(dwFlags, srcW, srclenW, NULL, 0);
|
||||
if (ret && dstlen)
|
||||
|
@ -2166,6 +2162,96 @@ FoldStringA_exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Unicode expanded ligatures */
|
||||
static const WCHAR ligatures[][5] =
|
||||
{
|
||||
{ 0x00c6, 'A','E',0 },
|
||||
{ 0x00de, 'T','H',0 },
|
||||
{ 0x00df, 's','s',0 },
|
||||
{ 0x00e6, 'a','e',0 },
|
||||
{ 0x00fe, 't','h',0 },
|
||||
{ 0x0132, 'I','J',0 },
|
||||
{ 0x0133, 'i','j',0 },
|
||||
{ 0x0152, 'O','E',0 },
|
||||
{ 0x0153, 'o','e',0 },
|
||||
{ 0x01c4, 'D',0x017d,0 },
|
||||
{ 0x01c5, 'D',0x017e,0 },
|
||||
{ 0x01c6, 'd',0x017e,0 },
|
||||
{ 0x01c7, 'L','J',0 },
|
||||
{ 0x01c8, 'L','j',0 },
|
||||
{ 0x01c9, 'l','j',0 },
|
||||
{ 0x01ca, 'N','J',0 },
|
||||
{ 0x01cb, 'N','j',0 },
|
||||
{ 0x01cc, 'n','j',0 },
|
||||
{ 0x01e2, 0x0100,0x0112,0 },
|
||||
{ 0x01e3, 0x0101,0x0113,0 },
|
||||
{ 0x01f1, 'D','Z',0 },
|
||||
{ 0x01f2, 'D','z',0 },
|
||||
{ 0x01f3, 'd','z',0 },
|
||||
{ 0x01fc, 0x00c1,0x00c9,0 },
|
||||
{ 0x01fd, 0x00e1,0x00e9,0 },
|
||||
{ 0x05f0, 0x05d5,0x05d5,0 },
|
||||
{ 0x05f1, 0x05d5,0x05d9,0 },
|
||||
{ 0x05f2, 0x05d9,0x05d9,0 },
|
||||
{ 0xfb00, 'f','f',0 },
|
||||
{ 0xfb01, 'f','i',0 },
|
||||
{ 0xfb02, 'f','l',0 },
|
||||
{ 0xfb03, 'f','f','i',0 },
|
||||
{ 0xfb04, 'f','f','l',0 },
|
||||
{ 0xfb05, 0x017f,'t',0 },
|
||||
{ 0xfb06, 's','t',0 },
|
||||
};
|
||||
|
||||
static const WCHAR *get_ligature( WCHAR wc )
|
||||
{
|
||||
int low = 0, high = ARRAY_SIZE( ligatures ) -1;
|
||||
while (low <= high)
|
||||
{
|
||||
int pos = (low + high) / 2;
|
||||
if (ligatures[pos][0] < wc) low = pos + 1;
|
||||
else if (ligatures[pos][0] > wc) high = pos - 1;
|
||||
else return ligatures[pos] + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int expand_ligatures( const WCHAR *src, int srclen, WCHAR *dst, int dstlen )
|
||||
{
|
||||
int i, len, pos = 0;
|
||||
const WCHAR *expand;
|
||||
|
||||
for (i = 0; i < srclen; i++)
|
||||
{
|
||||
if (!(expand = get_ligature( src[i] )))
|
||||
{
|
||||
expand = src + i;
|
||||
len = 1;
|
||||
}
|
||||
else len = lstrlenW( expand );
|
||||
|
||||
if (dstlen)
|
||||
{
|
||||
if (pos + len > dstlen) break;
|
||||
memcpy( dst + pos, expand, len * sizeof(WCHAR) );
|
||||
}
|
||||
pos += len;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int fold_digits( const WCHAR *src, int srclen, WCHAR *dst, int dstlen )
|
||||
{
|
||||
extern const WCHAR wine_digitmap[] DECLSPEC_HIDDEN;
|
||||
int i;
|
||||
|
||||
if (!dstlen) return srclen;
|
||||
if (srclen > dstlen) return 0;
|
||||
for (i = 0; i < srclen; i++)
|
||||
dst[i] = src[i] + wine_digitmap[wine_digitmap[src[i] >> 8] + (src[i] & 0xff)];
|
||||
return srclen;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* FoldStringW (KERNEL32.@)
|
||||
*
|
||||
|
@ -2174,33 +2260,73 @@ FoldStringA_exit:
|
|||
INT WINAPI FoldStringW(DWORD dwFlags, LPCWSTR src, INT srclen,
|
||||
LPWSTR dst, INT dstlen)
|
||||
{
|
||||
WCHAR *tmp;
|
||||
int ret;
|
||||
|
||||
switch (dwFlags & (MAP_COMPOSITE|MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES))
|
||||
{
|
||||
case 0:
|
||||
if (dwFlags)
|
||||
break;
|
||||
/* Fall through for dwFlags == 0 */
|
||||
case MAP_PRECOMPOSED|MAP_COMPOSITE:
|
||||
case MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES:
|
||||
case MAP_COMPOSITE|MAP_EXPAND_LIGATURES:
|
||||
SetLastError(ERROR_INVALID_FLAGS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return 0;
|
||||
}
|
||||
if (srclen == -1) srclen = lstrlenW(src) + 1;
|
||||
|
||||
ret = wine_fold_string(dwFlags, src, srclen, dst, dstlen);
|
||||
if (!ret)
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
switch (dwFlags)
|
||||
{
|
||||
case MAP_PRECOMPOSED:
|
||||
return NormalizeString( NormalizationC, src, srclen, dst, dstlen );
|
||||
case MAP_FOLDCZONE:
|
||||
case MAP_PRECOMPOSED | MAP_FOLDCZONE:
|
||||
return NormalizeString( NormalizationKC, src, srclen, dst, dstlen );
|
||||
case MAP_COMPOSITE:
|
||||
return NormalizeString( NormalizationD, src, srclen, dst, dstlen );
|
||||
case MAP_COMPOSITE | MAP_FOLDCZONE:
|
||||
return NormalizeString( NormalizationKD, src, srclen, dst, dstlen );
|
||||
case MAP_FOLDDIGITS:
|
||||
return fold_digits( src, srclen, dst, dstlen );
|
||||
case MAP_EXPAND_LIGATURES:
|
||||
case MAP_EXPAND_LIGATURES | MAP_FOLDCZONE:
|
||||
return expand_ligatures( src, srclen, dst, dstlen );
|
||||
case MAP_FOLDDIGITS | MAP_PRECOMPOSED:
|
||||
if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, srclen * sizeof(WCHAR) ))) break;
|
||||
if (!(ret = fold_digits( src, srclen, tmp, srclen ))) break;
|
||||
ret = NormalizeString( NormalizationC, tmp, srclen, dst, dstlen );
|
||||
break;
|
||||
case MAP_FOLDDIGITS | MAP_FOLDCZONE:
|
||||
case MAP_FOLDDIGITS | MAP_PRECOMPOSED | MAP_FOLDCZONE:
|
||||
if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, srclen * sizeof(WCHAR) ))) break;
|
||||
if (!(ret = fold_digits( src, srclen, tmp, srclen ))) break;
|
||||
ret = NormalizeString( NormalizationKC, tmp, srclen, dst, dstlen );
|
||||
break;
|
||||
case MAP_FOLDDIGITS | MAP_COMPOSITE:
|
||||
if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, srclen * sizeof(WCHAR) ))) break;
|
||||
if (!(ret = fold_digits( src, srclen, tmp, srclen ))) break;
|
||||
ret = NormalizeString( NormalizationD, tmp, srclen, dst, dstlen );
|
||||
break;
|
||||
case MAP_FOLDDIGITS | MAP_COMPOSITE | MAP_FOLDCZONE:
|
||||
if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, srclen * sizeof(WCHAR) ))) break;
|
||||
if (!(ret = fold_digits( src, srclen, tmp, srclen ))) break;
|
||||
ret = NormalizeString( NormalizationKD, tmp, srclen, dst, dstlen );
|
||||
break;
|
||||
case MAP_EXPAND_LIGATURES | MAP_FOLDDIGITS:
|
||||
case MAP_EXPAND_LIGATURES | MAP_FOLDDIGITS | MAP_FOLDCZONE:
|
||||
if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, srclen * sizeof(WCHAR) ))) break;
|
||||
if (!(ret = fold_digits( src, srclen, tmp, srclen ))) break;
|
||||
ret = expand_ligatures( tmp, srclen, dst, dstlen );
|
||||
break;
|
||||
default:
|
||||
SetLastError( ERROR_INVALID_FLAGS );
|
||||
return 0;
|
||||
}
|
||||
if (!tmp)
|
||||
{
|
||||
SetLastError( ERROR_OUTOFMEMORY );
|
||||
return 0;
|
||||
}
|
||||
RtlFreeHeap( GetProcessHeap(), 0, tmp );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* CompareStringW (KERNEL32.@)
|
||||
*
|
||||
|
|
|
@ -3429,23 +3429,15 @@ static void test_FoldStringW(void)
|
|||
static const WCHAR foldczone_src[] =
|
||||
{
|
||||
'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
|
||||
0xff37, 0xff49, 0xff4e, 0xff45, '\0'
|
||||
0xff37, 0xff49, 0xff4e, 0xff45, 0x3c5, 0x308, 0x6a, 0x30c, 0xa0, 0xaa, 0
|
||||
};
|
||||
static const WCHAR foldczone_dst[] =
|
||||
{
|
||||
'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
|
||||
'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x3cb,0x1f0,' ','a',0
|
||||
};
|
||||
static const WCHAR foldczone_todo_src[] =
|
||||
static const WCHAR foldczone_broken_dst[] =
|
||||
{
|
||||
0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
|
||||
};
|
||||
static const WCHAR foldczone_todo_dst[] =
|
||||
{
|
||||
0x3cb,0x1f0,' ','a',0
|
||||
};
|
||||
static const WCHAR foldczone_todo_broken_dst[] =
|
||||
{
|
||||
0x3cb,0x1f0,0xa0,0xaa,0
|
||||
'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x3cb,0x1f0,0xa0,0xaa,0
|
||||
};
|
||||
static const WCHAR ligatures_src[] =
|
||||
{
|
||||
|
@ -3589,15 +3581,10 @@ static void test_FoldStringW(void)
|
|||
SetLastError(0);
|
||||
ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
|
||||
ok(ret == ARRAY_SIZE(foldczone_dst), "Got %d, error %d\n", ret, GetLastError());
|
||||
ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
|
||||
ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst))
|
||||
|| broken(!memcmp(dst, foldczone_broken_dst, sizeof(foldczone_broken_dst))),
|
||||
"MAP_FOLDCZONE: Expanded incorrectly\n");
|
||||
|
||||
ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
|
||||
todo_wine ok(ret == ARRAY_SIZE(foldczone_todo_dst), "Got %d, error %d\n", ret, GetLastError());
|
||||
todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
|
||||
|| broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
|
||||
"MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
|
||||
|
||||
/* MAP_EXPAND_LIGATURES */
|
||||
SetLastError(0);
|
||||
ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
|
||||
|
@ -4439,7 +4426,6 @@ static void test_IdnToNameprepUnicode(void)
|
|||
const WCHAR out[64];
|
||||
DWORD flags;
|
||||
DWORD err;
|
||||
DWORD todo;
|
||||
} test_data[] = {
|
||||
{
|
||||
5, {'t','e','s','t',0},
|
||||
|
@ -4481,20 +4467,20 @@ static void test_IdnToNameprepUnicode(void)
|
|||
0, 0, {0},
|
||||
IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
|
||||
},
|
||||
{ /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
|
||||
{
|
||||
10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
|
||||
12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
|
||||
0, 0xdeadbeef, TRUE
|
||||
0, 0xdeadbeef
|
||||
},
|
||||
{
|
||||
11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
|
||||
2, 0, {'t',0},
|
||||
0, 0xdeadbeef
|
||||
},
|
||||
{ /* Another example of incorrectly working FoldString (composition) */
|
||||
{
|
||||
2, {0x3b0, 0},
|
||||
2, 2, {0x3b0, 0},
|
||||
0, 0xdeadbeef, TRUE
|
||||
0, 0xdeadbeef,
|
||||
},
|
||||
{
|
||||
2, {0x221, 0},
|
||||
|
@ -4580,9 +4566,7 @@ static void test_IdnToNameprepUnicode(void)
|
|||
buf, ARRAY_SIZE(buf));
|
||||
err = GetLastError();
|
||||
|
||||
todo_wine_if (test_data[i].todo)
|
||||
ok(ret == test_data[i].ret ||
|
||||
broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
|
||||
ok(ret == test_data[i].ret || broken(ret == test_data[i].broken_ret), "%d: ret = %d\n", i, ret);
|
||||
|
||||
if(ret != test_data[i].ret)
|
||||
continue;
|
||||
|
|
Loading…
Reference in New Issue