From: Paul Gofman pgofman@codeweavers.com
--- dlls/crypt32/base64.c | 60 ++++++++++++++++++++++++++++++++ dlls/crypt32/tests/base64.c | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c index 11fb137ed91..9523eb1914c 100644 --- a/dlls/crypt32/base64.c +++ b/dlls/crypt32/base64.c @@ -241,6 +241,63 @@ static BOOL BinaryToBase64A(const BYTE *pbBinary, return ret; }
+static BOOL BinaryToHexRawA(const BYTE *bin, DWORD nbin, DWORD flags, char *str, DWORD *nstr) +{ + static const char hex[] = "0123456789abcdef"; + DWORD needed; + + if (flags & CRYPT_STRING_NOCRLF) + needed = 0; + else if (flags & CRYPT_STRING_NOCR) + needed = 1; + else + needed = 2; + + needed += nbin * 2 + 1; + + if (!str) + { + *nstr = needed; + return TRUE; + } + + if (needed > *nstr && *nstr < 3) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + nbin = min(nbin, (*nstr - 1) / 2); + + while (nbin--) + { + *str++ = hex[(*bin >> 4) & 0xf]; + *str++ = hex[*bin & 0xf]; + bin++; + } + + if (needed > *nstr) + { + *str = 0; + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + if (flags & CRYPT_STRING_NOCR) + { + *str++ = '\n'; + } + else if (!(flags & CRYPT_STRING_NOCRLF)) + { + *str++ = '\r'; + *str++ = '\n'; + } + + *str = 0; + *nstr = needed - 1; + return TRUE; +} + BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) { @@ -271,6 +328,9 @@ BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, case CRYPT_STRING_BASE64X509CRLHEADER: encoder = BinaryToBase64A; break; + case CRYPT_STRING_HEXRAW: + encoder = BinaryToHexRawA; + break; case CRYPT_STRING_HEX: case CRYPT_STRING_HEXASCII: case CRYPT_STRING_HEXADDR: diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c index 0839543f0f0..42252557455 100644 --- a/dlls/crypt32/tests/base64.c +++ b/dlls/crypt32/tests/base64.c @@ -266,6 +266,7 @@ static void test_CryptBinaryToString(void) BYTE input[256 * sizeof(WCHAR)]; DWORD strLen, strLen2, i, j, k; WCHAR *hex, *cmp, *ptr; + char *hex_a, *cmp_a; BOOL ret;
ret = CryptBinaryToStringA(NULL, 0, 0, NULL, NULL); @@ -401,11 +402,17 @@ static void test_CryptBinaryToString(void)
for (i = 0; i < ARRAY_SIZE(flags); i++) { + winetest_push_context("i %lu", i); strLen = 0; ret = CryptBinaryToStringW(input, sizeof(input), CRYPT_STRING_HEXRAW|flags[i], NULL, &strLen); ok(ret, "CryptBinaryToStringW failed: %ld\n", GetLastError()); ok(strLen > 0, "Unexpected string length.\n");
+ strLen = 0; + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW|flags[i], NULL, &strLen); + ok(ret, "failed, error %ld.\n", GetLastError()); + ok(strLen > 0, "Unexpected string length.\n"); + strLen = ~0; ret = CryptBinaryToStringW(input, sizeof(input), CRYPT_STRING_HEXRAW|flags[i], NULL, &strLen); @@ -420,8 +427,11 @@ static void test_CryptBinaryToString(void) ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen2, strLen);
hex = malloc(strLen * sizeof(WCHAR)); + hex_a = malloc(strLen); + memset(hex, 0xcc, strLen * sizeof(WCHAR)); ptr = cmp = malloc(strLen * sizeof(WCHAR)); + cmp_a = malloc(strLen); for (j = 0; j < ARRAY_SIZE(input); j++) { *ptr++ = hexdig[(input[j] >> 4) & 0xf]; @@ -437,6 +447,11 @@ static void test_CryptBinaryToString(void) *ptr++ = '\n'; } *ptr++ = 0; + + for (j = 0; cmp[j]; ++j) + cmp_a[j] = cmp[j]; + cmp_a[j] = 0; + ret = CryptBinaryToStringW(input, sizeof(input), CRYPT_STRING_HEXRAW|flags[i], hex, &strLen); ok(ret, "CryptBinaryToStringW failed: %ld\n", GetLastError()); @@ -444,6 +459,13 @@ static void test_CryptBinaryToString(void) ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen, strLen2); ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "Unexpected value\n");
+ ++strLen; + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW | flags[i], + hex_a, &strLen); + ok(ret, "failed, error %ld.\n", GetLastError()); + ok(strLen == strLen2, "Expected length %ld, got %ld.\n", strLen, strLen2); + ok(!memcmp(hex_a, cmp_a, strLen), "Unexpected value.\n"); + /* adjusts size if buffer too big */ strLen *= 2; ret = CryptBinaryToStringW(input, sizeof(input), CRYPT_STRING_HEXRAW|flags[i], @@ -451,6 +473,12 @@ static void test_CryptBinaryToString(void) ok(ret, "CryptBinaryToStringW failed: %ld\n", GetLastError()); ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen, strLen2);
+ strLen *= 2; + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW|flags[i], + hex_a, &strLen); + ok(ret, "failed, error %ld.\n", GetLastError()); + ok(strLen == strLen2, "Expected length %ld, got %ld.\n", strLen, strLen2); + /* no writes if buffer too small */ strLen /= 2; strLen2 /= 2; @@ -464,8 +492,49 @@ static void test_CryptBinaryToString(void) ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen, strLen2); ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "Unexpected value\n");
+ SetLastError(0xdeadbeef); + memset(hex_a, 0xcc, strLen + 3); + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW | flags[i], + hex_a, &strLen); + ok(!ret && GetLastError() == ERROR_MORE_DATA,"got ret %d, error %lu.\n", ret, GetLastError()); + ok(strLen == strLen2, "Expected length %ld, got %ld.\n", strLen2, strLen); + /* Output consists of the number of full bytes which fit in plus terminating 0. */ + strLen = (strLen - 1) & ~1; + ok(!memcmp(hex_a, cmp_a, strLen), "Unexpected value\n"); + ok(!hex_a[strLen], "got %#x.\n", (unsigned char)hex_a[strLen]); + ok((unsigned char)hex_a[strLen + 1] == 0xcc, "got %#x.\n", (unsigned char)hex_a[strLen + 1]); + + /* Output is not filled if string length is less than 3. */ + strLen = 1; + memset(hex_a, 0xcc, strLen2); + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW | flags[i], + hex_a, &strLen); + ok(strLen == 1, "got %ld.\n", strLen); + ok((unsigned char)hex_a[0] == 0xcc, "got %#x.\n", (unsigned char)hex_a[strLen - 1]); + + strLen = 2; + memset(hex_a, 0xcc, strLen2); + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW | flags[i], + hex_a, &strLen); + ok(strLen == 2, "got %ld.\n", strLen); + ok((unsigned char)hex_a[0] == 0xcc, "got %#x.\n", (unsigned char)hex_a[0]); + ok((unsigned char)hex_a[1] == 0xcc, "got %#x.\n", (unsigned char)hex_a[1]); + + strLen = 3; + memset(hex_a, 0xcc, strLen2); + ret = CryptBinaryToStringA(input, sizeof(input), CRYPT_STRING_HEXRAW | flags[i], + hex_a, &strLen); + ok(strLen == 3, "got %ld.\n", strLen); + ok(hex_a[0] == 0x30, "got %#x.\n", (unsigned char)hex_a[0]); + ok(hex_a[1] == 0x30, "got %#x.\n", (unsigned char)hex_a[1]); + ok(!hex_a[2], "got %#x.\n", (unsigned char)hex_a[2]); + free(hex); + free(hex_a); free(cmp); + free(cmp_a); + + winetest_pop_context(); }
for (k = 0; k < ARRAY_SIZE(sizes); k++)
From: Paul Gofman pgofman@codeweavers.com
--- dlls/crypt32/base64.c | 123 ++++++++++++ dlls/crypt32/tests/base64.c | 386 +++++++++++++++++++++++++++++++++++- 2 files changed, 505 insertions(+), 4 deletions(-)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c index 9523eb1914c..b61ed7ff8cc 100644 --- a/dlls/crypt32/base64.c +++ b/dlls/crypt32/base64.c @@ -943,6 +943,120 @@ static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString, return ret; }
+static BOOL is_hex_string_special_char(WCHAR c) +{ + switch (c) + { + case '-': + case ',': + case ' ': + case '\t': + case '\r': + case '\n': + return TRUE; + + default: + return FALSE; + } +} + +static WCHAR wchar_from_str(BOOL wide, const void **str, DWORD *len) +{ + WCHAR c; + + if (!*len) + return 0; + + --*len; + if (wide) + c = *(*(const WCHAR **)str)++; + else + c = *(*(const char **)str)++; + + return c ? c : 0xffff; +} + +static BYTE digit_from_char(WCHAR c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + c = towlower(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 0xa; + return 0xff; +} + +static LONG string_to_hex(const void* str, BOOL wide, DWORD len, BYTE *hex, DWORD *hex_len, + DWORD *skipped, DWORD *ret_flags) +{ + unsigned int byte_idx = 0; + BYTE d1, d2; + WCHAR c; + + if (!str || !hex_len) + return ERROR_INVALID_PARAMETER; + + if (!len) + len = wide ? wcslen(str) : strlen(str); + + if (wide && !len) + return ERROR_INVALID_PARAMETER; + + if (skipped) + *skipped = 0; + if (ret_flags) + *ret_flags = 0; + + while ((c = wchar_from_str(wide, &str, &len)) && is_hex_string_special_char(c)) + ; + + while ((d1 = digit_from_char(c)) != 0xff) + { + if ((d2 = digit_from_char(wchar_from_str(wide, &str, &len))) == 0xff) + { + if (!hex) + *hex_len = 0; + return ERROR_INVALID_DATA; + } + + if (hex && byte_idx < *hex_len) + hex[byte_idx] = (d1 << 4) | d2; + + ++byte_idx; + + do + { + c = wchar_from_str(wide, &str, &len); + } while (c == '-' || c == ','); + } + + while (c) + { + if (!is_hex_string_special_char(c)) + { + if (!hex) + *hex_len = 0; + return ERROR_INVALID_DATA; + } + c = wchar_from_str(wide, &str, &len); + } + + if (hex && byte_idx > *hex_len) + return ERROR_MORE_DATA; + + if (ret_flags) + *ret_flags = CRYPT_STRING_HEX; + + *hex_len = byte_idx; + + return ERROR_SUCCESS; +} + +static LONG string_to_hexA(const char *str, DWORD len, BYTE *hex, DWORD *hex_len, DWORD *skipped, DWORD *ret_flags) +{ + return string_to_hex(str, FALSE, len, hex, hex_len, skipped, ret_flags); +} + BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) @@ -988,6 +1102,8 @@ BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString, decoder = DecodeAnyA; break; case CRYPT_STRING_HEX: + decoder = string_to_hexA; + break; case CRYPT_STRING_HEXASCII: case CRYPT_STRING_HEXADDR: case CRYPT_STRING_HEXASCIIADDR: @@ -1154,6 +1270,11 @@ static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString, return ret; }
+static LONG string_to_hexW(const WCHAR *str, DWORD len, BYTE *hex, DWORD *hex_len, DWORD *skipped, DWORD *ret_flags) +{ + return string_to_hex(str, TRUE, len, hex, hex_len, skipped, ret_flags); +} + BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags) @@ -1199,6 +1320,8 @@ BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString, decoder = DecodeAnyW; break; case CRYPT_STRING_HEX: + decoder = string_to_hexW; + break; case CRYPT_STRING_HEXASCII: case CRYPT_STRING_HEXADDR: case CRYPT_STRING_HEXASCIIADDR: diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c index 42252557455..e81a57c576d 100644 --- a/dlls/crypt32/tests/base64.c +++ b/dlls/crypt32/tests/base64.c @@ -775,11 +775,145 @@ static const struct BadString badStrings[] = { { "-----BEGIN X509 CRL-----\r\nAA==\r\n", CRYPT_STRING_BASE64X509CRLHEADER }, };
-static void testStringToBinaryA(void) +static BOOL is_hex_string_special_char(WCHAR c) { - BOOL ret; + switch (c) + { + case '-': + case ',': + case ' ': + case '\t': + case '\r': + case '\n': + return TRUE; + + default: + return FALSE; + } +} + +static WCHAR wchar_from_str(BOOL wide, const void **str, DWORD *len) +{ + WCHAR c; + + if (!*len) + return 0; + + --*len; + if (wide) + c = *(*(const WCHAR **)str)++; + else + c = *(*(const char **)str)++; + + return c ? c : 0xffff; +} + +static BYTE digit_from_char(WCHAR c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + c = towlower(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 0xa; + return 0xff; +} + +static LONG string_to_hex(const void* str, BOOL wide, DWORD len, BYTE *hex, DWORD *hex_len, + DWORD *skipped, DWORD *ret_flags) +{ + unsigned int byte_idx = 0; + BYTE d1, d2; + WCHAR c; + + if (!str || !hex_len) + return ERROR_INVALID_PARAMETER; + + if (!len) + len = wide ? wcslen(str) : strlen(str); + + if (wide && !len) + return ERROR_INVALID_PARAMETER; + + if (skipped) + *skipped = 0; + if (ret_flags) + *ret_flags = 0; + + while ((c = wchar_from_str(wide, &str, &len)) && is_hex_string_special_char(c)) + ; + + while ((d1 = digit_from_char(c)) != 0xff) + { + if ((d2 = digit_from_char(wchar_from_str(wide, &str, &len))) == 0xff) + { + if (!hex) + *hex_len = 0; + return ERROR_INVALID_DATA; + } + + if (hex && byte_idx < *hex_len) + hex[byte_idx] = (d1 << 4) | d2; + + ++byte_idx; + + do + { + c = wchar_from_str(wide, &str, &len); + } while (c == '-' || c == ','); + } + + while (c) + { + if (!is_hex_string_special_char(c)) + { + if (!hex) + *hex_len = 0; + return ERROR_INVALID_DATA; + } + c = wchar_from_str(wide, &str, &len); + } + + if (hex && byte_idx > *hex_len) + return ERROR_MORE_DATA; + + if (ret_flags) + *ret_flags = CRYPT_STRING_HEX; + + *hex_len = byte_idx; + + return ERROR_SUCCESS; +} + +static void test_CryptStringToBinary(void) +{ + static const char *string_hex_tests[] = + { + "", + "-", + ",-", + "0", + "00", + "000", + "11220", + "1122q", + "q1122", + " aE\t\n\r\n", + "01-02", + "-,01-02", + "01-02-", + "aa,BB-ff,-,", + "1-2", + "010-02", + "aa,BBff,-,", + "aa,,-BB---ff,-,", + "010203040506070809q", + }; + + DWORD skipped, flags, expected_err, expected_len, expected_skipped, expected_flags; + BYTE buf[8], expected[8]; DWORD bufLen = 0, i; - BYTE buf[8]; + WCHAR str_w[64]; + BOOL ret, wide;
ret = CryptStringToBinaryA(NULL, 0, 0, NULL, NULL, NULL, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, @@ -959,10 +1093,254 @@ static void testStringToBinaryA(void) CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); } + + /* CRYPT_STRING_HEX */ + + ret = CryptStringToBinaryW(L"01", 2, CRYPT_STRING_HEX, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got ret %d, error %lu.\n", ret, GetLastError()); + if (0) + { + /* access violation on Windows. */ + CryptStringToBinaryA("01", 2, CRYPT_STRING_HEX, NULL, NULL, NULL, NULL); + } + + bufLen = 8; + ret = CryptStringToBinaryW(L"0102", 2, CRYPT_STRING_HEX, NULL, &bufLen, NULL, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + ok(bufLen == 1, "got length %lu.\n", bufLen); + + bufLen = 8; + ret = CryptStringToBinaryW(NULL, 0, CRYPT_STRING_HEX, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 8, "got length %lu.\n", bufLen); + + bufLen = 8; + ret = CryptStringToBinaryA(NULL, 0, CRYPT_STRING_HEX, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 8, "got length %lu.\n", bufLen); + + bufLen = 8; + ret = CryptStringToBinaryW(L"0102", 3, CRYPT_STRING_HEX, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(!bufLen, "got length %lu.\n", bufLen); + + bufLen = 8; + buf[0] = 0xcc; + ret = CryptStringToBinaryW(L"0102", 3, CRYPT_STRING_HEX, buf, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 8, "got length %lu.\n", bufLen); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + + bufLen = 8; + buf[0] = 0xcc; + ret = CryptStringToBinaryW(L"0102", 2, CRYPT_STRING_HEX, buf, &bufLen, NULL, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + ok(bufLen == 1, "got length %lu.\n", bufLen); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + + bufLen = 8; + buf[0] = buf[1] = 0xcc; + ret = CryptStringToBinaryA("01\0 02", 4, CRYPT_STRING_HEX, buf, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 8, "got length %lu.\n", bufLen); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + + bufLen = 8; + buf[0] = buf[1] = 0xcc; + ret = CryptStringToBinaryW(L"01\0 02", 4, CRYPT_STRING_HEX, buf, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 8, "got length %lu.\n", bufLen); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + + bufLen = 1; + buf[0] = 0xcc; + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + ret = CryptStringToBinaryW(L"0102", 4, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + ok(!ret && GetLastError() == ERROR_MORE_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 1, "got length %lu.\n", bufLen); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(!flags, "got flags %lu.\n", flags); + ok(!skipped, "got skipped %lu.\n", skipped); + + for (i = 0; i < ARRAY_SIZE(string_hex_tests); ++i) + { + for (wide = 0; wide < 2; ++wide) + { + if (wide) + { + unsigned int j = 0; + + while ((str_w[j] = string_hex_tests[i][j])) + ++j; + } + winetest_push_context("test %lu, %s", i, wide ? debugstr_w(str_w) + : debugstr_a(string_hex_tests[i])); + + expected_len = 0xdeadbeef; + expected_skipped = 0xdeadbeef; + expected_flags = 0xdeadbeef; + expected_err = string_to_hex(wide ? (void *)str_w : (void *)string_hex_tests[i], wide, 0, NULL, + &expected_len, &expected_skipped, &expected_flags); + + bufLen = 0xdeadbeef; + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + SetLastError(0xdeadbeef); + if (wide) + ret = CryptStringToBinaryW(str_w, 0, CRYPT_STRING_HEX, NULL, &bufLen, &skipped, &flags); + else + ret = CryptStringToBinaryA(string_hex_tests[i], 0, CRYPT_STRING_HEX, NULL, &bufLen, &skipped, &flags); + + ok(bufLen == expected_len, "got length %lu.\n", bufLen); + ok(skipped == expected_skipped, "got skipped %lu.\n", skipped); + ok(flags == expected_flags, "got flags %lu.\n", flags); + + if (expected_err) + ok(!ret && GetLastError() == expected_err, "got ret %d, error %lu.\n", ret, GetLastError()); + else + ok(ret, "got error %lu.\n", GetLastError()); + + memset(expected, 0xcc, sizeof(expected)); + expected_len = 8; + expected_skipped = 0xdeadbeef; + expected_flags = 0xdeadbeef; + expected_err = string_to_hex(wide ? (void *)str_w : (void *)string_hex_tests[i], wide, 0, expected, + &expected_len, &expected_skipped, &expected_flags); + + memset(buf, 0xcc, sizeof(buf)); + bufLen = 8; + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + SetLastError(0xdeadbeef); + if (wide) + ret = CryptStringToBinaryW(str_w, 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + else + ret = CryptStringToBinaryA(string_hex_tests[i], 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + + ok(!memcmp(buf, expected, sizeof(buf)), "data does not match, buf[0] %#x, buf[1] %#x.\n", buf[0], buf[1]); + ok(bufLen == expected_len, "got length %lu.\n", bufLen); + if (expected_err) + ok(!ret && GetLastError() == expected_err, "got ret %d, error %lu.\n", ret, GetLastError()); + else + ok(ret, "got error %lu.\n", GetLastError()); + + ok(bufLen == expected_len, "got length %lu.\n", bufLen); + ok(skipped == expected_skipped, "got skipped %lu.\n", skipped); + ok(flags == expected_flags, "got flags %lu.\n", flags); + + winetest_pop_context(); + } + } + + bufLen = 1; + SetLastError(0xdeadbeef); + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + ret = CryptStringToBinaryA("0102", 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + ok(!ret && GetLastError() == ERROR_MORE_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 1, "got length %lu.\n", bufLen); + ok(!skipped, "got skipped %lu.\n", skipped); + ok(!flags, "got flags %lu.\n", flags); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + + bufLen = 1; + SetLastError(0xdeadbeef); + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + ret = CryptStringToBinaryA("0102q", 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 1, "got length %lu.\n", bufLen); + ok(!skipped, "got skipped %lu.\n", skipped); + ok(!flags, "got flags %lu.\n", flags); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + + bufLen = 1; + SetLastError(0xdeadbeef); + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + ret = CryptStringToBinaryW(L"0102q", 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(bufLen == 1, "got length %lu.\n", bufLen); + ok(!skipped, "got skipped %lu.\n", skipped); + ok(!flags, "got flags %lu.\n", flags); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + + bufLen = 1; + SetLastError(0xdeadbeef); + skipped = 0xdeadbeef; + flags = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + ret = CryptStringToBinaryW(L"0102", 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + ok(bufLen == 1, "got length %lu.\n", bufLen); + ok(!ret && GetLastError() == ERROR_MORE_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(buf[0] == 1, "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + + /* It looks like Windows is normalizing Unicode strings in some way which depending on locale may result in + * some invalid characters in 128-255 range being converted into sequences starting with valid hex numbers. + * Just avoiding characters in the 128-255 range in test. */ + for (i = 1; i < 128; ++i) + { + char str_a[16]; + + for (wide = 0; wide < 2; ++wide) + { + if (wide) + { + str_w[0] = i; + wcscpy(str_w + 1, L"00"); + } + else + { + str_a[0] = i; + strcpy(str_a + 1, "00"); + } + + winetest_push_context("char %#lx, %s", i, wide ? debugstr_w(str_w) : debugstr_a(str_a)); + + bufLen = 1; + buf[0] = buf[1] = 0xcc; + SetLastError(0xdeadbeef); + if (wide) + ret = CryptStringToBinaryW(str_w, 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + else + ret = CryptStringToBinaryA(str_a, 0, CRYPT_STRING_HEX, buf, &bufLen, &skipped, &flags); + ok(bufLen == 1, "got length %lu.\n", bufLen); + if (is_hex_string_special_char(i)) + { + ok(ret, "got error %lu.\n", GetLastError()); + ok(!buf[0], "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[1] %#x.\n", buf[1]); + } + else + { + ok(!ret && GetLastError() == ERROR_INVALID_DATA, "got ret %d, error %lu.\n", ret, GetLastError()); + if (isdigit(i) || (tolower(i) >= 'a' && tolower(i) <= 'f')) + { + ok(buf[0] == (digit_from_char(i) << 4), "got buf[0] %#x.\n", buf[0]); + ok(buf[1] == 0xcc, "got buf[0] %#x.\n", buf[1]); + } + else + { + ok(buf[0] == 0xcc, "got buf[0] %#x.\n", buf[0]); + } + } + winetest_pop_context(); + } + } }
START_TEST(base64) { test_CryptBinaryToString(); - testStringToBinaryA(); + test_CryptStringToBinary(); }
Sorry, I didn't know about that bug. Since now this is committed I just put the note on the bug ticket.
Regards, Paul.
On 9/21/22 03:47, Gijs Vermeulen (@gverm) wrote:
Could you add `Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48487%60?
This merge request was approved by Hans Leidekker.